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