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