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