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