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