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 void delMacroAll(MacroContext mc, const char * n);
00817 static const char *
00818 doUnglobal(MacroContext mc, const char * se)
00819
00820
00821 {
00822 const char *s = se;
00823 char *buf = alloca(_macro_BUFSIZ);
00824 char *n = buf, *ne = n;
00825 int c;
00826
00827 COPYNAME(ne, s, c);
00828
00829
00830 while (iseol(*s))
00831 s++;
00832 se = s;
00833
00834
00835 if (!((c = *n) && (xisalpha(c) || c == '_') && (ne - n) > 2)) {
00836 rpmError(RPMERR_BADSPEC,
00837 _("Macro %%%s has illegal name (%%unglobal)\n"), n);
00838 return se;
00839 }
00840
00841 delMacroAll(mc, n);
00842
00843 return se;
00844 }
00845
00846 #ifdef DYING
00847 static void
00848 dumpME(const char * msg, MacroEntry me)
00849
00850
00851 {
00852 if (msg)
00853 fprintf(stderr, "%s", msg);
00854 fprintf(stderr, "\tme %p", me);
00855 if (me)
00856 fprintf(stderr,"\tname %p(%s) prev %p",
00857 me->name, me->name, me->prev);
00858 fprintf(stderr, "\n");
00859 }
00860 #endif
00861
00870 static void
00871 pushMacro( MacroEntry * mep, const char * n, const char * o,
00872 const char * b, int level)
00873
00874 {
00875 MacroEntry prev = (mep && *mep ? *mep : NULL);
00876 MacroEntry me = (MacroEntry) xmalloc(sizeof(*me));
00877 const char *name = n;
00878
00879 if (*name == '.')
00880 name++;
00881 if (*name == '.')
00882 name++;
00883
00884
00885 me->prev = prev;
00886
00887 me->name = (prev ? prev->name : xstrdup(name));
00888 me->opts = (o ? xstrdup(o) : NULL);
00889 me->body = xstrdup(b ? b : "");
00890 me->used = 0;
00891 me->level = level;
00892 me->flags = (name != n);
00893
00894
00895 if (mep)
00896 *mep = me;
00897 else
00898 me = _free(me);
00899
00900
00901 }
00902
00907 static void
00908 popMacro(MacroEntry * mep)
00909
00910 {
00911 MacroEntry me = (*mep ? *mep : NULL);
00912
00913
00914 if (me) {
00915
00916
00917
00918 if ((*mep = me->prev) == NULL)
00919 me->name = _free(me->name);
00920
00921 me->opts = _free(me->opts);
00922 me->body = _free(me->body);
00923 me = _free(me);
00924
00925 }
00926
00927 }
00928
00933 static void
00934 freeArgs(MacroBuf mb)
00935
00936 {
00937 MacroContext mc = mb->mc;
00938 int ndeleted = 0;
00939 int i;
00940
00941 if (mc == NULL || mc->macroTable == NULL)
00942 return;
00943
00944
00945 for (i = 0; i < mc->firstFree; i++) {
00946 MacroEntry *mep, me;
00947 int skiptest = 0;
00948 mep = &mc->macroTable[i];
00949 me = *mep;
00950
00951 if (me == NULL)
00952 continue;
00953 if (me->level < mb->depth)
00954 continue;
00955 if (strlen(me->name) == 1 && strchr("#*0", *me->name)) {
00956 if (*me->name == '*' && me->used > 0)
00957 skiptest = 1;
00958 } else if (!skiptest && me->used <= 0) {
00959 #if NOTYET
00960 rpmError(RPMERR_BADSPEC,
00961 _("Macro %%%s (%s) was not used below level %d\n"),
00962 me->name, me->body, me->level);
00963 #endif
00964 }
00965 popMacro(mep);
00966 if (!(mep && *mep))
00967 ndeleted++;
00968 }
00969
00970
00971 if (ndeleted)
00972 sortMacroTable(mc);
00973 }
00974
00984
00985 static const char *
00986 grabArgs(MacroBuf mb, const MacroEntry me, const char * se,
00987 const char * lastc)
00988
00989
00990 {
00991 size_t bufn = _macro_BUFSIZ;
00992 char *buf = alloca(bufn);
00993 char *b, *be;
00994 char aname[16];
00995 const char *opts, *o;
00996 int argc = 0;
00997 const char **argv;
00998 int c;
00999
01000
01001 buf[0] = '\0';
01002 b = be = stpcpy(buf, me->name);
01003
01004 addMacro(mb->mc, "0", NULL, buf, mb->depth);
01005
01006 argc = 1;
01007
01008
01009 *be++ = ' ';
01010 while ((c = *se++) != '\0' && (se-1) != lastc) {
01011
01012 if (!isblank(c)) {
01013 *be++ = c;
01014 continue;
01015 }
01016
01017
01018 if (be[-1] == ' ')
01019 continue;
01020
01021 *be++ = ' ';
01022 argc++;
01023 }
01024 if (c == '\0') se--;
01025 if (be[-1] != ' ')
01026 argc++, be++;
01027 be[-1] = '\0';
01028 if (*b == ' ') b++;
01029
01030
01031
01032
01033
01034
01035
01036
01037
01038
01039 addMacro(mb->mc, "**", NULL, b, mb->depth);
01040
01041 #ifdef NOTYET
01042
01043 expandU(mb, buf, bufn);
01044 #endif
01045
01046
01047 argv = (const char **) alloca((argc + 1) * sizeof(*argv));
01048 be[-1] = ' ';
01049 be[0] = '\0';
01050 b = buf;
01051 for (c = 0; c < argc; c++) {
01052 argv[c] = b;
01053 b = strchr(b, ' ');
01054 *b++ = '\0';
01055 }
01056
01057 argv[argc] = NULL;
01058
01059
01060
01061
01062
01063
01064
01065
01066
01067
01068
01069
01070
01071
01072
01073
01074 #ifdef __GLIBC__
01075
01076 optind = 0;
01077
01078 #else
01079 optind = 1;
01080 #endif
01081
01082 opts = me->opts;
01083
01084
01085
01086 while((c = getopt(argc, (char **)argv, opts)) != -1)
01087
01088 {
01089 if (c == '?' || (o = strchr(opts, c)) == NULL) {
01090 rpmError(RPMERR_BADSPEC, _("Unknown option %c in %s(%s)\n"),
01091 (char)c, me->name, opts);
01092 return se;
01093 }
01094 *be++ = '-';
01095 *be++ = c;
01096 if (o[1] == ':') {
01097 *be++ = ' ';
01098 be = stpcpy(be, optarg);
01099 }
01100 *be++ = '\0';
01101 aname[0] = '-'; aname[1] = c; aname[2] = '\0';
01102 addMacro(mb->mc, aname, NULL, b, mb->depth);
01103 if (o[1] == ':') {
01104 aname[0] = '-'; aname[1] = c; aname[2] = '*'; aname[3] = '\0';
01105 addMacro(mb->mc, aname, NULL, optarg, mb->depth);
01106 }
01107 be = b;
01108 }
01109
01110
01111 sprintf(aname, "%d", (argc - optind));
01112 addMacro(mb->mc, "#", NULL, aname, mb->depth);
01113
01114
01115 if (be) {
01116 *be = '\0';
01117 for (c = optind; c < argc; c++) {
01118 sprintf(aname, "%d", (c - optind + 1));
01119 addMacro(mb->mc, aname, NULL, argv[c], mb->depth);
01120 if (be != b) *be++ = ' ';
01121
01122 be = stpcpy(be, argv[c]);
01123
01124 }
01125 }
01126
01127
01128 addMacro(mb->mc, "*", NULL, b, mb->depth);
01129
01130 return se;
01131 }
01132
01133
01141 static void
01142 doOutput(MacroBuf mb, int waserror, const char * msg, size_t msglen)
01143
01144
01145 {
01146 size_t bufn = _macro_BUFSIZ + msglen;
01147 char *buf = alloca(bufn);
01148
01149 strncpy(buf, msg, msglen);
01150 buf[msglen] = '\0';
01151 (void) expandU(mb, buf, bufn);
01152 if (waserror)
01153 rpmError(RPMERR_BADSPEC, "%s\n", buf);
01154 else
01155 fprintf(stderr, "%s", buf);
01156 }
01157
01167 static void
01168 doFoo(MacroBuf mb, int negate, const char * f, size_t fn,
01169 const char * g, size_t gn)
01170
01171
01172 {
01173 size_t bufn = _macro_BUFSIZ + fn + gn;
01174 char * buf = alloca(bufn);
01175 char *b = NULL, *be;
01176 int c;
01177
01178 buf[0] = '\0';
01179 if (g != NULL) {
01180 strncpy(buf, g, gn);
01181 buf[gn] = '\0';
01182 (void) expandU(mb, buf, bufn);
01183 }
01184 #if defined(NOTYET)
01185 if (fn > 5 && STREQ("patch", f, 5) && xisdigit(f[5])) {
01186
01187 for (c = 5; c < fn-1 && f[c] == '0' && xisdigit(f[c+1]);)
01188 c++;
01189 b = buf;
01190 be = stpncpy( stpcpy(b, "%patch -P "), f+c, fn-c);
01191 *be = '\0';
01192 } else
01193 #endif
01194 if (STREQ("basename", f, fn)) {
01195 if ((b = strrchr(buf, '/')) == NULL)
01196 b = buf;
01197 else
01198 b++;
01199 } else if (STREQ("dirname", f, fn)) {
01200 if ((b = strrchr(buf, '/')) != NULL)
01201 *b = '\0';
01202 b = buf;
01203 } else if (STREQ("suffix", f, fn)) {
01204 if ((b = strrchr(buf, '.')) != NULL)
01205 b++;
01206 } else if (STREQ("expand", f, fn)) {
01207 b = buf;
01208 } else if (STREQ("verbose", f, fn)) {
01209 if (negate)
01210 b = (rpmIsVerbose() ? NULL : buf);
01211 else
01212 b = (rpmIsVerbose() ? buf : NULL);
01213 } else if (STREQ("url2path", f, fn) || STREQ("u2p", f, fn)) {
01214 int ut = urlPath(buf, (const char **)&b);
01215 ut = ut;
01216
01217 if (*b == '\0') b = "/";
01218
01219 } else if (STREQ("uncompress", f, fn)) {
01220 rpmCompressedMagic compressed = COMPRESSED_OTHER;
01221
01222 for (b = buf; (c = *b) && isblank(c);)
01223 b++;
01224 for (be = b; (c = *be) && !isblank(c);)
01225 be++;
01226
01227 *be++ = '\0';
01228 (void) isCompressed(b, &compressed);
01229 switch(compressed) {
01230 default:
01231 case 0:
01232 sprintf(be, "%%__cat %s", b);
01233 break;
01234 case 1:
01235 sprintf(be, "%%__gzip -dc %s", b);
01236 break;
01237 case 2:
01238 sprintf(be, "%%__bzip2 -dc %s", b);
01239 break;
01240 case 3:
01241 sprintf(be, "%%__unzip -qq %s", b);
01242 break;
01243 case 4:
01244 sprintf(be, "%%__lzop %s", b);
01245 break;
01246 case 5:
01247 sprintf(be, "%%__lzma %s", b);
01248 break;
01249 }
01250 b = be;
01251 } else if (STREQ("S", f, fn)) {
01252 for (b = buf; (c = *b) && xisdigit(c);)
01253 b++;
01254 if (!c) {
01255 b++;
01256 sprintf(b, "%%SOURCE%s", buf);
01257 } else
01258 b = buf;
01259 } else if (STREQ("P", f, fn)) {
01260 for (b = buf; (c = *b) && xisdigit(c);)
01261 b++;
01262 if (!c) {
01263 b++;
01264 sprintf(b, "%%PATCH%s", buf);
01265 } else
01266 b = buf;
01267 } else if (STREQ("F", f, fn)) {
01268 b = buf + strlen(buf) + 1;
01269 sprintf(b, "file%s.file", buf);
01270 }
01271
01272 if (b) {
01273 (void) expandT(mb, b, strlen(b));
01274 }
01275 }
01276
01283 static int
01284 expandMacro(MacroBuf mb)
01285
01286
01287
01288
01289 {
01290 MacroEntry *mep;
01291 MacroEntry me;
01292 const char *s = mb->s, *se;
01293 const char *f, *fe;
01294 const char *g, *ge;
01295 size_t fn, gn;
01296 char *t = mb->t;
01297 int c;
01298 int rc = 0;
01299 int negate;
01300 const char * lastc;
01301 int chkexist;
01302
01303 if (++mb->depth > max_macro_depth) {
01304 rpmError(RPMERR_BADSPEC,
01305 _("Recursion depth(%d) greater than max(%d)\n"),
01306 mb->depth, max_macro_depth);
01307 mb->depth--;
01308 mb->expand_trace = 1;
01309 return 1;
01310 }
01311
01312
01313 while (rc == 0 && mb->nb > 0 && (c = *s) != '\0') {
01314 s++;
01315
01316 switch(c) {
01317 case '%':
01318 if (*s) {
01319 if (*s != '%')
01320 break;
01321 s++;
01322 }
01323
01324 default:
01325 SAVECHAR(mb, c);
01326 continue;
01327 break;
01328 }
01329
01330
01331 f = fe = NULL;
01332 g = ge = NULL;
01333 if (mb->depth > 1)
01334 t = mb->t;
01335 negate = 0;
01336 lastc = NULL;
01337 chkexist = 0;
01338 switch ((c = *s)) {
01339 default:
01340 while (*s != '\0' && strchr("!?", *s) != NULL) {
01341 switch(*s++) {
01342 case '!':
01343 negate = ((negate + 1) % 2);
01344 break;
01345 case '?':
01346 chkexist++;
01347 break;
01348 }
01349 }
01350 f = se = s;
01351 if (*se == '-')
01352 se++;
01353 while((c = *se) && (xisalnum(c) || c == '_'))
01354 se++;
01355
01356 switch (*se) {
01357 case '*':
01358 se++;
01359 if (*se == '*') se++;
01360 break;
01361 case '#':
01362 se++;
01363 break;
01364 default:
01365 break;
01366 }
01367 fe = se;
01368
01369
01370 if ((c = *fe) && isblank(c))
01371 if ((lastc = strchr(fe,'\n')) == NULL)
01372 lastc = strchr(fe, '\0');
01373
01374 break;
01375 case '(':
01376 if ((se = matchchar(s, c, ')')) == NULL) {
01377 rpmError(RPMERR_BADSPEC,
01378 _("Unterminated %c: %s\n"), (char)c, s);
01379 rc = 1;
01380 continue;
01381 }
01382 if (mb->macro_trace)
01383 printMacro(mb, s, se+1);
01384
01385 s++;
01386 rc = doShellEscape(mb, s, (se - s));
01387 se++;
01388
01389 s = se;
01390 continue;
01391 break;
01392 case '{':
01393 if ((se = matchchar(s, c, '}')) == NULL) {
01394 rpmError(RPMERR_BADSPEC,
01395 _("Unterminated %c: %s\n"), (char)c, s);
01396 rc = 1;
01397 continue;
01398 }
01399 f = s+1;
01400 se++;
01401 while (strchr("!?", *f) != NULL) {
01402 switch(*f++) {
01403 case '!':
01404 negate = ((negate + 1) % 2);
01405 break;
01406 case '?':
01407 chkexist++;
01408 break;
01409 }
01410 }
01411
01412 for (fe = f; (c = *fe) && !strchr(" :}", c);)
01413 fe++;
01414 switch (c) {
01415 case ':':
01416 g = fe + 1;
01417 ge = se - 1;
01418 break;
01419 case ' ':
01420 lastc = se-1;
01421 break;
01422 default:
01423 break;
01424 }
01425 break;
01426 }
01427
01428
01429 fn = (fe - f);
01430 gn = (ge - g);
01431 if ((fe - f) <= 0) {
01432
01433 c = '%';
01434 SAVECHAR(mb, c);
01435 #if 0
01436 rpmError(RPMERR_BADSPEC,
01437 _("A %% is followed by an unparseable macro\n"));
01438 #endif
01439 s = se;
01440 continue;
01441 }
01442
01443 if (mb->macro_trace)
01444 printMacro(mb, s, se);
01445
01446
01447 if (STREQ("load", f, fn)) {
01448 if (g != NULL) {
01449 char * mfn = strncpy(alloca(gn + 1), g, gn);
01450 int xx;
01451 mfn[gn] = '\0';
01452 xx = rpmLoadMacroFile(NULL, mfn);
01453 }
01454 s = se;
01455 continue;
01456 }
01457 if (STREQ("global", f, fn)) {
01458 s = doDefine(mb, se, RMIL_GLOBAL, 1);
01459 continue;
01460 }
01461 if (STREQ("define", f, fn)) {
01462 s = doDefine(mb, se, mb->depth, 0);
01463 continue;
01464 }
01465 if (STREQ("undefine", f, fn)) {
01466 s = doUndefine(mb->mc, se);
01467 continue;
01468 }
01469 if (STREQ("unglobal", f, fn)) {
01470 s = doUnglobal(mb->mc, se);
01471 continue;
01472 }
01473
01474 if (STREQ("echo", f, fn) ||
01475 STREQ("warn", f, fn) ||
01476 STREQ("error", f, fn)) {
01477 int waserror = 0;
01478 if (STREQ("error", f, fn))
01479 waserror = 1;
01480 if (g != NULL && g < ge)
01481 doOutput(mb, waserror, g, gn);
01482 else
01483 doOutput(mb, waserror, f, fn);
01484 s = se;
01485 continue;
01486 }
01487
01488 if (STREQ("trace", f, fn)) {
01489
01490 mb->expand_trace = mb->macro_trace = (negate ? 0 : mb->depth);
01491 if (mb->depth == 1) {
01492 print_macro_trace = mb->macro_trace;
01493 print_expand_trace = mb->expand_trace;
01494 }
01495 s = se;
01496 continue;
01497 }
01498
01499 if (STREQ("dump", f, fn)) {
01500 rpmDumpMacroTable(mb->mc, NULL);
01501 while (iseol(*se))
01502 se++;
01503 s = se;
01504 continue;
01505 }
01506
01507 #ifdef WITH_LUA
01508 if (STREQ("lua", f, fn)) {
01509 rpmlua lua = NULL;
01510 const char *ls = s+sizeof("{lua:")-1;
01511 const char *lse = se-sizeof("}")+1;
01512 char *scriptbuf = (char *)xmalloc((lse-ls)+1);
01513 const char *printbuf;
01514 memcpy(scriptbuf, ls, lse-ls);
01515 scriptbuf[lse-ls] = '\0';
01516 rpmluaSetPrintBuffer(lua, 1);
01517 if (rpmluaRunScript(lua, scriptbuf, NULL) == -1)
01518 rc = 1;
01519 printbuf = rpmluaGetPrintBuffer(lua);
01520 if (printbuf) {
01521 int len = strlen(printbuf);
01522 if (len > mb->nb)
01523 len = mb->nb;
01524 memcpy(mb->t, printbuf, len);
01525 mb->t += len;
01526 mb->nb -= len;
01527 }
01528 rpmluaSetPrintBuffer(lua, 0);
01529 free(scriptbuf);
01530 s = se;
01531 continue;
01532 }
01533 #endif
01534
01535 #if defined(NOTYET)
01536
01537 if (lastc != NULL && fn > 5 && STREQ("patch", f, 5) && xisdigit(f[5])) {
01538
01539 doFoo(mb, negate, f, (lastc - f), NULL, 0);
01540
01541 s = lastc;
01542 continue;
01543 }
01544 #endif
01545
01546
01547 if (STREQ("basename", f, fn) ||
01548 STREQ("dirname", f, fn) ||
01549 STREQ("suffix", f, fn) ||
01550 STREQ("expand", f, fn) ||
01551 STREQ("verbose", f, fn) ||
01552 STREQ("uncompress", f, fn) ||
01553 STREQ("url2path", f, fn) ||
01554 STREQ("u2p", f, fn) ||
01555 STREQ("S", f, fn) ||
01556 STREQ("P", f, fn) ||
01557 STREQ("F", f, fn)) {
01558
01559 doFoo(mb, negate, f, fn, g, gn);
01560
01561 s = se;
01562 continue;
01563 }
01564
01565
01566 mep = findEntry(mb->mc, f, fn);
01567 me = (mep ? *mep : NULL);
01568
01569
01570 if (*f == '-') {
01571 if (me)
01572 me->used++;
01573 if ((me == NULL && !negate) ||
01574 (me != NULL && negate)) {
01575 s = se;
01576 continue;
01577 }
01578
01579 if (g && g < ge) {
01580 rc = expandT(mb, g, gn);
01581 } else
01582 if (me && me->body && *me->body) {
01583 rc = expandT(mb, me->body, strlen(me->body));
01584 }
01585 s = se;
01586 continue;
01587 }
01588
01589
01590 if (chkexist) {
01591 if ((me == NULL && !negate) ||
01592 (me != NULL && negate)) {
01593 s = se;
01594 continue;
01595 }
01596 if (g && g < ge) {
01597 rc = expandT(mb, g, gn);
01598 } else
01599 if (me && me->body && *me->body) {
01600 rc = expandT(mb, me->body, strlen(me->body));
01601 }
01602 s = se;
01603 continue;
01604 }
01605
01606 if (me == NULL) {
01607 #ifndef HACK
01608 #if DEAD
01609
01610 if (fn == 1 && *f == '*') {
01611 s = se;
01612 continue;
01613 }
01614 #endif
01615
01616 c = '%';
01617 SAVECHAR(mb, c);
01618 #else
01619 if (!strncmp(f, "if", fn) ||
01620 !strncmp(f, "else", fn) ||
01621 !strncmp(f, "endif", fn)) {
01622 c = '%';
01623 SAVECHAR(mb, c);
01624 } else {
01625 rpmError(RPMERR_BADSPEC,
01626 _("Macro %%%.*s not found, skipping\n"), fn, f);
01627 s = se;
01628 }
01629 #endif
01630 continue;
01631 }
01632
01633
01634 if (me && me->opts != NULL) {
01635 if (lastc != NULL) {
01636 se = grabArgs(mb, me, fe, lastc);
01637 } else {
01638 addMacro(mb->mc, "**", NULL, "", mb->depth);
01639 addMacro(mb->mc, "*", NULL, "", mb->depth);
01640 addMacro(mb->mc, "#", NULL, "0", mb->depth);
01641 addMacro(mb->mc, "0", NULL, me->name, mb->depth);
01642 }
01643 }
01644
01645
01646 if (me->body && *me->body) {
01647 mb->s = me->body;
01648 rc = expandMacro(mb);
01649 if (rc == 0)
01650 me->used++;
01651 }
01652
01653
01654 if (me->opts != NULL)
01655 freeArgs(mb);
01656
01657 s = se;
01658 }
01659
01660
01661 *mb->t = '\0';
01662 mb->s = s;
01663 mb->depth--;
01664 if (rc != 0 || mb->expand_trace)
01665 printExpansion(mb, t, mb->t);
01666 return rc;
01667 }
01668
01669 #if !defined(DEBUG_MACROS)
01670
01671
01672
01673 #define POPT_ERROR_NOARG -10
01674 #define POPT_ERROR_BADQUOTE -15
01675 #define POPT_ERROR_MALLOC -21
01677 #define POPT_ARGV_ARRAY_GROW_DELTA 5
01678
01679
01680 static int XpoptDupArgv(int argc, const char **argv,
01681 int * argcPtr, const char *** argvPtr)
01682
01683 {
01684 size_t nb = (argc + 1) * sizeof(*argv);
01685 const char ** argv2;
01686 char * dst;
01687 int i;
01688
01689 if (argc <= 0 || argv == NULL)
01690 return POPT_ERROR_NOARG;
01691 for (i = 0; i < argc; i++) {
01692 if (argv[i] == NULL)
01693 return POPT_ERROR_NOARG;
01694 nb += strlen(argv[i]) + 1;
01695 }
01696
01697 dst = malloc(nb);
01698 if (dst == NULL)
01699 return POPT_ERROR_MALLOC;
01700 argv2 = (void *) dst;
01701 dst += (argc + 1) * sizeof(*argv);
01702
01703
01704 for (i = 0; i < argc; i++) {
01705 argv2[i] = dst;
01706 dst += strlen(strcpy(dst, argv[i])) + 1;
01707 }
01708
01709 argv2[argc] = NULL;
01710
01711 if (argvPtr) {
01712 *argvPtr = argv2;
01713 } else {
01714 free(argv2);
01715 argv2 = NULL;
01716 }
01717 if (argcPtr)
01718 *argcPtr = argc;
01719 return 0;
01720 }
01721
01722
01723
01724 static int XpoptParseArgvString(const char * s, int * argcPtr, const char *** argvPtr)
01725
01726 {
01727 const char * src;
01728 char quote = '\0';
01729 int argvAlloced = POPT_ARGV_ARRAY_GROW_DELTA;
01730 const char ** argv = malloc(sizeof(*argv) * argvAlloced);
01731 int argc = 0;
01732 int buflen = strlen(s) + 1;
01733 char * buf = memset(alloca(buflen), 0, buflen);
01734 int rc = POPT_ERROR_MALLOC;
01735
01736 if (argv == NULL) return rc;
01737 argv[argc] = buf;
01738
01739 for (src = s; *src != '\0'; src++) {
01740 if (quote == *src) {
01741 quote = '\0';
01742 } else if (quote != '\0') {
01743 if (*src == '\\') {
01744 src++;
01745 if (!*src) {
01746 rc = POPT_ERROR_BADQUOTE;
01747 goto exit;
01748 }
01749 if (*src != quote) *buf++ = '\\';
01750 }
01751 *buf++ = *src;
01752 } else if (isspace(*src)) {
01753 if (*argv[argc] != '\0') {
01754 buf++, argc++;
01755 if (argc == argvAlloced) {
01756 argvAlloced += POPT_ARGV_ARRAY_GROW_DELTA;
01757 argv = realloc(argv, sizeof(*argv) * argvAlloced);
01758 if (argv == NULL) goto exit;
01759 }
01760 argv[argc] = buf;
01761 }
01762 } else switch (*src) {
01763 case '"':
01764 case '\'':
01765 quote = *src;
01766 break;
01767 case '\\':
01768 src++;
01769 if (!*src) {
01770 rc = POPT_ERROR_BADQUOTE;
01771 goto exit;
01772 }
01773
01774 default:
01775 *buf++ = *src;
01776 break;
01777 }
01778 }
01779
01780 if (strlen(argv[argc])) {
01781 argc++, buf++;
01782 }
01783
01784 rc = XpoptDupArgv(argc, argv, argcPtr, argvPtr);
01785
01786 exit:
01787 if (argv) free(argv);
01788 return rc;
01789 }
01790
01791
01792
01793 static int _debug = 0;
01794
01795 int rpmGlob(const char * patterns, int * argcPtr, const char *** argvPtr)
01796 {
01797 int ac = 0;
01798 const char ** av = NULL;
01799 int argc = 0;
01800 const char ** argv = NULL;
01801 char * globRoot = NULL;
01802 #ifdef ENABLE_NLS
01803 const char * old_collate = NULL;
01804 const char * old_ctype = NULL;
01805 const char * t;
01806 #endif
01807 size_t maxb, nb;
01808 int i, j;
01809 int rc;
01810
01811 rc = XpoptParseArgvString(patterns, &ac, &av);
01812 if (rc)
01813 return rc;
01814 #ifdef ENABLE_NLS
01815
01816 t = setlocale(LC_COLLATE, NULL);
01817 if (t)
01818 old_collate = xstrdup(t);
01819 t = setlocale(LC_CTYPE, NULL);
01820 if (t)
01821 old_ctype = xstrdup(t);
01822
01823 (void) setlocale(LC_COLLATE, "C");
01824 (void) setlocale(LC_CTYPE, "C");
01825 #endif
01826
01827 if (av != NULL)
01828 for (j = 0; j < ac; j++) {
01829 const char * globURL;
01830 const char * path;
01831 int ut = urlPath(av[j], &path);
01832 glob_t gl;
01833
01834 if (!Glob_pattern_p(av[j], 0) && strchr(path, '~') == NULL) {
01835 argv = xrealloc(argv, (argc+2) * sizeof(*argv));
01836 argv[argc] = xstrdup(av[j]);
01837 if (_debug)
01838 fprintf(stderr, "*** rpmGlob argv[%d] \"%s\"\n", argc, argv[argc]);
01839 argc++;
01840 continue;
01841 }
01842
01843 gl.gl_pathc = 0;
01844 gl.gl_pathv = NULL;
01845 rc = Glob(av[j], GLOB_TILDE, Glob_error, &gl);
01846 if (rc)
01847 goto exit;
01848
01849
01850 maxb = 0;
01851 for (i = 0; i < gl.gl_pathc; i++) {
01852 if ((nb = strlen(&(gl.gl_pathv[i][0]))) > maxb)
01853 maxb = nb;
01854 }
01855
01856 nb = ((ut == URL_IS_PATH) ? (path - av[j]) : 0);
01857 maxb += nb;
01858 maxb += 1;
01859 globURL = globRoot = xmalloc(maxb);
01860
01861 switch (ut) {
01862 case URL_IS_PATH:
01863 case URL_IS_DASH:
01864 strncpy(globRoot, av[j], nb);
01865 break;
01866 case URL_IS_HTTPS:
01867 case URL_IS_HTTP:
01868 case URL_IS_FTP:
01869 case URL_IS_HKP:
01870 case URL_IS_UNKNOWN:
01871 default:
01872 break;
01873 }
01874 globRoot += nb;
01875 *globRoot = '\0';
01876 if (_debug)
01877 fprintf(stderr, "*** GLOB maxb %d diskURL %d %*s globURL %p %s\n", (int)maxb, (int)nb, (int)nb, av[j], globURL, globURL);
01878
01879 argv = xrealloc(argv, (argc+gl.gl_pathc+1) * sizeof(*argv));
01880
01881 if (argv != NULL)
01882 for (i = 0; i < gl.gl_pathc; i++) {
01883 const char * globFile = &(gl.gl_pathv[i][0]);
01884 if (globRoot > globURL && globRoot[-1] == '/')
01885 while (*globFile == '/') globFile++;
01886 strcpy(globRoot, globFile);
01887 if (_debug)
01888 fprintf(stderr, "*** rpmGlob argv[%d] \"%s\"\n", argc, globURL);
01889 argv[argc++] = xstrdup(globURL);
01890 }
01891
01892 Globfree(&gl);
01893
01894 globURL = _free(globURL);
01895 }
01896
01897 if (argv != NULL && argc > 0) {
01898 argv[argc] = NULL;
01899 if (argvPtr)
01900 *argvPtr = argv;
01901 if (argcPtr)
01902 *argcPtr = argc;
01903 rc = 0;
01904 } else
01905 rc = 1;
01906
01907
01908 exit:
01909 #ifdef ENABLE_NLS
01910
01911 if (old_collate) {
01912 (void) setlocale(LC_COLLATE, old_collate);
01913 old_collate = _free(old_collate);
01914 }
01915 if (old_ctype) {
01916 (void) setlocale(LC_CTYPE, old_ctype);
01917 old_ctype = _free(old_ctype);
01918 }
01919
01920 #endif
01921 av = _free(av);
01922
01923 if (rc || argvPtr == NULL) {
01924
01925 if (argv != NULL)
01926 for (i = 0; i < argc; i++)
01927 argv[i] = _free(argv[i]);
01928 argv = _free(argv);
01929
01930 }
01931
01932 return rc;
01933 }
01934 #endif
01935
01936
01937
01938 int
01939 expandMacros(void * spec, MacroContext mc, char * sbuf, size_t slen)
01940 {
01941 MacroBuf mb = alloca(sizeof(*mb));
01942 char *tbuf;
01943 int rc;
01944
01945 if (sbuf == NULL || slen == 0)
01946 return 0;
01947 if (mc == NULL) mc = rpmGlobalMacroContext;
01948
01949 tbuf = alloca(slen + 1);
01950 memset(tbuf, 0, (slen + 1));
01951
01952 mb->s = sbuf;
01953 mb->t = tbuf;
01954 mb->nb = slen;
01955 mb->depth = 0;
01956 mb->macro_trace = print_macro_trace;
01957 mb->expand_trace = print_expand_trace;
01958
01959 mb->spec = spec;
01960 mb->mc = mc;
01961
01962 rc = expandMacro(mb);
01963
01964 tbuf[slen] = '\0';
01965 if (mb->nb == 0)
01966 rpmError(RPMERR_BADSPEC, _("Macro expansion too big for target buffer\n"));
01967 else
01968 strncpy(sbuf, tbuf, (slen - mb->nb + 1));
01969
01970 return rc;
01971 }
01972
01973 void
01974 addMacro(MacroContext mc,
01975 const char * n, const char * o, const char * b, int level)
01976 {
01977 MacroEntry * mep;
01978 const char * name = n;
01979
01980 if (*name == '.')
01981 name++;
01982 if (*name == '.')
01983 name++;
01984
01985 if (mc == NULL) mc = rpmGlobalMacroContext;
01986
01987
01988 if ((mep = findEntry(mc, name, 0)) == NULL) {
01989 if (mc->firstFree == mc->macrosAllocated)
01990 expandMacroTable(mc);
01991 if (mc->macroTable != NULL)
01992 mep = mc->macroTable + mc->firstFree++;
01993 }
01994
01995 if (mep != NULL) {
01996
01997 if (*mep && (*mep)->flags && !(n[0] == '.' && n[1] == '.')) {
01998
01999 if (strcmp((*mep)->name, "buildroot"))
02000 rpmError(RPMERR_BADSPEC, _("Macro '%s' is readonly and cannot be changed.\n"), n);
02001 return;
02002 }
02003
02004 pushMacro(mep, n, o, b, level);
02005
02006
02007 if ((*mep)->prev == NULL)
02008 sortMacroTable(mc);
02009 }
02010 }
02011
02012 void
02013 delMacro(MacroContext mc, const char * n)
02014 {
02015 MacroEntry * mep;
02016
02017 if (mc == NULL) mc = rpmGlobalMacroContext;
02018
02019 if ((mep = findEntry(mc, n, 0)) != NULL) {
02020 popMacro(mep);
02021
02022 if (!(mep && *mep))
02023 sortMacroTable(mc);
02024 }
02025 }
02026
02027 void
02028 delMacroAll(MacroContext mc, const char * n)
02029 {
02030 MacroEntry * mep;
02031
02032 if (mc == NULL) mc = rpmGlobalMacroContext;
02033
02034 while ((mep = findEntry(mc, n, 0)) != NULL) {
02035 delMacro(mc, n);
02036 }
02037 }
02038
02039
02040 int
02041 rpmDefineMacro(MacroContext mc, const char * macro, int level)
02042 {
02043 MacroBuf mb = alloca(sizeof(*mb));
02044
02045 memset(mb, 0, sizeof(*mb));
02046
02047 mb->mc = (mc ? mc : rpmGlobalMacroContext);
02048 (void) doDefine(mb, macro, level, 0);
02049 return 0;
02050 }
02051
02052
02053 void
02054 rpmLoadMacros(MacroContext mc, int level)
02055 {
02056
02057 if (mc == NULL || mc == rpmGlobalMacroContext)
02058 return;
02059
02060 if (mc->macroTable != NULL) {
02061 int i;
02062 for (i = 0; i < mc->firstFree; i++) {
02063 MacroEntry *mep, me;
02064 mep = &mc->macroTable[i];
02065 me = *mep;
02066
02067 if (me == NULL)
02068 continue;
02069 addMacro(NULL, me->name, me->opts, me->body, (level - 1));
02070 }
02071 }
02072 }
02073
02074 int
02075 rpmLoadMacroFile(MacroContext mc, const char * fn)
02076 {
02077 FD_t fd = Fopen(fn, "r.fpio");
02078 size_t bufn = _macro_BUFSIZ;
02079 char *buf = alloca(bufn);
02080 int rc = -1;
02081
02082 if (fd == NULL || Ferror(fd)) {
02083 if (fd) (void) Fclose(fd);
02084 return rc;
02085 }
02086
02087
02088
02089 max_macro_depth = _MAX_MACRO_DEPTH;
02090
02091
02092 buf[0] = '\0';
02093 while(rdcl(buf, bufn, fd) != NULL) {
02094 char c, *n;
02095
02096 n = buf;
02097 SKIPBLANK(n, c);
02098
02099 if (c != '%')
02100 continue;
02101 n++;
02102 rc = rpmDefineMacro(mc, n, RMIL_MACROFILES);
02103 }
02104 rc = Fclose(fd);
02105 return rc;
02106 }
02107
02108 void
02109 rpmInitMacros(MacroContext mc, const char * macrofiles)
02110 {
02111 char *mfiles, *m, *me;
02112
02113 if (macrofiles == NULL)
02114 return;
02115 #ifdef DYING
02116 if (mc == NULL) mc = rpmGlobalMacroContext;
02117 #endif
02118
02119 mfiles = xstrdup(macrofiles);
02120 for (m = mfiles; m && *m != '\0'; m = me) {
02121 const char ** av;
02122 int ac;
02123 int i;
02124
02125 for (me = m; (me = strchr(me, ':')) != NULL; me++) {
02126
02127 if (!(me[1] == '/' && me[2] == '/'))
02128 break;
02129 }
02130
02131 if (me && *me == ':')
02132 *me++ = '\0';
02133 else
02134 me = m + strlen(m);
02135
02136
02137 ac = 0;
02138 av = NULL;
02139 #if defined(DEBUG_MACROS)
02140 ac = 1;
02141 av = xmalloc((ac + 1) * sizeof(*av));
02142 av[0] = strdup(m);
02143 av[1] = NULL;
02144 #else
02145 i = rpmGlob(m, &ac, &av);
02146 if (i != 0)
02147 continue;
02148 #endif
02149
02150
02151
02152 for (i = 0; i < ac; i++) {
02153 size_t slen = strlen(av[i]);
02154
02155
02156 #define _suffix(_s, _x) \
02157 (slen >= sizeof(_x) && !strcmp((_s)+slen-(sizeof(_x)-1), (_x)))
02158 if (!(_suffix(av[i], "~")
02159 || _suffix(av[i], ".rpmnew")
02160 || _suffix(av[i], ".rpmorig")
02161 || _suffix(av[i], ".rpmsave"))
02162 )
02163 (void) rpmLoadMacroFile(mc, av[i]);
02164 #undef _suffix
02165
02166 av[i] = _free(av[i]);
02167 }
02168 av = _free(av);
02169 }
02170 mfiles = _free(mfiles);
02171
02172
02173
02174 rpmLoadMacros(rpmCLIMacroContext, RMIL_CMDLINE);
02175
02176 }
02177
02178
02179 void
02180 rpmFreeMacros(MacroContext mc)
02181 {
02182
02183 if (mc == NULL) mc = rpmGlobalMacroContext;
02184
02185 if (mc->macroTable != NULL) {
02186 int i;
02187 for (i = 0; i < mc->firstFree; i++) {
02188 MacroEntry me;
02189 while ((me = mc->macroTable[i]) != NULL) {
02190
02191
02192 if ((mc->macroTable[i] = me->prev) == NULL)
02193 me->name = _free(me->name);
02194
02195 me->opts = _free(me->opts);
02196 me->body = _free(me->body);
02197 me = _free(me);
02198 }
02199 }
02200 mc->macroTable = _free(mc->macroTable);
02201 }
02202 memset(mc, 0, sizeof(*mc));
02203 }
02204
02205
02206
02207 int isCompressed(const char * file, rpmCompressedMagic * compressed)
02208 {
02209 FD_t fd;
02210 ssize_t nb;
02211 int rc = -1;
02212 unsigned char magic[13];
02213 char *end, *ext;
02214
02215 *compressed = COMPRESSED_NOT;
02216
02217 fd = Fopen(file, "r");
02218 if (fd == NULL || Ferror(fd)) {
02219
02220 rpmError(RPMERR_BADSPEC, _("File %s: %s\n"), file, Fstrerror(fd));
02221 if (fd) (void) Fclose(fd);
02222 return 1;
02223 }
02224 nb = Fread(magic, sizeof(magic[0]), sizeof(magic), fd);
02225 if (nb < 0) {
02226 rpmError(RPMERR_BADSPEC, _("File %s: %s\n"), file, Fstrerror(fd));
02227 rc = 1;
02228 } else if (nb < sizeof(magic)) {
02229 rpmError(RPMERR_BADSPEC, _("File %s is smaller than %u bytes\n"),
02230 file, (unsigned)sizeof(magic));
02231 rc = 0;
02232 }
02233 (void) Fclose(fd);
02234 if (rc >= 0)
02235 return rc;
02236
02237 rc = 0;
02238
02239
02240 end = strchr(file, '\0');
02241 ext = end - 4;
02242 if (ext > file && !strcasecmp(ext, ".tar")) return rc;
02243
02244 if (magic[0] == 'B' && magic[1] == 'Z')
02245 *compressed = COMPRESSED_BZIP2;
02246 else
02247 if (magic[0] == 0120 && magic[1] == 0113
02248 && magic[2] == 0003 && magic[3] == 0004)
02249 *compressed = COMPRESSED_ZIP;
02250 else
02251 if (magic[0] == 0x89 && magic[1] == 'L'
02252 && magic[2] == 'Z' && magic[3] == 'O')
02253 *compressed = COMPRESSED_LZOP;
02254 else
02255
02256 if (magic[ 9] == 0x00 && magic[10] == 0x00 &&
02257 magic[11] == 0x00 && magic[12] == 0x00)
02258 *compressed = COMPRESSED_LZMA;
02259 else
02260 if ((magic[0] == 0037 && magic[1] == 0213)
02261 || (magic[0] == 0037 && magic[1] == 0236)
02262 || (magic[0] == 0037 && magic[1] == 0036)
02263 || (magic[0] == 0037 && magic[1] == 0240)
02264 || (magic[0] == 0037 && magic[1] == 0235))
02265 *compressed = COMPRESSED_OTHER;
02266
02267 return rc;
02268 }
02269
02270
02271
02272
02273 char *
02274 rpmExpand(const char *arg, ...)
02275 {
02276 const char *s;
02277 char *t, *te;
02278 size_t sn, tn;
02279 size_t bufn = 8 * _macro_BUFSIZ;
02280
02281 va_list ap;
02282
02283 if (arg == NULL)
02284 return xstrdup("");
02285
02286 t = xmalloc(bufn + strlen(arg) + 1);
02287 *t = '\0';
02288 te = stpcpy(t, arg);
02289
02290
02291 va_start(ap, arg);
02292 while ((s = va_arg(ap, const char *)) != NULL) {
02293 sn = strlen(s);
02294 tn = (te - t);
02295 t = xrealloc(t, tn + sn + bufn + 1);
02296 te = t + tn;
02297 te = stpcpy(te, s);
02298 }
02299 va_end(ap);
02300
02301
02302 *te = '\0';
02303 tn = (te - t);
02304 (void) expandMacros(NULL, NULL, t, tn + bufn + 1);
02305 t[tn + bufn] = '\0';
02306 t = xrealloc(t, strlen(t) + 1);
02307
02308 return t;
02309 }
02310
02311
02312 int
02313 rpmExpandNumeric(const char *arg)
02314 {
02315 const char *val;
02316 int rc;
02317
02318 if (arg == NULL)
02319 return 0;
02320
02321 val = rpmExpand(arg, NULL);
02322 if (!(val && *val != '%'))
02323 rc = 0;
02324 else if (*val == 'Y' || *val == 'y')
02325 rc = 1;
02326 else if (*val == 'N' || *val == 'n')
02327 rc = 0;
02328 else {
02329 char *end;
02330 rc = strtol(val, &end, 0);
02331 if (!(end && *end == '\0'))
02332 rc = 0;
02333 }
02334 val = _free(val);
02335
02336 return rc;
02337 }
02338
02339
02340 char *rpmCleanPath(char * path)
02341 {
02342 const char *s;
02343 char *se, *t, *te;
02344 int begin = 1;
02345
02346 if (path == NULL)
02347 return NULL;
02348
02349
02350 s = t = te = path;
02351 while (*s != '\0') {
02352
02353 switch(*s) {
02354 case ':':
02355 if (s[1] == '/' && s[2] == '/') {
02356 *t++ = *s++;
02357 *t++ = *s++;
02358
02359 if (s[0] == '/') *t++ = *s++;
02360 te = t;
02361 break;
02362 }
02363 begin=1;
02364 break;
02365 case '/':
02366
02367 for (se = te + 1; se < t && *se != '/'; se++)
02368 {};
02369 if (se < t && *se == '/') {
02370 te = se;
02371
02372 }
02373 while (s[1] == '/')
02374 s++;
02375 while (t > te && t[-1] == '/')
02376 t--;
02377 break;
02378 case '.':
02379
02380
02381
02382
02383
02384
02385 if (begin && s[1] == '.' && (s[2] == '/' || s[2] == '\0')) {
02386
02387 *t++ = *s++;
02388 break;
02389 }
02390
02391 if (begin && s[1] == '\0') {
02392 break;
02393 }
02394
02395 if ((t[-1] == '/' && s[1] == '\0') || (t > path && t[-1] == '/' && s[1] == '/')) {
02396 s++;
02397 continue;
02398 }
02399
02400 if (!begin && t > path && t[-1] == '/' && s[1] == '.' && (s[2] == '/' || s[2] == '\0')) {
02401 t = te;
02402
02403 if (te > path)
02404 for (--te; te > path && *te != '/'; te--)
02405 {};
02406
02407 s++;
02408 s++;
02409 continue;
02410 }
02411 break;
02412 default:
02413 begin = 0;
02414 break;
02415 }
02416 *t++ = *s++;
02417 }
02418
02419
02420 if (t > &path[1] && t[-1] == '/')
02421 t--;
02422 *t = '\0';
02423
02424
02425 return path;
02426 }
02427
02428
02429
02430 const char *
02431 rpmGetPath(const char *path, ...)
02432 {
02433 size_t bufn = _macro_BUFSIZ;
02434 char *buf = alloca(bufn);
02435 const char * s;
02436 char * t, * te;
02437 va_list ap;
02438
02439 if (path == NULL)
02440 return xstrdup("");
02441
02442 buf[0] = '\0';
02443 t = buf;
02444 te = stpcpy(t, path);
02445 *te = '\0';
02446
02447 va_start(ap, path);
02448 while ((s = va_arg(ap, const char *)) != NULL) {
02449 te = stpcpy(te, s);
02450 *te = '\0';
02451 }
02452 va_end(ap);
02453
02454 (void) expandMacros(NULL, NULL, buf, bufn);
02455
02456
02457 (void) rpmCleanPath(buf);
02458 return xstrdup(buf);
02459 }
02460
02461
02462
02463 const char * rpmGenPath(const char * urlroot, const char * urlmdir,
02464 const char *urlfile)
02465 {
02466 const char * xroot = rpmGetPath(urlroot, NULL);
02467 const char * root = xroot;
02468 const char * xmdir = rpmGetPath(urlmdir, NULL);
02469 const char * mdir = xmdir;
02470 const char * xfile = rpmGetPath(urlfile, NULL);
02471 const char * file = xfile;
02472 const char * result;
02473 const char * url = NULL;
02474 int nurl = 0;
02475 int ut;
02476
02477 #if 0
02478 if (_debug) fprintf(stderr, "*** RGP xroot %s xmdir %s xfile %s\n", xroot, xmdir, xfile);
02479 #endif
02480 ut = urlPath(xroot, &root);
02481 if (url == NULL && ut > URL_IS_DASH) {
02482 url = xroot;
02483 nurl = root - xroot;
02484 #if 0
02485 if (_debug) fprintf(stderr, "*** RGP ut %d root %s nurl %d\n", ut, root, nurl);
02486 #endif
02487 }
02488 if (root == NULL || *root == '\0') root = "/";
02489
02490 ut = urlPath(xmdir, &mdir);
02491 if (url == NULL && ut > URL_IS_DASH) {
02492 url = xmdir;
02493 nurl = mdir - xmdir;
02494 #if 0
02495 if (_debug) fprintf(stderr, "*** RGP ut %d mdir %s nurl %d\n", ut, mdir, nurl);
02496 #endif
02497 }
02498 if (mdir == NULL || *mdir == '\0') mdir = "/";
02499
02500 ut = urlPath(xfile, &file);
02501 if (url == NULL && ut > URL_IS_DASH) {
02502 url = xfile;
02503 nurl = file - xfile;
02504 #if 0
02505 if (_debug) fprintf(stderr, "*** RGP ut %d file %s nurl %d\n", ut, file, nurl);
02506 #endif
02507 }
02508
02509
02510 if (url && nurl > 0) {
02511 char *t = strncpy(alloca(nurl+1), url, nurl);
02512 t[nurl] = '\0';
02513 url = t;
02514 } else
02515 url = "";
02516
02517
02518 result = rpmGetPath(url, root, "/", mdir, "/", file, NULL);
02519
02520 xroot = _free(xroot);
02521 xmdir = _free(xmdir);
02522 xfile = _free(xfile);
02523 #if 0
02524 if (_debug) fprintf(stderr, "*** RGP result %s\n", result);
02525 #endif
02526 return result;
02527 }
02528
02529
02530
02531 #if defined(DEBUG_MACROS)
02532
02533 #if defined(EVAL_MACROS)
02534
02535 const char *rpmMacrofiles = MACROFILES;
02536
02537 int
02538 main(int argc, char *argv[])
02539 {
02540 int c;
02541 int errflg = 0;
02542 extern char *optarg;
02543 extern int optind;
02544
02545 while ((c = getopt(argc, argv, "f:")) != EOF ) {
02546 switch (c) {
02547 case 'f':
02548 rpmMacrofiles = optarg;
02549 break;
02550 case '?':
02551 default:
02552 errflg++;
02553 break;
02554 }
02555 }
02556 if (errflg || optind >= argc) {
02557 fprintf(stderr, "Usage: %s [-f macropath ] macro ...\n", argv[0]);
02558 exit(1);
02559 }
02560
02561 rpmInitMacros(NULL, rpmMacrofiles);
02562
02563 for ( ; optind < argc; optind++) {
02564 const char *val;
02565
02566 val = rpmExpand(argv[optind], NULL);
02567 if (val) {
02568 fprintf(stdout, "%s:\t%s\n", argv[optind], val);
02569 val = _free(val);
02570 }
02571 }
02572 rpmFreeMacros(NULL);
02573 return 0;
02574 }
02575
02576 #else
02577
02578 const char *rpmMacrofiles = "../macros:./testmacros";
02579 const char *testfile = "./test";
02580
02581 int
02582 main(int argc, char *argv[])
02583 {
02584 size_t bufn = _macro_BUFSIZ;
02585 char *buf = alloca(bufn);
02586 FILE *fp;
02587 int x;
02588
02589 rpmInitMacros(NULL, rpmMacrofiles);
02590
02591 if ((fp = fopen(testfile, "r")) != NULL) {
02592 while(rdcl(buf, bufn, fp)) {
02593 x = expandMacros(NULL, NULL, buf, bufn);
02594 fprintf(stderr, "%d->%s\n", x, buf);
02595 memset(buf, 0, bufn);
02596 }
02597 fclose(fp);
02598 }
02599
02600 while(rdcl(buf, bufn, stdin)) {
02601 x = expandMacros(NULL, NULL, buf, bufn);
02602 fprintf(stderr, "%d->%s\n <-\n", x, buf);
02603 memset(buf, 0, bufn);
02604 }
02605 rpmFreeMacros(NULL);
02606
02607 return 0;
02608 }
02609 #endif
02610 #endif
02611