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