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