00001
00005 static int _debug = 0;
00006
00007 #include "system.h"
00008 #include <stdarg.h>
00009
00010 #if !defined(isblank)
00011 #define isblank(_c) ((_c) == ' ' || (_c) == '\t')
00012 #endif
00013 #define iseol(_c) ((_c) == '\n' || (_c) == '\r')
00014
00015 #define STREQ(_t, _f, _fn) ((_fn) == (sizeof(_t)-1) && !strncmp((_t), (_f), (_fn)))
00016 #define FREE(_x) { if (_x) free((void *)_x); (_x) = NULL; }
00017
00018 #ifdef DEBUG_MACROS
00019 #include <sys/types.h>
00020 #include <errno.h>
00021 #include <fcntl.h>
00022 #include <getopt.h>
00023 #include <stdio.h>
00024 #include <stdlib.h>
00025 #include <string.h>
00026 #define rpmError fprintf
00027 #define RPMERR_BADSPEC stderr
00028 #undef _
00029 #define _(x) x
00030
00031 #define vmefail() (exit(1), NULL)
00032 #define urlPath(_xr, _r) *(_r) = (_xr)
00033
00034 typedef FILE * FD_t;
00035 #define Fopen(_path, _fmode) fopen(_path, "r");
00036 #define Ferror ferror
00037 #define Fstrerror(_fd) strerror(errno)
00038 #define Fread fread
00039 #define Fclose fclose
00040
00041 #define fdGetFILE(_fd) (_fd)
00042
00043 #else
00044
00045 #include <rpmio_internal.h>
00046 #include <rpmmessages.h>
00047 #include <rpmerr.h>
00048
00049 #endif
00050
00051 #include <rpmmacro.h>
00052
00053 #include "debug.h"
00054
00055
00056
00057
00058
00059 struct MacroContext rpmGlobalMacroContext;
00060 struct MacroContext rpmCLIMacroContext;
00061
00065 typedef struct MacroBuf {
00066 const char *s;
00067 char *t;
00068 size_t nb;
00069 int depth;
00070 int macro_trace;
00071 int expand_trace;
00072 void *spec;
00073 MacroContext *mc;
00074 } MacroBuf;
00075
00076 #define SAVECHAR(_mb, _c) { *(_mb)->t = (_c), (_mb)->t++, (_mb)->nb--; }
00077
00078 static int expandMacro(MacroBuf *mb);
00079
00080 #define MAX_MACRO_DEPTH 16
00081 int max_macro_depth = MAX_MACRO_DEPTH;
00082
00083 #ifdef DEBUG_MACROS
00084 int print_macro_trace = 0;
00085 int print_expand_trace = 0;
00086 #else
00087 int print_macro_trace = 0;
00088 int print_expand_trace = 0;
00089 #endif
00090
00091 #define MACRO_CHUNK_SIZE 16
00092
00093
00094
00101 static int
00102 compareMacroName(const void *ap, const void *bp)
00103 {
00104 MacroEntry *ame = *((MacroEntry **)ap);
00105 MacroEntry *bme = *((MacroEntry **)bp);
00106
00107 if (ame == NULL && bme == NULL)
00108 return 0;
00109 if (ame == NULL)
00110 return 1;
00111 if (bme == NULL)
00112 return -1;
00113 return strcmp(ame->name, bme->name);
00114 }
00115
00120 static void
00121 expandMacroTable(MacroContext *mc)
00122 {
00123 if (mc->macroTable == NULL) {
00124 mc->macrosAllocated = MACRO_CHUNK_SIZE;
00125 mc->macroTable = (MacroEntry **)
00126 xmalloc(sizeof(*(mc->macroTable)) * mc->macrosAllocated);
00127 mc->firstFree = 0;
00128 } else {
00129 mc->macrosAllocated += MACRO_CHUNK_SIZE;
00130 mc->macroTable = (MacroEntry **)
00131 xrealloc(mc->macroTable, sizeof(*(mc->macroTable)) *
00132 mc->macrosAllocated);
00133 }
00134 memset(&mc->macroTable[mc->firstFree], 0, MACRO_CHUNK_SIZE * sizeof(*(mc->macroTable)));
00135 }
00136
00141 static void
00142 sortMacroTable(MacroContext *mc)
00143 {
00144 int i;
00145
00146 qsort(mc->macroTable, mc->firstFree, sizeof(*(mc->macroTable)),
00147 compareMacroName);
00148
00149
00150 for (i = 0; i < mc->firstFree; i++) {
00151 if (mc->macroTable[i] != NULL)
00152 continue;
00153 mc->firstFree = i;
00154 break;
00155 }
00156 }
00157
00158 void
00159 rpmDumpMacroTable(MacroContext * mc, FILE * fp)
00160 {
00161 int i;
00162 int nempty = 0;
00163 int nactive = 0;
00164
00165 if (mc == NULL)
00166 mc = &rpmGlobalMacroContext;
00167 if (fp == NULL)
00168 fp = stderr;
00169
00170 fprintf(fp, "========================\n");
00171 for (i = 0; i < mc->firstFree; i++) {
00172 MacroEntry *me;
00173 if ((me = mc->macroTable[i]) == NULL) {
00174
00175 nempty++;
00176 continue;
00177 }
00178 fprintf(fp, "%3d%c %s", me->level,
00179 (me->used > 0 ? '=' : ':'), me->name);
00180 if (me->opts && *me->opts)
00181 fprintf(fp, "(%s)", me->opts);
00182 if (me->body && *me->body)
00183 fprintf(fp, "\t%s", me->body);
00184 fprintf(fp, "\n");
00185 nactive++;
00186 }
00187 fprintf(fp, _("======================== active %d empty %d\n"),
00188 nactive, nempty);
00189 }
00190
00198 static MacroEntry **
00199 findEntry(MacroContext *mc, const char *name, size_t namelen)
00200 {
00201 MacroEntry keybuf, *key, **ret;
00202 char namebuf[1024];
00203
00204 if (mc == NULL)
00205 mc = &rpmGlobalMacroContext;
00206 if (! mc->firstFree)
00207 return NULL;
00208
00209 if (namelen > 0) {
00210 strncpy(namebuf, name, namelen);
00211 namebuf[namelen] = '\0';
00212 name = namebuf;
00213 }
00214
00215 key = &keybuf;
00216 memset(key, 0, sizeof(*key));
00217 key->name = (char *)name;
00218 ret = (MacroEntry **)bsearch(&key, mc->macroTable, mc->firstFree,
00219 sizeof(*(mc->macroTable)), compareMacroName);
00220
00221 return ret;
00222 }
00223
00224
00225
00229 static char *
00230 rdcl(char *buf, size_t size, FD_t fd, int escapes)
00231 {
00232 char *q = buf;
00233 size_t nb = 0;
00234 size_t nread = 0;
00235
00236 *q = '\0';
00237 do {
00238
00239 if (fgets(q, size, fdGetFILE(fd)) == NULL)
00240 break;
00241 nb = strlen(q);
00242 nread += nb;
00243 for (q += nb - 1; nb > 0 && iseol(*q); q--)
00244 nb--;
00245 if (!(nb > 0 && *q == '\\')) {
00246 *(++q) = '\0';
00247 break;
00248 }
00249 if (escapes) {
00250 q++;
00251 nb++;
00252 }
00253 size -= nb;
00254 if (*q == '\r')
00255 *q = '\n';
00256 *(++q) = '\0';
00257 } while (size > 0);
00258 return (nread > 0 ? buf : NULL);
00259 }
00260
00268 static const char *
00269 matchchar(const char *p, char pl, char pr)
00270 {
00271 int lvl = 0;
00272 char c;
00273
00274 while ((c = *p++) != '\0') {
00275 if (c == '\\') {
00276 p++;
00277 continue;
00278 }
00279 if (c == pr) {
00280 if (--lvl <= 0) return --p;
00281 } else if (c == pl)
00282 lvl++;
00283 }
00284 return (const char *)NULL;
00285 }
00286
00293 static void
00294 printMacro(MacroBuf *mb, const char *s, const char *se)
00295 {
00296 const char *senl;
00297 const char *ellipsis;
00298 int choplen;
00299
00300 if (s >= se) {
00301 fprintf(stderr, _("%3d>%*s(empty)"), mb->depth,
00302 (2 * mb->depth + 1), "");
00303 return;
00304 }
00305
00306 if (s[-1] == '{')
00307 s--;
00308
00309
00310 for (senl = se; *senl && !iseol(*senl); senl++)
00311 ;
00312
00313
00314 choplen = 61 - (2 * mb->depth);
00315 if ((senl - s) > choplen) {
00316 senl = s + choplen;
00317 ellipsis = "...";
00318 } else
00319 ellipsis = "";
00320
00321
00322 fprintf(stderr, "%3d>%*s%%%.*s^", mb->depth,
00323 (2 * mb->depth + 1), "", (int)(se - s), s);
00324 if (se[1] != '\0' && (senl - (se+1)) > 0)
00325 fprintf(stderr, "%-.*s%s", (int)(senl - (se+1)), se+1, ellipsis);
00326 fprintf(stderr, "\n");
00327 }
00328
00335 static void
00336 printExpansion(MacroBuf *mb, const char *t, const char *te)
00337 {
00338 const char *ellipsis;
00339 int choplen;
00340
00341 if (!(te > t)) {
00342 fprintf(stderr, _("%3d<%*s(empty)\n"), mb->depth, (2 * mb->depth + 1), "");
00343 return;
00344 }
00345
00346
00347 while (te > t && iseol(te[-1]))
00348 te--;
00349 ellipsis = "";
00350 if (mb->depth > 0) {
00351 const char *tenl;
00352
00353
00354 while ((tenl = strchr(t, '\n')) && tenl < te)
00355 t = ++tenl;
00356
00357
00358 choplen = 61 - (2 * mb->depth);
00359 if ((te - t) > choplen) {
00360 te = t + choplen;
00361 ellipsis = "...";
00362 }
00363 }
00364
00365 fprintf(stderr, "%3d<%*s", mb->depth, (2 * mb->depth + 1), "");
00366 if (te > t)
00367 fprintf(stderr, "%.*s%s", (int)(te - t), t, ellipsis);
00368 fprintf(stderr, "\n");
00369 }
00370
00371 #define SKIPBLANK(_s, _c) \
00372 while (((_c) = *(_s)) && isblank(_c)) \
00373 (_s)++;
00374
00375 #define SKIPNONBLANK(_s, _c) \
00376 while (((_c) = *(_s)) && !(isblank(_c) || iseol(_c))) \
00377 (_s)++;
00378
00379 #define COPYNAME(_ne, _s, _c) \
00380 { SKIPBLANK(_s,_c); \
00381 while(((_c) = *(_s)) && (isalnum(_c) || (_c) == '_')) \
00382 *(_ne)++ = *(_s)++; \
00383 *(_ne) = '\0'; \
00384 }
00385
00386 #define COPYOPTS(_oe, _s, _c) \
00387 { while(((_c) = *(_s)) && (_c) != ')') \
00388 *(_oe)++ = *(_s)++; \
00389 *(_oe) = '\0'; \
00390 }
00391
00392 #define COPYBODY(_be, _s, _c) \
00393 { while(((_c) = *(_s)) && !iseol(_c)) { \
00394 if ((_c) == '\\') \
00395 (_s)++; \
00396 *(_be)++ = *(_s)++; \
00397 } \
00398 *(_be) = '\0'; \
00399 }
00400
00408 static int
00409 expandT(MacroBuf *mb, const char *f, size_t flen)
00410 {
00411 char *sbuf;
00412 const char *s = mb->s;
00413 int rc;
00414
00415 sbuf = alloca(flen + 1);
00416 memset(sbuf, 0, (flen + 1));
00417
00418 strncpy(sbuf, f, flen);
00419 sbuf[flen] = '\0';
00420 mb->s = sbuf;
00421 rc = expandMacro(mb);
00422 mb->s = s;
00423 return rc;
00424 }
00425
00426 #if 0
00427
00434 static int
00435 expandS(MacroBuf *mb, char *tbuf, size_t tbuflen)
00436 {
00437 const char *t = mb->t;
00438 size_t nb = mb->nb;
00439 int rc;
00440
00441 mb->t = tbuf;
00442 mb->nb = tbuflen;
00443 rc = expandMacro(mb);
00444 mb->t = t;
00445 mb->nb = nb;
00446 return rc;
00447 }
00448 #endif
00449
00457 static int
00458 expandU(MacroBuf *mb, char *u, size_t ulen)
00459 {
00460 const char *s = mb->s;
00461 char *t = mb->t;
00462 size_t nb = mb->nb;
00463 char *tbuf;
00464 int rc;
00465
00466 tbuf = alloca(ulen + 1);
00467 memset(tbuf, 0, (ulen + 1));
00468
00469 mb->s = u;
00470 mb->t = tbuf;
00471 mb->nb = ulen;
00472 rc = expandMacro(mb);
00473
00474 tbuf[ulen] = '\0';
00475 if (ulen > mb->nb)
00476 strncpy(u, tbuf, (ulen - mb->nb + 1));
00477
00478 mb->s = s;
00479 mb->t = t;
00480 mb->nb = nb;
00481
00482 return rc;
00483 }
00484
00492 static int
00493 doShellEscape(MacroBuf *mb, const char *cmd, size_t clen)
00494 {
00495 char pcmd[BUFSIZ];
00496 FILE *shf;
00497 int rc;
00498 int c;
00499
00500 strncpy(pcmd, cmd, clen);
00501 pcmd[clen] = '\0';
00502 rc = expandU(mb, pcmd, sizeof(pcmd));
00503 if (rc)
00504 return rc;
00505
00506 if ((shf = popen(pcmd, "r")) == NULL)
00507 return 1;
00508 while(mb->nb > 0 && (c = fgetc(shf)) != EOF)
00509 SAVECHAR(mb, c);
00510 pclose(shf);
00511
00512
00513 while (iseol(mb->t[-1])) {
00514 *(mb->t--) = '\0';
00515 mb->nb++;
00516 }
00517 return 0;
00518 }
00519
00528 static const char *
00529 doDefine(MacroBuf *mb, const char *se, int level, int expandbody)
00530 {
00531 const char *s = se;
00532 char buf[BUFSIZ], *n = buf, *ne = n;
00533 char *o = NULL, *oe;
00534 char *b, *be;
00535 int c;
00536 int oc = ')';
00537
00538
00539 COPYNAME(ne, s, c);
00540
00541
00542 oe = ne + 1;
00543 if (*s == '(') {
00544 s++;
00545 o = oe;
00546 COPYOPTS(oe, s, oc);
00547 s++;
00548 }
00549
00550
00551 b = be = oe + 1;
00552 SKIPBLANK(s, c);
00553 if (c == '{') {
00554 if ((se = matchchar(s, c, '}')) == NULL) {
00555 rpmError(RPMERR_BADSPEC,
00556 _("Macro %%%s has unterminated body\n"), n);
00557 se = s;
00558 return se;
00559 }
00560 s++;
00561 strncpy(b, s, (se - s));
00562 b[se - s] = '\0';
00563 be += strlen(b);
00564 se++;
00565 s = se;
00566 } else {
00567 COPYBODY(be, s, c);
00568
00569
00570 while (--be >= b && (c = *be) && (isblank(c) || iseol(c)))
00571 ;
00572 *(++be) = '\0';
00573 }
00574
00575
00576 while (iseol(*s))
00577 s++;
00578 se = s;
00579
00580
00581 if (!((c = *n) && (isalpha(c) || c == '_') && (ne - n) > 2)) {
00582 rpmError(RPMERR_BADSPEC,
00583 _("Macro %%%s has illegal name (%%define)\n"), n);
00584 return se;
00585 }
00586
00587
00588 if (o && oc != ')') {
00589 rpmError(RPMERR_BADSPEC,
00590 _("Macro %%%s has unterminated opts\n"), n);
00591 return se;
00592 }
00593
00594 if ((be - b) < 1) {
00595 rpmError(RPMERR_BADSPEC, _("Macro %%%s has empty body\n"), n);
00596 return se;
00597 }
00598
00599 if (expandbody && expandU(mb, b, (&buf[sizeof(buf)] - b))) {
00600 rpmError(RPMERR_BADSPEC, _("Macro %%%s failed to expand\n"), n);
00601 return se;
00602 }
00603
00604 addMacro(mb->mc, n, o, b, (level - 1));
00605
00606 return se;
00607 }
00608
00615 static const char *
00616 doUndefine(MacroContext *mc, const char *se)
00617 {
00618 const char *s = se;
00619 char buf[BUFSIZ], *n = buf, *ne = n;
00620 int c;
00621
00622 COPYNAME(ne, s, c);
00623
00624
00625 while (iseol(*s))
00626 s++;
00627 se = s;
00628
00629
00630 if (!((c = *n) && (isalpha(c) || c == '_') && (ne - n) > 2)) {
00631 rpmError(RPMERR_BADSPEC,
00632 _("Macro %%%s has illegal name (%%undefine)\n"), n);
00633 return se;
00634 }
00635
00636 delMacro(mc, n);
00637
00638 return se;
00639 }
00640
00641 #ifdef DYING
00642 static void
00643 dumpME(const char *msg, MacroEntry *me)
00644 {
00645 if (msg)
00646 fprintf(stderr, "%s", msg);
00647 fprintf(stderr, "\tme %p", me);
00648 if (me)
00649 fprintf(stderr,"\tname %p(%s) prev %p",
00650 me->name, me->name, me->prev);
00651 fprintf(stderr, "\n");
00652 }
00653 #endif
00654
00663 static void
00664 pushMacro(MacroEntry **mep, const char *n, const char *o, const char *b, int level)
00665 {
00666 MacroEntry *prev = (*mep ? *mep : NULL);
00667 MacroEntry *me = (MacroEntry *) xmalloc(sizeof(*me));
00668
00669 me->prev = prev;
00670 me->name = (prev ? prev->name : xstrdup(n));
00671 me->opts = (o ? xstrdup(o) : NULL);
00672 me->body = xstrdup(b ? b : "");
00673 me->used = 0;
00674 me->level = level;
00675 *mep = me;
00676 }
00677
00682 static void
00683 popMacro(MacroEntry **mep)
00684 {
00685 MacroEntry *me = (*mep ? *mep : NULL);
00686
00687 if (me) {
00688
00689 if ((*mep = me->prev) == NULL)
00690 FREE(me->name);
00691 FREE(me->opts);
00692 FREE(me->body);
00693 FREE(me);
00694 }
00695 }
00696
00701 static void
00702 freeArgs(MacroBuf *mb)
00703 {
00704 MacroContext *mc = mb->mc;
00705 int ndeleted = 0;
00706 int i;
00707
00708
00709 for (i = 0; i < mc->firstFree; i++) {
00710 MacroEntry **mep, *me;
00711 int skiptest = 0;
00712 mep = &mc->macroTable[i];
00713 me = *mep;
00714
00715 if (me == NULL)
00716 continue;
00717 if (me->level < mb->depth)
00718 continue;
00719 if (strlen(me->name) == 1 && strchr("#*0", *me->name)) {
00720 if (*me->name == '*' && me->used > 0)
00721 skiptest = 1;
00722
00723 } else if (!skiptest && me->used <= 0) {
00724 #if NOTYET
00725 rpmError(RPMERR_BADSPEC,
00726 _("Macro %%%s (%s) was not used below level %d\n"),
00727 me->name, me->body, me->level);
00728 #endif
00729 }
00730 popMacro(mep);
00731 if (!(mep && *mep))
00732 ndeleted++;
00733 }
00734
00735
00736 if (ndeleted)
00737 sortMacroTable(mc);
00738 }
00739
00748 static const char *
00749 grabArgs(MacroBuf *mb, const MacroEntry *me, const char *se, char lastc)
00750 {
00751 char buf[BUFSIZ], *b, *be;
00752 char aname[16];
00753 const char *opts, *o;
00754 int argc = 0;
00755 const char **argv;
00756 int c;
00757
00758
00759 b = be = stpcpy(buf, me->name);
00760
00761 addMacro(mb->mc, "0", NULL, buf, mb->depth);
00762
00763 argc = 1;
00764
00765
00766 *be++ = ' ';
00767 while ((c = *se++) != '\0' && c != lastc) {
00768 if (!isblank(c)) {
00769 *be++ = c;
00770 continue;
00771 }
00772
00773 if (be[-1] == ' ')
00774 continue;
00775
00776 *be++ = ' ';
00777 argc++;
00778 }
00779 if (c == '\0') se--;
00780 if (be[-1] != ' ')
00781 argc++, be++;
00782 be[-1] = '\0';
00783 if (*b == ' ') b++;
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794 addMacro(mb->mc, "**", NULL, b, mb->depth);
00795
00796 #ifdef NOTYET
00797
00798 expandU(mb, buf, sizeof(buf));
00799 #endif
00800
00801
00802 argv = (const char **) alloca((argc + 1) * sizeof(char *));
00803 be[-1] = ' ';
00804 buf[0] = '\0';
00805 b = buf;
00806 for (c = 0; c < argc; c++) {
00807 argv[c] = b;
00808 b = strchr(b, ' ');
00809 *b++ = '\0';
00810 }
00811
00812 argv[argc] = NULL;
00813
00814 opts = me->opts;
00815
00816
00817 while((c = getopt(argc, (char **)argv, opts)) != -1) {
00818 if (c == '?' || (o = strchr(opts, c)) == NULL) {
00819 rpmError(RPMERR_BADSPEC, _("Unknown option %c in %s(%s)\n"),
00820 c, me->name, opts);
00821 return se;
00822 }
00823 *be++ = '-';
00824 *be++ = c;
00825 if (o[1] == ':') {
00826 *be++ = ' ';
00827 be = stpcpy(be, optarg);
00828 }
00829 *be++ = '\0';
00830 aname[0] = '-'; aname[1] = c; aname[2] = '\0';
00831 addMacro(mb->mc, aname, NULL, b, mb->depth);
00832 if (o[1] == ':') {
00833 aname[0] = '-'; aname[1] = c; aname[2] = '*'; aname[3] = '\0';
00834 addMacro(mb->mc, aname, NULL, optarg, mb->depth);
00835 }
00836 be = b;
00837 }
00838
00839
00840 sprintf(aname, "%d", (argc - optind));
00841 addMacro(mb->mc, "#", NULL, aname, mb->depth);
00842
00843
00844 *be = '\0';
00845 for (c = optind; c < argc; c++) {
00846 sprintf(aname, "%d", (c - optind + 1));
00847 addMacro(mb->mc, aname, NULL, argv[c], mb->depth);
00848 *be++ = ' ';
00849 be = stpcpy(be, argv[c]);
00850 }
00851
00852
00853 addMacro(mb->mc, "*", NULL, b, mb->depth);
00854
00855 return se;
00856 }
00857
00865 static void
00866 doOutput(MacroBuf *mb, int waserror, const char *msg, size_t msglen)
00867 {
00868 char buf[BUFSIZ];
00869
00870 strncpy(buf, msg, msglen);
00871 buf[msglen] = '\0';
00872 expandU(mb, buf, sizeof(buf));
00873 if (waserror)
00874 rpmError(RPMERR_BADSPEC, "%s\n", buf);
00875 else
00876 fprintf(stderr, "%s", buf);
00877 }
00878
00888 static void
00889 doFoo(MacroBuf *mb, int negate, const char *f, size_t fn, const char *g, size_t glen)
00890 {
00891 char buf[BUFSIZ], *b = NULL, *be;
00892 int c;
00893
00894 buf[0] = '\0';
00895 if (g) {
00896 strncpy(buf, g, glen);
00897 buf[glen] = '\0';
00898 expandU(mb, buf, sizeof(buf));
00899 }
00900 if (STREQ("basename", f, fn)) {
00901 if ((b = strrchr(buf, '/')) == NULL)
00902 b = buf;
00903 #if NOTYET
00904
00905 } else if (STREQ("dirname", f, fn)) {
00906 if ((b = strrchr(buf, '/')) != NULL)
00907 *b = '\0';
00908 b = buf;
00909 #endif
00910 } else if (STREQ("suffix", f, fn)) {
00911 if ((b = strrchr(buf, '.')) != NULL)
00912 b++;
00913 } else if (STREQ("expand", f, fn)) {
00914 b = buf;
00915 } else if (STREQ("verbose", f, fn)) {
00916 if (negate)
00917 b = (rpmIsVerbose() ? NULL : buf);
00918 else
00919 b = (rpmIsVerbose() ? buf : NULL);
00920 } else if (STREQ("url2path", f, fn) || STREQ("u2p", f, fn)) {
00921 (void)urlPath(buf, (const char **)&b);
00922 if (*b == '\0') b = "/";
00923 } else if (STREQ("uncompress", f, fn)) {
00924 rpmCompressedMagic compressed = COMPRESSED_OTHER;
00925 for (b = buf; (c = *b) && isblank(c);)
00926 b++;
00927 for (be = b; (c = *be) && !isblank(c);)
00928 be++;
00929 *be++ = '\0';
00930 #ifndef DEBUG_MACROS
00931 isCompressed(b, &compressed);
00932 #endif
00933 switch(compressed) {
00934 default:
00935 case 0:
00936 sprintf(be, "%%_cat %s", b);
00937 break;
00938 case 1:
00939 sprintf(be, "%%_gzip -dc %s", b);
00940 break;
00941 case 2:
00942 sprintf(be, "%%_bzip2 %s", b);
00943 break;
00944 case 3:
00945 sprintf(be, "%%_unzip %s", b);
00946 break;
00947 }
00948 b = be;
00949 } else if (STREQ("S", f, fn)) {
00950 for (b = buf; (c = *b) && isdigit(c);)
00951 b++;
00952 if (!c) {
00953 b++;
00954 sprintf(b, "%%SOURCE%s", buf);
00955 } else
00956 b = buf;
00957 } else if (STREQ("P", f, fn)) {
00958 for (b = buf; (c = *b) && isdigit(c);)
00959 b++;
00960 if (!c) {
00961 b++;
00962 sprintf(b, "%%PATCH%s", buf);
00963 } else
00964 b = buf;
00965 } else if (STREQ("F", f, fn)) {
00966 b = buf + strlen(buf) + 1;
00967 sprintf(b, "file%s.file", buf);
00968 }
00969
00970 if (b) {
00971 expandT(mb, b, strlen(b));
00972 }
00973 }
00974
00981 static int
00982 expandMacro(MacroBuf *mb)
00983 {
00984 MacroEntry **mep;
00985 MacroEntry *me;
00986 const char *s = mb->s, *se;
00987 const char *f, *fe;
00988 const char *g, *ge;
00989 size_t fn, gn;
00990 char *t = mb->t;
00991 int c;
00992 int rc = 0;
00993 int negate;
00994 char grab;
00995 int chkexist;
00996
00997 if (++mb->depth > max_macro_depth) {
00998 rpmError(RPMERR_BADSPEC,
00999 _("Recursion depth(%d) greater than max(%d)\n"),
01000 mb->depth, max_macro_depth);
01001 mb->depth--;
01002 mb->expand_trace = 1;
01003 return 1;
01004 }
01005
01006 while (rc == 0 && mb->nb > 0 && (c = *s) != '\0') {
01007 s++;
01008
01009 switch(c) {
01010 case '%':
01011 if (*s != '%')
01012 break;
01013 s++;
01014
01015 default:
01016 SAVECHAR(mb, c);
01017 continue;
01018 break;
01019 }
01020
01021
01022 f = fe = NULL;
01023 g = ge = NULL;
01024 if (mb->depth > 1)
01025 t = mb->t;
01026 negate = 0;
01027 grab = '\0';
01028 chkexist = 0;
01029 switch ((c = *s)) {
01030 default:
01031 while (strchr("!?", *s) != NULL) {
01032 switch(*s++) {
01033 case '!':
01034 negate = ((negate + 1) % 2);
01035 break;
01036 case '?':
01037 chkexist++;
01038 break;
01039 }
01040 }
01041 f = se = s;
01042 if (*se == '-')
01043 se++;
01044 while((c = *se) && (isalnum(c) || c == '_'))
01045 se++;
01046
01047 switch (*se) {
01048 case '*':
01049 se++;
01050 if (*se == '*') se++;
01051 break;
01052 case '#':
01053 se++;
01054 break;
01055 default:
01056 break;
01057 }
01058 fe = se;
01059
01060 if ((c = *fe) && isblank(c))
01061 grab = '\n';
01062 break;
01063 case '(':
01064 if ((se = matchchar(s, c, ')')) == NULL) {
01065 rpmError(RPMERR_BADSPEC,
01066 _("Unterminated %c: %s\n"), c, s);
01067 rc = 1;
01068 continue;
01069 }
01070 if (mb->macro_trace)
01071 printMacro(mb, s, se+1);
01072
01073 s++;
01074 rc = doShellEscape(mb, s, (se - s));
01075 se++;
01076
01077 s = se;
01078 continue;
01079 break;
01080 case '{':
01081 if ((se = matchchar(s, c, '}')) == NULL) {
01082 rpmError(RPMERR_BADSPEC,
01083 _("Unterminated %c: %s\n"), c, s);
01084 rc = 1;
01085 continue;
01086 }
01087 f = s+1;
01088 se++;
01089 while (strchr("!?", *f) != NULL) {
01090 switch(*f++) {
01091 case '!':
01092 negate = ((negate + 1) % 2);
01093 break;
01094 case '?':
01095 chkexist++;
01096 break;
01097 }
01098 }
01099 for (fe = f; (c = *fe) && !strchr(" :}", c);)
01100 fe++;
01101 switch (c) {
01102 case ':':
01103 g = fe + 1;
01104 ge = se - 1;
01105 break;
01106 case ' ':
01107 grab = se[-1];
01108 break;
01109 default:
01110 break;
01111 }
01112 break;
01113 }
01114
01115
01116 fn = (fe - f);
01117 gn = (ge - g);
01118 if (fn <= 0) {
01119
01120 c = '%';
01121 SAVECHAR(mb, c);
01122 #if 0
01123 rpmError(RPMERR_BADSPEC,
01124 _("A %% is followed by an unparseable macro\n"));
01125 #endif
01126 s = se;
01127 continue;
01128 }
01129
01130 if (mb->macro_trace)
01131 printMacro(mb, s, se);
01132
01133
01134 if (STREQ("global", f, fn)) {
01135 s = doDefine(mb, se, RMIL_GLOBAL, 1);
01136 continue;
01137 }
01138 if (STREQ("define", f, fn)) {
01139 s = doDefine(mb, se, mb->depth, 0);
01140 continue;
01141 }
01142 if (STREQ("undefine", f, fn)) {
01143 s = doUndefine(mb->mc, se);
01144 continue;
01145 }
01146
01147 if (STREQ("echo", f, fn) ||
01148 STREQ("warn", f, fn) ||
01149 STREQ("error", f, fn)) {
01150 int waserror = 0;
01151 if (STREQ("error", f, fn))
01152 waserror = 1;
01153 if (g < ge)
01154 doOutput(mb, waserror, g, gn);
01155 else
01156 doOutput(mb, waserror, f, fn);
01157 s = se;
01158 continue;
01159 }
01160
01161 if (STREQ("trace", f, fn)) {
01162
01163 mb->expand_trace = mb->macro_trace = (negate ? 0 : mb->depth);
01164 if (mb->depth == 1) {
01165 print_macro_trace = mb->macro_trace;
01166 print_expand_trace = mb->expand_trace;
01167 }
01168 s = se;
01169 continue;
01170 }
01171
01172 if (STREQ("dump", f, fn)) {
01173 rpmDumpMacroTable(mb->mc, NULL);
01174 while (iseol(*se))
01175 se++;
01176 s = se;
01177 continue;
01178 }
01179
01180
01181 if (STREQ("basename", f, fn) ||
01182 STREQ("suffix", f, fn) ||
01183 STREQ("expand", f, fn) ||
01184 STREQ("verbose", f, fn) ||
01185 STREQ("uncompress", f, fn) ||
01186 STREQ("url2path", f, fn) ||
01187 STREQ("u2p", f, fn) ||
01188 STREQ("S", f, fn) ||
01189 STREQ("P", f, fn) ||
01190 STREQ("F", f, fn)) {
01191 doFoo(mb, negate, f, fn, g, gn);
01192 s = se;
01193 continue;
01194 }
01195
01196
01197 mep = findEntry(mb->mc, f, fn);
01198 me = (mep ? *mep : NULL);
01199
01200
01201 if (*f == '-') {
01202 if (me)
01203 me->used++;
01204 if ((me == NULL && !negate) ||
01205 (me != NULL && negate)) {
01206 s = se;
01207 continue;
01208 }
01209
01210 if (g && g < ge) {
01211 rc = expandT(mb, g, gn);
01212 } else
01213 if (me->body && *me->body) {
01214 rc = expandT(mb, me->body, strlen(me->body));
01215 }
01216 s = se;
01217 continue;
01218 }
01219
01220
01221 if (chkexist) {
01222 if ((me == NULL && !negate) ||
01223 (me != NULL && negate)) {
01224 s = se;
01225 continue;
01226 }
01227 if (g && g < ge) {
01228 rc = expandT(mb, g, gn);
01229 } else
01230 if (me && me->body && *me->body) {
01231 rc = expandT(mb, me->body, strlen(me->body));
01232 }
01233 s = se;
01234 continue;
01235 }
01236
01237 if (me == NULL) {
01238 #ifndef HACK
01239 #if DEAD
01240
01241 if (fn == 1 && *f == '*') {
01242 s = se;
01243 continue;
01244 }
01245 #endif
01246
01247 c = '%';
01248 SAVECHAR(mb, c);
01249 #else
01250 rpmError(RPMERR_BADSPEC,
01251 _("Macro %%%.*s not found, skipping\n"), fn, f);
01252 s = se;
01253 #endif
01254 continue;
01255 }
01256
01257
01258 if (me && me->opts != NULL) {
01259 if (grab) {
01260 se = grabArgs(mb, me, fe, grab);
01261 } else {
01262 addMacro(mb->mc, "**", NULL, "", mb->depth);
01263 addMacro(mb->mc, "*", NULL, "", mb->depth);
01264 addMacro(mb->mc, "#", NULL, "0", mb->depth);
01265 addMacro(mb->mc, "0", NULL, me->name, mb->depth);
01266 }
01267 }
01268
01269
01270 if (me->body && *me->body) {
01271 mb->s = me->body;
01272 rc = expandMacro(mb);
01273 if (rc == 0)
01274 me->used++;
01275 }
01276
01277
01278 if (me->opts != NULL)
01279 freeArgs(mb);
01280
01281 s = se;
01282 }
01283
01284 *mb->t = '\0';
01285 mb->s = s;
01286 mb->depth--;
01287 if (rc != 0 || mb->expand_trace)
01288 printExpansion(mb, t, mb->t);
01289 return rc;
01290 }
01291
01292
01293
01294 int
01295 expandMacros(void *spec, MacroContext *mc, char *s, size_t slen)
01296 {
01297 MacroBuf macrobuf, *mb = ¯obuf;
01298 char *tbuf;
01299 int rc;
01300
01301 if (s == NULL || slen <= 0)
01302 return 0;
01303 if (mc == NULL)
01304 mc = &rpmGlobalMacroContext;
01305
01306 tbuf = alloca(slen + 1);
01307 memset(tbuf, 0, (slen + 1));
01308
01309 mb->s = s;
01310 mb->t = tbuf;
01311 mb->nb = slen;
01312 mb->depth = 0;
01313 mb->macro_trace = print_macro_trace;
01314 mb->expand_trace = print_expand_trace;
01315
01316 mb->spec = spec;
01317 mb->mc = mc;
01318
01319 rc = expandMacro(mb);
01320
01321 if (mb->nb <= 0)
01322 rpmError(RPMERR_BADSPEC, _("Target buffer overflow\n"));
01323
01324 tbuf[slen] = '\0';
01325 strncpy(s, tbuf, (slen - mb->nb + 1));
01326
01327 return rc;
01328 }
01329
01330 void
01331 addMacro(MacroContext *mc, const char *n, const char *o, const char *b, int level)
01332 {
01333 MacroEntry **mep;
01334
01335 if (mc == NULL)
01336 mc = &rpmGlobalMacroContext;
01337
01338
01339 if ((mep = findEntry(mc, n, 0)) == NULL) {
01340 if (mc->firstFree == mc->macrosAllocated)
01341 expandMacroTable(mc);
01342 mep = mc->macroTable + mc->firstFree++;
01343 }
01344
01345
01346 pushMacro(mep, n, o, b, level);
01347
01348
01349 if ((*mep)->prev == NULL)
01350 sortMacroTable(mc);
01351 }
01352
01353 void
01354 delMacro(MacroContext *mc, const char *n)
01355 {
01356 MacroEntry **mep;
01357
01358 if (mc == NULL)
01359 mc = &rpmGlobalMacroContext;
01360
01361 if ((mep = findEntry(mc, n, 0)) != NULL) {
01362 popMacro(mep);
01363
01364 if (!(mep && *mep))
01365 sortMacroTable(mc);
01366 }
01367 }
01368
01369 int
01370 rpmDefineMacro(MacroContext *mc, const char *macro, int level)
01371 {
01372 MacroBuf macrobuf, *mb = ¯obuf;
01373
01374 memset(mb, 0, sizeof(*mb));
01375
01376 mb->mc = (mc ? mc : &rpmGlobalMacroContext);
01377 (void)doDefine(mb, macro, level, 0);
01378 return 0;
01379 }
01380
01381 void
01382 rpmLoadMacros(MacroContext * mc, int level)
01383 {
01384 int i;
01385
01386 if (mc == NULL || mc == &rpmGlobalMacroContext)
01387 return;
01388
01389 for (i = 0; i < mc->firstFree; i++) {
01390 MacroEntry **mep, *me;
01391 mep = &mc->macroTable[i];
01392 me = *mep;
01393
01394 if (me == NULL)
01395 continue;
01396 addMacro(NULL, me->name, me->opts, me->body, (level - 1));
01397 }
01398 }
01399
01400 void
01401 rpmInitMacros(MacroContext *mc, const char *macrofiles)
01402 {
01403 char *m, *mfile, *me;
01404
01405 if (macrofiles == NULL)
01406 return;
01407 if (mc == NULL)
01408 mc = &rpmGlobalMacroContext;
01409
01410 for (mfile = m = xstrdup(macrofiles); *mfile; mfile = me) {
01411 FD_t fd;
01412 char buf[BUFSIZ];
01413
01414 for (me = mfile; (me = strchr(me, ':')) != NULL; me++) {
01415 if (!(me[1] == '/' && me[2] == '/'))
01416 break;
01417 }
01418
01419 if (me && *me == ':')
01420 *me++ = '\0';
01421 else
01422 me = mfile + strlen(mfile);
01423
01424
01425 buf[0] = '\0';
01426 if (mfile[0] == '~' && mfile[1] == '/') {
01427 char *home;
01428 if ((home = getenv("HOME")) != NULL) {
01429 mfile += 2;
01430 strncpy(buf, home, sizeof(buf));
01431 strncat(buf, "/", sizeof(buf) - strlen(buf));
01432 }
01433 }
01434 strncat(buf, mfile, sizeof(buf) - strlen(buf));
01435 buf[sizeof(buf)-1] = '\0';
01436
01437 fd = Fopen(buf, "r.fpio");
01438 if (fd == NULL || Ferror(fd)) {
01439 if (fd) Fclose(fd);
01440 continue;
01441 }
01442
01443
01444 max_macro_depth = 16;
01445
01446 while(rdcl(buf, sizeof(buf), fd, 1) != NULL) {
01447 char c, *n;
01448
01449 n = buf;
01450 SKIPBLANK(n, c);
01451
01452 if (c != '%')
01453 continue;
01454 n++;
01455 (void)rpmDefineMacro(NULL, n, RMIL_MACROFILES);
01456 }
01457 Fclose(fd);
01458 }
01459 if (m)
01460 free(m);
01461
01462
01463 rpmLoadMacros(&rpmCLIMacroContext, RMIL_CMDLINE);
01464 }
01465
01466 void
01467 rpmFreeMacros(MacroContext *mc)
01468 {
01469 int i;
01470
01471 if (mc == NULL)
01472 mc = &rpmGlobalMacroContext;
01473
01474 for (i = 0; i < mc->firstFree; i++) {
01475 MacroEntry *me;
01476 while ((me = mc->macroTable[i]) != NULL) {
01477
01478 if ((mc->macroTable[i] = me->prev) == NULL)
01479 FREE(me->name);
01480 FREE(me->opts);
01481 FREE(me->body);
01482 FREE(me);
01483 }
01484 }
01485 FREE(mc->macroTable);
01486 memset(mc, 0, sizeof(*mc));
01487 }
01488
01489
01490 int isCompressed(const char *file, rpmCompressedMagic *compressed)
01491 {
01492 FD_t fd;
01493 ssize_t nb;
01494 int rc = -1;
01495 unsigned char magic[4];
01496
01497 *compressed = COMPRESSED_NOT;
01498
01499 fd = Fopen(file, "r.ufdio");
01500 if (fd == NULL || Ferror(fd)) {
01501
01502 rpmError(RPMERR_BADSPEC, _("File %s: %s\n"), file, Fstrerror(fd));
01503 if (fd) Fclose(fd);
01504 return 1;
01505 }
01506 nb = Fread(magic, sizeof(char), sizeof(magic), fd);
01507 if (nb < 0) {
01508 rpmError(RPMERR_BADSPEC, _("File %s: %s\n"), file, Fstrerror(fd));
01509 rc = 1;
01510 } else if (nb < sizeof(magic)) {
01511 rpmError(RPMERR_BADSPEC, _("File %s is smaller than %u bytes\n"),
01512 file, (unsigned)sizeof(magic));
01513 rc = 0;
01514 }
01515 Fclose(fd);
01516 if (rc >= 0)
01517 return rc;
01518
01519 rc = 0;
01520
01521 if ((magic[0] == 'B') && (magic[1] == 'Z')) {
01522 *compressed = COMPRESSED_BZIP2;
01523 } else if ((magic[0] == 0120) && (magic[1] == 0113) &&
01524 (magic[2] == 0003) && (magic[3] == 0004)) {
01525 *compressed = COMPRESSED_ZIP;
01526 } else if (((magic[0] == 0037) && (magic[1] == 0213)) ||
01527 ((magic[0] == 0037) && (magic[1] == 0236)) ||
01528 ((magic[0] == 0037) && (magic[1] == 0036)) ||
01529 ((magic[0] == 0037) && (magic[1] == 0240)) ||
01530 ((magic[0] == 0037) && (magic[1] == 0235))
01531 ) {
01532 *compressed = COMPRESSED_OTHER;
01533 }
01534
01535 return rc;
01536 }
01537
01538
01539
01540 char *
01541 rpmExpand(const char *arg, ...)
01542 {
01543 char buf[BUFSIZ], *p, *pe;
01544 const char *s;
01545 va_list ap;
01546
01547 if (arg == NULL)
01548 return xstrdup("");
01549
01550 buf[0] = '\0';
01551 p = buf;
01552 pe = stpcpy(p, arg);
01553
01554 va_start(ap, arg);
01555 while ((s = va_arg(ap, const char *)) != NULL)
01556 pe = stpcpy(pe, s);
01557 va_end(ap);
01558 expandMacros(NULL, NULL, buf, sizeof(buf));
01559 return xstrdup(buf);
01560 }
01561
01562 int
01563 rpmExpandNumeric(const char *arg)
01564 {
01565 const char *val;
01566 int rc;
01567
01568 if (arg == NULL)
01569 return 0;
01570
01571 val = rpmExpand(arg, NULL);
01572 if (!(val && *val != '%'))
01573 rc = 0;
01574 else if (*val == 'Y' || *val == 'y')
01575 rc = 1;
01576 else if (*val == 'N' || *val == 'n')
01577 rc = 0;
01578 else {
01579 char *end;
01580 rc = strtol(val, &end, 0);
01581 if (!(end && *end == '\0'))
01582 rc = 0;
01583 }
01584 free((void *)val);
01585
01586 return rc;
01587 }
01588
01589
01590 char *rpmCleanPath(char * path)
01591 {
01592 const char *s;
01593 char *se, *t, *te;
01594 int begin = 1;
01595
01596
01597 s = t = te = path;
01598 while (*s) {
01599
01600 switch(*s) {
01601 case ':':
01602 if (s[1] == '/' && s[2] == '/') {
01603 *t++ = *s++;
01604 *t++ = *s++;
01605 break;
01606 }
01607 begin=1;
01608 break;
01609 case '/':
01610
01611 for (se = te + 1; se < t && *se != '/'; se++)
01612 ;
01613 if (se < t && *se == '/') {
01614 te = se;
01615
01616 }
01617 while (s[1] == '/')
01618 s++;
01619 while (t > path && t[-1] == '/')
01620 t--;
01621 break;
01622 case '.':
01623
01624 if (begin && s[1] == '.') {
01625
01626 *t++ = *s++;
01627 break;
01628 }
01629
01630 if (begin && s[1] == '\0') {
01631 break;
01632 }
01633
01634 if ((t[-1] == '/' && s[1] == '\0') || (t != path && s[1] == '/')) {
01635 s++;
01636 continue;
01637 }
01638
01639 if (!begin && t > path && t[-1] == '/' && s[1] == '.' && (s[2] == '/' || s[2] == '\0')) {
01640 t = te;
01641
01642 if (te > path)
01643 for (--te; te > path && *te != '/'; te--)
01644 ;
01645
01646 s++;
01647 s++;
01648 continue;
01649 }
01650 break;
01651 default:
01652 begin = 0;
01653 break;
01654 }
01655 *t++ = *s++;
01656 }
01657
01658
01659 if (t > &path[1] && t[-1] == '/')
01660 t--;
01661 *t = '\0';
01662
01663
01664 return path;
01665 }
01666
01667
01668
01669 const char *
01670 rpmGetPath(const char *path, ...)
01671 {
01672 char buf[BUFSIZ];
01673 const char * s;
01674 char * t, * te;
01675 va_list ap;
01676
01677 if (path == NULL)
01678 return xstrdup("");
01679
01680 buf[0] = '\0';
01681 t = buf;
01682 te = stpcpy(t, path);
01683 *te = '\0';
01684
01685 va_start(ap, path);
01686 while ((s = va_arg(ap, const char *)) != NULL) {
01687 te = stpcpy(te, s);
01688 *te = '\0';
01689 }
01690 va_end(ap);
01691 expandMacros(NULL, NULL, buf, sizeof(buf));
01692
01693 (void) rpmCleanPath(buf);
01694 return xstrdup(buf);
01695 }
01696
01697
01698
01699 const char * rpmGenPath(const char * urlroot, const char * urlmdir,
01700 const char *urlfile)
01701 {
01702 const char * xroot = rpmGetPath(urlroot, NULL);
01703 const char * root = xroot;
01704 const char * xmdir = rpmGetPath(urlmdir, NULL);
01705 const char * mdir = xmdir;
01706 const char * xfile = rpmGetPath(urlfile, NULL);
01707 const char * file = xfile;
01708 const char * result;
01709 const char * url = NULL;
01710 int nurl = 0;
01711 int ut;
01712
01713 if (_debug)
01714 fprintf(stderr, "*** RGP xroot %s xmdir %s xfile %s\n", xroot, xmdir, xfile);
01715 ut = urlPath(xroot, &root);
01716 if (url == NULL && ut > URL_IS_DASH) {
01717 url = xroot;
01718 nurl = root - xroot;
01719 if (_debug)
01720 fprintf(stderr, "*** RGP ut %d root %s nurl %d\n", ut, root, nurl);
01721 }
01722 if (root == NULL || *root == '\0') root = "/";
01723
01724 ut = urlPath(xmdir, &mdir);
01725 if (url == NULL && ut > URL_IS_DASH) {
01726 url = xmdir;
01727 nurl = mdir - xmdir;
01728 if (_debug)
01729 fprintf(stderr, "*** RGP ut %d mdir %s nurl %d\n", ut, mdir, nurl);
01730 }
01731 if (mdir == NULL || *mdir == '\0') mdir = "/";
01732
01733 ut = urlPath(xfile, &file);
01734 if (url == NULL && ut > URL_IS_DASH) {
01735 url = xfile;
01736 nurl = file - xfile;
01737 if (_debug)
01738 fprintf(stderr, "*** RGP ut %d file %s nurl %d\n", ut, file, nurl);
01739 }
01740
01741 if (url && nurl > 0) {
01742 char *t = strncpy(alloca(nurl+1), url, nurl);
01743 t[nurl] = '\0';
01744 url = t;
01745 } else
01746 url = "";
01747
01748 result = rpmGetPath(url, root, "/", mdir, "/", file, NULL);
01749
01750 free((void *)xroot);
01751 free((void *)xmdir);
01752 free((void *)xfile);
01753 if (_debug)
01754 fprintf(stderr, "*** RGP result %s\n", result);
01755 return result;
01756 }
01757
01758
01759
01760 #if defined(DEBUG_MACROS)
01761
01762 #if defined(EVAL_MACROS)
01763
01764 char *macrofiles = "/usr/lib/rpm/macros:/etc/rpm/macros:~/.rpmmacros";
01765
01766 int
01767 main(int argc, char *argv[])
01768 {
01769 int c;
01770 int errflg = 0;
01771 extern char *optarg;
01772 extern int optind;
01773
01774 while ((c = getopt(argc, argv, "f:")) != EOF ) {
01775 switch (c) {
01776 case 'f':
01777 macrofiles = optarg;
01778 break;
01779 case '?':
01780 default:
01781 errflg++;
01782 break;
01783 }
01784 }
01785 if (errflg || optind >= argc) {
01786 fprintf(stderr, "Usage: %s [-f macropath ] macro ...\n", argv[0]);
01787 exit(1);
01788 }
01789
01790 rpmInitMacros(NULL, macrofiles);
01791 for ( ; optind < argc; optind++) {
01792 const char *val;
01793
01794 val = rpmGetPath(argv[optind], NULL);
01795 if (val) {
01796 fprintf(stdout, "%s:\t%s\n", argv[optind], val);
01797 free((void *)val);
01798 }
01799 }
01800 rpmFreeMacros(NULL);
01801 return 0;
01802 }
01803
01804 #else
01805
01806 char *macrofiles = "../macros:./testmacros";
01807 char *testfile = "./test";
01808
01809 int
01810 main(int argc, char *argv[])
01811 {
01812 char buf[BUFSIZ];
01813 FILE *fp;
01814 int x;
01815
01816 rpmInitMacros(NULL, macrofiles);
01817 rpmDumpMacroTable(NULL, NULL);
01818
01819 if ((fp = fopen(testfile, "r")) != NULL) {
01820 while(rdcl(buf, sizeof(buf), fp, 1)) {
01821 x = expandMacros(NULL, NULL, buf, sizeof(buf));
01822 fprintf(stderr, "%d->%s\n", x, buf);
01823 memset(buf, 0, sizeof(buf));
01824 }
01825 fclose(fp);
01826 }
01827
01828 while(rdcl(buf, sizeof(buf), stdin, 1)) {
01829 x = expandMacros(NULL, NULL, buf, sizeof(buf));
01830 fprintf(stderr, "%d->%s\n <-\n", x, buf);
01831 memset(buf, 0, sizeof(buf));
01832 }
01833 rpmFreeMacros(NULL);
01834
01835 return 0;
01836 }
01837 #endif
01838 #endif