00001
00006 static int _debug = 0;
00007
00008 #include "system.h"
00009 #include <stdarg.h>
00010
00011 #if !defined(isblank)
00012 #define isblank(_c) ((_c) == ' ' || (_c) == '\t')
00013 #endif
00014 #define iseol(_c) ((_c) == '\n' || (_c) == '\r')
00015
00016 #define STREQ(_t, _f, _fn) ((_fn) == (sizeof(_t)-1) && !strncmp((_t), (_f), (_fn)))
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 static struct MacroContext_s rpmGlobalMacroContext_s;
00060
00061 MacroContext rpmGlobalMacroContext = &rpmGlobalMacroContext_s;
00062
00063
00064 static struct MacroContext_s rpmCLIMacroContext_s;
00065
00066 MacroContext rpmCLIMacroContext = &rpmCLIMacroContext_s;
00067
00068
00072 typedef struct MacroBuf_s {
00073 const char * s;
00074 char * t;
00075 size_t nb;
00076 int depth;
00077 int macro_trace;
00078 int expand_trace;
00079 void * spec;
00080 MacroContext mc;
00081 } * MacroBuf;
00082
00083 #define SAVECHAR(_mb, _c) { *(_mb)->t = (_c), (_mb)->t++, (_mb)->nb--; }
00084
00085
00086
00087 #define MAX_MACRO_DEPTH 16
00088
00089 int max_macro_depth = MAX_MACRO_DEPTH;
00090
00091 #ifdef DEBUG_MACROS
00092
00093 int print_macro_trace = 0;
00094
00095 int print_expand_trace = 0;
00096 #else
00097
00098 int print_macro_trace = 0;
00099
00100 int print_expand_trace = 0;
00101 #endif
00102
00103
00104 #define MACRO_CHUNK_SIZE 16
00105
00106
00107 static int expandMacro(MacroBuf mb)
00108
00109
00110
00111
00112
00113 ;
00114
00120 static inline void *
00121 _free( const void * p)
00122
00123 {
00124 if (p != NULL) free((void *)p);
00125 return NULL;
00126 }
00127
00128
00129
00136 static int
00137 compareMacroName(const void * ap, const void * bp)
00138
00139 {
00140 MacroEntry ame = *((MacroEntry *)ap);
00141 MacroEntry bme = *((MacroEntry *)bp);
00142
00143 if (ame == NULL && bme == NULL)
00144 return 0;
00145 if (ame == NULL)
00146 return 1;
00147 if (bme == NULL)
00148 return -1;
00149 return strcmp(ame->name, bme->name);
00150 }
00151
00156 static void
00157 expandMacroTable(MacroContext mc)
00158
00159 {
00160 if (mc->macroTable == NULL) {
00161 mc->macrosAllocated = MACRO_CHUNK_SIZE;
00162 mc->macroTable = (MacroEntry *)
00163 xmalloc(sizeof(*(mc->macroTable)) * mc->macrosAllocated);
00164 mc->firstFree = 0;
00165 } else {
00166 mc->macrosAllocated += MACRO_CHUNK_SIZE;
00167 mc->macroTable = (MacroEntry *)
00168 xrealloc(mc->macroTable, sizeof(*(mc->macroTable)) *
00169 mc->macrosAllocated);
00170 }
00171 memset(&mc->macroTable[mc->firstFree], 0, MACRO_CHUNK_SIZE * sizeof(*(mc->macroTable)));
00172 }
00173
00178 static void
00179 sortMacroTable(MacroContext mc)
00180
00181 {
00182 int i;
00183
00184 if (mc == NULL || mc->macroTable == NULL)
00185 return;
00186
00187 qsort(mc->macroTable, mc->firstFree, sizeof(*(mc->macroTable)),
00188 compareMacroName);
00189
00190
00191 for (i = 0; i < mc->firstFree; i++) {
00192 if (mc->macroTable[i] != NULL)
00193 continue;
00194 mc->firstFree = i;
00195 break;
00196 }
00197 }
00198
00199 void
00200 rpmDumpMacroTable(MacroContext mc, FILE * fp)
00201 {
00202 int nempty = 0;
00203 int nactive = 0;
00204
00205 if (mc == NULL) mc = rpmGlobalMacroContext;
00206 if (fp == NULL) fp = stderr;
00207
00208 fprintf(fp, "========================\n");
00209 if (mc->macroTable != NULL) {
00210 int i;
00211 for (i = 0; i < mc->firstFree; i++) {
00212 MacroEntry me;
00213 if ((me = mc->macroTable[i]) == NULL) {
00214
00215 nempty++;
00216 continue;
00217 }
00218 fprintf(fp, "%3d%c %s", me->level,
00219 (me->used > 0 ? '=' : ':'), me->name);
00220 if (me->opts && *me->opts)
00221 fprintf(fp, "(%s)", me->opts);
00222 if (me->body && *me->body)
00223 fprintf(fp, "\t%s", me->body);
00224 fprintf(fp, "\n");
00225 nactive++;
00226 }
00227 }
00228 fprintf(fp, _("======================== active %d empty %d\n"),
00229 nactive, nempty);
00230 }
00231
00239
00240 static MacroEntry *
00241 findEntry(MacroContext mc, const char * name, size_t namelen)
00242
00243
00244 {
00245 MacroEntry key, *ret;
00246 struct MacroEntry_s keybuf;
00247 char namebuf[1024];
00248
00249 if (mc == NULL) mc = rpmGlobalMacroContext;
00250 if (mc->macroTable == NULL || mc->firstFree == 0)
00251 return NULL;
00252
00253 if (namelen > 0) {
00254 strncpy(namebuf, name, namelen);
00255 namebuf[namelen] = '\0';
00256 name = namebuf;
00257 }
00258
00259 key = &keybuf;
00260 memset(key, 0, sizeof(*key));
00261
00262 key->name = (char *)name;
00263
00264 ret = (MacroEntry *) bsearch(&key, mc->macroTable, mc->firstFree,
00265 sizeof(*(mc->macroTable)), compareMacroName);
00266
00267 return ret;
00268 }
00269
00270
00271
00272
00276 static char *
00277 rdcl(char * buf, size_t size, FD_t fd, int escapes)
00278
00279
00280 {
00281 char *q = buf;
00282 size_t nb = 0;
00283 size_t nread = 0;
00284 FILE * f = fdGetFILE(fd);
00285
00286 *q = '\0';
00287 if (f != NULL)
00288 do {
00289
00290 if (fgets(q, size, f) == NULL)
00291 break;
00292 nb = strlen(q);
00293 nread += nb;
00294 for (q += nb - 1; nb > 0 && iseol(*q); q--)
00295 nb--;
00296 if (!(nb > 0 && *q == '\\')) {
00297 *(++q) = '\0';
00298 break;
00299 }
00300 if (escapes) {
00301 q++;
00302 nb++;
00303 }
00304 size -= nb;
00305 if (*q == '\r')
00306 *q = '\n';
00307 *(++q) = '\0';
00308 } while (size > 0);
00309 return (nread > 0 ? buf : NULL);
00310 }
00311
00319 static const char *
00320 matchchar(const char * p, char pl, char pr)
00321
00322 {
00323 int lvl = 0;
00324 char c;
00325
00326 while ((c = *p++) != '\0') {
00327 if (c == '\\') {
00328 p++;
00329 continue;
00330 }
00331 if (c == pr) {
00332 if (--lvl <= 0) return --p;
00333 } else if (c == pl)
00334 lvl++;
00335 }
00336 return (const char *)NULL;
00337 }
00338
00345 static void
00346 printMacro(MacroBuf mb, const char * s, const char * se)
00347
00348
00349 {
00350 const char *senl;
00351 const char *ellipsis;
00352 int choplen;
00353
00354 if (s >= se) {
00355 fprintf(stderr, _("%3d>%*s(empty)"), mb->depth,
00356 (2 * mb->depth + 1), "");
00357 return;
00358 }
00359
00360 if (s[-1] == '{')
00361 s--;
00362
00363
00364 for (senl = se; *senl && !iseol(*senl); senl++)
00365 {};
00366
00367
00368 choplen = 61 - (2 * mb->depth);
00369 if ((senl - s) > choplen) {
00370 senl = s + choplen;
00371 ellipsis = "...";
00372 } else
00373 ellipsis = "";
00374
00375
00376 fprintf(stderr, "%3d>%*s%%%.*s^", mb->depth,
00377 (2 * mb->depth + 1), "", (int)(se - s), s);
00378 if (se[1] != '\0' && (senl - (se+1)) > 0)
00379 fprintf(stderr, "%-.*s%s", (int)(senl - (se+1)), se+1, ellipsis);
00380 fprintf(stderr, "\n");
00381 }
00382
00389 static void
00390 printExpansion(MacroBuf mb, const char * t, const char * te)
00391
00392
00393 {
00394 const char *ellipsis;
00395 int choplen;
00396
00397 if (!(te > t)) {
00398 fprintf(stderr, _("%3d<%*s(empty)\n"), mb->depth, (2 * mb->depth + 1), "");
00399 return;
00400 }
00401
00402
00403 while (te > t && iseol(te[-1]))
00404 te--;
00405 ellipsis = "";
00406 if (mb->depth > 0) {
00407 const char *tenl;
00408
00409
00410 while ((tenl = strchr(t, '\n')) && tenl < te)
00411 t = ++tenl;
00412
00413
00414 choplen = 61 - (2 * mb->depth);
00415 if ((te - t) > choplen) {
00416 te = t + choplen;
00417 ellipsis = "...";
00418 }
00419 }
00420
00421 fprintf(stderr, "%3d<%*s", mb->depth, (2 * mb->depth + 1), "");
00422 if (te > t)
00423 fprintf(stderr, "%.*s%s", (int)(te - t), t, ellipsis);
00424 fprintf(stderr, "\n");
00425 }
00426
00427 #define SKIPBLANK(_s, _c) \
00428 while (((_c) = *(_s)) && isblank(_c)) \
00429 (_s)++;
00430
00431 #define SKIPNONBLANK(_s, _c) \
00432 while (((_c) = *(_s)) && !(isblank(_c) || iseol(_c))) \
00433 (_s)++;
00434
00435 #define COPYNAME(_ne, _s, _c) \
00436 { SKIPBLANK(_s,_c); \
00437 while(((_c) = *(_s)) && (xisalnum(_c) || (_c) == '_')) \
00438 *(_ne)++ = *(_s)++; \
00439 *(_ne) = '\0'; \
00440 }
00441
00442 #define COPYOPTS(_oe, _s, _c) \
00443 { while(((_c) = *(_s)) && (_c) != ')') \
00444 *(_oe)++ = *(_s)++; \
00445 *(_oe) = '\0'; \
00446 }
00447
00448 #define COPYBODY(_be, _s, _c) \
00449 { while(((_c) = *(_s)) && !iseol(_c)) { \
00450 if ((_c) == '\\') \
00451 (_s)++; \
00452 *(_be)++ = *(_s)++; \
00453 } \
00454 *(_be) = '\0'; \
00455 }
00456
00464 static int
00465 expandT(MacroBuf mb, const char * f, size_t flen)
00466
00467
00468
00469 {
00470 char *sbuf;
00471 const char *s = mb->s;
00472 int rc;
00473
00474 sbuf = alloca(flen + 1);
00475 memset(sbuf, 0, (flen + 1));
00476
00477 strncpy(sbuf, f, flen);
00478 sbuf[flen] = '\0';
00479 mb->s = sbuf;
00480 rc = expandMacro(mb);
00481 mb->s = s;
00482 return rc;
00483 }
00484
00485 #if 0
00486
00493 static int
00494 expandS(MacroBuf mb, char * tbuf, size_t tbuflen)
00495
00496
00497
00498 {
00499 const char *t = mb->t;
00500 size_t nb = mb->nb;
00501 int rc;
00502
00503 mb->t = tbuf;
00504 mb->nb = tbuflen;
00505 rc = expandMacro(mb);
00506 mb->t = t;
00507 mb->nb = nb;
00508 return rc;
00509 }
00510 #endif
00511
00519 static int
00520 expandU(MacroBuf mb, char * u, size_t ulen)
00521
00522
00523
00524 {
00525 const char *s = mb->s;
00526 char *t = mb->t;
00527 size_t nb = mb->nb;
00528 char *tbuf;
00529 int rc;
00530
00531 tbuf = alloca(ulen + 1);
00532 memset(tbuf, 0, (ulen + 1));
00533
00534
00535 mb->s = u;
00536
00537 mb->t = tbuf;
00538 mb->nb = ulen;
00539 rc = expandMacro(mb);
00540
00541 tbuf[ulen] = '\0';
00542 if (ulen > mb->nb)
00543 strncpy(u, tbuf, (ulen - mb->nb + 1));
00544
00545 mb->s = s;
00546 mb->t = t;
00547 mb->nb = nb;
00548
00549 return rc;
00550 }
00551
00559 static int
00560 doShellEscape(MacroBuf mb, const char * cmd, size_t clen)
00561
00562
00563
00564
00565 {
00566 char pcmd[BUFSIZ];
00567 FILE *shf;
00568 int rc;
00569 int c;
00570
00571 strncpy(pcmd, cmd, clen);
00572 pcmd[clen] = '\0';
00573 rc = expandU(mb, pcmd, sizeof(pcmd));
00574 if (rc)
00575 return rc;
00576
00577 if ((shf = popen(pcmd, "r")) == NULL)
00578 return 1;
00579 while(mb->nb > 0 && (c = fgetc(shf)) != EOF)
00580 SAVECHAR(mb, c);
00581 (void) pclose(shf);
00582
00583
00584 while (iseol(mb->t[-1])) {
00585 *(mb->t--) = '\0';
00586 mb->nb++;
00587 }
00588 return 0;
00589 }
00590
00599 static const char *
00600 doDefine(MacroBuf mb, const char * se, int level, int expandbody)
00601
00602
00603 {
00604 const char *s = se;
00605 char buf[BUFSIZ], *n = buf, *ne = n;
00606 char *o = NULL, *oe;
00607 char *b, *be;
00608 int c;
00609 int oc = ')';
00610
00611
00612
00613 COPYNAME(ne, s, c);
00614
00615
00616
00617 oe = ne + 1;
00618 if (*s == '(') {
00619 s++;
00620 o = oe;
00621 COPYOPTS(oe, s, oc);
00622 s++;
00623 }
00624
00625
00626 b = be = oe + 1;
00627
00628 SKIPBLANK(s, c);
00629
00630 if (c == '{') {
00631 if ((se = matchchar(s, c, '}')) == NULL) {
00632 rpmError(RPMERR_BADSPEC,
00633 _("Macro %%%s has unterminated body\n"), n);
00634 se = s;
00635 return se;
00636 }
00637 s++;
00638 strncpy(b, s, (se - s));
00639 b[se - s] = '\0';
00640 be += strlen(b);
00641 se++;
00642 s = se;
00643 } else {
00644 COPYBODY(be, s, c);
00645
00646
00647
00648 while (--be >= b && (c = *be) && (isblank(c) || iseol(c)))
00649 {};
00650
00651 *(++be) = '\0';
00652 }
00653
00654
00655 while (iseol(*s))
00656 s++;
00657 se = s;
00658
00659
00660 if (!((c = *n) && (xisalpha(c) || c == '_') && (ne - n) > 2)) {
00661 rpmError(RPMERR_BADSPEC,
00662 _("Macro %%%s has illegal name (%%define)\n"), n);
00663 return se;
00664 }
00665
00666
00667 if (o && oc != ')') {
00668 rpmError(RPMERR_BADSPEC, _("Macro %%%s has unterminated opts\n"), n);
00669 return se;
00670 }
00671
00672 if ((be - b) < 1) {
00673 rpmError(RPMERR_BADSPEC, _("Macro %%%s has empty body\n"), n);
00674 return se;
00675 }
00676
00677
00678 if (expandbody && expandU(mb, b, (&buf[sizeof(buf)] - b))) {
00679 rpmError(RPMERR_BADSPEC, _("Macro %%%s failed to expand\n"), n);
00680 return se;
00681 }
00682
00683
00684 addMacro(mb->mc, n, o, b, (level - 1));
00685
00686 return se;
00687 }
00688
00695 static const char *
00696 doUndefine(MacroContext mc, const char * se)
00697
00698
00699 {
00700 const char *s = se;
00701 char buf[BUFSIZ], *n = buf, *ne = n;
00702 int c;
00703
00704
00705 COPYNAME(ne, s, c);
00706
00707
00708
00709 while (iseol(*s))
00710 s++;
00711 se = s;
00712
00713
00714 if (!((c = *n) && (xisalpha(c) || c == '_') && (ne - n) > 2)) {
00715 rpmError(RPMERR_BADSPEC,
00716 _("Macro %%%s has illegal name (%%undefine)\n"), n);
00717 return se;
00718 }
00719
00720 delMacro(mc, n);
00721
00722 return se;
00723 }
00724
00725 #ifdef DYING
00726 static void
00727 dumpME(const char * msg, MacroEntry me)
00728
00729
00730 {
00731 if (msg)
00732 fprintf(stderr, "%s", msg);
00733 fprintf(stderr, "\tme %p", me);
00734 if (me)
00735 fprintf(stderr,"\tname %p(%s) prev %p",
00736 me->name, me->name, me->prev);
00737 fprintf(stderr, "\n");
00738 }
00739 #endif
00740
00749 static void
00750 pushMacro( MacroEntry * mep,
00751 const char * n, const char * o,
00752 const char * b, int level)
00753
00754 {
00755
00756 MacroEntry prev = (mep && *mep ? *mep : NULL);
00757
00758 MacroEntry me = (MacroEntry) xmalloc(sizeof(*me));
00759
00760
00761 me->prev = prev;
00762
00763 me->name = (prev ? prev->name : xstrdup(n));
00764 me->opts = (o ? xstrdup(o) : NULL);
00765 me->body = xstrdup(b ? b : "");
00766 me->used = 0;
00767 me->level = level;
00768 if (mep)
00769 *mep = me;
00770 else
00771 me = _free(me);
00772 }
00773
00778 static void
00779 popMacro(MacroEntry * mep)
00780
00781 {
00782 MacroEntry me = (*mep ? *mep : NULL);
00783
00784 if (me) {
00785
00786
00787 if ((*mep = me->prev) == NULL)
00788 me->name = _free(me->name);
00789 me->opts = _free(me->opts);
00790 me->body = _free(me->body);
00791 me = _free(me);
00792
00793 }
00794 }
00795
00800 static void
00801 freeArgs(MacroBuf mb)
00802
00803 {
00804 MacroContext mc = mb->mc;
00805 int ndeleted = 0;
00806 int i;
00807
00808 if (mc == NULL || mc->macroTable == NULL)
00809 return;
00810
00811
00812 for (i = 0; i < mc->firstFree; i++) {
00813 MacroEntry *mep, me;
00814 int skiptest = 0;
00815 mep = &mc->macroTable[i];
00816 me = *mep;
00817
00818 if (me == NULL)
00819 continue;
00820 if (me->level < mb->depth)
00821 continue;
00822 if (strlen(me->name) == 1 && strchr("#*0", *me->name)) {
00823 if (*me->name == '*' && me->used > 0)
00824 skiptest = 1;
00825 } else if (!skiptest && me->used <= 0) {
00826 #if NOTYET
00827 rpmError(RPMERR_BADSPEC,
00828 _("Macro %%%s (%s) was not used below level %d\n"),
00829 me->name, me->body, me->level);
00830 #endif
00831 }
00832 popMacro(mep);
00833 if (!(mep && *mep))
00834 ndeleted++;
00835 }
00836
00837
00838 if (ndeleted)
00839 sortMacroTable(mc);
00840 }
00841
00851 static const char *
00852 grabArgs(MacroBuf mb, const MacroEntry me, const char * se, char lastc)
00853
00854
00855 {
00856 char buf[BUFSIZ], *b, *be;
00857 char aname[16];
00858 const char *opts, *o;
00859 int argc = 0;
00860 const char **argv;
00861 int c;
00862
00863
00864 buf[0] = '\0';
00865 b = be = stpcpy(buf, me->name);
00866
00867 addMacro(mb->mc, "0", NULL, buf, mb->depth);
00868
00869 argc = 1;
00870
00871
00872 *be++ = ' ';
00873 while ((c = *se++) != '\0' && c != lastc) {
00874
00875 if (!isblank(c)) {
00876 *be++ = c;
00877 continue;
00878 }
00879
00880
00881 if (be[-1] == ' ')
00882 continue;
00883
00884 *be++ = ' ';
00885 argc++;
00886 }
00887 if (c == '\0') se--;
00888 if (be[-1] != ' ')
00889 argc++, be++;
00890 be[-1] = '\0';
00891 if (*b == ' ') b++;
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902 addMacro(mb->mc, "**", NULL, b, mb->depth);
00903
00904 #ifdef NOTYET
00905
00906 expandU(mb, buf, sizeof(buf));
00907 #endif
00908
00909
00910 argv = (const char **) alloca((argc + 1) * sizeof(*argv));
00911 be[-1] = ' ';
00912 be[0] = '\0';
00913 b = buf;
00914 for (c = 0; c < argc; c++) {
00915 argv[c] = b;
00916 b = strchr(b, ' ');
00917 *b++ = '\0';
00918 }
00919
00920 argv[argc] = NULL;
00921
00922
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932
00933
00934
00935
00936
00937 #ifdef __GLIBC__
00938
00939 optind = 1;
00940
00941 #endif
00942
00943 opts = me->opts;
00944
00945
00946 while((c = getopt(argc, (char **)argv, opts)) != -1) {
00947 if (c == '?' || (o = strchr(opts, c)) == NULL) {
00948 rpmError(RPMERR_BADSPEC, _("Unknown option %c in %s(%s)\n"),
00949 (char)c, me->name, opts);
00950 return se;
00951 }
00952 *be++ = '-';
00953 *be++ = c;
00954
00955 if (o[1] == ':') {
00956
00957 *be++ = ' ';
00958 be = stpcpy(be, optarg);
00959 }
00960 *be++ = '\0';
00961 aname[0] = '-'; aname[1] = c; aname[2] = '\0';
00962 addMacro(mb->mc, aname, NULL, b, mb->depth);
00963 if (o[1] == ':') {
00964 aname[0] = '-'; aname[1] = c; aname[2] = '*'; aname[3] = '\0';
00965 addMacro(mb->mc, aname, NULL, optarg, mb->depth);
00966 }
00967 be = b;
00968 }
00969
00970
00971 sprintf(aname, "%d", (argc - optind));
00972 addMacro(mb->mc, "#", NULL, aname, mb->depth);
00973
00974
00975 if (be) {
00976 *be = '\0';
00977 for (c = optind; c < argc; c++) {
00978 sprintf(aname, "%d", (c - optind + 1));
00979 addMacro(mb->mc, aname, NULL, argv[c], mb->depth);
00980 *be++ = ' ';
00981 be = stpcpy(be, argv[c]);
00982 }
00983 }
00984
00985
00986 addMacro(mb->mc, "*", NULL, b, mb->depth);
00987
00988 return se;
00989 }
00990
00998 static void
00999 doOutput(MacroBuf mb, int waserror, const char * msg, size_t msglen)
01000
01001
01002
01003
01004 {
01005 char buf[BUFSIZ];
01006
01007 strncpy(buf, msg, msglen);
01008 buf[msglen] = '\0';
01009 (void) expandU(mb, buf, sizeof(buf));
01010 if (waserror)
01011 rpmError(RPMERR_BADSPEC, "%s\n", buf);
01012 else
01013 fprintf(stderr, "%s", buf);
01014 }
01015
01025 static void
01026 doFoo(MacroBuf mb, int negate, const char * f, size_t fn,
01027 const char * g, size_t gn)
01028
01029
01030
01031
01032 {
01033 char buf[BUFSIZ], *b = NULL, *be;
01034 int c;
01035
01036 buf[0] = '\0';
01037 if (g) {
01038 strncpy(buf, g, gn);
01039 buf[gn] = '\0';
01040 (void) expandU(mb, buf, sizeof(buf));
01041 }
01042 if (STREQ("basename", f, fn)) {
01043 if ((b = strrchr(buf, '/')) == NULL)
01044 b = buf;
01045 #if NOTYET
01046
01047 } else if (STREQ("dirname", f, fn)) {
01048 if ((b = strrchr(buf, '/')) != NULL)
01049 *b = '\0';
01050 b = buf;
01051 #endif
01052 } else if (STREQ("suffix", f, fn)) {
01053 if ((b = strrchr(buf, '.')) != NULL)
01054 b++;
01055 } else if (STREQ("expand", f, fn)) {
01056 b = buf;
01057 } else if (STREQ("verbose", f, fn)) {
01058 if (negate)
01059 b = (rpmIsVerbose() ? NULL : buf);
01060 else
01061 b = (rpmIsVerbose() ? buf : NULL);
01062 } else if (STREQ("url2path", f, fn) || STREQ("u2p", f, fn)) {
01063 (void)urlPath(buf, (const char **)&b);
01064 if (*b == '\0') b = "/";
01065 } else if (STREQ("uncompress", f, fn)) {
01066 rpmCompressedMagic compressed = COMPRESSED_OTHER;
01067
01068 for (b = buf; (c = *b) && isblank(c);)
01069 b++;
01070 for (be = b; (c = *be) && !isblank(c);)
01071 be++;
01072
01073 *be++ = '\0';
01074 #ifndef DEBUG_MACROS
01075 (void) isCompressed(b, &compressed);
01076 #endif
01077 switch(compressed) {
01078 default:
01079 case 0:
01080 sprintf(be, "%%_cat %s", b);
01081 break;
01082 case 1:
01083 sprintf(be, "%%_gzip -dc %s", b);
01084 break;
01085 case 2:
01086 sprintf(be, "%%_bzip2 %s", b);
01087 break;
01088 case 3:
01089 sprintf(be, "%%_unzip %s", b);
01090 break;
01091 }
01092 b = be;
01093 } else if (STREQ("S", f, fn)) {
01094 for (b = buf; (c = *b) && xisdigit(c);)
01095 b++;
01096 if (!c) {
01097 b++;
01098 sprintf(b, "%%SOURCE%s", buf);
01099 } else
01100 b = buf;
01101 } else if (STREQ("P", f, fn)) {
01102 for (b = buf; (c = *b) && xisdigit(c);)
01103 b++;
01104 if (!c) {
01105 b++;
01106 sprintf(b, "%%PATCH%s", buf);
01107 } else
01108 b = buf;
01109 } else if (STREQ("F", f, fn)) {
01110 b = buf + strlen(buf) + 1;
01111 sprintf(b, "file%s.file", buf);
01112 }
01113
01114 if (b) {
01115 (void) expandT(mb, b, strlen(b));
01116 }
01117 }
01118
01125 static int
01126 expandMacro(MacroBuf mb)
01127
01128
01129
01130
01131
01132
01133 {
01134 MacroEntry *mep;
01135 MacroEntry me;
01136 const char *s = mb->s, *se;
01137 const char *f, *fe;
01138 const char *g, *ge;
01139 size_t fn, gn;
01140 char *t = mb->t;
01141 int c;
01142 int rc = 0;
01143 int negate;
01144 char grab;
01145 int chkexist;
01146
01147 if (++mb->depth > max_macro_depth) {
01148 rpmError(RPMERR_BADSPEC,
01149 _("Recursion depth(%d) greater than max(%d)\n"),
01150 mb->depth, max_macro_depth);
01151 mb->depth--;
01152 mb->expand_trace = 1;
01153 return 1;
01154 }
01155
01156 while (rc == 0 && mb->nb > 0 && (c = *s) != '\0') {
01157 s++;
01158
01159 switch(c) {
01160 case '%':
01161 if (*s != '%')
01162 break;
01163 s++;
01164
01165 default:
01166 SAVECHAR(mb, c);
01167 continue;
01168 break;
01169 }
01170
01171
01172 f = fe = NULL;
01173 g = ge = NULL;
01174 if (mb->depth > 1)
01175 t = mb->t;
01176 negate = 0;
01177 grab = '\0';
01178 chkexist = 0;
01179 switch ((c = *s)) {
01180 default:
01181 while (strchr("!?", *s) != NULL) {
01182 switch(*s++) {
01183 case '!':
01184 negate = ((negate + 1) % 2);
01185 break;
01186 case '?':
01187 chkexist++;
01188 break;
01189 }
01190 }
01191 f = se = s;
01192 if (*se == '-')
01193 se++;
01194 while((c = *se) && (xisalnum(c) || c == '_'))
01195 se++;
01196
01197 switch (*se) {
01198 case '*':
01199 se++;
01200 if (*se == '*') se++;
01201 break;
01202 case '#':
01203 se++;
01204 break;
01205 default:
01206 break;
01207 }
01208 fe = se;
01209
01210
01211 if ((c = *fe) && isblank(c))
01212 grab = '\n';
01213
01214 break;
01215 case '(':
01216 if ((se = matchchar(s, c, ')')) == NULL) {
01217 rpmError(RPMERR_BADSPEC,
01218 _("Unterminated %c: %s\n"), (char)c, s);
01219 rc = 1;
01220 continue;
01221 }
01222 if (mb->macro_trace)
01223 printMacro(mb, s, se+1);
01224
01225 s++;
01226 rc = doShellEscape(mb, s, (se - s));
01227 se++;
01228
01229 s = se;
01230 continue;
01231 break;
01232 case '{':
01233 if ((se = matchchar(s, c, '}')) == NULL) {
01234 rpmError(RPMERR_BADSPEC,
01235 _("Unterminated %c: %s\n"), (char)c, s);
01236 rc = 1;
01237 continue;
01238 }
01239 f = s+1;
01240 se++;
01241 while (strchr("!?", *f) != NULL) {
01242 switch(*f++) {
01243 case '!':
01244 negate = ((negate + 1) % 2);
01245 break;
01246 case '?':
01247 chkexist++;
01248 break;
01249 }
01250 }
01251 for (fe = f; (c = *fe) && !strchr(" :}", c);)
01252 fe++;
01253 switch (c) {
01254 case ':':
01255 g = fe + 1;
01256 ge = se - 1;
01257 break;
01258 case ' ':
01259 grab = se[-1];
01260 break;
01261 default:
01262 break;
01263 }
01264 break;
01265 }
01266
01267
01268 fn = (fe - f);
01269 gn = (ge - g);
01270 if ((fe - f) <= 0) {
01271
01272 c = '%';
01273 SAVECHAR(mb, c);
01274 #if 0
01275 rpmError(RPMERR_BADSPEC,
01276 _("A %% is followed by an unparseable macro\n"));
01277 #endif
01278 s = se;
01279 continue;
01280 }
01281
01282 if (mb->macro_trace)
01283 printMacro(mb, s, se);
01284
01285
01286 if (STREQ("global", f, fn)) {
01287 s = doDefine(mb, se, RMIL_GLOBAL, 1);
01288 continue;
01289 }
01290 if (STREQ("define", f, fn)) {
01291 s = doDefine(mb, se, mb->depth, 0);
01292 continue;
01293 }
01294 if (STREQ("undefine", f, fn)) {
01295 s = doUndefine(mb->mc, se);
01296 continue;
01297 }
01298
01299 if (STREQ("echo", f, fn) ||
01300 STREQ("warn", f, fn) ||
01301 STREQ("error", f, fn)) {
01302 int waserror = 0;
01303 if (STREQ("error", f, fn))
01304 waserror = 1;
01305 if (g < ge)
01306 doOutput(mb, waserror, g, gn);
01307 else
01308 doOutput(mb, waserror, f, fn);
01309 s = se;
01310 continue;
01311 }
01312
01313 if (STREQ("trace", f, fn)) {
01314
01315 mb->expand_trace = mb->macro_trace = (negate ? 0 : mb->depth);
01316 if (mb->depth == 1) {
01317 print_macro_trace = mb->macro_trace;
01318 print_expand_trace = mb->expand_trace;
01319 }
01320 s = se;
01321 continue;
01322 }
01323
01324 if (STREQ("dump", f, fn)) {
01325 rpmDumpMacroTable(mb->mc, NULL);
01326 while (iseol(*se))
01327 se++;
01328 s = se;
01329 continue;
01330 }
01331
01332
01333 if (STREQ("basename", f, fn) ||
01334 STREQ("suffix", f, fn) ||
01335 STREQ("expand", f, fn) ||
01336 STREQ("verbose", f, fn) ||
01337 STREQ("uncompress", f, fn) ||
01338 STREQ("url2path", f, fn) ||
01339 STREQ("u2p", f, fn) ||
01340 STREQ("S", f, fn) ||
01341 STREQ("P", f, fn) ||
01342 STREQ("F", f, fn)) {
01343
01344 doFoo(mb, negate, f, fn, g, gn);
01345
01346 s = se;
01347 continue;
01348 }
01349
01350
01351 mep = findEntry(mb->mc, f, fn);
01352 me = (mep ? *mep : NULL);
01353
01354
01355 if (*f == '-') {
01356 if (me)
01357 me->used++;
01358 if ((me == NULL && !negate) ||
01359 (me != NULL && negate)) {
01360 s = se;
01361 continue;
01362 }
01363
01364 if (g && g < ge) {
01365 rc = expandT(mb, g, gn);
01366 } else
01367 if (me && me->body && *me->body) {
01368 rc = expandT(mb, me->body, strlen(me->body));
01369 }
01370 s = se;
01371 continue;
01372 }
01373
01374
01375 if (chkexist) {
01376 if ((me == NULL && !negate) ||
01377 (me != NULL && negate)) {
01378 s = se;
01379 continue;
01380 }
01381 if (g && g < ge) {
01382 rc = expandT(mb, g, gn);
01383 } else
01384 if (me && me->body && *me->body) {
01385 rc = expandT(mb, me->body, strlen(me->body));
01386 }
01387 s = se;
01388 continue;
01389 }
01390
01391 if (me == NULL) {
01392 #ifndef HACK
01393 #if DEAD
01394
01395 if (fn == 1 && *f == '*') {
01396 s = se;
01397 continue;
01398 }
01399 #endif
01400
01401 c = '%';
01402 SAVECHAR(mb, c);
01403 #else
01404 rpmError(RPMERR_BADSPEC,
01405 _("Macro %%%.*s not found, skipping\n"), fn, f);
01406 s = se;
01407 #endif
01408 continue;
01409 }
01410
01411
01412 if (me && me->opts != NULL) {
01413 if (grab != '\0') {
01414 se = grabArgs(mb, me, fe, grab);
01415 } else {
01416 addMacro(mb->mc, "**", NULL, "", mb->depth);
01417 addMacro(mb->mc, "*", NULL, "", mb->depth);
01418 addMacro(mb->mc, "#", NULL, "0", mb->depth);
01419 addMacro(mb->mc, "0", NULL, me->name, mb->depth);
01420 }
01421 }
01422
01423
01424 if (me->body && *me->body) {
01425
01426 mb->s = me->body;
01427
01428 rc = expandMacro(mb);
01429 if (rc == 0)
01430 me->used++;
01431 }
01432
01433
01434 if (me->opts != NULL)
01435 freeArgs(mb);
01436
01437 s = se;
01438 }
01439
01440 *mb->t = '\0';
01441 mb->s = s;
01442 mb->depth--;
01443 if (rc != 0 || mb->expand_trace)
01444 printExpansion(mb, t, mb->t);
01445 return rc;
01446 }
01447
01448
01449
01450 int
01451 expandMacros(void * spec, MacroContext mc, char * sbuf, size_t slen)
01452 {
01453 MacroBuf mb = alloca(sizeof(*mb));
01454 char *tbuf;
01455 int rc;
01456
01457 if (sbuf == NULL || slen == 0)
01458 return 0;
01459 if (mc == NULL) mc = rpmGlobalMacroContext;
01460
01461 tbuf = alloca(slen + 1);
01462 memset(tbuf, 0, (slen + 1));
01463
01464
01465 mb->s = sbuf;
01466
01467 mb->t = tbuf;
01468 mb->nb = slen;
01469 mb->depth = 0;
01470 mb->macro_trace = print_macro_trace;
01471 mb->expand_trace = print_expand_trace;
01472
01473
01474 mb->spec = spec;
01475 mb->mc = mc;
01476
01477
01478 rc = expandMacro(mb);
01479
01480 if (mb->nb == 0)
01481 rpmError(RPMERR_BADSPEC, _("Target buffer overflow\n"));
01482
01483 tbuf[slen] = '\0';
01484 strncpy(sbuf, tbuf, (slen - mb->nb + 1));
01485
01486 return rc;
01487 }
01488
01489 void
01490 addMacro(MacroContext mc,
01491 const char * n, const char * o, const char * b, int level)
01492 {
01493 MacroEntry * mep;
01494
01495 if (mc == NULL) mc = rpmGlobalMacroContext;
01496
01497
01498 if ((mep = findEntry(mc, n, 0)) == NULL) {
01499 if (mc->firstFree == mc->macrosAllocated)
01500 expandMacroTable(mc);
01501 if (mc->macroTable != NULL)
01502 mep = mc->macroTable + mc->firstFree++;
01503 }
01504
01505 if (mep != NULL) {
01506
01507 pushMacro(mep, n, o, b, level);
01508
01509
01510 if ((*mep)->prev == NULL)
01511 sortMacroTable(mc);
01512 }
01513 }
01514
01515 void
01516 delMacro(MacroContext mc, const char * n)
01517 {
01518 MacroEntry * mep;
01519
01520 if (mc == NULL) mc = rpmGlobalMacroContext;
01521
01522 if ((mep = findEntry(mc, n, 0)) != NULL) {
01523 popMacro(mep);
01524
01525 if (!(mep && *mep))
01526 sortMacroTable(mc);
01527 }
01528 }
01529
01530
01531 int
01532 rpmDefineMacro(MacroContext mc, const char * macro, int level)
01533 {
01534 MacroBuf mb = alloca(sizeof(*mb));
01535
01536 memset(mb, 0, sizeof(*mb));
01537
01538
01539 mb->mc = (mc ? mc : rpmGlobalMacroContext);
01540
01541 (void) doDefine(mb, macro, level, 0);
01542 return 0;
01543 }
01544
01545
01546 void
01547 rpmLoadMacros(MacroContext mc, int level)
01548 {
01549
01550 if (mc == NULL || mc == rpmGlobalMacroContext)
01551 return;
01552
01553 if (mc->macroTable != NULL) {
01554 int i;
01555 for (i = 0; i < mc->firstFree; i++) {
01556 MacroEntry *mep, me;
01557 mep = &mc->macroTable[i];
01558 me = *mep;
01559
01560 if (me == NULL)
01561 continue;
01562 addMacro(NULL, me->name, me->opts, me->body, (level - 1));
01563 }
01564 }
01565 }
01566
01567 void
01568 rpmInitMacros( MacroContext mc, const char *macrofiles)
01569 {
01570 char *m, *mfile, *me;
01571
01572 if (macrofiles == NULL)
01573 return;
01574 #ifdef DYING
01575 if (mc == NULL) mc = rpmGlobalMacroContext;
01576 #endif
01577
01578 for (mfile = m = xstrdup(macrofiles); mfile && *mfile != '\0'; mfile = me) {
01579 FD_t fd;
01580 char buf[BUFSIZ];
01581
01582 for (me = mfile; (me = strchr(me, ':')) != NULL; me++) {
01583 if (!(me[1] == '/' && me[2] == '/'))
01584 break;
01585 }
01586
01587 if (me && *me == ':')
01588 *me++ = '\0';
01589 else
01590 me = mfile + strlen(mfile);
01591
01592
01593 buf[0] = '\0';
01594 if (mfile[0] == '~' && mfile[1] == '/') {
01595 char *home;
01596 if ((home = getenv("HOME")) != NULL) {
01597 mfile += 2;
01598 strncpy(buf, home, sizeof(buf));
01599 strncat(buf, "/", sizeof(buf) - strlen(buf));
01600 }
01601 }
01602 strncat(buf, mfile, sizeof(buf) - strlen(buf));
01603 buf[sizeof(buf)-1] = '\0';
01604
01605 fd = Fopen(buf, "r.fpio");
01606 if (fd == NULL || Ferror(fd)) {
01607 if (fd) (void) Fclose(fd);
01608 continue;
01609 }
01610
01611
01612
01613 max_macro_depth = 16;
01614
01615
01616 while(rdcl(buf, sizeof(buf), fd, 1) != NULL) {
01617 char c, *n;
01618
01619 n = buf;
01620
01621 SKIPBLANK(n, c);
01622
01623
01624 if (c != '%')
01625 continue;
01626 n++;
01627 (void) rpmDefineMacro(NULL, n, RMIL_MACROFILES);
01628 }
01629 (void) Fclose(fd);
01630 }
01631 m = _free(m);
01632
01633
01634
01635 rpmLoadMacros(rpmCLIMacroContext, RMIL_CMDLINE);
01636
01637 }
01638
01639
01640 void
01641 rpmFreeMacros(MacroContext mc)
01642 {
01643
01644 if (mc == NULL) mc = rpmGlobalMacroContext;
01645
01646 if (mc->macroTable != NULL) {
01647 int i;
01648 for (i = 0; i < mc->firstFree; i++) {
01649 MacroEntry me;
01650 while ((me = mc->macroTable[i]) != NULL) {
01651
01652
01653 if ((mc->macroTable[i] = me->prev) == NULL)
01654 me->name = _free(me->name);
01655
01656 me->opts = _free(me->opts);
01657 me->body = _free(me->body);
01658 me = _free(me);
01659 }
01660 }
01661 mc->macroTable = _free(mc->macroTable);
01662 }
01663 memset(mc, 0, sizeof(*mc));
01664 }
01665
01666
01667
01668 int isCompressed(const char * file, rpmCompressedMagic * compressed)
01669 {
01670 FD_t fd;
01671 ssize_t nb;
01672 int rc = -1;
01673 unsigned char magic[4];
01674
01675 *compressed = COMPRESSED_NOT;
01676
01677 fd = Fopen(file, "r.ufdio");
01678 if (fd == NULL || Ferror(fd)) {
01679
01680 rpmError(RPMERR_BADSPEC, _("File %s: %s\n"), file, Fstrerror(fd));
01681 if (fd) (void) Fclose(fd);
01682 return 1;
01683 }
01684 nb = Fread(magic, sizeof(magic[0]), sizeof(magic), fd);
01685 if (nb < 0) {
01686 rpmError(RPMERR_BADSPEC, _("File %s: %s\n"), file, Fstrerror(fd));
01687 rc = 1;
01688 } else if (nb < sizeof(magic)) {
01689 rpmError(RPMERR_BADSPEC, _("File %s is smaller than %u bytes\n"),
01690 file, (unsigned)sizeof(magic));
01691 rc = 0;
01692 }
01693 (void) Fclose(fd);
01694 if (rc >= 0)
01695 return rc;
01696
01697 rc = 0;
01698
01699 if ((magic[0] == 'B') && (magic[1] == 'Z')) {
01700 *compressed = COMPRESSED_BZIP2;
01701 } else if ((magic[0] == 0120) && (magic[1] == 0113) &&
01702 (magic[2] == 0003) && (magic[3] == 0004)) {
01703 *compressed = COMPRESSED_ZIP;
01704 } else if (((magic[0] == 0037) && (magic[1] == 0213)) ||
01705 ((magic[0] == 0037) && (magic[1] == 0236)) ||
01706 ((magic[0] == 0037) && (magic[1] == 0036)) ||
01707 ((magic[0] == 0037) && (magic[1] == 0240)) ||
01708 ((magic[0] == 0037) && (magic[1] == 0235))
01709 ) {
01710 *compressed = COMPRESSED_OTHER;
01711 }
01712
01713 return rc;
01714 }
01715
01716
01717
01718
01719 char *
01720 rpmExpand(const char *arg, ...)
01721 {
01722 char buf[BUFSIZ], *p, *pe;
01723 const char *s;
01724 va_list ap;
01725
01726 if (arg == NULL)
01727 return xstrdup("");
01728
01729 buf[0] = '\0';
01730 p = buf;
01731 pe = stpcpy(p, arg);
01732
01733 va_start(ap, arg);
01734 while ((s = va_arg(ap, const char *)) != NULL)
01735 pe = stpcpy(pe, s);
01736 va_end(ap);
01737 (void) expandMacros(NULL, NULL, buf, sizeof(buf));
01738 return xstrdup(buf);
01739 }
01740
01741
01742 int
01743 rpmExpandNumeric(const char *arg)
01744 {
01745 const char *val;
01746 int rc;
01747
01748 if (arg == NULL)
01749 return 0;
01750
01751 val = rpmExpand(arg, NULL);
01752 if (!(val && *val != '%'))
01753 rc = 0;
01754 else if (*val == 'Y' || *val == 'y')
01755 rc = 1;
01756 else if (*val == 'N' || *val == 'n')
01757 rc = 0;
01758 else {
01759 char *end;
01760 rc = strtol(val, &end, 0);
01761 if (!(end && *end == '\0'))
01762 rc = 0;
01763 }
01764 val = _free(val);
01765
01766 return rc;
01767 }
01768
01769
01770 char *rpmCleanPath(char * path)
01771 {
01772 const char *s;
01773 char *se, *t, *te;
01774 int begin = 1;
01775
01776 if (path == NULL)
01777 return NULL;
01778
01779
01780 s = t = te = path;
01781 while (*s != '\0') {
01782
01783 switch(*s) {
01784 case ':':
01785 if (s[1] == '/' && s[2] == '/') {
01786 *t++ = *s++;
01787 *t++ = *s++;
01788 break;
01789 }
01790 begin=1;
01791 break;
01792 case '/':
01793
01794 for (se = te + 1; se < t && *se != '/'; se++)
01795 {};
01796 if (se < t && *se == '/') {
01797 te = se;
01798
01799 }
01800 while (s[1] == '/')
01801 s++;
01802 while (t > path && t[-1] == '/')
01803 t--;
01804 break;
01805 case '.':
01806
01807
01808
01809
01810
01811
01812 if (begin && s[1] == '.' && (s[2] == '/' || s[2] == '\0')) {
01813
01814 *t++ = *s++;
01815 break;
01816 }
01817
01818 if (begin && s[1] == '\0') {
01819 break;
01820 }
01821
01822 if ((t[-1] == '/' && s[1] == '\0') || (t != path && s[1] == '/')) {
01823 s++;
01824 continue;
01825 }
01826
01827 if (!begin && t > path && t[-1] == '/' && s[1] == '.' && (s[2] == '/' || s[2] == '\0')) {
01828 t = te;
01829
01830 if (te > path)
01831 for (--te; te > path && *te != '/'; te--)
01832 {};
01833
01834 s++;
01835 s++;
01836 continue;
01837 }
01838 break;
01839 default:
01840 begin = 0;
01841 break;
01842 }
01843 *t++ = *s++;
01844 }
01845
01846
01847 if (t > &path[1] && t[-1] == '/')
01848 t--;
01849 *t = '\0';
01850
01851
01852 return path;
01853 }
01854
01855
01856
01857 const char *
01858 rpmGetPath(const char *path, ...)
01859 {
01860 char buf[BUFSIZ];
01861 const char * s;
01862 char * t, * te;
01863 va_list ap;
01864
01865 if (path == NULL)
01866 return xstrdup("");
01867
01868 buf[0] = '\0';
01869 t = buf;
01870 te = stpcpy(t, path);
01871 *te = '\0';
01872
01873 va_start(ap, path);
01874 while ((s = va_arg(ap, const char *)) != NULL) {
01875 te = stpcpy(te, s);
01876 *te = '\0';
01877 }
01878 va_end(ap);
01879
01880 (void) expandMacros(NULL, NULL, buf, sizeof(buf));
01881
01882
01883 (void) rpmCleanPath(buf);
01884 return xstrdup(buf);
01885 }
01886
01887
01888
01889 const char * rpmGenPath(const char * urlroot, const char * urlmdir,
01890 const char *urlfile)
01891 {
01892 const char * xroot = rpmGetPath(urlroot, NULL);
01893 const char * root = xroot;
01894 const char * xmdir = rpmGetPath(urlmdir, NULL);
01895 const char * mdir = xmdir;
01896 const char * xfile = rpmGetPath(urlfile, NULL);
01897 const char * file = xfile;
01898 const char * result;
01899 const char * url = NULL;
01900 int nurl = 0;
01901 int ut;
01902
01903 #if 0
01904 if (_debug) fprintf(stderr, "*** RGP xroot %s xmdir %s xfile %s\n", xroot, xmdir, xfile);
01905 #endif
01906 ut = urlPath(xroot, &root);
01907 if (url == NULL && ut > URL_IS_DASH) {
01908 url = xroot;
01909 nurl = root - xroot;
01910 #if 0
01911 if (_debug) fprintf(stderr, "*** RGP ut %d root %s nurl %d\n", ut, root, nurl);
01912 #endif
01913 }
01914 if (root == NULL || *root == '\0') root = "/";
01915
01916 ut = urlPath(xmdir, &mdir);
01917 if (url == NULL && ut > URL_IS_DASH) {
01918 url = xmdir;
01919 nurl = mdir - xmdir;
01920 #if 0
01921 if (_debug) fprintf(stderr, "*** RGP ut %d mdir %s nurl %d\n", ut, mdir, nurl);
01922 #endif
01923 }
01924 if (mdir == NULL || *mdir == '\0') mdir = "/";
01925
01926 ut = urlPath(xfile, &file);
01927 if (url == NULL && ut > URL_IS_DASH) {
01928 url = xfile;
01929 nurl = file - xfile;
01930 #if 0
01931 if (_debug) fprintf(stderr, "*** RGP ut %d file %s nurl %d\n", ut, file, nurl);
01932 #endif
01933 }
01934
01935 if (url && nurl > 0) {
01936 char *t = strncpy(alloca(nurl+1), url, nurl);
01937 t[nurl] = '\0';
01938 url = t;
01939 } else
01940 url = "";
01941
01942 result = rpmGetPath(url, root, "/", mdir, "/", file, NULL);
01943
01944 xroot = _free(xroot);
01945 xmdir = _free(xmdir);
01946 xfile = _free(xfile);
01947 #if 0
01948 if (_debug) fprintf(stderr, "*** RGP result %s\n", result);
01949 #endif
01950 return result;
01951 }
01952
01953
01954
01955 #if defined(DEBUG_MACROS)
01956
01957 #if defined(EVAL_MACROS)
01958
01959 char *macrofiles = "/usr/lib/rpm/macros:/etc/rpm/macros:~/.rpmmacros";
01960
01961 int
01962 main(int argc, char *argv[])
01963 {
01964 int c;
01965 int errflg = 0;
01966 extern char *optarg;
01967 extern int optind;
01968
01969 while ((c = getopt(argc, argv, "f:")) != EOF ) {
01970 switch (c) {
01971 case 'f':
01972 macrofiles = optarg;
01973 break;
01974 case '?':
01975 default:
01976 errflg++;
01977 break;
01978 }
01979 }
01980 if (errflg || optind >= argc) {
01981 fprintf(stderr, "Usage: %s [-f macropath ] macro ...\n", argv[0]);
01982 exit(1);
01983 }
01984
01985 rpmInitMacros(NULL, macrofiles);
01986 for ( ; optind < argc; optind++) {
01987 const char *val;
01988
01989 val = rpmGetPath(argv[optind], NULL);
01990 if (val) {
01991 fprintf(stdout, "%s:\t%s\n", argv[optind], val);
01992 val = _free(val);
01993 }
01994 }
01995 rpmFreeMacros(NULL);
01996 return 0;
01997 }
01998
01999 #else
02000
02001 char *macrofiles = "../macros:./testmacros";
02002 char *testfile = "./test";
02003
02004 int
02005 main(int argc, char *argv[])
02006 {
02007 char buf[BUFSIZ];
02008 FILE *fp;
02009 int x;
02010
02011 rpmInitMacros(NULL, macrofiles);
02012 rpmDumpMacroTable(NULL, NULL);
02013
02014 if ((fp = fopen(testfile, "r")) != NULL) {
02015 while(rdcl(buf, sizeof(buf), fp, 1)) {
02016 x = expandMacros(NULL, NULL, buf, sizeof(buf));
02017 fprintf(stderr, "%d->%s\n", x, buf);
02018 memset(buf, 0, sizeof(buf));
02019 }
02020 fclose(fp);
02021 }
02022
02023 while(rdcl(buf, sizeof(buf), stdin, 1)) {
02024 x = expandMacros(NULL, NULL, buf, sizeof(buf));
02025 fprintf(stderr, "%d->%s\n <-\n", x, buf);
02026 memset(buf, 0, sizeof(buf));
02027 }
02028 rpmFreeMacros(NULL);
02029
02030 return 0;
02031 }
02032 #endif
02033 #endif
02034