Axe the rpmsq debug code which was never getting built anyway
[platform/upstream/rpm.git] / rpmio / macro.c
1 /** \ingroup rpmrc rpmio
2  * \file rpmio/macro.c
3  */
4
5 #include "system.h"
6 #include <stdarg.h>
7 #ifdef HAVE_GETOPT_H
8 #include <getopt.h>
9 #else
10 extern char *optarg;
11 extern int optind;
12 #endif
13
14 #if !defined(isblank)
15 #define isblank(_c)     ((_c) == ' ' || (_c) == '\t')
16 #endif
17 #define iseol(_c)       ((_c) == '\n' || (_c) == '\r')
18
19 #define STREQ(_t, _f, _fn)      ((_fn) == (sizeof(_t)-1) && rstreqn((_t), (_f), (_fn)))
20
21 #define MACROBUFSIZ (BUFSIZ * 2)
22
23 #include <rpm/rpmio.h>
24 #include <rpm/rpmstring.h>
25 #include <rpm/rpmfileutil.h>
26 #include <rpm/rpmurl.h>
27 #include <rpm/rpmlog.h>
28 #include <rpm/rpmmacro.h>
29 #include <rpm/argv.h>
30
31 #ifdef  WITH_LUA
32 #include "rpmio/rpmlua.h"
33 #endif
34
35 #include "debug.h"
36
37 /*! The structure used to store a macro. */
38 struct rpmMacroEntry_s {
39     struct rpmMacroEntry_s *prev;/*!< Macro entry stack. */
40     char *name;         /*!< Macro name. */
41     char *opts;         /*!< Macro parameters (a la getopt) */
42     char *body;         /*!< Macro body. */
43     int used;           /*!< No. of expansions. */
44     int level;          /*!< Scoping level. */
45 };
46
47 /*! The structure used to store the set of macros in a context. */
48 struct rpmMacroContext_s {
49     rpmMacroEntry *macroTable;  /*!< Macro entry table for context. */
50     int macrosAllocated;/*!< No. of allocated macros. */
51     int firstFree;      /*!< No. of macros. */
52 };
53
54
55 static struct rpmMacroContext_s rpmGlobalMacroContext_s;
56 rpmMacroContext rpmGlobalMacroContext = &rpmGlobalMacroContext_s;
57
58 static struct rpmMacroContext_s rpmCLIMacroContext_s;
59 rpmMacroContext rpmCLIMacroContext = &rpmCLIMacroContext_s;
60
61 /**
62  * Macro expansion state.
63  */
64 typedef struct MacroBuf_s {
65     char * buf;                 /*!< Expansion buffer. */
66     size_t tpos;                /*!< Current position in expansion buffer */
67     size_t nb;                  /*!< No. bytes remaining in expansion buffer. */
68     int depth;                  /*!< Current expansion depth. */
69     int macro_trace;            /*!< Pre-print macro to expand? */
70     int expand_trace;           /*!< Post-print macro expansion? */
71     rpmMacroContext mc;
72 } * MacroBuf;
73
74 #define _MAX_MACRO_DEPTH        16
75 static int max_macro_depth = _MAX_MACRO_DEPTH;
76
77 #define _PRINT_MACRO_TRACE      0
78 static int print_macro_trace = _PRINT_MACRO_TRACE;
79
80 #define _PRINT_EXPAND_TRACE     0
81 static int print_expand_trace = _PRINT_EXPAND_TRACE;
82
83 #define MACRO_CHUNK_SIZE        16
84
85 /* forward ref */
86 static int expandMacro(MacroBuf mb, const char *src, size_t slen);
87
88 /* =============================================================== */
89
90 /**
91  * Compare macro entries by name (qsort/bsearch).
92  * @param ap            1st macro entry
93  * @param bp            2nd macro entry
94  * @return              result of comparison
95  */
96 static int
97 compareMacroName(const void * ap, const void * bp)
98 {
99     rpmMacroEntry ame = *((const rpmMacroEntry *)ap);
100     rpmMacroEntry bme = *((const rpmMacroEntry *)bp);
101
102     if (ame == NULL && bme == NULL)
103         return 0;
104     if (ame == NULL)
105         return 1;
106     if (bme == NULL)
107         return -1;
108     return strcmp(ame->name, bme->name);
109 }
110
111 /**
112  * Enlarge macro table.
113  * @param mc            macro context
114  */
115 static void
116 expandMacroTable(rpmMacroContext mc)
117 {
118     if (mc->macroTable == NULL) {
119         mc->macrosAllocated = MACRO_CHUNK_SIZE;
120         mc->macroTable = (rpmMacroEntry *)
121             xmalloc(sizeof(*(mc->macroTable)) * mc->macrosAllocated);
122         mc->firstFree = 0;
123     } else {
124         mc->macrosAllocated += MACRO_CHUNK_SIZE;
125         mc->macroTable = (rpmMacroEntry *)
126             xrealloc(mc->macroTable, sizeof(*(mc->macroTable)) *
127                         mc->macrosAllocated);
128     }
129     memset(&mc->macroTable[mc->firstFree], 0, MACRO_CHUNK_SIZE * sizeof(*(mc->macroTable)));
130 }
131
132 /**
133  * Sort entries in macro table.
134  * @param mc            macro context
135  */
136 static void
137 sortMacroTable(rpmMacroContext mc)
138 {
139     int i;
140
141     if (mc == NULL || mc->macroTable == NULL)
142         return;
143
144     qsort(mc->macroTable, mc->firstFree, sizeof(*(mc->macroTable)),
145                 compareMacroName);
146
147     /* Empty pointers are now at end of table. Reset first free index. */
148     for (i = 0; i < mc->firstFree; i++) {
149         if (mc->macroTable[i] != NULL)
150             continue;
151         mc->firstFree = i;
152         break;
153     }
154 }
155
156 void
157 rpmDumpMacroTable(rpmMacroContext mc, FILE * fp)
158 {
159     int nempty = 0;
160     int nactive = 0;
161
162     if (mc == NULL) mc = rpmGlobalMacroContext;
163     if (fp == NULL) fp = stderr;
164     
165     fprintf(fp, "========================\n");
166     if (mc->macroTable != NULL) {
167         int i;
168         for (i = 0; i < mc->firstFree; i++) {
169             rpmMacroEntry me;
170             if ((me = mc->macroTable[i]) == NULL) {
171                 /* XXX this should never happen */
172                 nempty++;
173                 continue;
174             }
175             fprintf(fp, "%3d%c %s", me->level,
176                         (me->used > 0 ? '=' : ':'), me->name);
177             if (me->opts && *me->opts)
178                     fprintf(fp, "(%s)", me->opts);
179             if (me->body && *me->body)
180                     fprintf(fp, "\t%s", me->body);
181             fprintf(fp, "\n");
182             nactive++;
183         }
184     }
185     fprintf(fp, _("======================== active %d empty %d\n"),
186                 nactive, nempty);
187 }
188
189 /**
190  * Find entry in macro table.
191  * @param mc            macro context
192  * @param name          macro name
193  * @param namelen       no. of bytes
194  * @return              address of slot in macro table with name (or NULL)
195  */
196 static rpmMacroEntry *
197 findEntry(rpmMacroContext mc, const char * name, size_t namelen)
198 {
199     rpmMacroEntry key, *ret;
200     struct rpmMacroEntry_s keybuf;
201     char namebuf[namelen+1];
202     const char *mname = name;
203
204     if (mc == NULL) mc = rpmGlobalMacroContext;
205     if (mc->macroTable == NULL || mc->firstFree == 0)
206         return NULL;
207
208     if (namelen > 0) {
209         strncpy(namebuf, name, namelen);
210         namebuf[namelen] = '\0';
211         mname = namebuf;
212     }
213     
214     key = &keybuf;
215     memset(key, 0, sizeof(*key));
216     key->name = (char *)mname;
217     ret = (rpmMacroEntry *) bsearch(&key, mc->macroTable, mc->firstFree,
218                         sizeof(*(mc->macroTable)), compareMacroName);
219     /* XXX TODO: find 1st empty slot and return that */
220     return ret;
221 }
222
223 /* =============================================================== */
224
225 /**
226  * fgets(3) analogue that reads \ continuations. Last newline always trimmed.
227  * @param buf           input buffer
228  * @param size          inbut buffer size (bytes)
229  * @param fd            file handle
230  * @return              buffer, or NULL on end-of-file
231  */
232 static char *
233 rdcl(char * buf, size_t size, FILE *f)
234 {
235     char *q = buf - 1;          /* initialize just before buffer. */
236     size_t nb = 0;
237     size_t nread = 0;
238     int pc = 0, bc = 0;
239     char *p = buf;
240
241     if (f != NULL)
242     do {
243         *(++q) = '\0';                  /* terminate and move forward. */
244         if (fgets(q, size, f) == NULL)  /* read next line. */
245             break;
246         nb = strlen(q);
247         nread += nb;                    /* trim trailing \r and \n */
248         for (q += nb - 1; nb > 0 && iseol(*q); q--)
249             nb--;
250         for (; p <= q; p++) {
251             switch (*p) {
252                 case '\\':
253                     switch (*(p+1)) {
254                         case '\0': break;
255                         default: p++; break;
256                     }
257                     break;
258                 case '%':
259                     switch (*(p+1)) {
260                         case '{': p++, bc++; break;
261                         case '(': p++, pc++; break;
262                         case '%': p++; break;
263                     }
264                     break;
265                 case '{': if (bc > 0) bc++; break;
266                 case '}': if (bc > 0) bc--; break;
267                 case '(': if (pc > 0) pc++; break;
268                 case ')': if (pc > 0) pc--; break;
269             }
270         }
271         if (nb == 0 || (*q != '\\' && !bc && !pc) || *(q+1) == '\0') {
272             *(++q) = '\0';              /* trim trailing \r, \n */
273             break;
274         }
275         q++; p++; nb++;                 /* copy newline too */
276         size -= nb;
277         if (*q == '\r')                 /* XXX avoid \r madness */
278             *q = '\n';
279     } while (size > 0);
280     return (nread > 0 ? buf : NULL);
281 }
282
283 /**
284  * Return text between pl and matching pr characters.
285  * @param p             start of text
286  * @param pl            left char, i.e. '[', '(', '{', etc.
287  * @param pr            right char, i.e. ']', ')', '}', etc.
288  * @return              address of last char before pr (or NULL)
289  */
290 static const char *
291 matchchar(const char * p, char pl, char pr)
292 {
293     int lvl = 0;
294     char c;
295
296     while ((c = *p++) != '\0') {
297         if (c == '\\') {                /* Ignore escaped chars */
298             p++;
299             continue;
300         }
301         if (c == pr) {
302             if (--lvl <= 0)     return --p;
303         } else if (c == pl)
304             lvl++;
305     }
306     return (const char *)NULL;
307 }
308
309 /**
310  * Pre-print macro expression to be expanded.
311  * @param mb            macro expansion state
312  * @param s             current expansion string
313  * @param se            end of string
314  */
315 static void
316 printMacro(MacroBuf mb, const char * s, const char * se)
317 {
318     const char *senl;
319     const char *ellipsis;
320     int choplen;
321
322     if (s >= se) {      /* XXX just in case */
323         fprintf(stderr, _("%3d>%*s(empty)"), mb->depth,
324                 (2 * mb->depth + 1), "");
325         return;
326     }
327
328     if (s[-1] == '{')
329         s--;
330
331     /* Print only to first end-of-line (or end-of-string). */
332     for (senl = se; *senl && !iseol(*senl); senl++)
333         {};
334
335     /* Limit trailing non-trace output */
336     choplen = 61 - (2 * mb->depth);
337     if ((senl - s) > choplen) {
338         senl = s + choplen;
339         ellipsis = "...";
340     } else
341         ellipsis = "";
342
343     /* Substitute caret at end-of-macro position */
344     fprintf(stderr, "%3d>%*s%%%.*s^", mb->depth,
345         (2 * mb->depth + 1), "", (int)(se - s), s);
346     if (se[1] != '\0' && (senl - (se+1)) > 0)
347         fprintf(stderr, "%-.*s%s", (int)(senl - (se+1)), se+1, ellipsis);
348     fprintf(stderr, "\n");
349 }
350
351 /**
352  * Post-print expanded macro expression.
353  * @param mb            macro expansion state
354  * @param t             current expansion string result
355  * @param te            end of string
356  */
357 static void
358 printExpansion(MacroBuf mb, const char * t, const char * te)
359 {
360     const char *ellipsis;
361     int choplen;
362
363     if (!(te > t)) {
364         rpmlog(RPMLOG_DEBUG, _("%3d<%*s(empty)\n"), mb->depth, (2 * mb->depth + 1), "");
365         return;
366     }
367
368     /* Shorten output which contains newlines */
369     while (te > t && iseol(te[-1]))
370         te--;
371     ellipsis = "";
372     if (mb->depth > 0) {
373         const char *tenl;
374
375         /* Skip to last line of expansion */
376         while ((tenl = strchr(t, '\n')) && tenl < te)
377             t = ++tenl;
378
379         /* Limit expand output */
380         choplen = 61 - (2 * mb->depth);
381         if ((te - t) > choplen) {
382             te = t + choplen;
383             ellipsis = "...";
384         }
385     }
386
387     rpmlog(RPMLOG_DEBUG,"%3d<%*s", mb->depth, (2 * mb->depth + 1), "");
388     if (te > t)
389         rpmlog(RPMLOG_DEBUG, "%.*s%s", (int)(te - t), t, ellipsis);
390     rpmlog(RPMLOG_DEBUG, "\n");
391 }
392
393 #define SKIPBLANK(_s, _c)       \
394         while (((_c) = *(_s)) && isblank(_c)) \
395                 (_s)++;         \
396
397 #define SKIPNONBLANK(_s, _c)    \
398         while (((_c) = *(_s)) && !(isblank(_c) || iseol(_c))) \
399                 (_s)++;         \
400
401 #define COPYNAME(_ne, _s, _c)   \
402     {   SKIPBLANK(_s,_c);       \
403         while(((_c) = *(_s)) && (risalnum(_c) || (_c) == '_')) \
404                 *(_ne)++ = *(_s)++; \
405         *(_ne) = '\0';          \
406     }
407
408 #define COPYOPTS(_oe, _s, _c)   \
409     { \
410         while(((_c) = *(_s)) && (_c) != ')') \
411                 *(_oe)++ = *(_s)++; \
412         *(_oe) = '\0';          \
413     }
414
415 /**
416  * Macro-expand string src, return result in dynamically allocated buffer.
417  * @param mb            macro expansion state
418  * @param src           string to expand
419  * @param slen          input string length (or 0 for strlen())
420  * @retval target       pointer to expanded string (malloced)
421  * @return              result of expansion
422  */
423 static int
424 expandThis(MacroBuf mb, const char * src, size_t slen, char **target)
425 {
426     struct MacroBuf_s umb;
427     int rc;
428
429     /* Copy other state from "parent", but we want a buffer of our own */
430     umb = *mb;
431     umb.buf = NULL;
432     rc = expandMacro(&umb, src, slen);
433     *target = umb.buf;
434
435     return rc;
436 }
437
438 static void mbAppend(MacroBuf mb, char c)
439 {
440     if (mb->nb < 1) {
441         mb->buf = xrealloc(mb->buf, mb->tpos + mb->nb + MACROBUFSIZ);
442         mb->nb += MACROBUFSIZ;
443     }
444     mb->buf[mb->tpos++] = c;
445     mb->nb--;
446 }
447
448 static void mbAppendStr(MacroBuf mb, const char *str)
449 {
450     size_t len = strlen(str);
451     if (len > mb->nb) {
452         mb->buf = xrealloc(mb->buf, mb->tpos + mb->nb + MACROBUFSIZ + len);
453         mb->nb += MACROBUFSIZ + len;
454     }
455     memcpy(mb->buf+mb->tpos, str, len);
456     mb->tpos += len;
457     mb->nb -= len;
458 }
459 /**
460  * Expand output of shell command into target buffer.
461  * @param mb            macro expansion state
462  * @param cmd           shell command
463  * @param clen          no. bytes in shell command
464  * @return              result of expansion
465  */
466 static int
467 doShellEscape(MacroBuf mb, const char * cmd, size_t clen)
468 {
469     char *buf = NULL;
470     FILE *shf;
471     int rc = 0;
472     int c;
473
474     rc = expandThis(mb, cmd, clen, &buf);
475     if (rc)
476         goto exit;
477
478     if ((shf = popen(buf, "r")) == NULL) {
479         rc = 1;
480         goto exit;
481     }
482     while((c = fgetc(shf)) != EOF) {
483         mbAppend(mb, c);
484     }
485     (void) pclose(shf);
486
487     /* XXX delete trailing \r \n */
488     while (iseol(mb->buf[mb->tpos-1])) {
489         mb->buf[mb->tpos--] = '\0';
490         mb->nb++;
491     }
492
493 exit:
494     _free(buf);
495     return rc;
496 }
497
498 /**
499  * Parse (and execute) new macro definition.
500  * @param mb            macro expansion state
501  * @param se            macro definition to parse
502  * @param level         macro recursion level
503  * @param expandbody    should body be expanded?
504  * @return              address to continue parsing
505  */
506 static const char *
507 doDefine(MacroBuf mb, const char * se, int level, int expandbody)
508 {
509     const char *s = se;
510     size_t blen = MACROBUFSIZ;
511     char *buf = xmalloc(blen);
512     char *n = buf, *ne = n;
513     char *o = NULL, *oe;
514     char *b, *be, *ebody = NULL;
515     int c;
516     int oc = ')';
517
518     /* Copy name */
519     COPYNAME(ne, s, c);
520
521     /* Copy opts (if present) */
522     oe = ne + 1;
523     if (*s == '(') {
524         s++;    /* skip ( */
525         o = oe;
526         COPYOPTS(oe, s, oc);
527         s++;    /* skip ) */
528     }
529
530     /* Copy body, skipping over escaped newlines */
531     b = be = oe + 1;
532     SKIPBLANK(s, c);
533     if (c == '{') {     /* XXX permit silent {...} grouping */
534         if ((se = matchchar(s, c, '}')) == NULL) {
535             rpmlog(RPMLOG_ERR,
536                 _("Macro %%%s has unterminated body\n"), n);
537             se = s;     /* XXX W2DO? */
538             return se;
539         }
540         s++;    /* XXX skip { */
541         strncpy(b, s, (se - s));
542         b[se - s] = '\0';
543         be += strlen(b);
544         se++;   /* XXX skip } */
545         s = se; /* move scan forward */
546     } else {    /* otherwise free-field */
547         int bc = 0, pc = 0;
548         while (*s && (bc || pc || !iseol(*s))) {
549             switch (*s) {
550                 case '\\':
551                     switch (*(s+1)) {
552                         case '\0': break;
553                         default: s++; break;
554                     }
555                     break;
556                 case '%':
557                     switch (*(s+1)) {
558                         case '{': *be++ = *s++; bc++; break;
559                         case '(': *be++ = *s++; pc++; break;
560                         case '%': *be++ = *s++; break;
561                     }
562                     break;
563                 case '{': if (bc > 0) bc++; break;
564                 case '}': if (bc > 0) bc--; break;
565                 case '(': if (pc > 0) pc++; break;
566                 case ')': if (pc > 0) pc--; break;
567             }
568             *be++ = *s++;
569         }
570         *be = '\0';
571
572         if (bc || pc) {
573             rpmlog(RPMLOG_ERR,
574                 _("Macro %%%s has unterminated body\n"), n);
575             se = s;     /* XXX W2DO? */
576             return se;
577         }
578
579         /* Trim trailing blanks/newlines */
580         while (--be >= b && (c = *be) && (isblank(c) || iseol(c)))
581             {};
582         *(++be) = '\0'; /* one too far */
583     }
584
585     /* Move scan over body */
586     while (iseol(*s))
587         s++;
588     se = s;
589
590     /* Names must start with alphabetic or _ and be at least 3 chars */
591     if (!((c = *n) && (risalpha(c) || c == '_') && (ne - n) > 2)) {
592         rpmlog(RPMLOG_ERR,
593                 _("Macro %%%s has illegal name (%%define)\n"), n);
594         return se;
595     }
596
597     /* Options must be terminated with ')' */
598     if (o && oc != ')') {
599         rpmlog(RPMLOG_ERR, _("Macro %%%s has unterminated opts\n"), n);
600         goto exit;
601     }
602
603     if ((be - b) < 1) {
604         rpmlog(RPMLOG_ERR, _("Macro %%%s has empty body\n"), n);
605         goto exit;
606     }
607
608     if (expandbody) {
609         if (expandThis(mb, b, 0, &ebody)) {
610             rpmlog(RPMLOG_ERR, _("Macro %%%s failed to expand\n"), n);
611             goto exit;
612         }
613         b = ebody;
614     }
615
616     addMacro(mb->mc, n, o, b, (level - 1));
617
618 exit:
619     _free(buf);
620     _free(ebody);
621     return se;
622 }
623
624 /**
625  * Parse (and execute) macro undefinition.
626  * @param mc            macro context
627  * @param se            macro name to undefine
628  * @return              address to continue parsing
629  */
630 static const char *
631 doUndefine(rpmMacroContext mc, const char * se)
632 {
633     const char *s = se;
634     char *buf = xmalloc(MACROBUFSIZ);
635     char *n = buf, *ne = n;
636     int c;
637
638     COPYNAME(ne, s, c);
639
640     /* Move scan over body */
641     while (iseol(*s))
642         s++;
643     se = s;
644
645     /* Names must start with alphabetic or _ and be at least 3 chars */
646     if (!((c = *n) && (risalpha(c) || c == '_') && (ne - n) > 2)) {
647         rpmlog(RPMLOG_ERR,
648                 _("Macro %%%s has illegal name (%%undefine)\n"), n);
649         goto exit;
650     }
651
652     delMacro(mc, n);
653
654 exit:
655     _free(buf);
656     return se;
657 }
658
659 /**
660  * Push new macro definition onto macro entry stack.
661  * @param mep           address of macro entry slot
662  * @param n             macro name
663  * @param o             macro parameters (NULL if none)
664  * @param b             macro body (NULL becomes "")
665  * @param level         macro recursion level
666  */
667 static void
668 pushMacro(rpmMacroEntry * mep,
669                 const char * n, const char * o,
670                 const char * b, int level)
671 {
672     rpmMacroEntry prev = (mep && *mep ? *mep : NULL);
673     rpmMacroEntry me = (rpmMacroEntry) xmalloc(sizeof(*me));
674
675     me->prev = prev;
676     me->name = (prev ? prev->name : xstrdup(n));
677     me->opts = (o ? xstrdup(o) : NULL);
678     me->body = xstrdup(b ? b : "");
679     me->used = 0;
680     me->level = level;
681     if (mep)
682         *mep = me;
683     else
684         me = _free(me);
685 }
686
687 /**
688  * Pop macro definition from macro entry stack.
689  * @param mep           address of macro entry slot
690  */
691 static void
692 popMacro(rpmMacroEntry * mep)
693 {
694         rpmMacroEntry me = (*mep ? *mep : NULL);
695
696         if (me) {
697                 /* XXX cast to workaround const */
698                 if ((*mep = me->prev) == NULL)
699                         me->name = _free(me->name);
700                 me->opts = _free(me->opts);
701                 me->body = _free(me->body);
702                 me = _free(me);
703         }
704 }
705
706 /**
707  * Free parsed arguments for parameterized macro.
708  * @param mb            macro expansion state
709  */
710 static void
711 freeArgs(MacroBuf mb)
712 {
713     rpmMacroContext mc = mb->mc;
714     int ndeleted = 0;
715     int i;
716
717     if (mc == NULL || mc->macroTable == NULL)
718         return;
719
720     /* Delete dynamic macro definitions */
721     for (i = 0; i < mc->firstFree; i++) {
722         rpmMacroEntry *mep, me;
723         int skiptest = 0;
724         mep = &mc->macroTable[i];
725         me = *mep;
726
727         if (me == NULL)         /* XXX this should never happen */
728             continue;
729         if (me->level < mb->depth)
730             continue;
731         if (strlen(me->name) == 1 && strchr("#*0", *me->name)) {
732             if (*me->name == '*' && me->used > 0)
733                 skiptest = 1; /* XXX skip test for %# %* %0 */
734         } else if (!skiptest && me->used <= 0) {
735 #if NOTYET
736             rpmlog(RPMLOG_ERR,
737                         _("Macro %%%s (%s) was not used below level %d\n"),
738                         me->name, me->body, me->level);
739 #endif
740         }
741         popMacro(mep);
742         if (!(mep && *mep))
743             ndeleted++;
744     }
745
746     /* If any deleted macros, sort macro table */
747     if (ndeleted)
748         sortMacroTable(mc);
749 }
750
751 /**
752  * Parse arguments (to next new line) for parameterized macro.
753  * @todo Use popt rather than getopt to parse args.
754  * @param mb            macro expansion state
755  * @param me            macro entry slot
756  * @param se            arguments to parse
757  * @param lastc         stop parsing at lastc
758  * @return              address to continue parsing
759  */
760 static const char *
761 grabArgs(MacroBuf mb, const rpmMacroEntry me, const char * se,
762                 const char * lastc)
763 {
764     const char *opts;
765     char *args = NULL;
766     ARGV_t argv = NULL;
767     int argc = 0;
768     int c;
769
770     /* Copy macro name as argv[0] */
771     argvAdd(&argv, me->name);
772     addMacro(mb->mc, "0", NULL, me->name, mb->depth);
773     
774     /* 
775      * Make a copy of se up to lastc string that we can pass to argvSplit().
776      * Append the results to main argv. 
777      */
778     {   ARGV_t av = NULL;
779         char *s = xcalloc((lastc-se)+1, sizeof(*s));
780         memcpy(s, se, (lastc-se));
781
782         argvSplit(&av, s, " \t");
783         argvAppend(&argv, av);
784
785         argvFree(av);
786         free(s);
787     }
788
789     /*
790      * The macro %* analoguous to the shell's $* means "Pass all non-macro
791      * parameters." Consequently, there needs to be a macro that means "Pass all
792      * (including macro parameters) options". This is useful for verifying
793      * parameters during expansion and yet transparently passing all parameters
794      * through for higher level processing (e.g. %description and/or %setup).
795      * This is the (potential) justification for %{**} ...
796     */
797     args = argvJoin(argv + 1, " ");
798     addMacro(mb->mc, "**", NULL, args, mb->depth);
799     free(args);
800
801     /*
802      * POSIX states optind must be 1 before any call but glibc uses 0
803      * to (re)initialize getopt structures, eww.
804      */
805 #ifdef __GLIBC__
806     optind = 0;
807 #else
808     optind = 1;
809 #endif
810
811     opts = me->opts;
812     argc = argvCount(argv);
813
814     /* Define option macros. */
815     while((c = getopt(argc, argv, opts)) != -1)
816     {
817         char *name = NULL, *body = NULL;
818         if (c == '?' || strchr(opts, c) == NULL) {
819             rpmlog(RPMLOG_ERR, _("Unknown option %c in %s(%s)\n"),
820                         (char)c, me->name, opts);
821             goto exit;
822         }
823
824         rasprintf(&name, "-%c", c);
825         if (optarg) {
826             rasprintf(&body, "-%c %s", c, optarg);
827         } else {
828             rasprintf(&body, "-%c", c);
829         }
830         addMacro(mb->mc, name, NULL, body, mb->depth);
831         free(name);
832         free(body);
833
834         if (optarg) {
835             rasprintf(&name, "-%c*", c);
836             addMacro(mb->mc, name, NULL, optarg, mb->depth);
837             free(name);
838         }
839     }
840
841     /* Add argument count (remaining non-option items) as macro. */
842     {   char *ac = NULL;
843         rasprintf(&ac, "%d", (argc - optind));
844         addMacro(mb->mc, "#", NULL, ac, mb->depth);
845         free(ac);
846     }
847
848     /* Add macro for each argument */
849     if (argc - optind) {
850         for (c = optind; c < argc; c++) {
851             char *name = NULL;
852             rasprintf(&name, "%d", (c - optind + 1));
853             addMacro(mb->mc, name, NULL, argv[c], mb->depth);
854             free(name);
855         }
856     }
857
858     /* Add concatenated unexpanded arguments as yet another macro. */
859     args = argvJoin(argv + optind, " ");
860     addMacro(mb->mc, "*", NULL, args ? args : "", mb->depth);
861     free(args);
862
863 exit:
864     argvFree(argv);
865     return *lastc ? lastc + 1 : lastc; 
866 }
867
868 /**
869  * Perform macro message output
870  * @param mb            macro expansion state
871  * @param waserror      use rpmlog()?
872  * @param msg           message to ouput
873  * @param msglen        no. of bytes in message
874  */
875 static void
876 doOutput(MacroBuf mb, int waserror, const char * msg, size_t msglen)
877 {
878     char *buf = NULL;
879
880     (void) expandThis(mb, msg, msglen, &buf);
881     if (waserror)
882         rpmlog(RPMLOG_ERR, "%s\n", buf);
883     else
884         fprintf(stderr, "%s", buf);
885     _free(buf);
886 }
887
888 /**
889  * Execute macro primitives.
890  * @param mb            macro expansion state
891  * @param negate        should logic be inverted?
892  * @param f             beginning of field f
893  * @param fn            length of field f
894  * @param g             beginning of field g
895  * @param gn            length of field g
896  */
897 static void
898 doFoo(MacroBuf mb, int negate, const char * f, size_t fn,
899                 const char * g, size_t gn)
900 {
901     char *buf = NULL;
902     char *b = NULL, *be;
903     int c;
904
905     if (g != NULL) {
906         (void) expandThis(mb, g, gn, &buf);
907     } else {
908         buf = xmalloc(MACROBUFSIZ + fn + gn);
909         buf[0] = '\0';
910     }
911     if (STREQ("basename", f, fn)) {
912         if ((b = strrchr(buf, '/')) == NULL)
913             b = buf;
914         else
915             b++;
916 #if NOTYET
917     /* XXX watchout for conflict with %dir */
918     } else if (STREQ("dirname", f, fn)) {
919         if ((b = strrchr(buf, '/')) != NULL)
920             *b = '\0';
921         b = buf;
922 #endif
923     } else if (STREQ("suffix", f, fn)) {
924         if ((b = strrchr(buf, '.')) != NULL)
925             b++;
926     } else if (STREQ("expand", f, fn)) {
927         b = buf;
928     } else if (STREQ("verbose", f, fn)) {
929         if (negate)
930             b = (rpmIsVerbose() ? NULL : buf);
931         else
932             b = (rpmIsVerbose() ? buf : NULL);
933     } else if (STREQ("url2path", f, fn) || STREQ("u2p", f, fn)) {
934         (void)urlPath(buf, (const char **)&b);
935         if (*b == '\0') b = "/";
936     } else if (STREQ("uncompress", f, fn)) {
937         rpmCompressedMagic compressed = COMPRESSED_OTHER;
938         for (b = buf; (c = *b) && isblank(c);)
939             b++;
940         for (be = b; (c = *be) && !isblank(c);)
941             be++;
942         *be++ = '\0';
943         (void) rpmFileIsCompressed(b, &compressed);
944         switch(compressed) {
945         default:
946         case COMPRESSED_NOT:
947             sprintf(be, "%%__cat %s", b);
948             break;
949         case COMPRESSED_OTHER:
950             sprintf(be, "%%__gzip -dc %s", b);
951             break;
952         case COMPRESSED_BZIP2:
953             sprintf(be, "%%__bzip2 -dc %s", b);
954             break;
955         case COMPRESSED_ZIP:
956             sprintf(be, "%%__unzip %s", b);
957             break;
958         case COMPRESSED_LZMA:
959         case COMPRESSED_XZ:
960             sprintf(be, "%%__xz -dc %s", b);
961             break;
962         }
963         b = be;
964     } else if (STREQ("getenv", f, fn)) {
965         b = getenv(buf);
966     } else if (STREQ("getconfdir", f, fn)) {
967         sprintf(buf, "%s", rpmConfigDir());
968         b = buf;
969     } else if (STREQ("S", f, fn)) {
970         for (b = buf; (c = *b) && risdigit(c);)
971             b++;
972         if (!c) {       /* digit index */
973             b++;
974             sprintf(b, "%%SOURCE%s", buf);
975         } else
976             b = buf;
977     } else if (STREQ("P", f, fn)) {
978         for (b = buf; (c = *b) && risdigit(c);)
979             b++;
980         if (!c) {       /* digit index */
981             b++;
982             sprintf(b, "%%PATCH%s", buf);
983         } else
984                         b = buf;
985     } else if (STREQ("F", f, fn)) {
986         b = buf + strlen(buf) + 1;
987         sprintf(b, "file%s.file", buf);
988     }
989
990     if (b) {
991         (void) expandMacro(mb, b, 0);
992     }
993     free(buf);
994 }
995
996 /**
997  * The main macro recursion loop.
998  * @param mb            macro expansion state
999  * @param src           string to expand
1000  * @return              0 on success, 1 on failure
1001  */
1002 static int
1003 expandMacro(MacroBuf mb, const char *src, size_t slen)
1004 {
1005     rpmMacroEntry *mep;
1006     rpmMacroEntry me;
1007     const char *s = src, *se;
1008     const char *f, *fe;
1009     const char *g, *ge;
1010     size_t fn, gn, tpos;
1011     int c;
1012     int rc = 0;
1013     int negate;
1014     const char * lastc;
1015     int chkexist;
1016     char *source = NULL;
1017
1018     /* Handle non-terminated substrings by creating a terminated copy */
1019     if (slen > 0) {
1020         source = xmalloc(slen + 1);
1021         strncpy(source, src, slen);
1022         source[slen] = '\0';
1023         s = source;
1024     }
1025
1026     if (mb->buf == NULL) {
1027         size_t blen = MACROBUFSIZ + strlen(s);
1028         mb->buf = xcalloc(blen + 1, sizeof(*mb->buf));
1029         mb->tpos = 0;
1030         mb->nb = blen;
1031     }
1032     tpos = mb->tpos; /* save expansion pointer for printExpand */
1033
1034     if (++mb->depth > max_macro_depth) {
1035         rpmlog(RPMLOG_ERR,
1036                 _("Too many levels of recursion in macro expansion. It is likely caused by recursive macro declaration.\n"));
1037         mb->depth--;
1038         mb->expand_trace = 1;
1039         _free(source);
1040         return 1;
1041     }
1042
1043     while (rc == 0 && (c = *s) != '\0') {
1044         s++;
1045         /* Copy text until next macro */
1046         switch(c) {
1047         case '%':
1048                 if (*s) {       /* Ensure not end-of-string. */
1049                     if (*s != '%')
1050                         break;
1051                     s++;        /* skip first % in %% */
1052                 }
1053         default:
1054                 mbAppend(mb, c);
1055                 continue;
1056                 break;
1057         }
1058
1059         /* Expand next macro */
1060         f = fe = NULL;
1061         g = ge = NULL;
1062         if (mb->depth > 1)      /* XXX full expansion for outermost level */
1063             tpos = mb->tpos;    /* save expansion pointer for printExpand */
1064         negate = 0;
1065         lastc = NULL;
1066         chkexist = 0;
1067         switch ((c = *s)) {
1068         default:                /* %name substitution */
1069                 while (strchr("!?", *s) != NULL) {
1070                         switch(*s++) {
1071                         case '!':
1072                                 negate = ((negate + 1) % 2);
1073                                 break;
1074                         case '?':
1075                                 chkexist++;
1076                                 break;
1077                         }
1078                 }
1079                 f = se = s;
1080                 if (*se == '-')
1081                         se++;
1082                 while((c = *se) && (risalnum(c) || c == '_'))
1083                         se++;
1084                 /* Recognize non-alnum macros too */
1085                 switch (*se) {
1086                 case '*':
1087                         se++;
1088                         if (*se == '*') se++;
1089                         break;
1090                 case '#':
1091                         se++;
1092                         break;
1093                 default:
1094                         break;
1095                 }
1096                 fe = se;
1097                 /* For "%name " macros ... */
1098                 if ((c = *fe) && isblank(c))
1099                         if ((lastc = strchr(fe,'\n')) == NULL)
1100                 lastc = strchr(fe, '\0');
1101                 break;
1102         case '(':               /* %(...) shell escape */
1103                 if ((se = matchchar(s, c, ')')) == NULL) {
1104                         rpmlog(RPMLOG_ERR,
1105                                 _("Unterminated %c: %s\n"), (char)c, s);
1106                         rc = 1;
1107                         continue;
1108                 }
1109                 if (mb->macro_trace)
1110                         printMacro(mb, s, se+1);
1111
1112                 s++;    /* skip ( */
1113                 rc = doShellEscape(mb, s, (se - s));
1114                 se++;   /* skip ) */
1115
1116                 s = se;
1117                 continue;
1118                 break;
1119         case '{':               /* %{...}/%{...:...} substitution */
1120                 if ((se = matchchar(s, c, '}')) == NULL) {
1121                         rpmlog(RPMLOG_ERR,
1122                                 _("Unterminated %c: %s\n"), (char)c, s);
1123                         rc = 1;
1124                         continue;
1125                 }
1126                 f = s+1;/* skip { */
1127                 se++;   /* skip } */
1128                 while (strchr("!?", *f) != NULL) {
1129                         switch(*f++) {
1130                         case '!':
1131                                 negate = ((negate + 1) % 2);
1132                                 break;
1133                         case '?':
1134                                 chkexist++;
1135                                 break;
1136                         }
1137                 }
1138                 for (fe = f; (c = *fe) && !strchr(" :}", c);)
1139                         fe++;
1140                 switch (c) {
1141                 case ':':
1142                         g = fe + 1;
1143                         ge = se - 1;
1144                         break;
1145                 case ' ':
1146                         lastc = se-1;
1147                         break;
1148                 default:
1149                         break;
1150                 }
1151                 break;
1152         }
1153
1154         /* XXX Everything below expects fe > f */
1155         fn = (fe - f);
1156         gn = (ge - g);
1157         if ((fe - f) <= 0) {
1158 /* XXX Process % in unknown context */
1159                 c = '%';        /* XXX only need to save % */
1160                 mbAppend(mb, c);
1161 #if 0
1162                 rpmlog(RPMLOG_ERR,
1163                         _("A %% is followed by an unparseable macro\n"));
1164 #endif
1165                 s = se;
1166                 continue;
1167         }
1168
1169         if (mb->macro_trace)
1170                 printMacro(mb, s, se);
1171
1172         /* Expand builtin macros */
1173         if (STREQ("global", f, fn)) {
1174                 s = doDefine(mb, se, RMIL_GLOBAL, 1);
1175                 continue;
1176         }
1177         if (STREQ("define", f, fn)) {
1178                 s = doDefine(mb, se, mb->depth, 0);
1179                 continue;
1180         }
1181         if (STREQ("undefine", f, fn)) {
1182                 s = doUndefine(mb->mc, se);
1183                 continue;
1184         }
1185
1186         if (STREQ("echo", f, fn) ||
1187             STREQ("warn", f, fn) ||
1188             STREQ("error", f, fn)) {
1189                 int waserror = 0;
1190                 if (STREQ("error", f, fn))
1191                         waserror = 1;
1192                 if (g != NULL && g < ge)
1193                         doOutput(mb, waserror, g, gn);
1194                 else
1195                         doOutput(mb, waserror, f, fn);
1196                 s = se;
1197                 continue;
1198         }
1199
1200         if (STREQ("trace", f, fn)) {
1201                 /* XXX TODO restore expand_trace/macro_trace to 0 on return */
1202                 mb->expand_trace = mb->macro_trace = (negate ? 0 : mb->depth);
1203                 if (mb->depth == 1) {
1204                         print_macro_trace = mb->macro_trace;
1205                         print_expand_trace = mb->expand_trace;
1206                 }
1207                 s = se;
1208                 continue;
1209         }
1210
1211         if (STREQ("dump", f, fn)) {
1212                 rpmDumpMacroTable(mb->mc, NULL);
1213                 while (iseol(*se))
1214                         se++;
1215                 s = se;
1216                 continue;
1217         }
1218
1219 #ifdef  WITH_LUA
1220         if (STREQ("lua", f, fn)) {
1221                 rpmlua lua = NULL; /* Global state. */
1222                 const char *ls = s+sizeof("{lua:")-1;
1223                 const char *lse = se-sizeof("}")+1;
1224                 char *scriptbuf = (char *)xmalloc((lse-ls)+1);
1225                 const char *printbuf;
1226                 memcpy(scriptbuf, ls, lse-ls);
1227                 scriptbuf[lse-ls] = '\0';
1228                 rpmluaSetPrintBuffer(lua, 1);
1229                 if (rpmluaRunScript(lua, scriptbuf, NULL) == -1)
1230                     rc = 1;
1231                 printbuf = rpmluaGetPrintBuffer(lua);
1232                 if (printbuf) {
1233                     mbAppendStr(mb, printbuf);
1234                 }
1235                 rpmluaSetPrintBuffer(lua, 0);
1236                 free(scriptbuf);
1237                 s = se;
1238                 continue;
1239         }
1240 #endif
1241
1242         /* XXX necessary but clunky */
1243         if (STREQ("basename", f, fn) ||
1244             STREQ("suffix", f, fn) ||
1245             STREQ("expand", f, fn) ||
1246             STREQ("verbose", f, fn) ||
1247             STREQ("uncompress", f, fn) ||
1248             STREQ("url2path", f, fn) ||
1249             STREQ("u2p", f, fn) ||
1250             STREQ("getenv", f, fn) ||
1251             STREQ("getconfdir", f, fn) ||
1252             STREQ("S", f, fn) ||
1253             STREQ("P", f, fn) ||
1254             STREQ("F", f, fn)) {
1255                 /* FIX: verbose may be set */
1256                 doFoo(mb, negate, f, fn, g, gn);
1257                 s = se;
1258                 continue;
1259         }
1260
1261         /* Expand defined macros */
1262         mep = findEntry(mb->mc, f, fn);
1263         me = (mep ? *mep : NULL);
1264
1265         /* XXX Special processing for flags */
1266         if (*f == '-') {
1267                 if (me)
1268                         me->used++;     /* Mark macro as used */
1269                 if ((me == NULL && !negate) ||  /* Without -f, skip %{-f...} */
1270                     (me != NULL && negate)) {   /* With -f, skip %{!-f...} */
1271                         s = se;
1272                         continue;
1273                 }
1274
1275                 if (g && g < ge) {              /* Expand X in %{-f:X} */
1276                         rc = expandMacro(mb, g, gn);
1277                 } else
1278                 if (me && me->body && *me->body) {/* Expand %{-f}/%{-f*} */
1279                         rc = expandMacro(mb, me->body, 0);
1280                 }
1281                 s = se;
1282                 continue;
1283         }
1284
1285         /* XXX Special processing for macro existence */
1286         if (chkexist) {
1287                 if ((me == NULL && !negate) ||  /* Without -f, skip %{?f...} */
1288                     (me != NULL && negate)) {   /* With -f, skip %{!?f...} */
1289                         s = se;
1290                         continue;
1291                 }
1292                 if (g && g < ge) {              /* Expand X in %{?f:X} */
1293                         rc = expandMacro(mb, g, gn);
1294                 } else
1295                 if (me && me->body && *me->body) { /* Expand %{?f}/%{?f*} */
1296                         rc = expandMacro(mb, me->body, 0);
1297                 }
1298                 s = se;
1299                 continue;
1300         }
1301         
1302         if (me == NULL) {       /* leave unknown %... as is */
1303                 /* XXX hack to permit non-overloaded %foo to be passed */
1304                 c = '%';        /* XXX only need to save % */
1305                 mbAppend(mb, c);
1306                 continue;
1307         }
1308
1309         /* Setup args for "%name " macros with opts */
1310         if (me && me->opts != NULL) {
1311                 if (lastc != NULL) {
1312                         se = grabArgs(mb, me, fe, lastc);
1313                 } else {
1314                         addMacro(mb->mc, "**", NULL, "", mb->depth);
1315                         addMacro(mb->mc, "*", NULL, "", mb->depth);
1316                         addMacro(mb->mc, "#", NULL, "0", mb->depth);
1317                         addMacro(mb->mc, "0", NULL, me->name, mb->depth);
1318                 }
1319         }
1320
1321         /* Recursively expand body of macro */
1322         if (me->body && *me->body) {
1323                 rc = expandMacro(mb, me->body, 0);
1324                 if (rc == 0)
1325                         me->used++;     /* Mark macro as used */
1326         }
1327
1328         /* Free args for "%name " macros with opts */
1329         if (me->opts != NULL)
1330                 freeArgs(mb);
1331
1332         s = se;
1333     }
1334
1335     mb->buf[mb->tpos] = '\0';
1336     mb->depth--;
1337     if (rc != 0 || mb->expand_trace)
1338         printExpansion(mb, mb->buf+tpos, mb->buf+mb->tpos);
1339     _free(source);
1340     return rc;
1341 }
1342
1343
1344 /* =============================================================== */
1345
1346 static int doExpandMacros(rpmMacroContext mc, const char *src, char **target)
1347 {
1348     MacroBuf mb = xcalloc(1, sizeof(*mb));
1349     int rc = 0;
1350
1351     if (mc == NULL) mc = rpmGlobalMacroContext;
1352
1353     mb->buf = NULL;
1354     mb->depth = 0;
1355     mb->macro_trace = print_macro_trace;
1356     mb->expand_trace = print_expand_trace;
1357     mb->mc = mc;
1358
1359     rc = expandMacro(mb, src, 0);
1360
1361     mb->buf[mb->tpos] = '\0';   /* XXX just in case */
1362     /* expanded output is usually much less than alloced buffer, downsize */
1363     *target = xrealloc(mb->buf, mb->tpos + 1);
1364
1365     _free(mb);
1366     return rc;
1367 }
1368
1369 int expandMacros(void * spec, rpmMacroContext mc, char * sbuf, size_t slen)
1370 {
1371     char *target = NULL;
1372     int rc = doExpandMacros(mc, sbuf, &target);
1373     rstrlcpy(sbuf, target, slen);
1374     free(target);
1375     return rc;
1376 }
1377
1378 void
1379 addMacro(rpmMacroContext mc,
1380         const char * n, const char * o, const char * b, int level)
1381 {
1382     rpmMacroEntry * mep;
1383
1384     if (mc == NULL) mc = rpmGlobalMacroContext;
1385
1386     /* If new name, expand macro table */
1387     if ((mep = findEntry(mc, n, 0)) == NULL) {
1388         if (mc->firstFree == mc->macrosAllocated)
1389             expandMacroTable(mc);
1390         if (mc->macroTable != NULL)
1391             mep = mc->macroTable + mc->firstFree++;
1392     }
1393
1394     if (mep != NULL) {
1395         /* Push macro over previous definition */
1396         pushMacro(mep, n, o, b, level);
1397
1398         /* If new name, sort macro table */
1399         if ((*mep)->prev == NULL)
1400             sortMacroTable(mc);
1401     }
1402 }
1403
1404 void
1405 delMacro(rpmMacroContext mc, const char * n)
1406 {
1407     rpmMacroEntry * mep;
1408
1409     if (mc == NULL) mc = rpmGlobalMacroContext;
1410     /* If name exists, pop entry */
1411     if ((mep = findEntry(mc, n, 0)) != NULL) {
1412         popMacro(mep);
1413         /* If deleted name, sort macro table */
1414         if (!(mep && *mep))
1415             sortMacroTable(mc);
1416     }
1417 }
1418
1419 int
1420 rpmDefineMacro(rpmMacroContext mc, const char * macro, int level)
1421 {
1422     MacroBuf mb = xcalloc(1, sizeof(*mb));
1423
1424     /* XXX just enough to get by */
1425     mb->mc = (mc ? mc : rpmGlobalMacroContext);
1426     (void) doDefine(mb, macro, level, 0);
1427     _free(mb);
1428     return 0;
1429 }
1430
1431 void
1432 rpmLoadMacros(rpmMacroContext mc, int level)
1433 {
1434
1435     if (mc == NULL || mc == rpmGlobalMacroContext)
1436         return;
1437
1438     if (mc->macroTable != NULL) {
1439         int i;
1440         for (i = 0; i < mc->firstFree; i++) {
1441             rpmMacroEntry *mep, me;
1442             mep = &mc->macroTable[i];
1443             me = *mep;
1444
1445             if (me == NULL)             /* XXX this should never happen */
1446                 continue;
1447             addMacro(NULL, me->name, me->opts, me->body, (level - 1));
1448         }
1449     }
1450 }
1451
1452 int
1453 rpmLoadMacroFile(rpmMacroContext mc, const char * fn)
1454 {
1455     FILE *fd = fopen(fn, "r");
1456     size_t blen = MACROBUFSIZ;
1457     char *buf = xmalloc(blen);
1458     int rc = -1;
1459
1460     if (fd == NULL || ferror(fd)) {
1461         if (fd) (void) fclose(fd);
1462         goto exit;
1463     }
1464
1465     /* XXX Assume new fangled macro expansion */
1466     max_macro_depth = 16;
1467
1468     buf[0] = '\0';
1469     while(rdcl(buf, blen, fd) != NULL) {
1470         char c, *n;
1471
1472         n = buf;
1473         SKIPBLANK(n, c);
1474
1475         if (c != '%')
1476                 continue;
1477         n++;    /* skip % */
1478         rc = rpmDefineMacro(mc, n, RMIL_MACROFILES);
1479     }
1480     rc = fclose(fd);
1481
1482 exit:
1483     _free(buf);
1484     return rc;
1485 }
1486
1487 void
1488 rpmInitMacros(rpmMacroContext mc, const char * macrofiles)
1489 {
1490     ARGV_t pattern, globs = NULL;
1491
1492     if (macrofiles == NULL)
1493         return;
1494
1495     argvSplit(&globs, macrofiles, ":");
1496     for (pattern = globs; *pattern; pattern++) {
1497         ARGV_t path, files = NULL;
1498     
1499         /* Glob expand the macro file path element, expanding ~ to $HOME. */
1500         if (rpmGlob(*pattern, NULL, &files) != 0) {
1501             continue;
1502         }
1503
1504         /* Read macros from each file. */
1505         for (path = files; *path; path++) {
1506             if (rpmFileHasSuffix(*path, ".rpmnew") || 
1507                 rpmFileHasSuffix(*path, ".rpmsave") ||
1508                 rpmFileHasSuffix(*path, ".rpmorig")) {
1509                 continue;
1510             }
1511             (void) rpmLoadMacroFile(mc, *path);
1512         }
1513         argvFree(files);
1514     }
1515     argvFree(globs);
1516
1517     /* Reload cmdline macros */
1518     rpmLoadMacros(rpmCLIMacroContext, RMIL_CMDLINE);
1519 }
1520
1521 void
1522 rpmFreeMacros(rpmMacroContext mc)
1523 {
1524     
1525     if (mc == NULL) mc = rpmGlobalMacroContext;
1526
1527     if (mc->macroTable != NULL) {
1528         int i;
1529         for (i = 0; i < mc->firstFree; i++) {
1530             rpmMacroEntry me;
1531             while ((me = mc->macroTable[i]) != NULL) {
1532                 /* XXX cast to workaround const */
1533                 if ((mc->macroTable[i] = me->prev) == NULL)
1534                     me->name = _free(me->name);
1535                 me->opts = _free(me->opts);
1536                 me->body = _free(me->body);
1537                 me = _free(me);
1538             }
1539         }
1540         mc->macroTable = _free(mc->macroTable);
1541     }
1542     memset(mc, 0, sizeof(*mc));
1543 }
1544
1545 char * 
1546 rpmExpand(const char *arg, ...)
1547 {
1548     size_t blen = 0;
1549     char *buf = NULL, *ret = NULL;
1550     char *pe;
1551     const char *s;
1552     va_list ap;
1553
1554     if (arg == NULL) {
1555         ret = xstrdup("");
1556         goto exit;
1557     }
1558
1559     /* precalculate unexpanded size */
1560     va_start(ap, arg);
1561     for (s = arg; s != NULL; s = va_arg(ap, const char *))
1562         blen += strlen(s);
1563     va_end(ap);
1564
1565     buf = xmalloc(blen + 1);
1566     buf[0] = '\0';
1567
1568     va_start(ap, arg);
1569     for (pe = buf, s = arg; s != NULL; s = va_arg(ap, const char *))
1570         pe = stpcpy(pe, s);
1571     va_end(ap);
1572
1573     (void) doExpandMacros(NULL, buf, &ret);
1574
1575     free(buf);
1576 exit:
1577     return ret;
1578 }
1579
1580 int
1581 rpmExpandNumeric(const char *arg)
1582 {
1583     char *val;
1584     int rc;
1585
1586     if (arg == NULL)
1587         return 0;
1588
1589     val = rpmExpand(arg, NULL);
1590     if (!(val && *val != '%'))
1591         rc = 0;
1592     else if (*val == 'Y' || *val == 'y')
1593         rc = 1;
1594     else if (*val == 'N' || *val == 'n')
1595         rc = 0;
1596     else {
1597         char *end;
1598         rc = strtol(val, &end, 0);
1599         if (!(end && *end == '\0'))
1600             rc = 0;
1601     }
1602     val = _free(val);
1603
1604     return rc;
1605 }