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