This is Unofficial EPICS BASE Doxygen Site
macCore.c
Go to the documentation of this file.
1 /*************************************************************************\
2 * Copyright (c) 2007 UChicago Argonne LLC, 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 core macro substitution library (macLib)
11  *
12  * The implementation is fairly unsophisticated and linked lists are
13  * used to store macro values. Typically there will will be only a
14  * small number of macros and performance won't be a problem. Special
15  * measures are taken to avoid unnecessary expansion of macros whose
16  * definitions reference other macros. Whenever a macro is created,
17  * modified or deleted, a "dirty" flag is set; this causes a full
18  * expansion of all macros the next time a macro value is read
19  *
20  * Original Author: William Lupton, W. M. Keck Observatory
21  */
22 
23 #include <ctype.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
27 
28 #include "dbDefs.h"
29 #include "errlog.h"
30 #include "dbmf.h"
31 #include "macLib.h"
32 
33 
34 /*** Local structure definitions ***/
35 
36 /*
37  * Entry in linked list of macro definitions
38  */
39 typedef struct mac_entry {
40  ELLNODE node; /* prev and next pointers */
41  char *name; /* entry name */
42  char *type; /* entry type */
43  char *rawval; /* raw (unexpanded) value */
44  char *value; /* expanded macro value */
45  size_t length; /* length of value */
46  int error; /* error expanding value? */
47  int visited; /* ever been visited? */
48  int special; /* special (internal) entry? */
49  int level; /* scoping level */
50 } MAC_ENTRY;
51 
52 
53 /*** Local function prototypes ***/
54 
55 /*
56  * These static functions peform low-level operations on macro entries
57  */
58 static MAC_ENTRY *first ( MAC_HANDLE *handle );
59 static MAC_ENTRY *last ( MAC_HANDLE *handle );
60 static MAC_ENTRY *next ( MAC_ENTRY *entry );
61 static MAC_ENTRY *previous( MAC_ENTRY *entry );
62 
63 static MAC_ENTRY *create( MAC_HANDLE *handle, const char *name, int special );
64 static MAC_ENTRY *lookup( MAC_HANDLE *handle, const char *name, int special );
65 static char *rawval( MAC_HANDLE *handle, MAC_ENTRY *entry, const char *value );
66 static void delete( MAC_HANDLE *handle, MAC_ENTRY *entry );
67 static long expand( MAC_HANDLE *handle );
68 static void trans ( MAC_HANDLE *handle, MAC_ENTRY *entry, int level,
69  const char *term, const char **rawval, char **value,
70  char *valend );
71 static void refer ( MAC_HANDLE *handle, MAC_ENTRY *entry, int level,
72  const char **rawval, char **value, char *valend );
73 
74 static void cpy2val( const char *src, char **value, char *valend );
75 static char *Strdup( const char *string );
76 
77 
78 /*** Constants ***/
79 
80 /*
81  * Magic number for validating context.
82  */
83 #define MAC_MAGIC 0xbadcafe /* ...sells sub-standard coffee? */
84 
85 /*
86  * Flag bits
87  */
88 #define FLAG_SUPPRESS_WARNINGS 0x1
89 #define FLAG_USE_ENVIRONMENT 0x80
90 
91 
92 /*** Library routines ***/
93 
94 /*
95  * Create a new macro substitution context and return an opaque handle
96  * associated with the new context. Also optionally load an initial set
97  * of macro definitions
98  */
99 long /* 0 = OK; <0 = ERROR */
100 epicsStdCall macCreateHandle(
101  MAC_HANDLE **pHandle, /* address of variable to receive pointer */
102  /* to new macro substitution context */
103 
104  const char * pairs[] ) /* pointer to NULL-terminated array of */
105  /* {name,value} pair strings; a NULL */
106  /* value implies undefined; a NULL */
107  /* argument implies no macros */
108 {
109  MAC_HANDLE *handle; /* pointer to macro substitution context */
110 
111  /* ensure NULL handle pointer is returned on error */
112  *pHandle = NULL;
113 
114  /* allocate macro substitution context */
115  handle = ( MAC_HANDLE * ) dbmfMalloc( sizeof( MAC_HANDLE ) );
116  if ( handle == NULL ) {
117  errlogPrintf( "macCreateHandle: failed to allocate context\n" );
118  return -1;
119  }
120 
121  /* initialize context */
122  handle->magic = MAC_MAGIC;
123  handle->dirty = FALSE;
124  handle->level = 0;
125  handle->debug = 0;
126  handle->flags = 0;
127  ellInit( &handle->list );
128 
129  /* use environment variables if so specified */
130  if (pairs && pairs[0] && !strcmp(pairs[0],"") && pairs[1] && !strcmp(pairs[1],"environ") && !pairs[3]) {
131  handle->flags |= FLAG_USE_ENVIRONMENT;
132  }
133  else {
134  /* if supplied, load macro definitions */
135  for ( ; pairs && pairs[0]; pairs += 2 ) {
136  if ( macPutValue( handle, pairs[0], pairs[1] ) < 0 ) {
137  dbmfFree( handle );
138  return -1;
139  }
140  }
141  }
142 
143  /* set returned handle pointer */
144  *pHandle = handle;
145 
146  return 0;
147 }
148 
149 /*
150  * Turn on/off suppression of printed warnings from macLib calls
151  * for the given handle
152  */
153 void
154 epicsStdCall macSuppressWarning(
155  MAC_HANDLE *handle, /* opaque handle */
156  int suppress /* 0 means issue, 1 means suppress */
157 )
158 {
159  if ( handle && handle->magic == MAC_MAGIC ) {
160  handle->flags = (handle->flags & ~FLAG_SUPPRESS_WARNINGS) |
161  (suppress ? FLAG_SUPPRESS_WARNINGS : 0);
162  }
163 }
164 
165 /*
166  * Expand a string that may contain macro references and return the
167  * expanded string
168  *
169  * This is a very basic and powerful routine. It's basically a wrapper
170  * around the the translation "engine" trans()
171  */
172 long /* strlen(dest), <0 if any macros are */
173  /* undefined */
174 epicsStdCall macExpandString(
175  MAC_HANDLE *handle, /* opaque handle */
176 
177  const char *src, /* source string */
178 
179  char *dest, /* destination string */
180 
181  long capacity ) /* capacity of destination buffer (dest) */
182 {
184  const char *s;
185  char *d;
186  long length;
187 
188  /* check handle */
189  if ( handle == NULL || handle->magic != MAC_MAGIC ) {
190  errlogPrintf( "macExpandString: NULL or invalid handle\n" );
191  return -1;
192  }
193 
194  /* debug output */
195  if ( handle->debug & 1 )
196  printf( "macExpandString( %s, capacity = %ld )\n", src, capacity );
197 
198  /* Check size */
199  if (capacity <= 1)
200  return -1;
201 
202  /* expand raw values if necessary */
203  if ( expand( handle ) < 0 )
204  errlogPrintf( "macExpandString: failed to expand raw values\n" );
205 
206  /* fill in necessary fields in fake macro entry structure */
207  entry.name = (char *) src;
208  entry.type = "string";
209  entry.error = FALSE;
210 
211  /* expand the string */
212  s = src;
213  d = dest;
214  *d = '\0';
215  trans( handle, &entry, 0, "", &s, &d, d + capacity - 1 );
216 
217  /* return +/- #chars copied depending on successful expansion */
218  length = d - dest;
219  length = ( entry.error ) ? -length : length;
220 
221  /* debug output */
222  if ( handle->debug & 1 )
223  printf( "macExpandString() -> %ld\n", length );
224 
225  return length;
226 }
227 
228 /*
229  * Define the value of a macro. A NULL value deletes the macro if it
230  * already existed
231  */
232 long /* strlen(value) */
233 epicsStdCall macPutValue(
234  MAC_HANDLE *handle, /* opaque handle */
235 
236  const char *name, /* macro name */
237 
238  const char *value ) /* macro value */
239 {
240  MAC_ENTRY *entry; /* pointer to this macro's entry structure */
241 
242  /* check handle */
243  if ( handle == NULL || handle->magic != MAC_MAGIC ) {
244  errlogPrintf( "macPutValue: NULL or invalid handle\n" );
245  return -1;
246  }
247 
248  if ( handle->debug & 1 )
249  printf( "macPutValue( %s, %s )\n", name, value ? value : "NULL" );
250 
251  /* handle NULL value case: if name was found, delete entry (may be
252  several entries at different scoping levels) */
253  if ( value == NULL ) {
254  /*
255  * FIXME: shouldn't be able to delete entries from lower scopes
256  * NOTE: when this is changed, this functionality of removing
257  * a macro from all scopes will still be needed by iocshEnvClear
258  */
259  while ( ( entry = lookup( handle, name, FALSE ) ) != NULL ) {
260  int done = strcmp(entry->type, "environment variable") == 0;
261  delete( handle, entry );
262 
263  if (done)
264  break;
265  }
266 
267  return 0;
268  }
269 
270  /* look up macro name */
271  entry = lookup( handle, name, FALSE );
272 
273  /* new entry must be created if macro doesn't exist or if it only
274  exists at a lower scoping level */
275  if ( entry == NULL || entry->level < handle->level ) {
276  entry = create( handle, name, FALSE );
277  if ( entry == NULL ) {
278  errlogPrintf( "macPutValue: failed to create macro %s = %s\n",
279  name, value );
280  return -1;
281  } else {
282  entry->type = "macro";
283  }
284  }
285 
286  /* copy raw value */
287  if ( rawval( handle, entry, value ) == NULL ) {
288  errlogPrintf( "macPutValue: failed to copy macro %s = %s\n",
289  name, value ) ;
290  return -1;
291  }
292 
293  /* return length of value */
294  return strlen( value );
295 }
296 
297 /*
298  * Return the value of a macro
299  */
300 long /* strlen(value), <0 if undefined */
301 epicsStdCall macGetValue(
302  MAC_HANDLE *handle, /* opaque handle */
303 
304  const char *name, /* macro name or reference */
305 
306  char *value, /* string to receive macro value or name */
307  /* argument if macro is undefined */
308 
309  long capacity ) /* capacity of destination buffer (value) */
310 {
311  MAC_ENTRY *entry; /* pointer to this macro's entry structure */
312  long length; /* number of characters returned */
313 
314  /* check handle */
315  if ( handle == NULL || handle->magic != MAC_MAGIC ) {
316  errlogPrintf( "macGetValue: NULL or invalid handle\n" );
317  return -1;
318  }
319 
320  /* debug output */
321  if ( handle->debug & 1 )
322  printf( "macGetValue( %s )\n", name );
323 
324  /* look up macro name */
325  entry = lookup( handle, name, FALSE );
326 
327  /* if capacity <= 1 or VALUE == NULL just return -1 / 0 for undefined /
328  defined macro */
329  if ( capacity <= 1 || value == NULL ) {
330  return ( entry == NULL ) ? -1 : 0;
331  }
332 
333  /* if not found, copy name to value and return minus #chars copied */
334  if ( entry == NULL ) {
335  strncpy( value, name, capacity );
336  return ( value[capacity-1] == '\0' ) ? - (long) strlen( name ) : -capacity;
337  }
338 
339  /* expand raw values if necessary; if fail (can only fail because of
340  memory allocation failure), return same as if not found */
341  if ( expand( handle ) < 0 ) {
342  errlogPrintf( "macGetValue: failed to expand raw values\n" );
343  strncpy( value, name, capacity );
344  return ( value[capacity-1] == '\0' ) ? - (long) strlen( name ) : -capacity;
345  }
346 
347  /* copy value and return +/- #chars copied depending on successful
348  expansion */
349  strncpy( value, entry->value, capacity );
350  length = ( value[capacity-1] == '\0' ) ? entry->length : capacity;
351 
352  return ( entry->error ) ? -length : length;
353 }
354 
355 /*
356  * Free up all storage associated with and delete a macro substitution
357  * context
358  */
359 long /* 0 = OK; <0 = ERROR */
360 epicsStdCall macDeleteHandle(
361  MAC_HANDLE *handle ) /* opaque handle */
362 {
363  MAC_ENTRY *entry, *nextEntry;
364 
365  /* check handle */
366  if ( handle == NULL || handle->magic != MAC_MAGIC ) {
367  errlogPrintf( "macDeleteHandle: NULL or invalid handle\n" );
368  return -1;
369  }
370 
371  /* debug output */
372  if ( handle->debug & 1 )
373  printf( "macDeleteHandle()\n" );
374 
375  /* delete all entries */
376  for ( entry = first( handle ); entry != NULL; entry = nextEntry ) {
377  nextEntry = next( entry );
378  delete( handle, entry );
379  }
380 
381  /* clear magic field and free context structure */
382  handle->magic = 0;
383  dbmfFree( handle );
384 
385  return 0;
386 }
387 
388 /*
389  * Mark the start of a new scoping level
390  */
391 long /* 0 = OK; <0 = ERROR */
392 epicsStdCall macPushScope(
393  MAC_HANDLE *handle ) /* opaque handle */
394 {
395  MAC_ENTRY *entry;
396 
397  /* check handle */
398  if ( handle == NULL || handle->magic != MAC_MAGIC ) {
399  errlogPrintf( "macPushScope: NULL or invalid handle\n" );
400  return -1;
401  }
402 
403  /* debug output */
404  if ( handle->debug & 1 )
405  printf( "macPushScope()\n" );
406 
407  /* increment scoping level */
408  handle->level++;
409 
410  /* create new "special" entry of name "<scope>" */
411  entry = create( handle, "<scope>", TRUE );
412  if ( entry == NULL ) {
413  handle->level--;
414  errlogPrintf( "macPushScope: failed to push scope\n" );
415  return -1;
416  } else {
417  entry->type = "scope marker";
418  }
419 
420  return 0;
421 }
422 
423 /*
424  * Pop all macros defined since the last call to macPushScope()
425  */
426 long /* 0 = OK; <0 = ERROR */
427 epicsStdCall macPopScope(
428  MAC_HANDLE *handle ) /* opaque handle */
429 {
430  MAC_ENTRY *entry, *nextEntry;
431 
432  /* check handle */
433  if ( handle == NULL || handle->magic != MAC_MAGIC ) {
434  errlogPrintf( "macPopScope: NULL or invalid handle\n" );
435  return -1;
436  }
437 
438  /* debug output */
439  if ( handle->debug & 1 )
440  printf( "macPopScope()\n" );
441 
442  /* check scoping level isn't already zero */
443  if ( handle->level == 0 ) {
444  errlogPrintf( "macPopScope: no scope to pop\n" );
445  return -1;
446  }
447 
448  /* look up most recent scope entry */
449  entry = lookup( handle, "<scope>", TRUE );
450  if ( entry == NULL ) {
451  errlogPrintf( "macPopScope: no scope to pop\n" );
452  return -1;
453  }
454 
455  /* delete scope entry and all macros defined since it */
456  for ( ; entry != NULL; entry = nextEntry ) {
457  nextEntry = next( entry );
458  delete( handle, entry );
459  }
460 
461  /* decrement scoping level */
462  handle->level--;
463 
464  return 0;
465 }
466 
467 /*
468  * Report macro details to standard output
469  */
470 long /* 0 = OK; <0 = ERROR */
471 epicsStdCall macReportMacros(
472  MAC_HANDLE *handle ) /* opaque handle */
473 {
474  const char *format = "%-1s %-16s %-16s %s\n";
475  MAC_ENTRY *entry;
476 
477  /* check handle */
478  if ( handle == NULL || handle->magic != MAC_MAGIC ) {
479  errlogPrintf( "macReportMacros: NULL or invalid handle\n" );
480  return -1;
481  }
482 
483  /* expand raw values if necessary; report but ignore failure */
484  if ( expand( handle ) < 0 )
485  errlogPrintf( "macGetValue: failed to expand raw values\n" );
486 
487  /* loop through macros, reporting names and values */
488  printf( format, "e", "name", "rawval", "value" );
489  printf( format, "-", "----", "------", "-----" );
490  for ( entry = first( handle ); entry != NULL; entry = next( entry ) ) {
491 
492  /* differentiate between "special" (scope marker) and ordinary
493  entries */
494  if ( entry->special )
495  printf( format, "s", "----", "------", "-----" );
496  else
497  printf( format, entry->error ? "*" : " ", entry->name,
498  entry->rawval ? entry->rawval : "",
499  entry->value ? entry->value : "");
500  }
501 
502  return 0;
503 }
504 
505 /******************** beginning of static functions ********************/
506 
507 /*
508  * Return pointer to first macro entry (could be preprocessor macro)
509  */
510 static MAC_ENTRY *first( MAC_HANDLE *handle )
511 {
512  return ( MAC_ENTRY * ) ellFirst( &handle->list );
513 }
514 
515 /*
516  * Return pointer to last macro entry (could be preprocessor macro)
517  */
518 static MAC_ENTRY *last( MAC_HANDLE *handle )
519 {
520  return ( MAC_ENTRY * ) ellLast( &handle->list );
521 }
522 
523 /*
524  * Return pointer to next macro entry (could be preprocessor macro)
525  */
526 static MAC_ENTRY *next( MAC_ENTRY *entry )
527 {
528  return ( MAC_ENTRY * ) ellNext( ( ELLNODE * ) entry );
529 }
530 
531 /*
532  * Return pointer to previous macro entry (could be preprocessor macro)
533  */
534 static MAC_ENTRY *previous( MAC_ENTRY *entry )
535 {
536  return ( MAC_ENTRY * ) ellPrevious( ( ELLNODE * ) entry );
537 }
538 
539 /*
540  * Create new macro entry (can assume it doesn't exist)
541  */
542 static MAC_ENTRY *create( MAC_HANDLE *handle, const char *name, int special )
543 {
544  ELLLIST *list = &handle->list;
545  MAC_ENTRY *entry = ( MAC_ENTRY * ) dbmfMalloc( sizeof( MAC_ENTRY ) );
546 
547  if ( entry != NULL ) {
548  entry->name = Strdup( name );
549  if ( entry->name == NULL ) {
550  dbmfFree( entry );
551  entry = NULL;
552  }
553  else {
554  entry->type = "";
555  entry->rawval = NULL;
556  entry->value = NULL;
557  entry->length = 0;
558  entry->error = FALSE;
559  entry->visited = FALSE;
560  entry->special = special;
561  entry->level = handle->level;
562 
563  ellAdd( list, ( ELLNODE * ) entry );
564  }
565  }
566 
567  return entry;
568 }
569 
570 /*
571  * Look up macro entry with matching "special" attribute by name
572  */
573 static MAC_ENTRY *lookup( MAC_HANDLE *handle, const char *name, int special )
574 {
575  MAC_ENTRY *entry;
576 
577  if ( handle->debug & 2 )
578  printf( "lookup-> level = %d, name = %s, special = %d\n",
579  handle->level, name, special );
580 
581  /* search backwards so scoping works */
582  for ( entry = last( handle ); entry != NULL; entry = previous( entry ) ) {
583  if ( entry->special != special )
584  continue;
585  if ( strcmp( name, entry->name ) == 0 )
586  break;
587  }
588  if ( (special == FALSE) && (entry == NULL) &&
589  (handle->flags & FLAG_USE_ENVIRONMENT) ) {
590  char *value = getenv(name);
591  if (value) {
592  entry = create( handle, name, FALSE );
593  if ( entry ) {
594  entry->type = "environment variable";
595  if ( rawval( handle, entry, value ) == NULL )
596  entry = NULL;
597  }
598  }
599  }
600 
601  if ( handle->debug & 2 )
602  printf( "<-lookup level = %d, name = %s, result = %p\n",
603  handle->level, name, entry );
604 
605  return entry;
606 }
607 
608 /*
609  * Copy raw value to macro entry
610  */
611 static char *rawval( MAC_HANDLE *handle, MAC_ENTRY *entry, const char *value )
612 {
613  if ( entry->rawval != NULL )
614  dbmfFree( entry->rawval );
615  entry->rawval = Strdup( value );
616 
617  handle->dirty = TRUE;
618 
619  return entry->rawval;
620 }
621 
622 /*
623  * Delete a macro entry; requires re-expansion of macro values since this
624  * macro may be referenced by another one
625  */
626 static void delete( MAC_HANDLE *handle, MAC_ENTRY *entry )
627 {
628  ELLLIST *list = &handle->list;
629 
630  ellDelete( list, ( ELLNODE * ) entry );
631 
632  dbmfFree( entry->name );
633  if ( entry->rawval != NULL )
634  dbmfFree( entry->rawval );
635  if ( entry->value != NULL )
636  free( entry->value );
637  dbmfFree( entry );
638 
639  handle->dirty = TRUE;
640 }
641 
642 /*
643  * Expand macro definitions (expensive but done very infrequently)
644  */
645 static long expand( MAC_HANDLE *handle )
646 {
647  MAC_ENTRY *entry;
648  const char *rawval;
649  char *value;
650 
651  if ( !handle->dirty )
652  return 0;
653 
654  for ( entry = first( handle ); entry != NULL; entry = next( entry ) ) {
655 
656  if ( handle->debug & 2 )
657  printf( "\nexpand %s = %s\n", entry->name,
658  entry->rawval ? entry->rawval : "" );
659 
660  if ( entry->value == NULL ) {
661  if ( ( entry->value = malloc( MAC_SIZE + 1 ) ) == NULL ) {
662  return -1;
663  }
664  }
665 
666  /* start at level 1 so quotes and escapes will be removed from
667  expanded value */
668  rawval = entry->rawval;
669  value = entry->value;
670  *value = '\0';
671  entry->error = FALSE;
672  trans( handle, entry, 1, "", &rawval, &value, entry->value + MAC_SIZE );
673  entry->length = value - entry->value;
674  entry->value[MAC_SIZE] = '\0';
675  }
676 
677  handle->dirty = FALSE;
678 
679  return 0;
680 }
681 
682 /*
683  * Translate raw macro value (recursive). This is by far the most complicated
684  * of the macro routines and calls itself recursively both to translate any
685  * macros referenced in the name and to translate the resulting name
686  */
687 static void trans( MAC_HANDLE *handle, MAC_ENTRY *entry, int level,
688  const char *term, const char **rawval, char **value,
689  char *valend )
690 {
691  char quote;
692  const char *r;
693  char *v;
694  int discard;
695  int macRef;
696 
697  /* return immediately if raw value is NULL */
698  if ( *rawval == NULL ) return;
699 
700  /* discard quotes and escapes if level is > 0 (i.e. if these aren't
701  the user's quotes and escapes) */
702  discard = ( level > 0 );
703 
704  /* debug output */
705  if ( handle->debug & 2 )
706  printf( "trans-> entry = %p, level = %d, capacity = %u, discard = %s, "
707  "rawval = %s\n", entry, level, (unsigned int)(valend - *value), discard ? "T" : "F", *rawval );
708 
709  /* initially not in quotes */
710  quote = 0;
711 
712  /* scan characters until hit terminator or end of string */
713  for ( r = *rawval, v = *value; strchr( term, *r ) == NULL; r++ ) {
714 
715  /* handle quoted characters (quotes are discarded if in name) */
716  if ( quote ) {
717  if ( *r == quote ) {
718  quote = 0;
719  if ( discard ) continue;
720  }
721  }
722  else if ( *r == '"' || *r == '\'' ) {
723  quote = *r;
724  if ( discard ) continue;
725  }
726 
727  /* macro reference if '$' followed by '(' or '{' */
728  macRef = ( *r == '$' &&
729  *( r + 1 ) != '\0' &&
730  strchr( "({", *( r + 1 ) ) != NULL );
731 
732  /* macros are not expanded in single quotes */
733  if ( macRef && quote != '\'' ) {
734  /* Handle macro reference */
735  refer ( handle, entry, level, &r, &v, valend );
736  }
737 
738  else {
739  /* handle escaped characters (escape is discarded if in name) */
740  if ( *r == '\\' && *( r + 1 ) != '\0' ) {
741  if ( v < valend && !discard ) *v++ = '\\';
742  if ( v < valend ) *v++ = *++r;
743  }
744 
745  /* copy character to output */
746  else {
747  if ( v < valend ) *v++ = *r;
748  }
749 
750  /* ensure string remains properly terminated */
751  if ( v <= valend ) *v = '\0';
752  }
753  }
754 
755  /* debug output */
756  if ( handle->debug & 2 )
757  printf( "<-trans level = %d, length = %4u, value = %s\n",
758  level, (unsigned int)(v - *value), *value );
759 
760  /* update pointers to next characters to scan in raw value and to fill
761  in in output value (if at end of input, step back so terminator is
762  still there to be seen) */
763  *rawval = ( *r == '\0' ) ? r - 1 : r;
764  *value = v;
765 
766  return;
767 }
768 
769 /*
770  * Expand a macro reference, handling default values and defining scoped
771  * macros as encountered. This code used to part of trans(), but was
772  * pulled out for ease of understanding.
773  */
774 static void refer ( MAC_HANDLE *handle, MAC_ENTRY *entry, int level,
775  const char **rawval, char **value, char *valend )
776 {
777  const char *r = *rawval;
778  char *v = *value;
779  char refname[MAC_SIZE + 1] = {'\0'};
780  char *rn = refname;
781  MAC_ENTRY *refentry;
782  const char *defval = NULL;
783  const char *macEnd;
784  const char *errval = NULL;
785  int pop = FALSE;
786 
787  /* debug output */
788  if ( handle->debug & 2 )
789  printf( "refer-> entry = %p, level = %d, capacity = %u, rawval = %s\n",
790  entry, level, (unsigned int)(valend - *value), *rawval );
791 
792  /* step over '$(' or '${' */
793  r++;
794  macEnd = ( *r == '(' ) ? "=,)" : "=,}";
795  r++;
796 
797  /* translate name (may contain macro references); truncated
798  quietly if too long but always guaranteed zero-terminated */
799  trans( handle, entry, level + 1, macEnd, &r, &rn, rn + MAC_SIZE );
800  refname[MAC_SIZE] = '\0';
801 
802  /* Is there a default value? */
803  if ( *r == '=' ) {
804  MAC_ENTRY dflt;
805  int flags = handle->flags;
806  handle->flags |= FLAG_SUPPRESS_WARNINGS;
807 
808  /* store its location in case we need it */
809  defval = ++r;
810 
811  /* Find the end, discarding its value */
812  dflt.name = refname;
813  dflt.type = "default value";
814  dflt.error = FALSE;
815  trans( handle, &dflt, level + 1, macEnd+1, &r, &v, v);
816 
817  handle->flags = flags;
818  }
819 
820  /* extract and set values for any scoped macros */
821  if ( *r == ',' ) {
822  MAC_ENTRY subs;
823  int flags = handle->flags;
824  handle->flags |= FLAG_SUPPRESS_WARNINGS;
825 
826  subs.type = "scoped macro";
827  subs.error = FALSE;
828 
829  macPushScope( handle );
830  pop = TRUE;
831 
832  while ( *r == ',' ) {
833  char subname[MAC_SIZE + 1] = {'\0'};
834  char subval[MAC_SIZE + 1] = {'\0'};
835  char *sn = subname;
836  char *sv = subval;
837 
838  /* translate the macro name */
839  ++r;
840  subs.name = refname;
841 
842  trans( handle, &subs, level + 1, macEnd, &r, &sn, sn + MAC_SIZE );
843  subname[MAC_SIZE] = '\0';
844 
845  /* If it has a value, translate that and assign it */
846  if ( *r == '=' ) {
847  ++r;
848  subs.name = subname;
849 
850  trans( handle, &subs, level + 1, macEnd+1, &r, &sv,
851  sv + MAC_SIZE);
852  subval[MAC_SIZE] = '\0';
853 
854  macPutValue( handle, subname, subval );
855  handle->dirty = TRUE; /* re-expand with new macro values */
856  }
857  }
858 
859  handle->flags = flags;
860  }
861 
862  /* Now we can look up the translated name */
863  refentry = lookup( handle, refname, FALSE );
864 
865  if ( refentry ) {
866  if ( !refentry->visited ) {
867  /* reference is good, use it */
868  if ( !handle->dirty ) {
869  /* copy the already-expanded value, merge any error status */
870  cpy2val( refentry->value, &v, valend );
871  entry->error = entry->error || refentry->error;
872  } else {
873  /* translate raw value */
874  const char *rv = refentry->rawval;
875  refentry->visited = TRUE;
876  trans( handle, entry, level + 1, "", &rv, &v, valend );
877  refentry->visited = FALSE;
878  }
879  goto cleanup;
880  }
881  /* reference is recursive */
882  entry->error = TRUE;
883  errval = ",recursive)";
884  if ( (handle->flags & FLAG_SUPPRESS_WARNINGS) == 0 ) {
885  errlogPrintf( "macLib: %s %s is recursive (expanding %s %s)\n",
886  entry->type, entry->name,
887  refentry->type, refentry->name );
888  }
889  } else {
890  /* no macro found by this name */
891  if ( defval ) {
892  /* there was a default value, translate that instead */
893  trans( handle, entry, level + 1, macEnd+1, &defval, &v, valend );
894  goto cleanup;
895  }
896  entry->error = TRUE;
897  errval = ",undefined)";
898  if ( (handle->flags & FLAG_SUPPRESS_WARNINGS) == 0 ) {
899  errlogPrintf( "macLib: macro %s is undefined (expanding %s %s)\n",
900  refname, entry->type, entry->name );
901  }
902  }
903 
904  /* Bad reference, insert either $(name,<error>) or $(name) */
905  if ( v < valend ) *v++ = '$';
906  if ( v < valend ) *v++ = '(';
907  cpy2val( refname, &v, valend );
908  if (handle->flags & FLAG_SUPPRESS_WARNINGS) {
909  if ( v < valend ) *v++ = ')';
910  *v = '\0';
911  }
912  else
913  cpy2val( errval, &v, valend );
914 
915 cleanup:
916  if (pop) {
917  macPopScope( handle );
918  }
919 
920  /* debug output */
921  if ( handle->debug & 2 )
922  printf( "<-refer level = %d, length = %4u, value = %s\n",
923  level, (unsigned int)(v - *value), *value );
924 
925  *rawval = r;
926  *value = v;
927  return;
928 }
929 
930 /*
931  * Copy a string, honoring the 'end of destination string' pointer
932  * Returns with **value pointing to the '\0' terminator
933  */
934 static void cpy2val(const char *src, char **value, char *valend)
935 {
936  char *v = *value;
937  while ((v < valend) && (*v = *src++)) { v++; }
938  *v = '\0';
939  *value = v;
940 }
941 
942 /*
943  * strdup() implementation which uses our own memory allocator
944  */
945 static char *Strdup(const char *string )
946 {
947  char *copy = dbmfMalloc( strlen( string ) + 1 );
948 
949  if ( copy != NULL )
950  strcpy( copy, string );
951 
952  return copy;
953 }
954 
long magic
magic number (used for authentication)
Definition: macLib.h:43
Definition: link.h:174
#define FALSE
Definition: dbDefs.h:32
char * type
Definition: macCore.c:42
#define quote(v)
#define printf
Definition: epicsStdio.h:41
long epicsStdCall macGetValue(MAC_HANDLE *handle, const char *name, char *value, long capacity)
Returns the value of a macro.
Definition: macCore.c:301
char * value
Definition: macCore.c:44
#define NULL
Definition: catime.c:38
char * name
Definition: macCore.c:41
#define FLAG_SUPPRESS_WARNINGS
Definition: macCore.c:88
Miscellaneous macro definitions.
A library to manage storage that is allocated and quickly freed.
int special
Definition: macCore.c:48
#define ellPrevious(PNODE)
Find the previous node in list.
Definition: ellLib.h:104
void copy(PVValueArray< T > &pvFrom, size_t fromOffset, size_t fromStride, PVValueArray< T > &pvTo, size_t toOffset, size_t toStride, size_t count)
Copy a subarray from one scalar array to another.
long epicsStdCall macExpandString(MAC_HANDLE *handle, const char *src, char *dest, long capacity)
Expand a string which may contain macro references.
Definition: macCore.c:174
int level
Definition: macCore.c:49
void ellAdd(ELLLIST *pList, ELLNODE *pNode)
Adds a node to the end of a list.
Definition: ellLib.c:24
#define ellNext(PNODE)
Find the next node in list.
Definition: ellLib.h:99
int flags
operating mode flags
Definition: macLib.h:48
Macro substitution context, for use by macLib routines only.
Definition: macLib.h:42
struct mac_entry MAC_ENTRY
void epicsStdCall macSuppressWarning(MAC_HANDLE *handle, int suppress)
Disable or enable warning messages.
Definition: macCore.c:154
void dbmfFree(void *mem)
Free the memory allocated by dbmfMalloc.
Definition: dbmf.c:175
int dirty
values need expanding from raw values?
Definition: macLib.h:44
Definition: macCore.c:39
#define ellLast(PLIST)
Find the last node in list.
Definition: ellLib.h:94
int errlogPrintf(const char *pFormat,...)
Definition: errlog.c:105
int error
Definition: macCore.c:46
List node type.
Definition: ellLib.h:45
#define MAC_MAGIC
Definition: macCore.c:83
long epicsStdCall macReportMacros(MAC_HANDLE *handle)
Reports details of current definitions.
Definition: macCore.c:471
long epicsStdCall macDeleteHandle(MAC_HANDLE *handle)
Marks a handle invalid, and frees all storage associated with it.
Definition: macCore.c:360
long epicsStdCall macPopScope(MAC_HANDLE *handle)
Retrieve the last pushed scope (like stack operations)
Definition: macCore.c:427
ELLLIST list
macro name / value list
Definition: macLib.h:47
int debug
debugging level
Definition: macLib.h:46
long epicsStdCall macCreateHandle(MAC_HANDLE **pHandle, const char *pairs[])
Creates a new macro substitution context.
Definition: macCore.c:100
void done(int k)
Definition: antelope.c:77
#define TRUE
Definition: dbDefs.h:27
#define ellInit(PLIST)
Initialize a list type.
Definition: ellLib.h:76
int level
scoping level
Definition: macLib.h:45
#define MAC_SIZE
Maximum size of a macro name or value.
Definition: macLib.h:36
Text macro substitution routines.
size_t length
Definition: macCore.c:45
int visited
Definition: macCore.c:47
long epicsStdCall macPutValue(MAC_HANDLE *handle, const char *name, const char *value)
Sets the value of a specific macro.
Definition: macCore.c:233
List header type.
Definition: ellLib.h:56
void ellDelete(ELLLIST *pList, ELLNODE *pNode)
Deletes a node from a list.
Definition: ellLib.c:75
char * rawval
Definition: macCore.c:43
void * dbmfMalloc(size_t size)
Allocate memory.
Definition: dbmf.c:97
#define FLAG_USE_ENVIRONMENT
Definition: macCore.c:89
ELLNODE node
Definition: macCore.c:40
long epicsStdCall macPushScope(MAC_HANDLE *handle)
Marks the start of a new scoping level.
Definition: macCore.c:392
#define ellFirst(PLIST)
Find the first node in list.
Definition: ellLib.h:89