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