[4.0] Use strip (instead of eu-strip) to support --strip-debug of *.so at build time
[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 + MACROBUFSIZ + 1);
442         mb->nb += MACROBUFSIZ;
443     }
444     mb->buf[mb->tpos++] = c;
445     mb->buf[mb->tpos] = '\0';
446     mb->nb--;
447 }
448
449 static void mbAppendStr(MacroBuf mb, const char *str)
450 {
451     size_t len = strlen(str);
452     if (len > mb->nb) {
453         mb->buf = xrealloc(mb->buf, mb->tpos + mb->nb + MACROBUFSIZ + len + 1);
454         mb->nb += MACROBUFSIZ + len;
455     }
456     memcpy(mb->buf+mb->tpos, str, len + 1);
457     mb->tpos += len;
458     mb->nb -= len;
459 }
460 /**
461  * Expand output of shell command into target buffer.
462  * @param mb            macro expansion state
463  * @param cmd           shell command
464  * @param clen          no. bytes in shell command
465  * @return              result of expansion
466  */
467 static int
468 doShellEscape(MacroBuf mb, const char * cmd, size_t clen)
469 {
470     char *buf = NULL;
471     FILE *shf;
472     int rc = 0;
473     int c;
474
475     rc = expandThis(mb, cmd, clen, &buf);
476     if (rc)
477         goto exit;
478
479     if ((shf = popen(buf, "r")) == NULL) {
480         rc = 1;
481         goto exit;
482     }
483     while((c = fgetc(shf)) != EOF) {
484         mbAppend(mb, c);
485     }
486     (void) pclose(shf);
487
488     /* XXX delete trailing \r \n */
489     while (iseol(mb->buf[mb->tpos-1])) {
490         mb->buf[mb->tpos--] = '\0';
491         mb->nb++;
492     }
493
494 exit:
495     _free(buf);
496     return rc;
497 }
498
499 /**
500  * Parse (and execute) new macro definition.
501  * @param mb            macro expansion state
502  * @param se            macro definition to parse
503  * @param level         macro recursion level
504  * @param expandbody    should body be expanded?
505  * @return              address to continue parsing
506  */
507 static const char *
508 doDefine(MacroBuf mb, const char * se, int level, int expandbody)
509 {
510     const char *s = se;
511     size_t blen = MACROBUFSIZ;
512     char *buf = xmalloc(blen);
513     char *n = buf, *ne = n;
514     char *o = NULL, *oe;
515     char *b, *be, *ebody = NULL;
516     int c;
517     int oc = ')';
518
519     /* Copy name */
520     COPYNAME(ne, s, c);
521
522     /* Copy opts (if present) */
523     oe = ne + 1;
524     if (*s == '(') {
525         s++;    /* skip ( */
526         o = oe;
527         COPYOPTS(oe, s, oc);
528         s++;    /* skip ) */
529     }
530
531     /* Copy body, skipping over escaped newlines */
532     b = be = oe + 1;
533     SKIPBLANK(s, c);
534     if (c == '{') {     /* XXX permit silent {...} grouping */
535         if ((se = matchchar(s, c, '}')) == NULL) {
536             rpmlog(RPMLOG_ERR,
537                 _("Macro %%%s has unterminated body\n"), n);
538             se = s;     /* XXX W2DO? */
539             goto exit;
540         }
541         s++;    /* XXX skip { */
542         strncpy(b, s, (se - s));
543         b[se - s] = '\0';
544         be += strlen(b);
545         se++;   /* XXX skip } */
546         s = se; /* move scan forward */
547     } else {    /* otherwise free-field */
548         int bc = 0, pc = 0;
549         while (*s && (bc || pc || !iseol(*s))) {
550             switch (*s) {
551                 case '\\':
552                     switch (*(s+1)) {
553                         case '\0': break;
554                         default: s++; break;
555                     }
556                     break;
557                 case '%':
558                     switch (*(s+1)) {
559                         case '{': *be++ = *s++; bc++; break;
560                         case '(': *be++ = *s++; pc++; break;
561                         case '%': *be++ = *s++; break;
562                     }
563                     break;
564                 case '{': if (bc > 0) bc++; break;
565                 case '}': if (bc > 0) bc--; break;
566                 case '(': if (pc > 0) pc++; break;
567                 case ')': if (pc > 0) pc--; break;
568             }
569             *be++ = *s++;
570         }
571         *be = '\0';
572
573         if (bc || pc) {
574             rpmlog(RPMLOG_ERR,
575                 _("Macro %%%s has unterminated body\n"), n);
576             se = s;     /* XXX W2DO? */
577             goto exit;
578         }
579
580         /* Trim trailing blanks/newlines */
581         while (--be >= b && (c = *be) && (isblank(c) || iseol(c)))
582             {};
583         *(++be) = '\0'; /* one too far */
584     }
585
586     /* Move scan over body */
587     while (iseol(*s))
588         s++;
589     se = s;
590
591     /* Names must start with alphabetic or _ and be at least 3 chars */
592     if (!((c = *n) && (risalpha(c) || c == '_') && (ne - n) > 2)) {
593         rpmlog(RPMLOG_ERR,
594                 _("Macro %%%s has illegal name (%%define)\n"), n);
595         goto exit;
596     }
597
598     /* Options must be terminated with ')' */
599     if (o && oc != ')') {
600         rpmlog(RPMLOG_ERR, _("Macro %%%s has unterminated opts\n"), n);
601         goto exit;
602     }
603
604     if ((be - b) < 1) {
605         rpmlog(RPMLOG_ERR, _("Macro %%%s has empty body\n"), n);
606         goto exit;
607     }
608
609     if (expandbody) {
610         if (expandThis(mb, b, 0, &ebody)) {
611             rpmlog(RPMLOG_ERR, _("Macro %%%s failed to expand\n"), n);
612             goto exit;
613         }
614         b = ebody;
615     }
616
617     addMacro(mb->mc, n, o, b, (level - 1));
618
619 exit:
620     _free(buf);
621     _free(ebody);
622     return se;
623 }
624
625 /**
626  * Parse (and execute) macro undefinition.
627  * @param mc            macro context
628  * @param se            macro name to undefine
629  * @return              address to continue parsing
630  */
631 static const char *
632 doUndefine(rpmMacroContext mc, const char * se)
633 {
634     const char *s = se;
635     char *buf = xmalloc(MACROBUFSIZ);
636     char *n = buf, *ne = n;
637     int c;
638
639     COPYNAME(ne, s, c);
640
641     /* Move scan over body */
642     while (iseol(*s))
643         s++;
644     se = s;
645
646     /* Names must start with alphabetic or _ and be at least 3 chars */
647     if (!((c = *n) && (risalpha(c) || c == '_') && (ne - n) > 2)) {
648         rpmlog(RPMLOG_ERR,
649                 _("Macro %%%s has illegal name (%%undefine)\n"), n);
650         goto exit;
651     }
652
653     delMacro(mc, n);
654
655 exit:
656     _free(buf);
657     return se;
658 }
659
660 /**
661  * Push new macro definition onto macro entry stack.
662  * @param mep           address of macro entry slot
663  * @param n             macro name
664  * @param o             macro parameters (NULL if none)
665  * @param b             macro body (NULL becomes "")
666  * @param level         macro recursion level
667  */
668 static void
669 pushMacro(rpmMacroEntry * mep,
670                 const char * n, const char * o,
671                 const char * b, int level)
672 {
673     rpmMacroEntry prev = (mep && *mep ? *mep : NULL);
674     rpmMacroEntry me = (rpmMacroEntry) xmalloc(sizeof(*me));
675
676     me->prev = prev;
677     me->name = (prev ? prev->name : xstrdup(n));
678     me->opts = (o ? xstrdup(o) : NULL);
679     me->body = xstrdup(b ? b : "");
680     me->used = 0;
681     me->level = level;
682     if (mep)
683         *mep = me;
684     else
685         me = _free(me);
686 }
687
688 /**
689  * Pop macro definition from macro entry stack.
690  * @param mep           address of macro entry slot
691  */
692 static void
693 popMacro(rpmMacroEntry * mep)
694 {
695     if (mep && *mep) {
696         rpmMacroEntry me = *mep;
697
698         /* restore previous definition of the macro */
699         *mep = me->prev;
700
701         /* name is shared between entries, only free if last of its kind */
702         if (me->prev == NULL)
703             free(me->name);
704         free(me->opts);
705         free(me->body);
706
707         memset(me, 0, sizeof(*me)); /* trash and burn */
708         free(me);
709     }
710 }
711
712 /**
713  * Free parsed arguments for parameterized macro.
714  * @param mb            macro expansion state
715  */
716 static void
717 freeArgs(MacroBuf mb)
718 {
719     rpmMacroContext mc = mb->mc;
720     int ndeleted = 0;
721     int i;
722
723     if (mc == NULL || mc->macroTable == NULL)
724         return;
725
726     /* Delete dynamic macro definitions */
727     for (i = 0; i < mc->firstFree; i++) {
728         rpmMacroEntry *mep, me;
729         int skiptest = 0;
730         mep = &mc->macroTable[i];
731         me = *mep;
732
733         if (me == NULL)         /* XXX this should never happen */
734             continue;
735         if (me->level < mb->depth)
736             continue;
737         if (strlen(me->name) == 1 && strchr("#*0", *me->name)) {
738             if (*me->name == '*' && me->used > 0)
739                 skiptest = 1; /* XXX skip test for %# %* %0 */
740         } else if (!skiptest && me->used <= 0) {
741 #if NOTYET
742             rpmlog(RPMLOG_ERR,
743                         _("Macro %%%s (%s) was not used below level %d\n"),
744                         me->name, me->body, me->level);
745 #endif
746         }
747         popMacro(mep);
748         if (!(mep && *mep))
749             ndeleted++;
750     }
751
752     /* If any deleted macros, sort macro table */
753     if (ndeleted)
754         sortMacroTable(mc);
755 }
756
757 /**
758  * Parse arguments (to next new line) for parameterized macro.
759  * @todo Use popt rather than getopt to parse args.
760  * @param mb            macro expansion state
761  * @param me            macro entry slot
762  * @param se            arguments to parse
763  * @param lastc         stop parsing at lastc
764  * @return              address to continue parsing
765  */
766 static const char *
767 grabArgs(MacroBuf mb, const rpmMacroEntry me, const char * se,
768                 const char * lastc)
769 {
770     const char *opts;
771     char *args = NULL;
772     ARGV_t argv = NULL;
773     int argc = 0;
774     int c;
775
776     /* Copy macro name as argv[0] */
777     argvAdd(&argv, me->name);
778     addMacro(mb->mc, "0", NULL, me->name, mb->depth);
779     
780     /* 
781      * Make a copy of se up to lastc string that we can pass to argvSplit().
782      * Append the results to main argv. 
783      */
784     {   ARGV_t av = NULL;
785         char *s = xcalloc((lastc-se)+1, sizeof(*s));
786         memcpy(s, se, (lastc-se));
787
788         argvSplit(&av, s, " \t");
789         argvAppend(&argv, av);
790
791         argvFree(av);
792         free(s);
793     }
794
795     /*
796      * The macro %* analoguous to the shell's $* means "Pass all non-macro
797      * parameters." Consequently, there needs to be a macro that means "Pass all
798      * (including macro parameters) options". This is useful for verifying
799      * parameters during expansion and yet transparently passing all parameters
800      * through for higher level processing (e.g. %description and/or %setup).
801      * This is the (potential) justification for %{**} ...
802     */
803     args = argvJoin(argv + 1, " ");
804     addMacro(mb->mc, "**", NULL, args, mb->depth);
805     free(args);
806
807     /*
808      * POSIX states optind must be 1 before any call but glibc uses 0
809      * to (re)initialize getopt structures, eww.
810      */
811 #ifdef __GLIBC__
812     optind = 0;
813 #else
814     optind = 1;
815 #endif
816
817     opts = me->opts;
818     argc = argvCount(argv);
819
820     /* Define option macros. */
821     while((c = getopt(argc, argv, opts)) != -1)
822     {
823         char *name = NULL, *body = NULL;
824         if (c == '?' || strchr(opts, c) == NULL) {
825             rpmlog(RPMLOG_ERR, _("Unknown option %c in %s(%s)\n"),
826                         (char)optopt, me->name, opts);
827             goto exit;
828         }
829
830         rasprintf(&name, "-%c", c);
831         if (optarg) {
832             rasprintf(&body, "-%c %s", c, optarg);
833         } else {
834             rasprintf(&body, "-%c", c);
835         }
836         addMacro(mb->mc, name, NULL, body, mb->depth);
837         free(name);
838         free(body);
839
840         if (optarg) {
841             rasprintf(&name, "-%c*", c);
842             addMacro(mb->mc, name, NULL, optarg, mb->depth);
843             free(name);
844         }
845     }
846
847     /* Add argument count (remaining non-option items) as macro. */
848     {   char *ac = NULL;
849         rasprintf(&ac, "%d", (argc - optind));
850         addMacro(mb->mc, "#", NULL, ac, mb->depth);
851         free(ac);
852     }
853
854     /* Add macro for each argument */
855     if (argc - optind) {
856         for (c = optind; c < argc; c++) {
857             char *name = NULL;
858             rasprintf(&name, "%d", (c - optind + 1));
859             addMacro(mb->mc, name, NULL, argv[c], mb->depth);
860             free(name);
861         }
862     }
863
864     /* Add concatenated unexpanded arguments as yet another macro. */
865     args = argvJoin(argv + optind, " ");
866     addMacro(mb->mc, "*", NULL, args ? args : "", mb->depth);
867     free(args);
868
869 exit:
870     argvFree(argv);
871     return *lastc ? lastc + 1 : lastc; 
872 }
873
874 /**
875  * Perform macro message output
876  * @param mb            macro expansion state
877  * @param waserror      use rpmlog()?
878  * @param msg           message to ouput
879  * @param msglen        no. of bytes in message
880  */
881 static void
882 doOutput(MacroBuf mb, int waserror, const char * msg, size_t msglen)
883 {
884     char *buf = NULL;
885
886     (void) expandThis(mb, msg, msglen, &buf);
887     if (waserror)
888         rpmlog(RPMLOG_ERR, "%s\n", buf);
889     else
890         fprintf(stderr, "%s", buf);
891     _free(buf);
892 }
893
894 /**
895  * Execute macro primitives.
896  * @param mb            macro expansion state
897  * @param negate        should logic be inverted?
898  * @param f             beginning of field f
899  * @param fn            length of field f
900  * @param g             beginning of field g
901  * @param gn            length of field g
902  */
903 static void
904 doFoo(MacroBuf mb, int negate, const char * f, size_t fn,
905                 const char * g, size_t gn)
906 {
907     char *buf = NULL;
908     char *b = NULL, *be;
909     int c;
910
911     if (g != NULL) {
912         (void) expandThis(mb, g, gn, &buf);
913     } else {
914         buf = xmalloc(MACROBUFSIZ + fn + gn);
915         buf[0] = '\0';
916     }
917     if (STREQ("basename", f, fn)) {
918         if ((b = strrchr(buf, '/')) == NULL)
919             b = buf;
920         else
921             b++;
922     } else if (STREQ("dirname", f, fn)) {
923         if ((b = strrchr(buf, '/')) != NULL)
924             *b = '\0';
925         b = buf;
926     } else if (STREQ("suffix", f, fn)) {
927         if ((b = strrchr(buf, '.')) != NULL)
928             b++;
929     } else if (STREQ("expand", f, fn)) {
930         b = buf;
931     } else if (STREQ("verbose", f, fn)) {
932         if (negate)
933             b = (rpmIsVerbose() ? NULL : buf);
934         else
935             b = (rpmIsVerbose() ? buf : NULL);
936     } else if (STREQ("url2path", f, fn) || STREQ("u2p", f, fn)) {
937         (void)urlPath(buf, (const char **)&b);
938         if (*b == '\0') b = "/";
939     } else if (STREQ("uncompress", f, fn)) {
940         rpmCompressedMagic compressed = COMPRESSED_OTHER;
941         for (b = buf; (c = *b) && isblank(c);)
942             b++;
943         for (be = b; (c = *be) && !isblank(c);)
944             be++;
945         *be++ = '\0';
946         (void) rpmFileIsCompressed(b, &compressed);
947         switch(compressed) {
948         default:
949         case COMPRESSED_NOT:
950             sprintf(be, "%%__cat %s", b);
951             break;
952         case COMPRESSED_OTHER:
953             sprintf(be, "%%__gzip -dc %s", b);
954             break;
955         case COMPRESSED_BZIP2:
956             sprintf(be, "%%__bzip2 -dc %s", b);
957             break;
958         case COMPRESSED_ZIP:
959             sprintf(be, "%%__unzip %s", b);
960             break;
961         case COMPRESSED_LZMA:
962         case COMPRESSED_XZ:
963             sprintf(be, "%%__xz -dc %s", b);
964             break;
965         case COMPRESSED_LZIP:
966             sprintf(be, "%%__lzip -dc %s", b);
967             break;
968         case COMPRESSED_LRZIP:
969             sprintf(be, "%%__lrzip -dqo- %s", b);
970             break;
971         case COMPRESSED_7ZIP:
972             sprintf(be, "%%__7zip x %s", b);
973             break;
974         }
975         b = be;
976     } else if (STREQ("getenv", f, fn)) {
977         b = getenv(buf);
978     } else if (STREQ("getconfdir", f, fn)) {
979         sprintf(buf, "%s", rpmConfigDir());
980         b = buf;
981     } else if (STREQ("S", f, fn)) {
982         for (b = buf; (c = *b) && risdigit(c);)
983             b++;
984         if (!c) {       /* digit index */
985             b++;
986             sprintf(b, "%%SOURCE%s", buf);
987         } else
988             b = buf;
989     } else if (STREQ("P", f, fn)) {
990         for (b = buf; (c = *b) && risdigit(c);)
991             b++;
992         if (!c) {       /* digit index */
993             b++;
994             sprintf(b, "%%PATCH%s", buf);
995         } else
996                         b = buf;
997     } else if (STREQ("F", f, fn)) {
998         b = buf + strlen(buf) + 1;
999         sprintf(b, "file%s.file", buf);
1000     }
1001
1002     if (b) {
1003         (void) expandMacro(mb, b, 0);
1004     }
1005     free(buf);
1006 }
1007
1008 /**
1009  * The main macro recursion loop.
1010  * @param mb            macro expansion state
1011  * @param src           string to expand
1012  * @return              0 on success, 1 on failure
1013  */
1014 static int
1015 expandMacro(MacroBuf mb, const char *src, size_t slen)
1016 {
1017     rpmMacroEntry *mep;
1018     rpmMacroEntry me;
1019     const char *s = src, *se;
1020     const char *f, *fe;
1021     const char *g, *ge;
1022     size_t fn, gn, tpos;
1023     int c;
1024     int rc = 0;
1025     int negate;
1026     const char * lastc;
1027     int chkexist;
1028     char *source = NULL;
1029
1030     /* Handle non-terminated substrings by creating a terminated copy */
1031     if (!slen)
1032         slen = strlen(src);
1033     source = xmalloc(slen + 1);
1034     strncpy(source, src, slen);
1035     source[slen] = '\0';
1036     s = source;
1037
1038     if (mb->buf == NULL) {
1039         size_t blen = MACROBUFSIZ + strlen(s);
1040         mb->buf = xcalloc(blen + 1, sizeof(*mb->buf));
1041         mb->tpos = 0;
1042         mb->nb = blen;
1043     }
1044     tpos = mb->tpos; /* save expansion pointer for printExpand */
1045
1046     if (++mb->depth > max_macro_depth) {
1047         rpmlog(RPMLOG_ERR,
1048                 _("Too many levels of recursion in macro expansion. It is likely caused by recursive macro declaration.\n"));
1049         mb->depth--;
1050         mb->expand_trace = 1;
1051         _free(source);
1052         return 1;
1053     }
1054
1055     while (rc == 0 && (c = *s) != '\0') {
1056         s++;
1057         /* Copy text until next macro */
1058         switch(c) {
1059         case '%':
1060                 if (*s) {       /* Ensure not end-of-string. */
1061                     if (*s != '%')
1062                         break;
1063                     s++;        /* skip first % in %% */
1064                 }
1065         default:
1066                 mbAppend(mb, c);
1067                 continue;
1068                 break;
1069         }
1070
1071         /* Expand next macro */
1072         f = fe = NULL;
1073         g = ge = NULL;
1074         if (mb->depth > 1)      /* XXX full expansion for outermost level */
1075             tpos = mb->tpos;    /* save expansion pointer for printExpand */
1076         negate = 0;
1077         lastc = NULL;
1078         chkexist = 0;
1079         switch ((c = *s)) {
1080         default:                /* %name substitution */
1081                 while (strchr("!?", *s) != NULL) {
1082                         switch(*s++) {
1083                         case '!':
1084                                 negate = ((negate + 1) % 2);
1085                                 break;
1086                         case '?':
1087                                 chkexist++;
1088                                 break;
1089                         }
1090                 }
1091                 f = se = s;
1092                 if (*se == '-')
1093                         se++;
1094                 while((c = *se) && (risalnum(c) || c == '_'))
1095                         se++;
1096                 /* Recognize non-alnum macros too */
1097                 switch (*se) {
1098                 case '*':
1099                         se++;
1100                         if (*se == '*') se++;
1101                         break;
1102                 case '#':
1103                         se++;
1104                         break;
1105                 default:
1106                         break;
1107                 }
1108                 fe = se;
1109                 /* For "%name " macros ... */
1110                 if ((c = *fe) && isblank(c))
1111                         if ((lastc = strchr(fe,'\n')) == NULL)
1112                 lastc = strchr(fe, '\0');
1113                 break;
1114         case '(':               /* %(...) shell escape */
1115                 if ((se = matchchar(s, c, ')')) == NULL) {
1116                         rpmlog(RPMLOG_ERR,
1117                                 _("Unterminated %c: %s\n"), (char)c, s);
1118                         rc = 1;
1119                         continue;
1120                 }
1121                 if (mb->macro_trace)
1122                         printMacro(mb, s, se+1);
1123
1124                 s++;    /* skip ( */
1125                 rc = doShellEscape(mb, s, (se - s));
1126                 se++;   /* skip ) */
1127
1128                 s = se;
1129                 continue;
1130                 break;
1131         case '{':               /* %{...}/%{...:...} substitution */
1132                 if ((se = matchchar(s, c, '}')) == NULL) {
1133                         rpmlog(RPMLOG_ERR,
1134                                 _("Unterminated %c: %s\n"), (char)c, s);
1135                         rc = 1;
1136                         continue;
1137                 }
1138                 f = s+1;/* skip { */
1139                 se++;   /* skip } */
1140                 while (strchr("!?", *f) != NULL) {
1141                         switch(*f++) {
1142                         case '!':
1143                                 negate = ((negate + 1) % 2);
1144                                 break;
1145                         case '?':
1146                                 chkexist++;
1147                                 break;
1148                         }
1149                 }
1150                 for (fe = f; (c = *fe) && !strchr(" :}", c);)
1151                         fe++;
1152                 switch (c) {
1153                 case ':':
1154                         g = fe + 1;
1155                         ge = se - 1;
1156                         break;
1157                 case ' ':
1158                         lastc = se-1;
1159                         break;
1160                 default:
1161                         break;
1162                 }
1163                 break;
1164         }
1165
1166         /* XXX Everything below expects fe > f */
1167         fn = (fe - f);
1168         gn = (ge - g);
1169         if ((fe - f) <= 0) {
1170 /* XXX Process % in unknown context */
1171                 c = '%';        /* XXX only need to save % */
1172                 mbAppend(mb, c);
1173 #if 0
1174                 rpmlog(RPMLOG_ERR,
1175                         _("A %% is followed by an unparseable macro\n"));
1176 #endif
1177                 s = se;
1178                 continue;
1179         }
1180
1181         if (mb->macro_trace)
1182                 printMacro(mb, s, se);
1183
1184         /* Expand builtin macros */
1185         if (STREQ("global", f, fn)) {
1186                 s = doDefine(mb, se, RMIL_GLOBAL, 1);
1187                 continue;
1188         }
1189         if (STREQ("define", f, fn)) {
1190                 s = doDefine(mb, se, mb->depth, 0);
1191                 continue;
1192         }
1193         if (STREQ("undefine", f, fn)) {
1194                 s = doUndefine(mb->mc, se);
1195                 continue;
1196         }
1197
1198         if (STREQ("echo", f, fn) ||
1199             STREQ("warn", f, fn) ||
1200             STREQ("error", f, fn)) {
1201                 int waserror = 0;
1202                 if (STREQ("error", f, fn))
1203                         waserror = 1;
1204                 if (g != NULL && g < ge)
1205                         doOutput(mb, waserror, g, gn);
1206                 else
1207                         doOutput(mb, waserror, f, fn);
1208                 s = se;
1209                 continue;
1210         }
1211
1212         if (STREQ("trace", f, fn)) {
1213                 /* XXX TODO restore expand_trace/macro_trace to 0 on return */
1214                 mb->expand_trace = mb->macro_trace = (negate ? 0 : mb->depth);
1215                 if (mb->depth == 1) {
1216                         print_macro_trace = mb->macro_trace;
1217                         print_expand_trace = mb->expand_trace;
1218                 }
1219                 s = se;
1220                 continue;
1221         }
1222
1223         if (STREQ("dump", f, fn)) {
1224                 rpmDumpMacroTable(mb->mc, NULL);
1225                 while (iseol(*se))
1226                         se++;
1227                 s = se;
1228                 continue;
1229         }
1230
1231 #ifdef  WITH_LUA
1232         if (STREQ("lua", f, fn)) {
1233                 rpmlua lua = NULL; /* Global state. */
1234                 const char *ls = s+sizeof("{lua:")-1;
1235                 const char *lse = se-sizeof("}")+1;
1236                 char *scriptbuf = (char *)xmalloc((lse-ls)+1);
1237                 char *printbuf;
1238                 memcpy(scriptbuf, ls, lse-ls);
1239                 scriptbuf[lse-ls] = '\0';
1240                 rpmluaPushPrintBuffer(lua);
1241                 if (rpmluaRunScript(lua, scriptbuf, NULL) == -1)
1242                     rc = 1;
1243                 printbuf = rpmluaPopPrintBuffer(lua);
1244                 if (printbuf) {
1245                     mbAppendStr(mb, printbuf);
1246                     free(printbuf);
1247                 }
1248                 free(scriptbuf);
1249                 s = se;
1250                 continue;
1251         }
1252 #endif
1253
1254         /* XXX necessary but clunky */
1255         if (STREQ("basename", f, fn) ||
1256             STREQ("dirname", f, fn) ||
1257             STREQ("suffix", f, fn) ||
1258             STREQ("expand", f, fn) ||
1259             STREQ("verbose", f, fn) ||
1260             STREQ("uncompress", f, fn) ||
1261             STREQ("url2path", f, fn) ||
1262             STREQ("u2p", f, fn) ||
1263             STREQ("getenv", f, fn) ||
1264             STREQ("getconfdir", f, fn) ||
1265             STREQ("S", f, fn) ||
1266             STREQ("P", f, fn) ||
1267             STREQ("F", f, fn)) {
1268                 /* FIX: verbose may be set */
1269                 doFoo(mb, negate, f, fn, g, gn);
1270                 s = se;
1271                 continue;
1272         }
1273
1274         /* Expand defined macros */
1275         mep = findEntry(mb->mc, f, fn);
1276         me = (mep ? *mep : NULL);
1277
1278         /* XXX Special processing for flags */
1279         if (*f == '-') {
1280                 if (me)
1281                         me->used++;     /* Mark macro as used */
1282                 if ((me == NULL && !negate) ||  /* Without -f, skip %{-f...} */
1283                     (me != NULL && negate)) {   /* With -f, skip %{!-f...} */
1284                         s = se;
1285                         continue;
1286                 }
1287
1288                 if (g && g < ge) {              /* Expand X in %{-f:X} */
1289                         rc = expandMacro(mb, g, gn);
1290                 } else
1291                 if (me && me->body && *me->body) {/* Expand %{-f}/%{-f*} */
1292                         rc = expandMacro(mb, me->body, 0);
1293                 }
1294                 s = se;
1295                 continue;
1296         }
1297
1298         /* XXX Special processing for macro existence */
1299         if (chkexist) {
1300                 if ((me == NULL && !negate) ||  /* Without -f, skip %{?f...} */
1301                     (me != NULL && negate)) {   /* With -f, skip %{!?f...} */
1302                         s = se;
1303                         continue;
1304                 }
1305                 if (g && g < ge) {              /* Expand X in %{?f:X} */
1306                         rc = expandMacro(mb, g, gn);
1307                 } else
1308                 if (me && me->body && *me->body) { /* Expand %{?f}/%{?f*} */
1309                         rc = expandMacro(mb, me->body, 0);
1310                 }
1311                 s = se;
1312                 continue;
1313         }
1314         
1315         if (me == NULL) {       /* leave unknown %... as is */
1316                 /* XXX hack to permit non-overloaded %foo to be passed */
1317                 c = '%';        /* XXX only need to save % */
1318                 mbAppend(mb, c);
1319                 continue;
1320         }
1321
1322         /* Setup args for "%name " macros with opts */
1323         if (me && me->opts != NULL) {
1324                 if (lastc != NULL) {
1325                         se = grabArgs(mb, me, fe, lastc);
1326                 } else {
1327                         addMacro(mb->mc, "**", NULL, "", mb->depth);
1328                         addMacro(mb->mc, "*", NULL, "", mb->depth);
1329                         addMacro(mb->mc, "#", NULL, "0", mb->depth);
1330                         addMacro(mb->mc, "0", NULL, me->name, mb->depth);
1331                 }
1332         }
1333
1334         /* Recursively expand body of macro */
1335         if (me->body && *me->body) {
1336                 rc = expandMacro(mb, me->body, 0);
1337                 if (rc == 0)
1338                         me->used++;     /* Mark macro as used */
1339         }
1340
1341         /* Free args for "%name " macros with opts */
1342         if (me->opts != NULL)
1343                 freeArgs(mb);
1344
1345         s = se;
1346     }
1347
1348     mb->buf[mb->tpos] = '\0';
1349     mb->depth--;
1350     if (rc != 0 || mb->expand_trace)
1351         printExpansion(mb, mb->buf+tpos, mb->buf+mb->tpos);
1352     _free(source);
1353     return rc;
1354 }
1355
1356
1357 /* =============================================================== */
1358
1359 static int doExpandMacros(rpmMacroContext mc, const char *src, char **target)
1360 {
1361     MacroBuf mb = xcalloc(1, sizeof(*mb));
1362     int rc = 0;
1363
1364     if (mc == NULL) mc = rpmGlobalMacroContext;
1365
1366     mb->buf = NULL;
1367     mb->depth = 0;
1368     mb->macro_trace = print_macro_trace;
1369     mb->expand_trace = print_expand_trace;
1370     mb->mc = mc;
1371
1372     rc = expandMacro(mb, src, 0);
1373
1374     mb->buf[mb->tpos] = '\0';   /* XXX just in case */
1375     /* expanded output is usually much less than alloced buffer, downsize */
1376     *target = xrealloc(mb->buf, mb->tpos + 1);
1377
1378     _free(mb);
1379     return rc;
1380 }
1381
1382 int expandMacros(void * spec, rpmMacroContext mc, char * sbuf, size_t slen)
1383 {
1384     char *target = NULL;
1385     int rc = doExpandMacros(mc, sbuf, &target);
1386     rstrlcpy(sbuf, target, slen);
1387     free(target);
1388     return rc;
1389 }
1390
1391 void
1392 addMacro(rpmMacroContext mc,
1393         const char * n, const char * o, const char * b, int level)
1394 {
1395     rpmMacroEntry * mep;
1396
1397     if (mc == NULL) mc = rpmGlobalMacroContext;
1398
1399     /* If new name, expand macro table */
1400     if ((mep = findEntry(mc, n, 0)) == NULL) {
1401         if (mc->firstFree == mc->macrosAllocated)
1402             expandMacroTable(mc);
1403         if (mc->macroTable != NULL)
1404             mep = mc->macroTable + mc->firstFree++;
1405     }
1406
1407     if (mep != NULL) {
1408         /* Push macro over previous definition */
1409         pushMacro(mep, n, o, b, level);
1410
1411         /* If new name, sort macro table */
1412         if ((*mep)->prev == NULL)
1413             sortMacroTable(mc);
1414     }
1415 }
1416
1417 void
1418 delMacro(rpmMacroContext mc, const char * n)
1419 {
1420     rpmMacroEntry * mep;
1421
1422     if (mc == NULL) mc = rpmGlobalMacroContext;
1423     /* If name exists, pop entry */
1424     if ((mep = findEntry(mc, n, 0)) != NULL) {
1425         popMacro(mep);
1426         /* If deleted name, sort macro table */
1427         if (!(mep && *mep))
1428             sortMacroTable(mc);
1429     }
1430 }
1431
1432 int
1433 rpmDefineMacro(rpmMacroContext mc, const char * macro, int level)
1434 {
1435     MacroBuf mb = xcalloc(1, sizeof(*mb));
1436
1437     /* XXX just enough to get by */
1438     mb->mc = (mc ? mc : rpmGlobalMacroContext);
1439     (void) doDefine(mb, macro, level, 0);
1440     _free(mb);
1441     return 0;
1442 }
1443
1444 void
1445 rpmLoadMacros(rpmMacroContext mc, int level)
1446 {
1447
1448     if (mc == NULL || mc == rpmGlobalMacroContext)
1449         return;
1450
1451     if (mc->macroTable != NULL) {
1452         int i;
1453         for (i = 0; i < mc->firstFree; i++) {
1454             rpmMacroEntry *mep, me;
1455             mep = &mc->macroTable[i];
1456             me = *mep;
1457
1458             if (me == NULL)             /* XXX this should never happen */
1459                 continue;
1460             addMacro(NULL, me->name, me->opts, me->body, (level - 1));
1461         }
1462     }
1463 }
1464
1465 int
1466 rpmLoadMacroFile(rpmMacroContext mc, const char * fn)
1467 {
1468     FILE *fd = fopen(fn, "r");
1469     size_t blen = MACROBUFSIZ;
1470     char *buf = xmalloc(blen);
1471     int rc = -1;
1472
1473     if (fd == NULL)
1474         goto exit;
1475
1476     /* XXX Assume new fangled macro expansion */
1477     max_macro_depth = 16;
1478
1479     buf[0] = '\0';
1480     while(rdcl(buf, blen, fd) != NULL) {
1481         char c, *n;
1482
1483         n = buf;
1484         SKIPBLANK(n, c);
1485
1486         if (c != '%')
1487                 continue;
1488         n++;    /* skip % */
1489         rc = rpmDefineMacro(mc, n, RMIL_MACROFILES);
1490     }
1491     rc = fclose(fd);
1492
1493 exit:
1494     _free(buf);
1495     return rc;
1496 }
1497
1498 void
1499 rpmInitMacros(rpmMacroContext mc, const char * macrofiles)
1500 {
1501     ARGV_t pattern, globs = NULL;
1502
1503     if (macrofiles == NULL)
1504         return;
1505
1506     argvSplit(&globs, macrofiles, ":");
1507     for (pattern = globs; *pattern; pattern++) {
1508         ARGV_t path, files = NULL;
1509     
1510         /* Glob expand the macro file path element, expanding ~ to $HOME. */
1511         if (rpmGlob(*pattern, NULL, &files) != 0) {
1512             continue;
1513         }
1514
1515         /* Read macros from each file. */
1516         for (path = files; *path; path++) {
1517             if (rpmFileHasSuffix(*path, ".rpmnew") || 
1518                 rpmFileHasSuffix(*path, ".rpmsave") ||
1519                 rpmFileHasSuffix(*path, ".rpmorig")) {
1520                 continue;
1521             }
1522             (void) rpmLoadMacroFile(mc, *path);
1523         }
1524         argvFree(files);
1525     }
1526     argvFree(globs);
1527
1528     /* Reload cmdline macros */
1529     rpmLoadMacros(rpmCLIMacroContext, RMIL_CMDLINE);
1530 }
1531
1532 void
1533 rpmFreeMacros(rpmMacroContext mc)
1534 {
1535     
1536     if (mc == NULL) mc = rpmGlobalMacroContext;
1537
1538     if (mc->macroTable != NULL) {
1539         for (int i = 0; i < mc->firstFree; i++) {
1540             while (mc->macroTable[i] != NULL) {
1541                 popMacro(&mc->macroTable[i]);
1542             }
1543         }
1544         free(mc->macroTable);
1545     }
1546     memset(mc, 0, sizeof(*mc));
1547 }
1548
1549 char * 
1550 rpmExpand(const char *arg, ...)
1551 {
1552     size_t blen = 0;
1553     char *buf = NULL, *ret = NULL;
1554     char *pe;
1555     const char *s;
1556     va_list ap;
1557
1558     if (arg == NULL) {
1559         ret = xstrdup("");
1560         goto exit;
1561     }
1562
1563     /* precalculate unexpanded size */
1564     va_start(ap, arg);
1565     for (s = arg; s != NULL; s = va_arg(ap, const char *))
1566         blen += strlen(s);
1567     va_end(ap);
1568
1569     buf = xmalloc(blen + 1);
1570     buf[0] = '\0';
1571
1572     va_start(ap, arg);
1573     for (pe = buf, s = arg; s != NULL; s = va_arg(ap, const char *))
1574         pe = stpcpy(pe, s);
1575     va_end(ap);
1576
1577     (void) doExpandMacros(NULL, buf, &ret);
1578
1579     free(buf);
1580 exit:
1581     return ret;
1582 }
1583
1584 int
1585 rpmExpandNumeric(const char *arg)
1586 {
1587     char *val;
1588     int rc;
1589
1590     if (arg == NULL)
1591         return 0;
1592
1593     val = rpmExpand(arg, NULL);
1594     if (!(val && *val != '%'))
1595         rc = 0;
1596     else if (*val == 'Y' || *val == 'y')
1597         rc = 1;
1598     else if (*val == 'N' || *val == 'n')
1599         rc = 0;
1600     else {
1601         char *end;
1602         rc = strtol(val, &end, 0);
1603         if (!(end && *end == '\0'))
1604             rc = 0;
1605     }
1606     free(val);
1607
1608     return rc;
1609 }