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