This is Unofficial EPICS BASE Doxygen Site
macUtil.c File Reference
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "dbDefs.h"
#include "errlog.h"
#include "macLib.h"
+ Include dependency graph for macUtil.c:

Go to the source code of this file.

Functions

long epicsStdCall macParseDefns (MAC_HANDLE *handle, const char *defns, char **pairs[])
 Parse macro definitions into an array of {name, value} pairs. More...
 
long epicsStdCall macInstallMacros (MAC_HANDLE *handle, char *pairs[])
 Install set of {name, value} pairs as definitions. More...
 

Function Documentation

long epicsStdCall macInstallMacros ( MAC_HANDLE handle,
char *  pairs[] 
)

Install set of {name, value} pairs as definitions.

Returns
Number of macros defined; <0 = ERROR

This takes an array of pairs as defined above and installs them as definitions by calling macPutValue(). The pairs array is terminated by a NULL pointer.

Parameters
handleopaque handle
pairspointer to NULL-terminated array of {name,value} pair strings; a NULL value implies undefined; a NULL argument implies no macros

Definition at line 253 of file macUtil.c.

260 {
261  int n;
262  char **p;
263 
264  /* debug output */
265  if ( handle->debug & 1 )
266  printf( "macInstallMacros( %s, %s, ... )\n",
267  pairs && pairs[0] ? pairs[0] : "NULL",
268  pairs && pairs[1] ? pairs[1] : "NULL" );
269 
270  /* go through array defining macros */
271  for ( n = 0, p = pairs; p != NULL && p[0] != NULL; n++, p += 2 ) {
272  if ( macPutValue( handle, p[0], p[1] ) < 0 )
273  return -1;
274  }
275 
276  /* debug output */
277  if ( handle->debug & 1 )
278  printf( "macInstallMacros() -> %d\n", n );
279 
280  /* return number of macros defined */
281  return n;
282 }
#define printf
Definition: epicsStdio.h:41
#define NULL
Definition: catime.c:38
int debug
debugging level
Definition: macLib.h:46
long epicsStdCall macPutValue(MAC_HANDLE *handle, const char *name, const char *value)
Sets the value of a specific macro.
Definition: macCore.c:233
long epicsStdCall macParseDefns ( MAC_HANDLE handle,
const char *  defns,
char **  pairs[] 
)

Parse macro definitions into an array of {name, value} pairs.

Returns
Number of macros found; <0 = ERROR

This takes a set of macro definitions in "a=xxx,b=yyy" format and converts them into an array of pointers to character strings which are, in order, "first name", "first value", "second name", "second value" etc. The array is terminated with two NULL pointers and all storage is allocated contiguously so that it can be freed with a single call to free().

This routine is independent of any handle and provides a generally useful service which may be used elsewhere. Any macro references in values are not expanded at this point since the referenced macros may be defined or redefined before the macro actually has to be translated.

Shell-style escapes and quotes are supported, as are things like "A=B,B=$(C$(A)),CA=CA,CB=CB" (sets B to "CB"). White space is significant within values but ignored elsewhere (i.e. surrounding "=" and "," characters).

The function returns the number of definitions encountered, or -1 if the supplied string is invalid.

Parameters
handleopaque handle; may be NULL if debug messages are not required.
defnsmacro definitions in "a=xxx,b=yyy" format
pairsaddress of variable to receive pointer to NULL-terminated array of {name, value} pair strings; all storage is allocated contiguously

Definition at line 32 of file macUtil.c.

