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