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