1 /** \ingroup rpmrc rpmio
15 #define isblank(_c) ((_c) == ' ' || (_c) == '\t')
17 #define iseol(_c) ((_c) == '\n' || (_c) == '\r')
19 #define STREQ(_t, _f, _fn) ((_fn) == (sizeof(_t)-1) && rstreqn((_t), (_f), (_fn)))
21 #define MACROBUFSIZ (BUFSIZ * 2)
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>
32 #include "rpmio/rpmlua.h"
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. */
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. */
55 static struct rpmMacroContext_s rpmGlobalMacroContext_s;
56 rpmMacroContext rpmGlobalMacroContext = &rpmGlobalMacroContext_s;
58 static struct rpmMacroContext_s rpmCLIMacroContext_s;
59 rpmMacroContext rpmCLIMacroContext = &rpmCLIMacroContext_s;
62 * Macro expansion state.
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? */
74 #define _MAX_MACRO_DEPTH 16
75 static int max_macro_depth = _MAX_MACRO_DEPTH;
77 #define _PRINT_MACRO_TRACE 0
78 static int print_macro_trace = _PRINT_MACRO_TRACE;
80 #define _PRINT_EXPAND_TRACE 0
81 static int print_expand_trace = _PRINT_EXPAND_TRACE;
83 #define MACRO_CHUNK_SIZE 16
86 static int expandMacro(MacroBuf mb, const char *src, size_t slen);
88 /* =============================================================== */
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
97 compareMacroName(const void * ap, const void * bp)
99 rpmMacroEntry ame = *((const rpmMacroEntry *)ap);
100 rpmMacroEntry bme = *((const rpmMacroEntry *)bp);
102 if (ame == NULL && bme == NULL)
108 return strcmp(ame->name, bme->name);
112 * Enlarge macro table.
113 * @param mc macro context
116 expandMacroTable(rpmMacroContext mc)
118 if (mc->macroTable == NULL) {
119 mc->macrosAllocated = MACRO_CHUNK_SIZE;
120 mc->macroTable = (rpmMacroEntry *)
121 xmalloc(sizeof(*(mc->macroTable)) * mc->macrosAllocated);
124 mc->macrosAllocated += MACRO_CHUNK_SIZE;
125 mc->macroTable = (rpmMacroEntry *)
126 xrealloc(mc->macroTable, sizeof(*(mc->macroTable)) *
127 mc->macrosAllocated);
129 memset(&mc->macroTable[mc->firstFree], 0, MACRO_CHUNK_SIZE * sizeof(*(mc->macroTable)));
133 * Sort entries in macro table.
134 * @param mc macro context
137 sortMacroTable(rpmMacroContext mc)
141 if (mc == NULL || mc->macroTable == NULL)
144 qsort(mc->macroTable, mc->firstFree, sizeof(*(mc->macroTable)),
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)
157 rpmDumpMacroTable(rpmMacroContext mc, FILE * fp)
162 if (mc == NULL) mc = rpmGlobalMacroContext;
163 if (fp == NULL) fp = stderr;
165 fprintf(fp, "========================\n");
166 if (mc->macroTable != NULL) {
168 for (i = 0; i < mc->firstFree; i++) {
170 if ((me = mc->macroTable[i]) == NULL) {
171 /* XXX this should never happen */
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);
185 fprintf(fp, _("======================== active %d empty %d\n"),
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)
196 static rpmMacroEntry *
197 findEntry(rpmMacroContext mc, const char * name, size_t namelen)
199 rpmMacroEntry key, *ret;
200 struct rpmMacroEntry_s keybuf;
201 char namebuf[namelen+1];
202 const char *mname = name;
204 if (mc == NULL) mc = rpmGlobalMacroContext;
205 if (mc->macroTable == NULL || mc->firstFree == 0)
209 strncpy(namebuf, name, namelen);
210 namebuf[namelen] = '\0';
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 */
223 /* =============================================================== */
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
233 rdcl(char * buf, size_t size, FILE *f)
235 char *q = buf - 1; /* initialize just before buffer. */
243 *(++q) = '\0'; /* terminate and move forward. */
244 if (fgets(q, size, f) == NULL) /* read next line. */
247 nread += nb; /* trim trailing \r and \n */
248 for (q += nb - 1; nb > 0 && iseol(*q); q--)
250 for (; p <= q; p++) {
260 case '{': p++, bc++; break;
261 case '(': p++, pc++; break;
262 case '%': p++; 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;
271 if (nb == 0 || (*q != '\\' && !bc && !pc) || *(q+1) == '\0') {
272 *(++q) = '\0'; /* trim trailing \r, \n */
275 q++; p++; nb++; /* copy newline too */
277 if (*q == '\r') /* XXX avoid \r madness */
280 return (nread > 0 ? buf : NULL);
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)
291 matchchar(const char * p, char pl, char pr)
296 while ((c = *p++) != '\0') {
297 if (c == '\\') { /* Ignore escaped chars */
302 if (--lvl <= 0) return --p;
306 return (const char *)NULL;
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
316 printMacro(MacroBuf mb, const char * s, const char * se)
319 const char *ellipsis;
322 if (s >= se) { /* XXX just in case */
323 fprintf(stderr, _("%3d>%*s(empty)"), mb->depth,
324 (2 * mb->depth + 1), "");
331 /* Print only to first end-of-line (or end-of-string). */
332 for (senl = se; *senl && !iseol(*senl); senl++)
335 /* Limit trailing non-trace output */
336 choplen = 61 - (2 * mb->depth);
337 if ((senl - s) > choplen) {
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");
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
358 printExpansion(MacroBuf mb, const char * t, const char * te)
360 const char *ellipsis;
364 rpmlog(RPMLOG_DEBUG, _("%3d<%*s(empty)\n"), mb->depth, (2 * mb->depth + 1), "");
368 /* Shorten output which contains newlines */
369 while (te > t && iseol(te[-1]))
375 /* Skip to last line of expansion */
376 while ((tenl = strchr(t, '\n')) && tenl < te)
379 /* Limit expand output */
380 choplen = 61 - (2 * mb->depth);
381 if ((te - t) > choplen) {
387 rpmlog(RPMLOG_DEBUG,"%3d<%*s", mb->depth, (2 * mb->depth + 1), "");
389 rpmlog(RPMLOG_DEBUG, "%.*s%s", (int)(te - t), t, ellipsis);
390 rpmlog(RPMLOG_DEBUG, "\n");
393 #define SKIPBLANK(_s, _c) \
394 while (((_c) = *(_s)) && isblank(_c)) \
397 #define SKIPNONBLANK(_s, _c) \
398 while (((_c) = *(_s)) && !(isblank(_c) || iseol(_c))) \
401 #define COPYNAME(_ne, _s, _c) \
402 { SKIPBLANK(_s,_c); \
403 while(((_c) = *(_s)) && (risalnum(_c) || (_c) == '_')) \
404 *(_ne)++ = *(_s)++; \
408 #define COPYOPTS(_oe, _s, _c) \
410 while(((_c) = *(_s)) && (_c) != ')') \
411 *(_oe)++ = *(_s)++; \
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
424 expandThis(MacroBuf mb, const char * src, size_t slen, char **target)
426 struct MacroBuf_s umb;
429 /* Copy other state from "parent", but we want a buffer of our own */
432 rc = expandMacro(&umb, src, slen);
438 static void mbAppend(MacroBuf mb, char c)
441 mb->buf = xrealloc(mb->buf, mb->tpos + mb->nb + MACROBUFSIZ);
442 mb->nb += MACROBUFSIZ;
444 mb->buf[mb->tpos++] = c;
448 static void mbAppendStr(MacroBuf mb, const char *str)
450 size_t len = strlen(str);
452 mb->buf = xrealloc(mb->buf, mb->tpos + mb->nb + MACROBUFSIZ + len);
453 mb->nb += MACROBUFSIZ + len;
455 memcpy(mb->buf+mb->tpos, str, len);
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
467 doShellEscape(MacroBuf mb, const char * cmd, size_t clen)
474 rc = expandThis(mb, cmd, clen, &buf);
478 if ((shf = popen(buf, "r")) == NULL) {
482 while((c = fgetc(shf)) != EOF) {
487 /* XXX delete trailing \r \n */
488 while (iseol(mb->buf[mb->tpos-1])) {
489 mb->buf[mb->tpos--] = '\0';
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
507 doDefine(MacroBuf mb, const char * se, int level, int expandbody)
510 size_t blen = MACROBUFSIZ;
511 char *buf = xmalloc(blen);
512 char *n = buf, *ne = n;
514 char *b, *be, *ebody = NULL;
521 /* Copy opts (if present) */
530 /* Copy body, skipping over escaped newlines */
533 if (c == '{') { /* XXX permit silent {...} grouping */
534 if ((se = matchchar(s, c, '}')) == NULL) {
536 _("Macro %%%s has unterminated body\n"), n);
537 se = s; /* XXX W2DO? */
540 s++; /* XXX skip { */
541 strncpy(b, s, (se - s));
544 se++; /* XXX skip } */
545 s = se; /* move scan forward */
546 } else { /* otherwise free-field */
548 while (*s && (bc || pc || !iseol(*s))) {
558 case '{': *be++ = *s++; bc++; break;
559 case '(': *be++ = *s++; pc++; break;
560 case '%': *be++ = *s++; 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;
574 _("Macro %%%s has unterminated body\n"), n);
575 se = s; /* XXX W2DO? */
579 /* Trim trailing blanks/newlines */
580 while (--be >= b && (c = *be) && (isblank(c) || iseol(c)))
582 *(++be) = '\0'; /* one too far */
585 /* Move scan over body */
590 /* Names must start with alphabetic or _ and be at least 3 chars */
591 if (!((c = *n) && (risalpha(c) || c == '_') && (ne - n) > 2)) {
593 _("Macro %%%s has illegal name (%%define)\n"), n);
597 /* Options must be terminated with ')' */
598 if (o && oc != ')') {
599 rpmlog(RPMLOG_ERR, _("Macro %%%s has unterminated opts\n"), n);
604 rpmlog(RPMLOG_ERR, _("Macro %%%s has empty body\n"), n);
609 if (expandThis(mb, b, 0, &ebody)) {
610 rpmlog(RPMLOG_ERR, _("Macro %%%s failed to expand\n"), n);
616 addMacro(mb->mc, n, o, b, (level - 1));
625 * Parse (and execute) macro undefinition.
626 * @param mc macro context
627 * @param se macro name to undefine
628 * @return address to continue parsing
631 doUndefine(rpmMacroContext mc, const char * se)
634 char *buf = xmalloc(MACROBUFSIZ);
635 char *n = buf, *ne = n;
640 /* Move scan over body */
645 /* Names must start with alphabetic or _ and be at least 3 chars */
646 if (!((c = *n) && (risalpha(c) || c == '_') && (ne - n) > 2)) {
648 _("Macro %%%s has illegal name (%%undefine)\n"), n);
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
668 pushMacro(rpmMacroEntry * mep,
669 const char * n, const char * o,
670 const char * b, int level)
672 rpmMacroEntry prev = (mep && *mep ? *mep : NULL);
673 rpmMacroEntry me = (rpmMacroEntry) xmalloc(sizeof(*me));
676 me->name = (prev ? prev->name : xstrdup(n));
677 me->opts = (o ? xstrdup(o) : NULL);
678 me->body = xstrdup(b ? b : "");
688 * Pop macro definition from macro entry stack.
689 * @param mep address of macro entry slot
692 popMacro(rpmMacroEntry * mep)
694 rpmMacroEntry me = (*mep ? *mep : NULL);
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);
707 * Free parsed arguments for parameterized macro.
708 * @param mb macro expansion state
711 freeArgs(MacroBuf mb)
713 rpmMacroContext mc = mb->mc;
717 if (mc == NULL || mc->macroTable == NULL)
720 /* Delete dynamic macro definitions */
721 for (i = 0; i < mc->firstFree; i++) {
722 rpmMacroEntry *mep, me;
724 mep = &mc->macroTable[i];
727 if (me == NULL) /* XXX this should never happen */
729 if (me->level < mb->depth)
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) {
737 _("Macro %%%s (%s) was not used below level %d\n"),
738 me->name, me->body, me->level);
746 /* If any deleted macros, sort macro table */
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
761 grabArgs(MacroBuf mb, const rpmMacroEntry me, const char * se,
770 /* Copy macro name as argv[0] */
771 argvAdd(&argv, me->name);
772 addMacro(mb->mc, "0", NULL, me->name, mb->depth);
775 * Make a copy of se up to lastc string that we can pass to argvSplit().
776 * Append the results to main argv.
779 char *s = xcalloc((lastc-se)+1, sizeof(*s));
780 memcpy(s, se, (lastc-se));
782 argvSplit(&av, s, " \t");
783 argvAppend(&argv, av);
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 %{**} ...
797 args = argvJoin(argv + 1, " ");
798 addMacro(mb->mc, "**", NULL, args, mb->depth);
802 * POSIX states optind must be 1 before any call but glibc uses 0
803 * to (re)initialize getopt structures, eww.
812 argc = argvCount(argv);
814 /* Define option macros. */
815 while((c = getopt(argc, argv, opts)) != -1)
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);
824 rasprintf(&name, "-%c", c);
826 rasprintf(&body, "-%c %s", c, optarg);
828 rasprintf(&body, "-%c", c);
830 addMacro(mb->mc, name, NULL, body, mb->depth);
835 rasprintf(&name, "-%c*", c);
836 addMacro(mb->mc, name, NULL, optarg, mb->depth);
841 /* Add argument count (remaining non-option items) as macro. */
843 rasprintf(&ac, "%d", (argc - optind));
844 addMacro(mb->mc, "#", NULL, ac, mb->depth);
848 /* Add macro for each argument */
850 for (c = optind; c < argc; c++) {
852 rasprintf(&name, "%d", (c - optind + 1));
853 addMacro(mb->mc, name, NULL, argv[c], mb->depth);
858 /* Add concatenated unexpanded arguments as yet another macro. */
859 args = argvJoin(argv + optind, " ");
860 addMacro(mb->mc, "*", NULL, args ? args : "", mb->depth);
865 return *lastc ? lastc + 1 : lastc;
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
876 doOutput(MacroBuf mb, int waserror, const char * msg, size_t msglen)
880 (void) expandThis(mb, msg, msglen, &buf);
882 rpmlog(RPMLOG_ERR, "%s\n", buf);
884 fprintf(stderr, "%s", buf);
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
898 doFoo(MacroBuf mb, int negate, const char * f, size_t fn,
899 const char * g, size_t gn)
906 (void) expandThis(mb, g, gn, &buf);
908 buf = xmalloc(MACROBUFSIZ + fn + gn);
911 if (STREQ("basename", f, fn)) {
912 if ((b = strrchr(buf, '/')) == NULL)
917 /* XXX watchout for conflict with %dir */
918 } else if (STREQ("dirname", f, fn)) {
919 if ((b = strrchr(buf, '/')) != NULL)
923 } else if (STREQ("suffix", f, fn)) {
924 if ((b = strrchr(buf, '.')) != NULL)
926 } else if (STREQ("expand", f, fn)) {
928 } else if (STREQ("verbose", f, fn)) {
930 b = (rpmIsVerbose() ? NULL : buf);
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);)
940 for (be = b; (c = *be) && !isblank(c);)
943 (void) rpmFileIsCompressed(b, &compressed);
947 sprintf(be, "%%__cat %s", b);
949 case COMPRESSED_OTHER:
950 sprintf(be, "%%__gzip -dc %s", b);
952 case COMPRESSED_BZIP2:
953 sprintf(be, "%%__bzip2 -dc %s", b);
956 sprintf(be, "%%__unzip %s", b);
958 case COMPRESSED_LZMA:
960 sprintf(be, "%%__xz -dc %s", b);
964 } else if (STREQ("getenv", f, fn)) {
966 } else if (STREQ("getconfdir", f, fn)) {
967 sprintf(buf, "%s", rpmConfigDir());
969 } else if (STREQ("S", f, fn)) {
970 for (b = buf; (c = *b) && risdigit(c);)
972 if (!c) { /* digit index */
974 sprintf(b, "%%SOURCE%s", buf);
977 } else if (STREQ("P", f, fn)) {
978 for (b = buf; (c = *b) && risdigit(c);)
980 if (!c) { /* digit index */
982 sprintf(b, "%%PATCH%s", buf);
985 } else if (STREQ("F", f, fn)) {
986 b = buf + strlen(buf) + 1;
987 sprintf(b, "file%s.file", buf);
991 (void) expandMacro(mb, b, 0);
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
1003 expandMacro(MacroBuf mb, const char *src, size_t slen)
1007 const char *s = src, *se;
1010 size_t fn, gn, tpos;
1016 char *source = NULL;
1018 /* Handle non-terminated substrings by creating a terminated copy */
1020 source = xmalloc(slen + 1);
1021 strncpy(source, src, slen);
1022 source[slen] = '\0';
1026 if (mb->buf == NULL) {
1027 size_t blen = MACROBUFSIZ + strlen(s);
1028 mb->buf = xcalloc(blen + 1, sizeof(*mb->buf));
1032 tpos = mb->tpos; /* save expansion pointer for printExpand */
1034 if (++mb->depth > max_macro_depth) {
1036 _("Too many levels of recursion in macro expansion. It is likely caused by recursive macro declaration.\n"));
1038 mb->expand_trace = 1;
1043 while (rc == 0 && (c = *s) != '\0') {
1045 /* Copy text until next macro */
1048 if (*s) { /* Ensure not end-of-string. */
1051 s++; /* skip first % in %% */
1059 /* Expand next macro */
1062 if (mb->depth > 1) /* XXX full expansion for outermost level */
1063 tpos = mb->tpos; /* save expansion pointer for printExpand */
1068 default: /* %name substitution */
1069 while (strchr("!?", *s) != NULL) {
1072 negate = ((negate + 1) % 2);
1082 while((c = *se) && (risalnum(c) || c == '_'))
1084 /* Recognize non-alnum macros too */
1088 if (*se == '*') se++;
1097 /* For "%name " macros ... */
1098 if ((c = *fe) && isblank(c))
1099 if ((lastc = strchr(fe,'\n')) == NULL)
1100 lastc = strchr(fe, '\0');
1102 case '(': /* %(...) shell escape */
1103 if ((se = matchchar(s, c, ')')) == NULL) {
1105 _("Unterminated %c: %s\n"), (char)c, s);
1109 if (mb->macro_trace)
1110 printMacro(mb, s, se+1);
1113 rc = doShellEscape(mb, s, (se - s));
1119 case '{': /* %{...}/%{...:...} substitution */
1120 if ((se = matchchar(s, c, '}')) == NULL) {
1122 _("Unterminated %c: %s\n"), (char)c, s);
1126 f = s+1;/* skip { */
1128 while (strchr("!?", *f) != NULL) {
1131 negate = ((negate + 1) % 2);
1138 for (fe = f; (c = *fe) && !strchr(" :}", c);)
1154 /* XXX Everything below expects fe > f */
1157 if ((fe - f) <= 0) {
1158 /* XXX Process % in unknown context */
1159 c = '%'; /* XXX only need to save % */
1163 _("A %% is followed by an unparseable macro\n"));
1169 if (mb->macro_trace)
1170 printMacro(mb, s, se);
1172 /* Expand builtin macros */
1173 if (STREQ("global", f, fn)) {
1174 s = doDefine(mb, se, RMIL_GLOBAL, 1);
1177 if (STREQ("define", f, fn)) {
1178 s = doDefine(mb, se, mb->depth, 0);
1181 if (STREQ("undefine", f, fn)) {
1182 s = doUndefine(mb->mc, se);
1186 if (STREQ("echo", f, fn) ||
1187 STREQ("warn", f, fn) ||
1188 STREQ("error", f, fn)) {
1190 if (STREQ("error", f, fn))
1192 if (g != NULL && g < ge)
1193 doOutput(mb, waserror, g, gn);
1195 doOutput(mb, waserror, f, fn);
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;
1211 if (STREQ("dump", f, fn)) {
1212 rpmDumpMacroTable(mb->mc, NULL);
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)
1231 printbuf = rpmluaGetPrintBuffer(lua);
1233 mbAppendStr(mb, printbuf);
1235 rpmluaSetPrintBuffer(lua, 0);
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);
1261 /* Expand defined macros */
1262 mep = findEntry(mb->mc, f, fn);
1263 me = (mep ? *mep : NULL);
1265 /* XXX Special processing for flags */
1268 me->used++; /* Mark macro as used */
1269 if ((me == NULL && !negate) || /* Without -f, skip %{-f...} */
1270 (me != NULL && negate)) { /* With -f, skip %{!-f...} */
1275 if (g && g < ge) { /* Expand X in %{-f:X} */
1276 rc = expandMacro(mb, g, gn);
1278 if (me && me->body && *me->body) {/* Expand %{-f}/%{-f*} */
1279 rc = expandMacro(mb, me->body, 0);
1285 /* XXX Special processing for macro existence */
1287 if ((me == NULL && !negate) || /* Without -f, skip %{?f...} */
1288 (me != NULL && negate)) { /* With -f, skip %{!?f...} */
1292 if (g && g < ge) { /* Expand X in %{?f:X} */
1293 rc = expandMacro(mb, g, gn);
1295 if (me && me->body && *me->body) { /* Expand %{?f}/%{?f*} */
1296 rc = expandMacro(mb, me->body, 0);
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 % */
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);
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);
1321 /* Recursively expand body of macro */
1322 if (me->body && *me->body) {
1323 rc = expandMacro(mb, me->body, 0);
1325 me->used++; /* Mark macro as used */
1328 /* Free args for "%name " macros with opts */
1329 if (me->opts != NULL)
1335 mb->buf[mb->tpos] = '\0';
1337 if (rc != 0 || mb->expand_trace)
1338 printExpansion(mb, mb->buf+tpos, mb->buf+mb->tpos);
1344 /* =============================================================== */
1346 static int doExpandMacros(rpmMacroContext mc, const char *src, char **target)
1348 MacroBuf mb = xcalloc(1, sizeof(*mb));
1351 if (mc == NULL) mc = rpmGlobalMacroContext;
1355 mb->macro_trace = print_macro_trace;
1356 mb->expand_trace = print_expand_trace;
1359 rc = expandMacro(mb, src, 0);
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);
1369 int expandMacros(void * spec, rpmMacroContext mc, char * sbuf, size_t slen)
1371 char *target = NULL;
1372 int rc = doExpandMacros(mc, sbuf, &target);
1373 rstrlcpy(sbuf, target, slen);
1379 addMacro(rpmMacroContext mc,
1380 const char * n, const char * o, const char * b, int level)
1382 rpmMacroEntry * mep;
1384 if (mc == NULL) mc = rpmGlobalMacroContext;
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++;
1395 /* Push macro over previous definition */
1396 pushMacro(mep, n, o, b, level);
1398 /* If new name, sort macro table */
1399 if ((*mep)->prev == NULL)
1405 delMacro(rpmMacroContext mc, const char * n)
1407 rpmMacroEntry * mep;
1409 if (mc == NULL) mc = rpmGlobalMacroContext;
1410 /* If name exists, pop entry */
1411 if ((mep = findEntry(mc, n, 0)) != NULL) {
1413 /* If deleted name, sort macro table */
1420 rpmDefineMacro(rpmMacroContext mc, const char * macro, int level)
1422 MacroBuf mb = xcalloc(1, sizeof(*mb));
1424 /* XXX just enough to get by */
1425 mb->mc = (mc ? mc : rpmGlobalMacroContext);
1426 (void) doDefine(mb, macro, level, 0);
1432 rpmLoadMacros(rpmMacroContext mc, int level)
1435 if (mc == NULL || mc == rpmGlobalMacroContext)
1438 if (mc->macroTable != NULL) {
1440 for (i = 0; i < mc->firstFree; i++) {
1441 rpmMacroEntry *mep, me;
1442 mep = &mc->macroTable[i];
1445 if (me == NULL) /* XXX this should never happen */
1447 addMacro(NULL, me->name, me->opts, me->body, (level - 1));
1453 rpmLoadMacroFile(rpmMacroContext mc, const char * fn)
1455 FILE *fd = fopen(fn, "r");
1456 size_t blen = MACROBUFSIZ;
1457 char *buf = xmalloc(blen);
1460 if (fd == NULL || ferror(fd)) {
1461 if (fd) (void) fclose(fd);
1465 /* XXX Assume new fangled macro expansion */
1466 max_macro_depth = 16;
1469 while(rdcl(buf, blen, fd) != NULL) {
1478 rc = rpmDefineMacro(mc, n, RMIL_MACROFILES);
1488 rpmInitMacros(rpmMacroContext mc, const char * macrofiles)
1490 ARGV_t pattern, globs = NULL;
1492 if (macrofiles == NULL)
1495 argvSplit(&globs, macrofiles, ":");
1496 for (pattern = globs; *pattern; pattern++) {
1497 ARGV_t path, files = NULL;
1499 /* Glob expand the macro file path element, expanding ~ to $HOME. */
1500 if (rpmGlob(*pattern, NULL, &files) != 0) {
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")) {
1511 (void) rpmLoadMacroFile(mc, *path);
1517 /* Reload cmdline macros */
1518 rpmLoadMacros(rpmCLIMacroContext, RMIL_CMDLINE);
1522 rpmFreeMacros(rpmMacroContext mc)
1525 if (mc == NULL) mc = rpmGlobalMacroContext;
1527 if (mc->macroTable != NULL) {
1529 for (i = 0; i < mc->firstFree; i++) {
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);
1540 mc->macroTable = _free(mc->macroTable);
1542 memset(mc, 0, sizeof(*mc));
1546 rpmExpand(const char *arg, ...)
1549 char *buf = NULL, *ret = NULL;
1559 /* precalculate unexpanded size */
1561 for (s = arg; s != NULL; s = va_arg(ap, const char *))
1565 buf = xmalloc(blen + 1);
1569 for (pe = buf, s = arg; s != NULL; s = va_arg(ap, const char *))
1573 (void) doExpandMacros(NULL, buf, &ret);
1581 rpmExpandNumeric(const char *arg)
1589 val = rpmExpand(arg, NULL);
1590 if (!(val && *val != '%'))
1592 else if (*val == 'Y' || *val == 'y')
1594 else if (*val == 'N' || *val == 'n')
1598 rc = strtol(val, &end, 0);
1599 if (!(end && *end == '\0'))