esrf

Beamline Instrument Software Support
SPEC Macro documentation: [ Macro Index | BCU Home ]


#%TITLE% STLIST.MAC
#
#%NAME%
#  STLIST.MAC - Macros for list handling
#
#%OVERVIEW%
#  This macro file provides a set of functions to handle lists of elements
#  with optional parameters.%BR%
#  A list is data structure stored in an associative array that is composed 
#  of a number of elements. Each element is a string that occupies a certain 
#  position in the list, numeric elements are not allowed.
#  An element can be referenced by it name (string) or by its position in 
#  the list (number).%BR%
#  Each element in the list can have an arbitrary number of parameters 
#  associated to it.
#  Each parameter has a name (a string) and a value (a number or a string).%BR%
#  This macro set provides functions to initialise the list and add elements 
#  and parameters to it. It also provides functions to retrieve information
#  from the list.%BR%
#  %BR%
#  When retrieving information it may be convenient to use shortcuts to 
#  access directily the content of the list instead of going through the 
#  macro functions. In this case there is no error checking but performance 
#  is considerably increased.%BR%
#  if LIST[] is the associative array that holds the list, the following 
#  expressions can be used:
#%UL%
#%LI% (LIST[0])  evaluates to the number of elements in the list.
#%LI% (elem in LIST)  is true if the string elem is a valid element.
#%LI% (LIST[n])  returns the element in position n (>0).
#%LI% (LIST[elem][par]) returns the value of the parameter par of element elem.
#%XUL%
#
#%ATTENTION%
# This macro set overrides some macros previously included in %B%stlocal.mac%B%.
#%EXAMPLE%
#%DL%
#%DT%list_add(mylist, \"el1\")
#%DD% Adds the element "el1" to the list stored in the associative array
#     mylist.

#%DT%list_add(mylist, \"el1\", \"par1\")
#%DD% Adds the parameter "par1" to the item "el1".
#%DT%list_setpar(mylist, \"el1\", \"par1\", 5312)
#%DD% Sets the parameter "par1" of the item "el1" to 5312.
#%DT%list_list(mylist)
#%DD% Prints on the screen the current content of the list mylist.
#%DD%
#%XDL%
#
#%END%


#%UU% <list>
#%MDESC%
#  This macro checks if <list> is an associative array and if not
#  initialises it to be ready to contain a list. It does nothing if
#  <list> was already initialised.
#
def list_test 'if (!(whatis("$1") & 0x01000000)) {$1[0]=0}'

#%UU% <list>
#%MDESC%
#  This macro clears and iniatilises <list> to contain a list. The information
#  contained (if any) is lost.
#
def list_init '{
   local i
   if (whatis("$1") & 0x01000000) {
      for (i in $1) 
         delete $1[i]
   }
   $1[0]=0
}'

#%UU% (<list>)
#%MDESC%
#  This function returns the number of elements contained in the list
#  specified as parameter. <list> must be an associative array (old-style
#  array), if not the function returns -1.
#
def list_n(list) '{
   local wl
   wl = whatis("list")
   if (wl) {
      if (wl & 0x01000000){
         return(list[0]+0)
      }else
         return (-1)
   } else
      return(0)
}'

#%UU% (<list>, <item>)
#%MDESC%
#  This function checks if <item> is contained in <list> and returns its
#  current position. If <item> is not in the list the function returns
#  zero.%BR% 
#  <list> must be an associative array (old-style array), if not the
#  function returns -1.%BR%
#  <item> is either a string or a number. If a number is used it refers to
#  the position of the element in the list.
#
def list_check(list, item) '{
   local i

   if (list_n(list) < 0)
      return(-1)

   if (item + 0 == item) {
      i = (item < 0) ? 0 : int(item)
   } else {
      i = (item in list)? list[item] : 0
   }
   if (i <= list[0])
      return(i)
   else
      return(0)
}'

#%UU% (<list>, <item>)
#%MDESC%
#  This function adds a new element to the list. The element is specified
#  by the string <item>. If such element already exists it is moved to the
#  end of the list but no new elements are appended.%BR%
#  The function returns the position in the list of the element recently 
#  added. This value is always the size of the list.%BR%
#  <item> cannot be a numeric value.%BR%
#  If <item> is a number, the element is not added and the function
#  returns 0. If <list> is not a valid list the function returns -1.
#
def list_add(list, item) '{
   local N

   if (item == (item+0))
      return(0)

   if (item in list) {
      for (N = list[item]; N < list[0]; N++) {
         list[N] = list[N+1]
         list[list[N+1]] = N
      }
      list[list[0]] = item
      list[item] = list[0]
   } else {
      list[++list[0]] = item
      list[item] = list[0]
   }
   return(list[0])
}'

#%UU% (<list>, <string> [,<separator>])
#%MDESC%
#  This function adds new elements to <list> in the same way than
#  %B%list_add%B% but several elements can be appended in the same function
#  call. The element specifiers are
#  obtained by spliting <string> by means of the %B%spec%B% function split(). 
#  If no <separator> is specified space characters are used as delimiters.%BR%
#  The function returns the number of elements added to the list. If an error
#  happens -1 is returned and <list> is not modified. 
def list_splitadd(list, str, sep) '{
   local i larr[] llist[] n

   if (list_n(list) < 0)
      return(-1)

   if (whatis("sep") & 0x08000000)
      n = split(str, larr)
   else
      n = split(str, larr, sep)

   for (i = 0; i < n; i++) if (list_add(llist, larr[i]) <= 0) return(-1)
   for (i = 0; i < n; i++) list_add(list, larr[i])
   return(llist[0])
}'

