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