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