43 {
44  static const size_t altNumMax = 4;
45  size_t numMax;
46  int i;
47  int num;
48  int quote;
49  int escape;
50  size_t nbytes;
51  const char **ptr;
52  const char **end;
53  int *del;
54  char *memCp, **memCpp;
55  const char *c;
56  char *s, *d, **p;
57  enum { preName, inName, preValue, inValue } state;
58 
59  /* debug output */
60  if ( handle && (handle->debug & 1) )
61  printf( "macParseDefns( %s )\n", defns );
62 
63  /* allocate temporary pointer arrays; in worst case they need to have
64  as many entries as the length of the defns string */
65  numMax = strlen( defns );
66  if ( numMax < altNumMax )
67  numMax = altNumMax;
68  ptr = (const char **) calloc( numMax, sizeof( char * ) );
69  end = (const char **) calloc( numMax, sizeof( char * ) );
70  del = (int *) calloc( numMax, sizeof( int ) );
71  if ( ptr == NULL || end == NULL || del == NULL ) goto error;
72 
73  /* go through definitions, noting pointers to starts and ends of macro
74  names and values; honor quotes and escapes; ignore white space
75  around assignment and separator characters */
76  num = 0;
77  del[0] = FALSE;
78  quote = 0;
79  state = preName;
80  for ( c = (const char *) defns; *c != '\0'; c++ ) {
81 
82  /* handle quotes */
83  if ( quote )
84  quote = ( *c == quote ) ? 0 : quote;
85  else if ( *c == '\'' || *c == '"' )
86  quote = *c;
87 
88  /* handle escapes (pointer incremented below) */
89  escape = ( *c == '\\' && *( c + 1 ) != '\0' );
90 
91  switch ( state ) {
92  case preName:
93  if ( !quote && !escape && ( isspace( (int) *c ) || *c == ',' ) ) break;
94  ptr[num] = c;
95  state = inName;
96  /* fall through (may be empty name) */
97 
98  case inName:
99  if ( quote || escape || ( *c != '=' && *c != ',' ) ) break;
100  end[num] = c;
101  while ( end[num] > ptr[num] && isspace( (int) *( end[num] - 1 ) ) )
102  end[num]--;
103  num++;
104  del[num] = FALSE;
105  state = preValue;
106  if ( *c != ',' ) break;
107  del[num] = TRUE;
108  /* fall through (','; will delete) */
109 
110  case preValue:
111  if ( !quote && !escape && isspace( (int) *c ) ) break;
112  ptr[num] = c;
113  state = inValue;
114  /* fall through (may be empty value) */
115 
116  case inValue:
117  if ( quote || escape || *c != ',' ) break;
118  end[num] = c;
119  while ( end[num] > ptr[num] && isspace( (int) *( end[num] - 1 ) ) )
120  end[num]--;
121  num++;
122  del[num] = FALSE;
123  state = preName;
124  break;
125  }
126 
127  /* if this was escape, increment pointer now (couldn't do
128  before because could have ignored escape at start of name
129  or value) */
130  if ( escape ) c++;
131  }
132 
133  /* tidy up from state at end of string */
134  switch ( state ) {
135  case preName:
136  break;
137  case inName:
138  end[num] = c;
139  while ( end[num] > ptr[num] && isspace( (int) *( end[num] - 1 ) ) )
140  end[num]--;
141  num++;
142  del[num] = TRUE;
143  case preValue:
144  ptr[num] = c;
145  case inValue:
146  end[num] = c;
147  while ( end[num] > ptr[num] && isspace( (int) *( end[num] - 1 ) ) )
148  end[num]--;
149  num++;
150  del[num] = FALSE;
151  }
152 
153  /* debug output */
154  if ( handle != NULL && handle->debug & 4 )
155  for ( i = 0; i < num; i += 2 )
156  printf( "[%ld] %.*s = [%ld] %.*s (%s) (%s)\n",
157  (long) (end[i+0] - ptr[i+0]), (int) (end[i+0] - ptr[i+0]), ptr[i+0],
158  (long) (end[i+1] - ptr[i+1]), (int) (end[i+1] - ptr[i+1]), ptr[i+1],
159  del[i+0] ? "del" : "nodel",
160  del[i+1] ? "del" : "nodel" );
161 
162  /* calculate how much memory to allocate: pointers followed by
163  strings */
164  nbytes = ( num + 2 ) * sizeof( char * );
165  for ( i = 0; i < num; i++ )
166  nbytes += end[i] - ptr[i] + 1;
167 
168  /* allocate memory and set returned pairs pointer */
169  memCp = malloc( nbytes );
170  if ( memCp == NULL ) goto error;
171  memCpp = ( char ** ) memCp;
172  *pairs = memCpp;
173 
174  /* copy pointers and strings (memCpp accesses the pointer section
175  and memCp accesses the string section) */
176  memCp += ( num + 2 ) * sizeof( char * );
177  for ( i = 0; i < num; i++ ) {
178 
179  /* if no '=' followed the name, macro will be deleted */
180  if ( del[i] )
181  *memCpp++ = NULL;
182  else
183  *memCpp++ = memCp;
184 
185  /* copy value regardless of the above */
186  strncpy( memCp, (const char *) ptr[i], end[i] - ptr[i] );
187  memCp += end[i] - ptr[i];
188  *memCp++ = '\0';
189  }
190 
191  /* add two NULL pointers */
192  *memCpp++ = NULL;
193  *memCpp++ = NULL;
194 
195  /* remove quotes and escapes from names in place (unlike values, they
196  will not be re-parsed) */
197  for ( p = *pairs; *p != NULL; p += 2 ) {
198  quote = 0;
199  for ( s = d = *p; *s != '\0'; s++ ) {
200 
201  /* quotes are not copied */
202  if ( quote ) {
203  if ( *s == quote ) {
204  quote = 0;
205  continue;
206  }
207  }
208  else if ( *s == '\'' || *s == '"' ) {
209  quote = *s;
210  continue;
211  }
212 
213  /* escapes are not copied but next character is */
214  if ( *s == '\\' && *( s + 1 ) != '\0' )
215  s++;
216 
217  /* others are copied */
218  *d++ = *s;
219  }
220 
221  /* need to terminate destination */
222  *d++ = '\0';
223  }
224 
225  /* free workspace */
226  free( ( void * ) ptr );
227  free( ( void * ) end );
228  free( ( char * ) del );
229 
230  /* debug output */
231  if ( handle != NULL && handle->debug & 1 )
232  printf( "macParseDefns() -> %d\n", num / 2 );
233 
234  /* success exit; return number of definitions */
235  return num / 2;
236 
237  /* error exit */
238 error:
239  errlogPrintf( "macParseDefns: failed to allocate memory\n" );
240  if ( ptr != NULL ) free( ( void * ) ptr );
241  if ( end != NULL ) free( ( void * ) end );
242  if ( del != NULL ) free( ( char * ) del );
243  *pairs = NULL;
244  return -1;
245 }
#define FALSE
Definition: dbDefs.h:32
#define quote(v)
int i
Definition: scan.c:967
#define printf
Definition: epicsStdio.h:41
#define NULL
Definition: catime.c:38
int errlogPrintf(const char *pFormat,...)
Definition: errlog.c:105
int debug
debugging level
Definition: macLib.h:46
#define TRUE
Definition: dbDefs.h:27