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