#%UU% (<list>, <item>, <param>, <value>)
#%MDESC%
#  This function sets the value of a parameter for a particular element in
#  a list.%BR%
#  <list> and <item> must follow the rules explained for the
#  function %BR%list_check()%BR%.
#  <param> is a string that specifies the parameter, if a number is used it is
#  internally converted to string. <value> can be a number or a string. %BR%
#  If no error is found, the function returns 1, otherwise it returns -1.
#
def list_setpar(list, item, param, value) '{
   local N parlist

   if ((N = list_check(list, item)) > 0) {
      item = list[N]
      parid = item "\034" param
      list[parid] = value
      return(1)
   } else
      return(-1)
}'

#%UU% (<list>, <item>, <param_list>)
#%MDESC%
#  This function creates an auxiliary list that contains all the parameters
#  associated to a given element in a list.%BR%
#  <list> and <item> must follow the rules explained for the
#  function %BR%list_check()%BR%.
#  The auxiliary list is created in <param_list> that must be also an 
#  associative array as <list>. When the function returns, the elements of 
#  <param_list> are the identifiers of all the parameters associated to the
#  element <item> in <list>. Each element of <param_list> has a single
#  parameter called `value' that is set to the actual value of the
#  corresponding parameter in <list>.%BR%
#  The function returns the total number of parameters associated to <item>,
#  i.e. the total number of elements in <param_list>, or -1 if an error
#  happens.
#
def list_getparlist(list, item, parlist) '{
   local N npar i len parid

   if ((N = list_check(list, item)) <= 0)
      return(-1)

   list_init parlist

   parid = list[N] "\034"
   len = length(parid)
   for (i in list) {
      if (length(i) >= len && substr(i, 1, len) == parid) {
         N = list_add(parlist, substr(i, len+1))
         list_setpar(parlist, N, "value", list[i])
      }
   }
   return(parlist[0])
}'

#%UU% (<list>, <item>, <param>)
#%MDESC%
#  This function returns the value of a particular parameter associated to
#  an element of a list. 
#  <list>, <item> and <param> must follow the rules explained for the
#  function %BR%list_setpar()%BR%.
#  If an error is found the function returns -1.
#
def list_getpar(list, item, param) '{
   local par
   
   if ((N = list_check(list, item)) <= 0)
      return(-1)

   par = list[N] "\034" param
   return((par in list)? list[par] : -1)
}'

#%UU% (<list>, <item> [, <param>])
#%MDESC%
#  This function removes a parameter associated to an element of a list.
#  If <param> is not especified, all the parameters associated with the
#  element <item> are removed.
# 
def list_removepar(list, item, param) '{
   local parid len i

   parid =  item "\034"
   len = length(parid)
   if (whatis("param") & 0x08000000) {
      for (i in list)
         if (length(i) >= len && substr(i, 1, len) == parid)
            delete list[i]
   } else {
      parid = parid param
      if (parid in list)
         delete list[parid]
      else
         return(-1)
   }
   return(0)
}'

#%UU% (<list>, <item>)
#%MDESC%
#  This function deletes a particular element in a list and returns its
#  position in the list before deletion.%BR%
#  If <item> is not in the list the function returns zero.
#  <list> must be an associative array (old-style array), if not the
#  function returns -1.%BR%
#
def list_remove(list, item) '{
   local N i len

   list_removepar(list, item)
   if ((N = list_check(list, item)) > 0){
      item = list[N]
      for (i=N; i<list[0]; i++) {
         list[i] = list[i+1]
         list[list[i+1]] = i
      }
      delete list[i]
      delete list[item]
      list[0] = list[0] - 1
   }
   return(N)
}'

#%UU% (<list>, <item>)
#%MDESC%
#  This function returns -1 if the element <item> is not included in <list>
#  or if an error happens. If <item> is a valid element the function returns
#  the element identifier (that may be different from <item> if a number is
#  used).%BR%
#
def list_item(list, item) '{
   local N
   if ((N = list_check(list, item)) > 0)
      return(list[N])
   else
      return(-1)
}'

#%UU% (<list>)
#%MDESC%
#  This function prints on the screen all the elements in a list along with
#  the associated parameters. It is intended for debugging purposes.%BR%
#  It returns the number of eleemnts in the list or -1 if an error happens.
#
def list_list(list) '{
   local N i j parlist[]

   if ((N = list_n(list)) < 0){
      return(-1)
   }
   if (N == 0) 
      print "List is empty"
   else {
      printf("List contains %d element%s:\n", N, N>1?"s":"")
      parlist[0]=0
      for (i=1; i<=N; i++) {
         printf("%3d - %10s  ", i, list[i])
         if (npar = list_getparlist(list, list[i], parlist) <= 0)
            print "No parameters"
         else {
            for (j = 1; j <= parlist[0]; j++)
               printf("%s:<%s> ", parlist[j], list_getpar(parlist, j, "value"))
            print
         }
      }
   }
   return(N)
}'
#%MACROS%
#%DEPENDENCIES%
#  No dependencies
#%AUTHOR% P. Fajardo, (Original 3/96 in stlocal.mac). %BR%
#  $Revision: 1.1 $ / $Date: 2008/11/17 12:39:27 $
#%TOC%