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