This is Unofficial EPICS BASE Doxygen Site
macUtil.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2002 The University of Chicago, as Operator of Argonne
3 * National Laboratory.
4 * Copyright (c) 2002 The Regents of the University of California, as
5 * Operator of Los Alamos National Laboratory.
6 * EPICS BASE is distributed subject to a Software License Agreement found
7 * in file LICENSE that is included with this distribution.
8 \*************************************************************************/
9 /*
10  * Implementation of utility macro substitution library (macLib)
11  *
12  * William Lupton, W. M. Keck Observatory
13  */
14 
15 #include <ctype.h>
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <string.h>
19 
20 #include "dbDefs.h"
21 #include "errlog.h"
22 #include "macLib.h"
23 
24 /*
25  * Parse macros definitions in "a=xxx,b=yyy" format and convert them to
26  * a contiguously allocated array pointers to names and values, and the
27  * name and value strings, terminated with two NULL pointers. Quotes
28  * and escapes are honored but only removed from macro names (not
29  * values)
30  */
31 long /* #defns encountered; <0 = ERROR */
32 epicsStdCall macParseDefns(
33  MAC_HANDLE *handle, /* opaque handle; can be NULL if default */
34  /* special characters are to be used */
35 
36  const char *defns, /* macro definitions in "a=xxx,b=yyy" */
37  /* format */
38 
39  char **pairs[] ) /* address of variable to receive pointer */
40  /* to NULL-terminated array of {name, */
41  /* value} pair strings; all storage is */
42  /* allocated contiguously */
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 }
246 
247 /*
248  * Install an array of name / value pairs as macro definitions. The
249  * array should have an even number of elements followed by at least
250  * one (preferably two) NULL pointers
251  */
252 long /* #macros defined; <0 = ERROR */
253 epicsStdCall macInstallMacros(
254  MAC_HANDLE *handle, /* opaque handle */
255 
256  char *pairs[] ) /* pointer to NULL-terminated array of */
257  /* {name,value} pair strings; a NULL */
258  /* value implies undefined; a NULL */
259  /* argument implies no macros */
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 }
283 
long epicsStdCall macInstallMacros(MAC_HANDLE *handle, char *pairs[])
Install set of {name, value} pairs as definitions.
Definition: macUtil.c:253
#define FALSE
Definition: dbDefs.h:32
#define quote(v)
int i
Definition: scan.c:967
#define printf
Definition: epicsStdio.h:41
long epicsStdCall macParseDefns(MAC_HANDLE *handle, const char *defns, char **pairs[])
Parse macro definitions into an array of {name, value} pairs.
Definition: macUtil.c:32
#define NULL
Definition: catime.c:38
Miscellaneous macro definitions.
Macro substitution context, for use by macLib routines only.
Definition: macLib.h:42
int errlogPrintf(const char *pFormat,...)
Definition: errlog.c:105
int debug
debugging level
Definition: macLib.h:46
#define TRUE
Definition: dbDefs.h:27
Text macro substitution routines.
long epicsStdCall macPutValue(MAC_HANDLE *handle, const char *name, const char *value)
Sets the value of a specific macro.
Definition: macCore.c:233