1998-07-26 05:00:26 +08:00
|
|
|
#include "system.h"
|
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
#include <assert.h>
|
1999-03-28 08:47:40 +08:00
|
|
|
#include <stdarg.h>
|
1998-01-13 05:31:29 +08:00
|
|
|
|
1999-10-28 07:18:10 +08:00
|
|
|
#if !defined(isblank)
|
1998-07-09 01:50:48 +08:00
|
|
|
#define isblank(_c) ((_c) == ' ' || (_c) == '\t')
|
1999-10-28 07:18:10 +08:00
|
|
|
#endif
|
1999-08-17 02:57:37 +08:00
|
|
|
#define iseol(_c) ((_c) == '\n' || (_c) == '\r')
|
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
#define STREQ(_t, _f, _fn) ((_fn) == (sizeof(_t)-1) && !strncmp((_t), (_f), (_fn)))
|
1999-04-09 04:53:45 +08:00
|
|
|
#define FREE(_x) { if (_x) free((void *)_x); (_x) = NULL; }
|
1997-03-31 22:13:21 +08:00
|
|
|
|
1998-01-13 05:31:29 +08:00
|
|
|
#ifdef DEBUG_MACROS
|
1999-07-03 05:15:25 +08:00
|
|
|
#include <sys/types.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <fcntl.h>
|
|
|
|
#include <getopt.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
1997-03-31 22:13:21 +08:00
|
|
|
#define rpmError fprintf
|
|
|
|
#define RPMERR_BADSPEC stderr
|
1999-04-21 03:17:23 +08:00
|
|
|
#undef _
|
1998-09-28 06:03:52 +08:00
|
|
|
#define _(x) x
|
1999-03-28 08:47:40 +08:00
|
|
|
#define xfree(_p) free((void *)_p)
|
1999-04-21 03:17:23 +08:00
|
|
|
typedef int FD_t;
|
|
|
|
#define fdFileno(_x) (_x)
|
|
|
|
#define fdOpen open
|
1999-10-28 07:18:10 +08:00
|
|
|
#define Fread(_b, _s, _n, _fd) read(_fd, _b, _s)
|
|
|
|
#define Fclose(_fd) close(_fd)
|
1997-03-31 22:13:21 +08:00
|
|
|
#else
|
1999-07-14 05:37:57 +08:00
|
|
|
#include <rpmlib.h>
|
1997-03-31 22:13:21 +08:00
|
|
|
#endif
|
|
|
|
|
1999-07-14 05:37:57 +08:00
|
|
|
#include <rpmmacro.h>
|
1998-07-09 01:50:48 +08:00
|
|
|
|
1999-04-02 06:26:44 +08:00
|
|
|
struct MacroContext globalMacroContext;
|
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
typedef struct MacroBuf {
|
|
|
|
const char *s; /* text to expand */
|
|
|
|
char *t; /* expansion buffer */
|
|
|
|
size_t nb; /* no. bytes remaining in expansion buffer */
|
|
|
|
int depth; /* current expansion depth */
|
|
|
|
int macro_trace; /* pre-print macro to expand? */
|
|
|
|
int expand_trace; /* post-print macro expansion? */
|
1998-08-01 04:11:49 +08:00
|
|
|
void *spec; /* (future) %file expansion info */
|
1998-07-09 01:50:48 +08:00
|
|
|
MacroContext *mc;
|
|
|
|
} MacroBuf;
|
|
|
|
|
|
|
|
#define SAVECHAR(_mb, _c) { *(_mb)->t = (_c), (_mb)->t++, (_mb)->nb--; }
|
1997-03-31 22:13:21 +08:00
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
static int expandMacro(MacroBuf *mb);
|
|
|
|
|
1998-12-03 02:09:41 +08:00
|
|
|
#define MAX_MACRO_DEPTH 16
|
1998-10-20 19:54:13 +08:00
|
|
|
int max_macro_depth = MAX_MACRO_DEPTH;
|
1998-07-09 01:50:48 +08:00
|
|
|
|
|
|
|
#ifdef DEBUG_MACROS
|
|
|
|
int print_macro_trace = 0;
|
|
|
|
int print_expand_trace = 0;
|
|
|
|
#else
|
|
|
|
int print_macro_trace = 0;
|
|
|
|
int print_expand_trace = 0;
|
|
|
|
#endif
|
1997-03-31 22:13:21 +08:00
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
#define MACRO_CHUNK_SIZE 16
|
1997-03-31 22:13:21 +08:00
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
/* =============================================================== */
|
1997-03-31 22:13:21 +08:00
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
static int
|
|
|
|
compareMacroName(const void *ap, const void *bp)
|
1997-03-31 22:13:21 +08:00
|
|
|
{
|
1998-07-09 01:50:48 +08:00
|
|
|
MacroEntry *ame = *((MacroEntry **)ap);
|
|
|
|
MacroEntry *bme = *((MacroEntry **)bp);
|
1997-07-02 00:29:30 +08:00
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
if (ame == NULL && bme == NULL) {
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if (ame == NULL) {
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
if (bme == NULL) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
return strcmp(ame->name, bme->name);
|
|
|
|
}
|
1997-03-31 22:13:21 +08:00
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
static void
|
|
|
|
expandMacroTable(MacroContext *mc)
|
|
|
|
{
|
|
|
|
if (mc->macroTable == NULL) {
|
|
|
|
mc->macrosAllocated = MACRO_CHUNK_SIZE;
|
1999-09-21 11:22:53 +08:00
|
|
|
mc->macroTable = (MacroEntry **)
|
|
|
|
xmalloc(sizeof(*(mc->macroTable)) * mc->macrosAllocated);
|
1998-07-09 01:50:48 +08:00
|
|
|
mc->firstFree = 0;
|
1997-03-31 22:13:21 +08:00
|
|
|
} else {
|
1998-07-09 01:50:48 +08:00
|
|
|
mc->macrosAllocated += MACRO_CHUNK_SIZE;
|
1999-09-21 11:22:53 +08:00
|
|
|
mc->macroTable = (MacroEntry **)
|
|
|
|
xrealloc(mc->macroTable, sizeof(*(mc->macroTable)) *
|
1998-07-09 01:50:48 +08:00
|
|
|
mc->macrosAllocated);
|
1997-03-31 22:13:21 +08:00
|
|
|
}
|
1998-07-09 01:50:48 +08:00
|
|
|
memset(&mc->macroTable[mc->firstFree], 0, MACRO_CHUNK_SIZE * sizeof(*(mc->macroTable)));
|
1997-03-31 22:13:21 +08:00
|
|
|
}
|
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
static void
|
|
|
|
sortMacroTable(MacroContext *mc)
|
1997-03-31 22:13:21 +08:00
|
|
|
{
|
1999-08-17 00:18:25 +08:00
|
|
|
int i;
|
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
qsort(mc->macroTable, mc->firstFree, sizeof(*(mc->macroTable)),
|
|
|
|
compareMacroName);
|
1999-08-17 00:18:25 +08:00
|
|
|
|
|
|
|
/* Empty pointers are now at end of table. Reset first free index. */
|
|
|
|
for (i = 0; i < mc->firstFree; i++) {
|
|
|
|
if (mc->macroTable[i] != NULL)
|
|
|
|
continue;
|
|
|
|
mc->firstFree = i;
|
|
|
|
break;
|
|
|
|
}
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
1997-03-31 22:13:21 +08:00
|
|
|
|
1998-12-02 07:28:26 +08:00
|
|
|
void
|
1999-03-28 08:47:40 +08:00
|
|
|
dumpMacroTable(MacroContext *mc, FILE *f)
|
1998-07-09 01:50:48 +08:00
|
|
|
{
|
|
|
|
int i;
|
|
|
|
int nempty = 0;
|
|
|
|
int nactive = 0;
|
1999-03-28 08:47:40 +08:00
|
|
|
|
1999-04-02 06:26:44 +08:00
|
|
|
if (mc == NULL)
|
|
|
|
mc = &globalMacroContext;
|
1999-03-28 08:47:40 +08:00
|
|
|
if (f == NULL)
|
|
|
|
f = stderr;
|
1997-03-31 22:13:21 +08:00
|
|
|
|
1999-03-28 08:47:40 +08:00
|
|
|
fprintf(f, "========================\n");
|
1998-07-09 01:50:48 +08:00
|
|
|
for (i = 0; i < mc->firstFree; i++) {
|
|
|
|
MacroEntry *me;
|
|
|
|
if ((me = mc->macroTable[i]) == NULL) {
|
1999-08-17 00:18:25 +08:00
|
|
|
/* XXX this should never happen */
|
1998-07-09 01:50:48 +08:00
|
|
|
nempty++;
|
|
|
|
continue;
|
|
|
|
}
|
1999-03-28 08:47:40 +08:00
|
|
|
fprintf(f, "%3d%c %s", me->level,
|
1998-07-09 01:50:48 +08:00
|
|
|
(me->used > 0 ? '=' : ':'), me->name);
|
1999-03-28 08:47:40 +08:00
|
|
|
if (me->opts && *me->opts)
|
|
|
|
fprintf(f, "(%s)", me->opts);
|
|
|
|
if (me->body && *me->body)
|
|
|
|
fprintf(f, "\t%s", me->body);
|
|
|
|
fprintf(f, "\n");
|
1998-07-09 01:50:48 +08:00
|
|
|
nactive++;
|
|
|
|
}
|
1999-03-28 08:47:40 +08:00
|
|
|
fprintf(f, _("======================== active %d empty %d\n"),
|
1998-07-09 01:50:48 +08:00
|
|
|
nactive, nempty);
|
|
|
|
}
|
1997-03-31 22:13:21 +08:00
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
static MacroEntry **
|
|
|
|
findEntry(MacroContext *mc, const char *name, size_t namelen)
|
|
|
|
{
|
|
|
|
MacroEntry keybuf, *key, **ret;
|
|
|
|
char namebuf[1024];
|
|
|
|
|
1999-04-02 06:26:44 +08:00
|
|
|
if (mc == NULL)
|
|
|
|
mc = &globalMacroContext;
|
1998-07-09 01:50:48 +08:00
|
|
|
if (! mc->firstFree)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (namelen > 0) {
|
|
|
|
strncpy(namebuf, name, namelen);
|
|
|
|
namebuf[namelen] = '\0';
|
|
|
|
name = namebuf;
|
|
|
|
}
|
1997-03-31 22:13:21 +08:00
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
key = &keybuf;
|
|
|
|
memset(key, 0, sizeof(*key));
|
|
|
|
key->name = (char *)name;
|
|
|
|
ret = (MacroEntry **)bsearch(&key, mc->macroTable, mc->firstFree,
|
|
|
|
sizeof(*(mc->macroTable)), compareMacroName);
|
|
|
|
/* XXX TODO: find 1st empty slot and return that */
|
|
|
|
return ret;
|
|
|
|
}
|
1997-03-31 22:13:21 +08:00
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
/* =============================================================== */
|
|
|
|
|
|
|
|
/* fgets analogue that reads \ continuations. Last newline always trimmed. */
|
|
|
|
|
|
|
|
static char *
|
|
|
|
rdcl(char *buf, size_t size, FILE *fp, int escapes)
|
|
|
|
{
|
|
|
|
char *q = buf;
|
|
|
|
size_t nb = 0;
|
1999-08-17 02:57:37 +08:00
|
|
|
size_t nread = 0;
|
1998-07-09 01:50:48 +08:00
|
|
|
|
1999-08-17 02:57:37 +08:00
|
|
|
*q = '\0';
|
1998-07-09 01:50:48 +08:00
|
|
|
do {
|
|
|
|
if (fgets(q, size, fp) == NULL) /* read next line */
|
|
|
|
break;
|
|
|
|
nb = strlen(q);
|
1999-08-17 02:57:37 +08:00
|
|
|
nread += nb;
|
|
|
|
for (q += nb - 1; nb > 0 && iseol(*q); q--)
|
|
|
|
nb--;
|
|
|
|
if (!(nb > 0 && *q == '\\')) { /* continue? */
|
|
|
|
*(++q) = '\0'; /* trim trailing \r, \n */
|
1998-07-09 01:50:48 +08:00
|
|
|
break;
|
1999-08-17 02:57:37 +08:00
|
|
|
}
|
|
|
|
if (escapes) { /* copy escape too */
|
1998-07-09 01:50:48 +08:00
|
|
|
q++;
|
1999-08-17 02:57:37 +08:00
|
|
|
nb++;
|
|
|
|
}
|
1998-07-09 01:50:48 +08:00
|
|
|
size -= nb;
|
1999-08-17 02:57:37 +08:00
|
|
|
if (*q == '\r') /* XXX avoid \r madness */
|
|
|
|
*q = '\n';
|
|
|
|
*(++q) = '\0'; /* next char in buf */
|
1998-07-09 01:50:48 +08:00
|
|
|
} while (size > 0);
|
1999-08-17 02:57:37 +08:00
|
|
|
return (nread > 0 ? buf : NULL);
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Return text between pl and matching pr */
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
matchchar(const char *p, char pl, char pr)
|
|
|
|
{
|
|
|
|
int lvl = 0;
|
|
|
|
char c;
|
|
|
|
|
|
|
|
while ((c = *p++) != '\0') {
|
|
|
|
if (c == '\\') { /* Ignore escaped chars */
|
|
|
|
p++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (c == pr) {
|
|
|
|
if (--lvl <= 0) return --p;
|
|
|
|
} else if (c == pl)
|
|
|
|
lvl++;
|
|
|
|
}
|
|
|
|
return (const char *)NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
printMacro(MacroBuf *mb, const char *s, const char *se)
|
|
|
|
{
|
|
|
|
const char *senl;
|
|
|
|
const char *ellipsis;
|
|
|
|
int choplen;
|
|
|
|
|
|
|
|
if (s >= se) { /* XXX just in case */
|
1998-09-28 06:03:52 +08:00
|
|
|
fprintf(stderr, _("%3d>%*s(empty)"), mb->depth,
|
1998-07-09 01:50:48 +08:00
|
|
|
(2 * mb->depth + 1), "");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (s[-1] == '{')
|
|
|
|
s--;
|
|
|
|
|
1999-08-17 02:57:37 +08:00
|
|
|
/* Print only to first end-of-line (or end-of-string). */
|
|
|
|
for (senl = se; *senl && !iseol(*senl); senl++)
|
|
|
|
;
|
1998-07-09 01:50:48 +08:00
|
|
|
|
|
|
|
/* Limit trailing non-trace output */
|
|
|
|
choplen = 61 - (2 * mb->depth);
|
|
|
|
if ((senl - s) > choplen) {
|
|
|
|
senl = s + choplen;
|
|
|
|
ellipsis = "...";
|
|
|
|
} else
|
|
|
|
ellipsis = "";
|
|
|
|
|
|
|
|
/* Substitute caret at end-of-macro position */
|
|
|
|
fprintf(stderr, "%3d>%*s%%%.*s^", mb->depth,
|
|
|
|
(2 * mb->depth + 1), "", (int)(se - s), s);
|
|
|
|
if (se[1] != '\0' && (senl - (se+1)) > 0)
|
|
|
|
fprintf(stderr, "%-.*s%s", (int)(senl - (se+1)), se+1, ellipsis);
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
printExpansion(MacroBuf *mb, const char *t, const char *te)
|
|
|
|
{
|
|
|
|
const char *ellipsis;
|
|
|
|
int choplen;
|
|
|
|
|
|
|
|
if (!(te > t)) {
|
1998-09-28 06:03:52 +08:00
|
|
|
fprintf(stderr, _("%3d<%*s(empty)\n"), mb->depth, (2 * mb->depth + 1), "");
|
1998-07-09 01:50:48 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Shorten output which contains newlines */
|
1999-08-17 02:57:37 +08:00
|
|
|
while (te > t && iseol(te[-1]))
|
1998-07-09 01:50:48 +08:00
|
|
|
te--;
|
|
|
|
ellipsis = "";
|
|
|
|
if (mb->depth > 0) {
|
|
|
|
const char *tenl;
|
1999-08-17 02:57:37 +08:00
|
|
|
|
|
|
|
/* Skip to last line of expansion */
|
1998-07-09 01:50:48 +08:00
|
|
|
while ((tenl = strchr(t, '\n')) && tenl < te)
|
|
|
|
t = ++tenl;
|
|
|
|
|
|
|
|
/* Limit expand output */
|
|
|
|
choplen = 61 - (2 * mb->depth);
|
|
|
|
if ((te - t) > choplen) {
|
|
|
|
te = t + choplen;
|
|
|
|
ellipsis = "...";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fprintf(stderr, "%3d<%*s", mb->depth, (2 * mb->depth + 1), "");
|
|
|
|
if (te > t)
|
|
|
|
fprintf(stderr, "%.*s%s", (int)(te - t), t, ellipsis);
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
#define SKIPBLANK(_s, _c) \
|
|
|
|
while (((_c) = *(_s)) && isblank(_c)) \
|
|
|
|
(_s)++;
|
|
|
|
|
|
|
|
#define SKIPNONBLANK(_s, _c) \
|
1999-08-17 02:57:37 +08:00
|
|
|
while (((_c) = *(_s)) && !(isblank(_c) || iseol(_c))) \
|
1998-07-09 01:50:48 +08:00
|
|
|
(_s)++;
|
|
|
|
|
|
|
|
#define COPYNAME(_ne, _s, _c) \
|
|
|
|
{ SKIPBLANK(_s,_c); \
|
|
|
|
while(((_c) = *(_s)) && (isalnum(_c) || (_c) == '_')) \
|
|
|
|
*(_ne)++ = *(_s)++; \
|
|
|
|
*(_ne) = '\0'; \
|
1997-03-31 22:13:21 +08:00
|
|
|
}
|
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
#define COPYOPTS(_oe, _s, _c) \
|
|
|
|
{ while(((_c) = *(_s)) && (_c) != ')') \
|
|
|
|
*(_oe)++ = *(_s)++; \
|
|
|
|
*(_oe) = '\0'; \
|
1997-03-31 22:13:21 +08:00
|
|
|
}
|
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
#define COPYBODY(_be, _s, _c) \
|
1999-08-17 02:57:37 +08:00
|
|
|
{ while(((_c) = *(_s)) && !iseol(_c)) { \
|
1998-07-09 01:50:48 +08:00
|
|
|
if ((_c) == '\\') \
|
|
|
|
(_s)++; \
|
|
|
|
*(_be)++ = *(_s)++; \
|
|
|
|
} \
|
|
|
|
*(_be) = '\0'; \
|
1997-03-31 22:13:21 +08:00
|
|
|
}
|
1998-07-09 01:50:48 +08:00
|
|
|
|
|
|
|
/* Save source and expand field into target */
|
|
|
|
static int
|
|
|
|
expandT(MacroBuf *mb, const char *f, size_t flen)
|
|
|
|
{
|
|
|
|
char *sbuf;
|
|
|
|
const char *s = mb->s;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
sbuf = alloca(flen + 1);
|
|
|
|
memset(sbuf, 0, (flen + 1));
|
|
|
|
|
|
|
|
strncpy(sbuf, f, flen);
|
|
|
|
sbuf[flen] = '\0';
|
|
|
|
mb->s = sbuf;
|
|
|
|
rc = expandMacro(mb);
|
|
|
|
mb->s = s;
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
#if 0
|
|
|
|
/* Save target and expand sbuf into target */
|
|
|
|
static int
|
|
|
|
expandS(MacroBuf *mb, char *tbuf, size_t tbuflen)
|
|
|
|
{
|
|
|
|
const char *t = mb->t;
|
|
|
|
size_t nb = mb->nb;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
mb->t = tbuf;
|
|
|
|
mb->nb = tbuflen;
|
|
|
|
rc = expandMacro(mb);
|
|
|
|
mb->t = t;
|
|
|
|
mb->nb = nb;
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
static int
|
|
|
|
expandU(MacroBuf *mb, char *u, size_t ulen)
|
|
|
|
{
|
|
|
|
const char *s = mb->s;
|
|
|
|
char *t = mb->t;
|
|
|
|
size_t nb = mb->nb;
|
|
|
|
char *tbuf;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
tbuf = alloca(ulen + 1);
|
|
|
|
memset(tbuf, 0, (ulen + 1));
|
|
|
|
|
|
|
|
mb->s = u;
|
|
|
|
mb->t = tbuf;
|
|
|
|
mb->nb = ulen;
|
|
|
|
rc = expandMacro(mb);
|
|
|
|
|
|
|
|
tbuf[ulen] = '\0'; /* XXX just in case */
|
|
|
|
if (ulen > mb->nb)
|
|
|
|
strncpy(u, tbuf, (ulen - mb->nb + 1));
|
|
|
|
|
|
|
|
mb->s = s;
|
|
|
|
mb->t = t;
|
|
|
|
mb->nb = nb;
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int
|
|
|
|
doShellEscape(MacroBuf *mb, const char *cmd, size_t clen)
|
|
|
|
{
|
|
|
|
char pcmd[BUFSIZ];
|
|
|
|
FILE *shf;
|
|
|
|
int rc;
|
|
|
|
int c;
|
|
|
|
|
|
|
|
strncpy(pcmd, cmd, clen);
|
|
|
|
pcmd[clen] = '\0';
|
|
|
|
rc = expandU(mb, pcmd, sizeof(pcmd));
|
|
|
|
if (rc)
|
|
|
|
return rc;
|
|
|
|
|
|
|
|
if ((shf = popen(pcmd, "r")) == NULL)
|
|
|
|
return 1;
|
|
|
|
while(mb->nb > 0 && (c = fgetc(shf)) != EOF)
|
|
|
|
SAVECHAR(mb, c);
|
|
|
|
pclose(shf);
|
|
|
|
|
1999-08-17 02:57:37 +08:00
|
|
|
/* XXX delete trailing \r \n */
|
|
|
|
while (iseol(mb->t[-1])) {
|
|
|
|
*(mb->t--) = '\0';
|
|
|
|
mb->nb++;
|
|
|
|
}
|
1997-03-31 22:13:21 +08:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
static const char *
|
|
|
|
doDefine(MacroBuf *mb, const char *se, int level, int expandbody)
|
1997-03-31 22:13:21 +08:00
|
|
|
{
|
1998-07-09 01:50:48 +08:00
|
|
|
const char *s = se;
|
|
|
|
char buf[BUFSIZ], *n = buf, *ne = n;
|
|
|
|
char *o = NULL, *oe;
|
|
|
|
char *b, *be;
|
|
|
|
int c;
|
|
|
|
int oc = ')';
|
1997-03-31 22:13:21 +08:00
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
/* Copy name */
|
|
|
|
COPYNAME(ne, s, c);
|
1997-03-31 22:13:21 +08:00
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
/* Copy opts (if present) */
|
|
|
|
oe = ne + 1;
|
|
|
|
if (*s == '(') {
|
|
|
|
s++; /* skip ( */
|
|
|
|
o = oe;
|
|
|
|
COPYOPTS(oe, s, oc);
|
|
|
|
s++; /* skip ) */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Copy body, skipping over escaped newlines */
|
|
|
|
b = be = oe + 1;
|
|
|
|
SKIPBLANK(s, c);
|
|
|
|
if (c == '{') { /* XXX permit silent {...} grouping */
|
|
|
|
if ((se = matchchar(s, c, '}')) == NULL) {
|
1998-09-28 06:03:52 +08:00
|
|
|
rpmError(RPMERR_BADSPEC, _("Macro %%%s has unterminated body"), n);
|
1998-07-09 01:50:48 +08:00
|
|
|
se = s; /* XXX W2DO? */
|
|
|
|
return se;
|
|
|
|
}
|
|
|
|
s++; /* XXX skip { */
|
|
|
|
strncpy(b, s, (se - s));
|
|
|
|
b[se - s] = '\0';
|
|
|
|
be += strlen(b);
|
|
|
|
se++; /* XXX skip } */
|
|
|
|
s = se; /* move scan forward */
|
|
|
|
} else { /* otherwise free-field */
|
|
|
|
COPYBODY(be, s, c);
|
|
|
|
|
|
|
|
/* Trim trailing blanks/newlines */
|
1999-08-17 02:57:37 +08:00
|
|
|
while (--be >= b && (c = *be) && (isblank(c) || iseol(c)))
|
1998-07-09 01:50:48 +08:00
|
|
|
;
|
|
|
|
*(++be) = '\0'; /* one too far */
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Move scan over body */
|
1999-08-17 02:57:37 +08:00
|
|
|
while (iseol(*s))
|
1998-07-09 01:50:48 +08:00
|
|
|
s++;
|
|
|
|
se = s;
|
|
|
|
|
|
|
|
/* Names must start with alphabetic or _ and be at least 3 chars */
|
|
|
|
if (!((c = *n) && (isalpha(c) || c == '_') && (ne - n) > 2)) {
|
1998-09-28 06:03:52 +08:00
|
|
|
rpmError(RPMERR_BADSPEC, _("Macro %%%s has illegal name (%%define)"), n);
|
1998-07-09 01:50:48 +08:00
|
|
|
return se;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Options must be terminated with ')' */
|
|
|
|
if (o && oc != ')') {
|
1998-09-28 06:03:52 +08:00
|
|
|
rpmError(RPMERR_BADSPEC, _("Macro %%%s has unterminated opts"), n);
|
1998-07-09 01:50:48 +08:00
|
|
|
return se;
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((be - b) < 1) {
|
1998-09-28 06:03:52 +08:00
|
|
|
rpmError(RPMERR_BADSPEC, _("Macro %%%s has empty body"), n);
|
1998-07-09 01:50:48 +08:00
|
|
|
return se;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (expandbody && expandU(mb, b, (&buf[sizeof(buf)] - b))) {
|
1998-09-28 06:03:52 +08:00
|
|
|
rpmError(RPMERR_BADSPEC, _("Macro %%%s failed to expand"), n);
|
1998-07-09 01:50:48 +08:00
|
|
|
return se;
|
|
|
|
}
|
|
|
|
|
|
|
|
addMacro(mb->mc, n, o, b, (level - 1));
|
|
|
|
|
|
|
|
return se;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const char *
|
|
|
|
doUndefine(MacroContext *mc, const char *se)
|
|
|
|
{
|
|
|
|
const char *s = se;
|
|
|
|
char buf[BUFSIZ], *n = buf, *ne = n;
|
|
|
|
int c;
|
|
|
|
|
|
|
|
COPYNAME(ne, s, c);
|
|
|
|
|
|
|
|
/* Move scan over body */
|
1999-08-17 02:57:37 +08:00
|
|
|
while (iseol(*s))
|
1998-07-09 01:50:48 +08:00
|
|
|
s++;
|
|
|
|
se = s;
|
|
|
|
|
|
|
|
/* Names must start with alphabetic or _ and be at least 3 chars */
|
|
|
|
if (!((c = *n) && (isalpha(c) || c == '_') && (ne - n) > 2)) {
|
1998-09-28 06:03:52 +08:00
|
|
|
rpmError(RPMERR_BADSPEC, _("Macro %%%s has illegal name (%%undefine)"), n);
|
1998-07-09 01:50:48 +08:00
|
|
|
return se;
|
|
|
|
}
|
|
|
|
|
|
|
|
delMacro(mc, n);
|
|
|
|
|
|
|
|
return se;
|
|
|
|
}
|
|
|
|
|
1998-10-08 19:55:37 +08:00
|
|
|
#ifdef DYING
|
1998-07-09 01:50:48 +08:00
|
|
|
static void
|
|
|
|
dumpME(const char *msg, MacroEntry *me)
|
|
|
|
{
|
|
|
|
if (msg)
|
|
|
|
fprintf(stderr, "%s", msg);
|
1998-07-26 05:00:26 +08:00
|
|
|
fprintf(stderr, "\tme %p", me);
|
1998-07-09 01:50:48 +08:00
|
|
|
if (me)
|
1998-07-26 05:00:26 +08:00
|
|
|
fprintf(stderr,"\tname %p(%s) prev %p",
|
1998-07-09 01:50:48 +08:00
|
|
|
me->name, me->name, me->prev);
|
|
|
|
fprintf(stderr, "\n");
|
|
|
|
}
|
1998-10-08 19:55:37 +08:00
|
|
|
#endif
|
1998-07-09 01:50:48 +08:00
|
|
|
|
|
|
|
static void
|
|
|
|
pushMacro(MacroEntry **mep, const char *n, const char *o, const char *b, int level)
|
|
|
|
{
|
|
|
|
MacroEntry *prev = (*mep ? *mep : NULL);
|
1999-09-21 11:22:53 +08:00
|
|
|
MacroEntry *me = (MacroEntry *) xmalloc(sizeof(*me));
|
1998-07-09 01:50:48 +08:00
|
|
|
|
|
|
|
me->prev = prev;
|
1999-09-21 11:22:53 +08:00
|
|
|
me->name = (prev ? prev->name : xstrdup(n));
|
|
|
|
me->opts = (o ? xstrdup(o) : NULL);
|
|
|
|
me->body = xstrdup(b ? b : "");
|
1998-07-09 01:50:48 +08:00
|
|
|
me->used = 0;
|
|
|
|
me->level = level;
|
|
|
|
*mep = me;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
popMacro(MacroEntry **mep)
|
|
|
|
{
|
|
|
|
MacroEntry *me = (*mep ? *mep : NULL);
|
|
|
|
|
|
|
|
if (me) {
|
|
|
|
/* XXX cast to workaround const */
|
|
|
|
if ((*mep = me->prev) == NULL)
|
1999-04-09 04:53:45 +08:00
|
|
|
FREE(me->name);
|
|
|
|
FREE(me->opts);
|
|
|
|
FREE(me->body);
|
1998-07-09 01:50:48 +08:00
|
|
|
FREE(me);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
freeArgs(MacroBuf *mb)
|
|
|
|
{
|
|
|
|
MacroContext *mc = mb->mc;
|
1999-08-17 00:18:25 +08:00
|
|
|
int ndeleted = 0;
|
|
|
|
int i;
|
1998-07-09 01:50:48 +08:00
|
|
|
|
|
|
|
/* Delete dynamic macro definitions */
|
1999-08-17 00:18:25 +08:00
|
|
|
for (i = 0; i < mc->firstFree; i++) {
|
|
|
|
MacroEntry **mep, *me;
|
1998-07-09 01:50:48 +08:00
|
|
|
int skiptest = 0;
|
1999-08-17 00:18:25 +08:00
|
|
|
mep = &mc->macroTable[i];
|
|
|
|
me = *mep;
|
|
|
|
|
|
|
|
if (me == NULL) /* XXX this should never happen */
|
1998-07-09 01:50:48 +08:00
|
|
|
continue;
|
|
|
|
if (me->level < mb->depth)
|
|
|
|
continue;
|
|
|
|
if (strlen(me->name) == 1 && strchr("#*0", *me->name)) {
|
|
|
|
if (*me->name == '*' && me->used > 0)
|
|
|
|
skiptest = 1;
|
1999-08-17 00:18:25 +08:00
|
|
|
/* XXX skip test for %# %* %0 */
|
1998-07-09 01:50:48 +08:00
|
|
|
} else if (!skiptest && me->used <= 0) {
|
|
|
|
#if NOTYET
|
1998-09-28 06:03:52 +08:00
|
|
|
rpmError(RPMERR_BADSPEC, _("Macro %%%s (%s) was not used below level %d"),
|
1998-07-09 01:50:48 +08:00
|
|
|
me->name, me->body, me->level);
|
|
|
|
#endif
|
|
|
|
}
|
1999-08-17 00:18:25 +08:00
|
|
|
popMacro(mep);
|
|
|
|
if (!(mep && *mep))
|
|
|
|
ndeleted++;
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
1999-08-17 00:18:25 +08:00
|
|
|
|
|
|
|
/* If any deleted macros, sort macro table */
|
|
|
|
if (ndeleted)
|
|
|
|
sortMacroTable(mc);
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static const char *
|
1999-07-29 20:36:03 +08:00
|
|
|
grabArgs(MacroBuf *mb, const MacroEntry *me, const char *se, char lastc)
|
1998-07-09 01:50:48 +08:00
|
|
|
{
|
|
|
|
char buf[BUFSIZ], *b, *be;
|
|
|
|
char aname[16];
|
|
|
|
const char *opts, *o;
|
|
|
|
int argc = 0;
|
|
|
|
const char **argv;
|
|
|
|
int optc = 0;
|
|
|
|
const char **optv;
|
|
|
|
int opte;
|
|
|
|
int c;
|
1999-07-29 19:20:20 +08:00
|
|
|
int saveoptind; /* XXX optind must be saved on non-linux */
|
1998-07-09 01:50:48 +08:00
|
|
|
|
|
|
|
/* Copy macro name as argv[0] */
|
|
|
|
argc = 0;
|
|
|
|
b = be = buf;
|
|
|
|
strcpy(b, me->name);
|
|
|
|
be += strlen(b);
|
|
|
|
*be = '\0';
|
|
|
|
argc++; /* XXX count argv[0] */
|
|
|
|
|
|
|
|
addMacro(mb->mc, "0", NULL, b, mb->depth);
|
1997-03-31 22:13:21 +08:00
|
|
|
|
1999-07-29 20:36:03 +08:00
|
|
|
/* Copy args into buf until lastc */
|
1998-07-09 01:50:48 +08:00
|
|
|
*be++ = ' ';
|
|
|
|
b = be; /* Save beginning of args */
|
1998-07-26 05:00:26 +08:00
|
|
|
while ((c = *se) != 0) {
|
1998-07-09 01:50:48 +08:00
|
|
|
char *a;
|
|
|
|
se++;
|
1999-07-29 20:36:03 +08:00
|
|
|
if (c == lastc)
|
1998-07-09 01:50:48 +08:00
|
|
|
break;
|
|
|
|
if (isblank(c))
|
|
|
|
continue;
|
|
|
|
if (argc > 1)
|
|
|
|
*be++ = ' ';
|
|
|
|
a = be;
|
1999-07-29 20:36:03 +08:00
|
|
|
while (!(isblank(c) || c == lastc)) {
|
1998-07-09 01:50:48 +08:00
|
|
|
*be++ = c;
|
|
|
|
if ((c = *se) == '\0')
|
|
|
|
break;
|
|
|
|
se++;
|
|
|
|
}
|
|
|
|
*be = '\0';
|
|
|
|
argc++;
|
1997-03-31 22:13:21 +08:00
|
|
|
}
|
1998-07-09 01:50:48 +08:00
|
|
|
|
1999-07-29 19:20:20 +08:00
|
|
|
/*
|
|
|
|
* The macro %* analoguous to the shell's $* means "Pass all non-macro
|
|
|
|
* parameters." Consequently, there needs to be a macro that means "Pass all
|
|
|
|
* (including macro parameters) options". This is useful for verifying
|
|
|
|
* parameters during expansion and yet transparently passing all parameters
|
|
|
|
* through for higher level processing (e.g. %description and/or %setup).
|
|
|
|
* This is the (potential) justification for %{**} ...
|
|
|
|
*/
|
1998-07-09 01:50:48 +08:00
|
|
|
/* Add unexpanded args as macro */
|
1999-07-29 19:20:20 +08:00
|
|
|
addMacro(mb->mc, "**", NULL, b, mb->depth);
|
1998-07-09 01:50:48 +08:00
|
|
|
|
|
|
|
#ifdef NOTYET
|
|
|
|
/* XXX if macros can be passed as args ... */
|
|
|
|
expandU(mb, buf, sizeof(buf));
|
|
|
|
#endif
|
|
|
|
|
|
|
|
/* Build argv array */
|
|
|
|
argv = (const char **)alloca((argc + 1) * sizeof(char *));
|
|
|
|
b = be = buf;
|
|
|
|
for (c = 0; c < argc; c++) {
|
|
|
|
b = be;
|
|
|
|
if ((be = strchr(b, ' ')) == NULL)
|
|
|
|
be = b + strlen(b);
|
|
|
|
*be++ = '\0';
|
|
|
|
argv[c] = b;
|
|
|
|
}
|
|
|
|
argv[argc] = NULL;
|
|
|
|
|
|
|
|
opts = me->opts;
|
|
|
|
|
|
|
|
/* First count number of options ... */
|
1999-07-29 19:20:20 +08:00
|
|
|
saveoptind = optind; /* XXX optind must be saved on non-linux */
|
1998-07-09 01:50:48 +08:00
|
|
|
optc = 0;
|
|
|
|
optc++; /* XXX count argv[0] too */
|
|
|
|
while((c = getopt(argc, (char **)argv, opts)) != -1) {
|
|
|
|
if (!(c != '?' && (o = strchr(opts, c)))) {
|
1998-09-28 06:03:52 +08:00
|
|
|
rpmError(RPMERR_BADSPEC, _("Unknown option %c in %s(%s)"),
|
1998-07-09 01:50:48 +08:00
|
|
|
c, me->name, opts);
|
|
|
|
return se;
|
1997-03-31 22:13:21 +08:00
|
|
|
}
|
1998-07-09 01:50:48 +08:00
|
|
|
optc++;
|
1997-03-31 22:13:21 +08:00
|
|
|
}
|
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
/* ... then allocate storage ... */
|
|
|
|
opte = optc + (argc - optind);
|
|
|
|
optv = (const char **)alloca((opte + 1) * sizeof(char *));
|
|
|
|
optv[0] = me->name;
|
|
|
|
optv[opte] = NULL;
|
1998-07-09 01:30:37 +08:00
|
|
|
|
1999-04-21 06:45:52 +08:00
|
|
|
/* ... and finally define option macros. */
|
1999-07-29 19:20:20 +08:00
|
|
|
optind = saveoptind; /* XXX optind must be restored on non-linux */
|
1998-07-09 01:50:48 +08:00
|
|
|
optc = 0;
|
1999-07-29 19:20:20 +08:00
|
|
|
optc++; /* XXX count optv[0] */
|
1998-07-09 01:50:48 +08:00
|
|
|
while((c = getopt(argc, (char **)argv, opts)) != -1) {
|
|
|
|
o = strchr(opts, c);
|
|
|
|
b = be;
|
|
|
|
*be++ = '-';
|
|
|
|
*be++ = c;
|
|
|
|
if (o[1] == ':') {
|
|
|
|
*be++ = ' ';
|
|
|
|
strcpy(be, optarg);
|
|
|
|
be += strlen(be);
|
|
|
|
}
|
|
|
|
*be++ = '\0';
|
|
|
|
sprintf(aname, "-%c", c);
|
|
|
|
addMacro(mb->mc, aname, NULL, b, mb->depth);
|
|
|
|
if (o[1] == ':') {
|
|
|
|
sprintf(aname, "-%c*", c);
|
|
|
|
addMacro(mb->mc, aname, NULL, optarg, mb->depth);
|
|
|
|
}
|
|
|
|
optv[optc] = b;
|
|
|
|
optc++;
|
1998-05-21 01:05:26 +08:00
|
|
|
}
|
1997-03-31 22:13:21 +08:00
|
|
|
|
1999-08-17 00:18:25 +08:00
|
|
|
/* Add macro for each arg. Concatenate args for !*. */
|
1999-04-21 06:45:52 +08:00
|
|
|
b = be;
|
1998-07-09 01:50:48 +08:00
|
|
|
for (c = optind; c < argc; c++) {
|
|
|
|
sprintf(aname, "%d", (c - optind + 1));
|
|
|
|
addMacro(mb->mc, aname, NULL, argv[c], mb->depth);
|
1999-04-21 06:45:52 +08:00
|
|
|
|
|
|
|
if (be > b) *be++ = ' ';
|
|
|
|
strcpy(be, argv[c]);
|
|
|
|
be += strlen(be);
|
|
|
|
*be = '\0';
|
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
optv[optc] = argv[c];
|
|
|
|
optc++;
|
|
|
|
}
|
1999-04-21 06:45:52 +08:00
|
|
|
|
1999-08-17 00:18:25 +08:00
|
|
|
/* Add arg count as macro. */
|
1999-07-29 20:36:03 +08:00
|
|
|
sprintf(aname, "%d", (argc - optind));
|
1998-07-09 01:50:48 +08:00
|
|
|
addMacro(mb->mc, "#", NULL, aname, mb->depth);
|
1997-03-31 22:13:21 +08:00
|
|
|
|
1999-08-17 00:18:25 +08:00
|
|
|
/* Add unexpanded args as macro. */
|
1999-04-21 06:45:52 +08:00
|
|
|
addMacro(mb->mc, "*", NULL, b, mb->depth);
|
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
return se;
|
|
|
|
}
|
1997-03-31 22:13:21 +08:00
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
static void
|
|
|
|
doOutput(MacroBuf *mb, int waserror, const char *msg, size_t msglen)
|
1998-01-13 05:31:29 +08:00
|
|
|
{
|
1998-07-09 01:50:48 +08:00
|
|
|
char buf[BUFSIZ];
|
|
|
|
|
|
|
|
strncpy(buf, msg, msglen);
|
|
|
|
buf[msglen] = '\0';
|
|
|
|
expandU(mb, buf, sizeof(buf));
|
|
|
|
if (waserror)
|
|
|
|
rpmError(RPMERR_BADSPEC, "%s", buf);
|
|
|
|
else
|
|
|
|
fprintf(stderr, "%s", buf);
|
1998-01-13 05:31:29 +08:00
|
|
|
}
|
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
static void
|
|
|
|
doFoo(MacroBuf *mb, const char *f, size_t fn, const char *g, size_t glen)
|
1997-03-31 22:13:21 +08:00
|
|
|
{
|
1998-07-09 01:50:48 +08:00
|
|
|
char buf[BUFSIZ], *b = NULL, *be;
|
|
|
|
int c;
|
|
|
|
|
|
|
|
buf[0] = '\0';
|
|
|
|
if (g) {
|
|
|
|
strncpy(buf, g, glen);
|
|
|
|
buf[glen] = '\0';
|
|
|
|
expandU(mb, buf, sizeof(buf));
|
|
|
|
}
|
|
|
|
if (STREQ("basename", f, fn)) {
|
|
|
|
if ((b = strrchr(buf, '/')) == NULL)
|
|
|
|
b = buf;
|
|
|
|
#if NOTYET
|
|
|
|
/* XXX watchout for conflict with %dir */
|
|
|
|
} else if (STREQ("dirname", f, fn)) {
|
|
|
|
if ((b = strrchr(buf, '/')) != NULL)
|
|
|
|
*b = '\0';
|
|
|
|
b = buf;
|
|
|
|
#endif
|
|
|
|
} else if (STREQ("suffix", f, fn)) {
|
|
|
|
if ((b = strrchr(buf, '.')) != NULL)
|
|
|
|
b++;
|
|
|
|
} else if (STREQ("expand", f, fn)) {
|
|
|
|
b = buf;
|
|
|
|
} else if (STREQ("uncompress", f, fn)) {
|
|
|
|
int compressed = 1;
|
|
|
|
for (b = buf; (c = *b) && isblank(c);)
|
|
|
|
b++;
|
|
|
|
for (be = b; (c = *be) && !isblank(c);)
|
|
|
|
be++;
|
|
|
|
*be++ = '\0';
|
|
|
|
#ifndef DEBUG_MACROS
|
|
|
|
isCompressed(b, &compressed);
|
|
|
|
#endif
|
|
|
|
switch(compressed) {
|
|
|
|
default:
|
|
|
|
case 0: /* COMPRESSED_NOT */
|
|
|
|
sprintf(be, "%%_cat %s", b);
|
|
|
|
break;
|
|
|
|
case 1: /* COMPRESSED_OTHER */
|
|
|
|
sprintf(be, "%%_gzip -dc %s", b);
|
|
|
|
break;
|
|
|
|
case 2: /* COMPRESSED_BZIP2 */
|
|
|
|
sprintf(be, "%%_bzip2 %s", b);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
b = be;
|
|
|
|
} else if (STREQ("S", f, fn)) {
|
|
|
|
for (b = buf; (c = *b) && isdigit(c);)
|
|
|
|
b++;
|
|
|
|
if (!c) { /* digit index */
|
|
|
|
b++;
|
|
|
|
sprintf(b, "%%SOURCE%s", buf);
|
|
|
|
} else
|
|
|
|
b = buf;
|
|
|
|
} else if (STREQ("P", f, fn)) {
|
|
|
|
for (b = buf; (c = *b) && isdigit(c);)
|
|
|
|
b++;
|
|
|
|
if (!c) { /* digit index */
|
|
|
|
b++;
|
|
|
|
sprintf(b, "%%PATCH%s", buf);
|
|
|
|
} else
|
|
|
|
b = buf;
|
|
|
|
} else if (STREQ("F", f, fn)) {
|
|
|
|
b = buf + strlen(buf) + 1;
|
|
|
|
sprintf(b, "file%s.file", buf);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (b) {
|
|
|
|
expandT(mb, b, strlen(b));
|
|
|
|
}
|
1997-03-31 22:13:21 +08:00
|
|
|
}
|
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
/* The main recursion engine */
|
|
|
|
|
|
|
|
static int
|
|
|
|
expandMacro(MacroBuf *mb)
|
1997-03-31 22:13:21 +08:00
|
|
|
{
|
1998-07-09 01:50:48 +08:00
|
|
|
MacroEntry **mep;
|
|
|
|
MacroEntry *me;
|
|
|
|
const char *s = mb->s, *se;
|
|
|
|
const char *f, *fe;
|
|
|
|
const char *g, *ge;
|
|
|
|
size_t fn, gn;
|
|
|
|
char *t = mb->t; /* save expansion pointer for printExpand */
|
|
|
|
int c;
|
|
|
|
int rc = 0;
|
|
|
|
int negate;
|
1999-07-29 20:36:03 +08:00
|
|
|
char grab;
|
1998-09-06 07:13:35 +08:00
|
|
|
int chkexist;
|
1997-03-31 22:13:21 +08:00
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
if (++mb->depth > max_macro_depth) {
|
1998-09-28 06:03:52 +08:00
|
|
|
rpmError(RPMERR_BADSPEC, _("Recursion depth(%d) greater than max(%d)"),
|
1998-07-09 01:50:48 +08:00
|
|
|
mb->depth, max_macro_depth);
|
|
|
|
mb->depth--;
|
|
|
|
mb->expand_trace = 1;
|
|
|
|
return 1;
|
1997-03-31 22:13:21 +08:00
|
|
|
}
|
1998-07-09 01:50:48 +08:00
|
|
|
|
|
|
|
while (rc == 0 && mb->nb > 0 && (c = *s) != '\0') {
|
|
|
|
s++;
|
|
|
|
/* Copy text until next macro */
|
|
|
|
switch(c) {
|
|
|
|
case '%':
|
|
|
|
if (*s != '%')
|
|
|
|
break;
|
|
|
|
s++; /* skip first % in %% */
|
|
|
|
/* fall thru */
|
|
|
|
default:
|
|
|
|
SAVECHAR(mb, c);
|
|
|
|
continue;
|
1999-10-21 05:40:10 +08:00
|
|
|
/*@notreached@*/ break;
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Expand next macro */
|
|
|
|
f = fe = NULL;
|
|
|
|
g = ge = NULL;
|
|
|
|
if (mb->depth > 1) /* XXX full expansion for outermost level */
|
|
|
|
t = mb->t; /* save expansion pointer for printExpand */
|
|
|
|
negate = 0;
|
1999-07-29 20:36:03 +08:00
|
|
|
grab = '\0';
|
1998-09-06 07:13:35 +08:00
|
|
|
chkexist = 0;
|
1998-07-09 01:50:48 +08:00
|
|
|
switch ((c = *s)) {
|
|
|
|
default: /* %name substitution */
|
1998-09-06 07:13:35 +08:00
|
|
|
while (strchr("!?", *s) != NULL) {
|
|
|
|
switch(*s++) {
|
|
|
|
case '!':
|
|
|
|
negate = (++negate % 2);
|
|
|
|
break;
|
|
|
|
case '?':
|
|
|
|
chkexist++;
|
|
|
|
break;
|
|
|
|
}
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
|
|
|
f = se = s;
|
|
|
|
if (*se == '-')
|
|
|
|
se++;
|
|
|
|
while((c = *se) && (isalnum(c) || c == '_'))
|
|
|
|
se++;
|
1999-07-29 20:36:03 +08:00
|
|
|
/* Recognize non-alnum macros too */
|
|
|
|
switch (*se) {
|
|
|
|
case '*':
|
|
|
|
se++;
|
|
|
|
if (*se == '*') se++;
|
|
|
|
break;
|
|
|
|
case '#':
|
1998-07-09 01:50:48 +08:00
|
|
|
se++;
|
1999-07-29 20:36:03 +08:00
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
1998-07-09 01:50:48 +08:00
|
|
|
fe = se;
|
|
|
|
/* For "%name " macros ... */
|
|
|
|
if ((c = *fe) && isblank(c))
|
1999-07-29 20:36:03 +08:00
|
|
|
grab = '\n';
|
1998-07-09 01:50:48 +08:00
|
|
|
break;
|
|
|
|
case '(': /* %(...) shell escape */
|
|
|
|
if ((se = matchchar(s, c, ')')) == NULL) {
|
1998-09-28 06:03:52 +08:00
|
|
|
rpmError(RPMERR_BADSPEC, _("Unterminated %c: %s"), c, s);
|
1998-07-09 01:50:48 +08:00
|
|
|
rc = 1;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (mb->macro_trace)
|
|
|
|
printMacro(mb, s, se+1);
|
|
|
|
|
|
|
|
s++; /* skip ( */
|
|
|
|
rc = doShellEscape(mb, s, (se - s));
|
|
|
|
se++; /* skip ) */
|
|
|
|
|
|
|
|
s = se;
|
|
|
|
continue;
|
1999-10-21 05:40:10 +08:00
|
|
|
/*@notreached@*/ break;
|
1998-07-09 01:50:48 +08:00
|
|
|
case '{': /* %{...}/%{...:...} substitution */
|
|
|
|
if ((se = matchchar(s, c, '}')) == NULL) {
|
1998-09-28 06:03:52 +08:00
|
|
|
rpmError(RPMERR_BADSPEC, _("Unterminated %c: %s"), c, s);
|
1998-07-09 01:50:48 +08:00
|
|
|
rc = 1;
|
|
|
|
continue;
|
|
|
|
}
|
1998-12-03 03:55:36 +08:00
|
|
|
f = s+1;/* skip { */
|
1998-07-09 01:50:48 +08:00
|
|
|
se++; /* skip } */
|
1998-09-06 07:13:35 +08:00
|
|
|
while (strchr("!?", *f) != NULL) {
|
|
|
|
switch(*f++) {
|
|
|
|
case '!':
|
|
|
|
negate = (++negate % 2);
|
|
|
|
break;
|
|
|
|
case '?':
|
|
|
|
chkexist++;
|
|
|
|
break;
|
|
|
|
}
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
1999-07-29 20:36:03 +08:00
|
|
|
for (fe = f; (c = *fe) && !strchr(" :}", c);)
|
1998-07-09 01:50:48 +08:00
|
|
|
fe++;
|
1999-07-29 20:36:03 +08:00
|
|
|
switch (c) {
|
|
|
|
case ':':
|
1998-07-09 01:50:48 +08:00
|
|
|
g = fe + 1;
|
|
|
|
ge = se - 1;
|
1999-07-29 20:36:03 +08:00
|
|
|
break;
|
|
|
|
case ' ':
|
|
|
|
grab = se[-1];
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX Everything below expects fe > f */
|
|
|
|
fn = (fe - f);
|
|
|
|
gn = (ge - g);
|
|
|
|
if (fn <= 0) {
|
1999-04-21 03:17:23 +08:00
|
|
|
/* XXX Process % in unknown context */
|
|
|
|
c = '%'; /* XXX only need to save % */
|
|
|
|
SAVECHAR(mb, c);
|
|
|
|
#if 0
|
1999-04-09 03:24:56 +08:00
|
|
|
rpmError(RPMERR_BADSPEC, _("A %% is followed by an unparseable macro"));
|
1999-04-21 03:17:23 +08:00
|
|
|
#endif
|
1998-07-09 01:50:48 +08:00
|
|
|
s = se;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (mb->macro_trace)
|
|
|
|
printMacro(mb, s, se);
|
|
|
|
|
|
|
|
/* Expand builtin macros */
|
|
|
|
if (STREQ("global", f, fn)) {
|
1998-08-02 23:14:38 +08:00
|
|
|
s = doDefine(mb, se, RMIL_GLOBAL, 1);
|
1998-07-09 01:50:48 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (STREQ("define", f, fn)) {
|
|
|
|
s = doDefine(mb, se, mb->depth, 0);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (STREQ("undefine", f, fn)) {
|
|
|
|
s = doUndefine(mb->mc, se);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (STREQ("echo", f, fn) ||
|
|
|
|
STREQ("warn", f, fn) ||
|
|
|
|
STREQ("error", f, fn)) {
|
|
|
|
int waserror = 0;
|
|
|
|
if (STREQ("error", f, fn))
|
|
|
|
waserror = 1;
|
|
|
|
if (g < ge)
|
|
|
|
doOutput(mb, waserror, g, gn);
|
|
|
|
else
|
|
|
|
doOutput(mb, waserror, f, fn);
|
|
|
|
s = se;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (STREQ("trace", f, fn)) {
|
|
|
|
/* XXX TODO restore expand_trace/macro_trace to 0 on return */
|
|
|
|
mb->expand_trace = mb->macro_trace = (negate ? 0 : mb->depth);
|
|
|
|
if (mb->depth == 1) {
|
|
|
|
print_macro_trace = mb->macro_trace;
|
|
|
|
print_expand_trace = mb->expand_trace;
|
|
|
|
}
|
|
|
|
s = se;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (STREQ("dump", f, fn)) {
|
1999-03-28 08:47:40 +08:00
|
|
|
dumpMacroTable(mb->mc, NULL);
|
1999-08-17 02:57:37 +08:00
|
|
|
while (iseol(*se))
|
1998-07-09 01:50:48 +08:00
|
|
|
se++;
|
|
|
|
s = se;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* XXX necessary but clunky */
|
|
|
|
if (STREQ("basename", f, fn) ||
|
|
|
|
STREQ("suffix", f, fn) ||
|
|
|
|
STREQ("expand", f, fn) ||
|
|
|
|
STREQ("uncompress", f, fn) ||
|
|
|
|
STREQ("S", f, fn) ||
|
|
|
|
STREQ("P", f, fn) ||
|
|
|
|
STREQ("F", f, fn)) {
|
|
|
|
doFoo(mb, f, fn, g, gn);
|
|
|
|
s = se;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Expand defined macros */
|
|
|
|
mep = findEntry(mb->mc, f, fn);
|
|
|
|
me = (mep ? *mep : NULL);
|
|
|
|
|
|
|
|
/* XXX Special processing for flags */
|
|
|
|
if (*f == '-') {
|
|
|
|
if (me)
|
|
|
|
me->used++; /* Mark macro as used */
|
|
|
|
if ((me == NULL && !negate) || /* Without -f, skip %{-f...} */
|
|
|
|
(me != NULL && negate)) { /* With -f, skip %{!-f...} */
|
|
|
|
s = se;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (g && g < ge) { /* Expand X in %{-f:X} */
|
|
|
|
rc = expandT(mb, g, gn);
|
|
|
|
} else
|
|
|
|
if (me->body && *me->body) { /* Expand %{-f}/%{-f*} */
|
|
|
|
rc = expandT(mb, me->body, strlen(me->body));
|
|
|
|
}
|
|
|
|
s = se;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
1998-09-06 07:13:35 +08:00
|
|
|
/* XXX Special processing for macro existence */
|
|
|
|
if (chkexist) {
|
|
|
|
if ((me == NULL && !negate) || /* Without -f, skip %{?f...} */
|
|
|
|
(me != NULL && negate)) { /* With -f, skip %{!?f...} */
|
|
|
|
s = se;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (g && g < ge) { /* Expand X in %{?f:X} */
|
|
|
|
rc = expandT(mb, g, gn);
|
|
|
|
} else
|
|
|
|
if (me->body && *me->body) { /* Expand %{?f}/%{?f*} */
|
|
|
|
rc = expandT(mb, me->body, strlen(me->body));
|
|
|
|
}
|
|
|
|
s = se;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
if (me == NULL) { /* leave unknown %... as is */
|
|
|
|
#ifndef HACK
|
|
|
|
#if DEAD
|
|
|
|
/* XXX hack to skip over empty arg list */
|
|
|
|
if (fn == 1 && *f == '*') {
|
|
|
|
s = se;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
#endif
|
|
|
|
/* XXX hack to permit non-overloaded %foo to be passed */
|
|
|
|
c = '%'; /* XXX only need to save % */
|
|
|
|
SAVECHAR(mb, c);
|
|
|
|
#else
|
1998-09-28 06:03:52 +08:00
|
|
|
rpmError(RPMERR_BADSPEC, _("Macro %%%.*s not found, skipping"), fn, f);
|
1998-07-09 01:50:48 +08:00
|
|
|
s = se;
|
|
|
|
#endif
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Setup args for "%name " macros with opts */
|
|
|
|
if (me && me->opts != NULL) {
|
1999-07-29 20:36:03 +08:00
|
|
|
if (grab) {
|
|
|
|
se = grabArgs(mb, me, fe, grab);
|
|
|
|
} else {
|
|
|
|
addMacro(mb->mc, "**", NULL, "", mb->depth);
|
|
|
|
addMacro(mb->mc, "*", NULL, "", mb->depth);
|
|
|
|
addMacro(mb->mc, "#", NULL, "0", mb->depth);
|
|
|
|
addMacro(mb->mc, "0", NULL, me->name, mb->depth);
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Recursively expand body of macro */
|
1999-03-28 08:47:40 +08:00
|
|
|
if (me->body && *me->body) {
|
|
|
|
mb->s = me->body;
|
|
|
|
rc = expandMacro(mb);
|
|
|
|
if (rc == 0)
|
|
|
|
me->used++; /* Mark macro as used */
|
|
|
|
}
|
1998-07-09 01:50:48 +08:00
|
|
|
|
|
|
|
/* Free args for "%name " macros with opts */
|
|
|
|
if (me->opts != NULL)
|
|
|
|
freeArgs(mb);
|
|
|
|
|
|
|
|
s = se;
|
1997-03-31 22:13:21 +08:00
|
|
|
}
|
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
*mb->t = '\0';
|
|
|
|
mb->s = s;
|
|
|
|
mb->depth--;
|
|
|
|
if (rc != 0 || mb->expand_trace)
|
|
|
|
printExpansion(mb, t, mb->t);
|
|
|
|
return rc;
|
|
|
|
}
|
1997-03-31 22:13:21 +08:00
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
/* =============================================================== */
|
1999-03-28 08:47:40 +08:00
|
|
|
/* XXX this is used only in build/expression.c and will go away. */
|
1998-07-09 01:50:48 +08:00
|
|
|
const char *
|
|
|
|
getMacroBody(MacroContext *mc, const char *name)
|
|
|
|
{
|
|
|
|
MacroEntry **mep = findEntry(mc, name, 0);
|
|
|
|
MacroEntry *me = (mep ? *mep : NULL);
|
|
|
|
return ( me ? me->body : (const char *)NULL );
|
1997-03-31 22:13:21 +08:00
|
|
|
}
|
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
/* =============================================================== */
|
1999-03-28 08:47:40 +08:00
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
int
|
1998-08-01 04:11:49 +08:00
|
|
|
expandMacros(void *spec, MacroContext *mc, char *s, size_t slen)
|
1997-03-31 22:13:21 +08:00
|
|
|
{
|
1998-07-09 01:50:48 +08:00
|
|
|
MacroBuf macrobuf, *mb = ¯obuf;
|
|
|
|
char *tbuf;
|
|
|
|
int rc;
|
1997-03-31 22:13:21 +08:00
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
if (s == NULL || slen <= 0)
|
|
|
|
return 0;
|
1999-04-02 06:26:44 +08:00
|
|
|
if (mc == NULL)
|
|
|
|
mc = &globalMacroContext;
|
1998-07-09 01:50:48 +08:00
|
|
|
|
|
|
|
tbuf = alloca(slen + 1);
|
|
|
|
memset(tbuf, 0, (slen + 1));
|
|
|
|
|
|
|
|
mb->s = s;
|
|
|
|
mb->t = tbuf;
|
|
|
|
mb->nb = slen;
|
|
|
|
mb->depth = 0;
|
|
|
|
mb->macro_trace = print_macro_trace;
|
|
|
|
mb->expand_trace = print_expand_trace;
|
|
|
|
|
1998-08-01 04:11:49 +08:00
|
|
|
mb->spec = spec; /* (future) %file expansion info */
|
1998-07-09 01:50:48 +08:00
|
|
|
mb->mc = mc;
|
|
|
|
|
|
|
|
rc = expandMacro(mb);
|
|
|
|
|
|
|
|
if (mb->nb <= 0)
|
1998-09-28 06:03:52 +08:00
|
|
|
rpmError(RPMERR_BADSPEC, _("Target buffer overflow"));
|
1998-07-09 01:50:48 +08:00
|
|
|
|
|
|
|
tbuf[slen] = '\0'; /* XXX just in case */
|
|
|
|
strncpy(s, tbuf, (slen - mb->nb + 1));
|
|
|
|
|
|
|
|
return rc;
|
1997-03-31 22:13:21 +08:00
|
|
|
}
|
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
void
|
|
|
|
addMacro(MacroContext *mc, const char *n, const char *o, const char *b, int level)
|
1997-03-31 22:13:21 +08:00
|
|
|
{
|
1998-07-09 01:50:48 +08:00
|
|
|
MacroEntry **mep;
|
|
|
|
|
1999-04-02 06:26:44 +08:00
|
|
|
if (mc == NULL)
|
|
|
|
mc = &globalMacroContext;
|
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
/* If new name, expand macro table */
|
|
|
|
if ((mep = findEntry(mc, n, 0)) == NULL) {
|
|
|
|
if (mc->firstFree == mc->macrosAllocated)
|
|
|
|
expandMacroTable(mc);
|
|
|
|
mep = mc->macroTable + mc->firstFree++;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Push macro over previous definition */
|
|
|
|
pushMacro(mep, n, o, b, level);
|
|
|
|
|
|
|
|
/* If new name, sort macro table */
|
|
|
|
if ((*mep)->prev == NULL)
|
|
|
|
sortMacroTable(mc);
|
1997-03-31 22:13:21 +08:00
|
|
|
}
|
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
void
|
1999-08-17 00:18:25 +08:00
|
|
|
delMacro(MacroContext *mc, const char *n)
|
1997-03-31 22:13:21 +08:00
|
|
|
{
|
1999-06-25 06:23:46 +08:00
|
|
|
MacroEntry **mep;
|
1998-07-09 01:50:48 +08:00
|
|
|
|
1999-04-02 06:26:44 +08:00
|
|
|
if (mc == NULL)
|
|
|
|
mc = &globalMacroContext;
|
1998-07-09 01:50:48 +08:00
|
|
|
/* If name exists, pop entry */
|
1999-08-17 00:18:25 +08:00
|
|
|
if ((mep = findEntry(mc, n, 0)) != NULL) {
|
1998-07-09 01:50:48 +08:00
|
|
|
popMacro(mep);
|
1999-06-25 06:23:46 +08:00
|
|
|
/* If deleted name, sort macro table */
|
|
|
|
if (!(mep && *mep))
|
|
|
|
sortMacroTable(mc);
|
|
|
|
}
|
1998-01-13 05:31:29 +08:00
|
|
|
}
|
|
|
|
|
1999-03-28 08:47:40 +08:00
|
|
|
int
|
|
|
|
rpmDefineMacro(MacroContext *mc, const char *macro, int level)
|
|
|
|
{
|
|
|
|
MacroBuf macrobuf, *mb = ¯obuf;
|
|
|
|
|
|
|
|
/* XXX just enough to get by */
|
|
|
|
mb->mc = (mc ? mc : &globalMacroContext);
|
|
|
|
(void)doDefine(mb, macro, level, 0);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
void
|
1999-04-01 00:57:01 +08:00
|
|
|
initMacros(MacroContext *mc, const char *macrofiles)
|
1998-07-09 01:50:48 +08:00
|
|
|
{
|
|
|
|
char *m, *mfile, *me;
|
|
|
|
|
1999-04-01 00:57:01 +08:00
|
|
|
if (macrofiles == NULL)
|
1998-07-09 01:50:48 +08:00
|
|
|
return;
|
1999-04-02 06:26:44 +08:00
|
|
|
if (mc == NULL)
|
|
|
|
mc = &globalMacroContext;
|
1998-07-09 01:50:48 +08:00
|
|
|
|
1999-09-21 11:22:53 +08:00
|
|
|
for (mfile = m = xstrdup(macrofiles); *mfile; mfile = me) {
|
1998-07-09 01:50:48 +08:00
|
|
|
FILE *fp;
|
|
|
|
char buf[BUFSIZ];
|
|
|
|
|
|
|
|
if ((me = strchr(mfile, ':')) != NULL)
|
|
|
|
*me++ = '\0';
|
|
|
|
else
|
|
|
|
me = mfile + strlen(mfile);
|
|
|
|
|
1999-04-01 00:57:01 +08:00
|
|
|
/* Expand ~/ to $HOME */
|
|
|
|
buf[0] = '\0';
|
|
|
|
if (mfile[0] == '~' && mfile[1] == '/') {
|
|
|
|
char *home;
|
|
|
|
if ((home = getenv("HOME")) != NULL) {
|
|
|
|
mfile += 2;
|
|
|
|
strncpy(buf, home, sizeof(buf));
|
|
|
|
strncat(buf, "/", sizeof(buf) - strlen(buf));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
strncat(buf, mfile, sizeof(buf) - strlen(buf));
|
|
|
|
buf[sizeof(buf)-1] = '\0';
|
|
|
|
|
|
|
|
if ((fp=fopen(buf, "r")) == NULL)
|
1998-07-09 01:50:48 +08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/* XXX Assume new fangled macro expansion */
|
|
|
|
max_macro_depth = 16;
|
|
|
|
|
|
|
|
while(rdcl(buf, sizeof(buf), fp, 1) != NULL) {
|
|
|
|
char c, *n;
|
|
|
|
|
|
|
|
n = buf;
|
|
|
|
SKIPBLANK(n, c);
|
|
|
|
|
|
|
|
if (c != '%')
|
|
|
|
continue;
|
1999-03-28 08:47:40 +08:00
|
|
|
n++; /* skip % */
|
|
|
|
(void)rpmDefineMacro(NULL, n, RMIL_MACROFILES);
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
|
|
|
fclose(fp);
|
|
|
|
}
|
|
|
|
if (m)
|
|
|
|
free(m);
|
|
|
|
}
|
1998-01-13 05:31:29 +08:00
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
void
|
|
|
|
freeMacros(MacroContext *mc)
|
1998-01-13 05:31:29 +08:00
|
|
|
{
|
1998-07-09 01:50:48 +08:00
|
|
|
int i;
|
1998-01-13 05:31:29 +08:00
|
|
|
|
1999-04-02 06:26:44 +08:00
|
|
|
if (mc == NULL)
|
|
|
|
mc = &globalMacroContext;
|
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
for (i = 0; i < mc->firstFree; i++) {
|
|
|
|
MacroEntry *me;
|
|
|
|
while ((me = mc->macroTable[i]) != NULL) {
|
|
|
|
/* XXX cast to workaround const */
|
|
|
|
if ((mc->macroTable[i] = me->prev) == NULL)
|
1999-04-09 04:53:45 +08:00
|
|
|
FREE(me->name);
|
|
|
|
FREE(me->opts);
|
|
|
|
FREE(me->body);
|
1998-07-09 01:50:48 +08:00
|
|
|
FREE(me);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
FREE(mc->macroTable);
|
1999-04-02 06:26:44 +08:00
|
|
|
memset(mc, 0, sizeof(*mc));
|
1998-01-13 05:31:29 +08:00
|
|
|
}
|
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
/* =============================================================== */
|
1999-01-06 07:13:56 +08:00
|
|
|
int isCompressed(const char *file, int *compressed)
|
1998-08-01 04:11:49 +08:00
|
|
|
{
|
1998-11-19 05:41:05 +08:00
|
|
|
FD_t fd;
|
|
|
|
ssize_t nb;
|
|
|
|
int rderrno;
|
1998-08-01 04:11:49 +08:00
|
|
|
unsigned char magic[4];
|
|
|
|
|
|
|
|
*compressed = COMPRESSED_NOT;
|
|
|
|
|
1998-11-19 05:41:05 +08:00
|
|
|
if (fdFileno(fd = fdOpen(file, O_RDONLY, 0)) < 0) {
|
1998-09-28 06:03:52 +08:00
|
|
|
rpmError(RPMERR_BADSPEC, _("File %s: %s"), file, strerror(errno));
|
1998-08-01 04:11:49 +08:00
|
|
|
return 1;
|
|
|
|
}
|
1999-10-28 07:18:10 +08:00
|
|
|
nb = Fread(magic, sizeof(magic), 1, fd);
|
1998-09-11 00:25:15 +08:00
|
|
|
rderrno = errno;
|
1999-10-28 07:18:10 +08:00
|
|
|
Fclose(fd);
|
1998-09-11 00:25:15 +08:00
|
|
|
|
|
|
|
if (nb < 0) {
|
1998-09-28 06:03:52 +08:00
|
|
|
rpmError(RPMERR_BADSPEC, _("File %s: %s"), file, strerror(rderrno));
|
1998-08-01 04:11:49 +08:00
|
|
|
return 1;
|
1998-09-11 00:25:15 +08:00
|
|
|
} else if (nb < sizeof(magic)) {
|
1998-09-28 06:03:52 +08:00
|
|
|
rpmError(RPMERR_BADSPEC, _("File %s is smaller than %d bytes"),
|
1998-09-11 00:25:15 +08:00
|
|
|
file, sizeof(magic));
|
|
|
|
return 0;
|
1998-08-01 04:11:49 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (((magic[0] == 0037) && (magic[1] == 0213)) || /* gzip */
|
|
|
|
((magic[0] == 0037) && (magic[1] == 0236)) || /* old gzip */
|
|
|
|
((magic[0] == 0037) && (magic[1] == 0036)) || /* pack */
|
|
|
|
((magic[0] == 0037) && (magic[1] == 0240)) || /* SCO lzh */
|
|
|
|
((magic[0] == 0037) && (magic[1] == 0235)) || /* compress */
|
|
|
|
((magic[0] == 0120) && (magic[1] == 0113) &&
|
|
|
|
(magic[2] == 0003) && (magic[3] == 0004)) /* pkzip */
|
|
|
|
) {
|
|
|
|
*compressed = COMPRESSED_OTHER;
|
|
|
|
} else if ((magic[0] == 'B') && (magic[1] == 'Z')) {
|
|
|
|
*compressed = COMPRESSED_BZIP2;
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
1999-03-28 08:47:40 +08:00
|
|
|
/* =============================================================== */
|
|
|
|
/* Return concatenated and expanded macro list */
|
|
|
|
char *
|
|
|
|
rpmExpand(const char *arg, ...)
|
|
|
|
{
|
|
|
|
char buf[BUFSIZ], *p, *pe;
|
|
|
|
const char *s;
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
if (arg == NULL)
|
1999-09-21 11:22:53 +08:00
|
|
|
return xstrdup("");
|
1999-03-28 08:47:40 +08:00
|
|
|
|
|
|
|
p = buf;
|
|
|
|
strcpy(p, arg);
|
|
|
|
pe = p + strlen(p);
|
|
|
|
*pe = '\0';
|
|
|
|
|
|
|
|
va_start(ap, arg);
|
|
|
|
while ((s = va_arg(ap, const char *)) != NULL) {
|
|
|
|
strcpy(pe, s);
|
|
|
|
pe += strlen(pe);
|
|
|
|
*pe = '\0';
|
|
|
|
}
|
|
|
|
va_end(ap);
|
1999-04-02 06:26:44 +08:00
|
|
|
expandMacros(NULL, NULL, buf, sizeof(buf));
|
1999-09-21 11:22:53 +08:00
|
|
|
return xstrdup(buf); /* XXX build memory leaks */
|
1999-03-28 08:47:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
rpmExpandNumeric(const char *arg)
|
|
|
|
{
|
|
|
|
const char *val;
|
|
|
|
int rc;
|
|
|
|
|
|
|
|
if (arg == NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
val = rpmExpand(arg, NULL);
|
|
|
|
if (!(val && *val != '%'))
|
|
|
|
rc = 0;
|
|
|
|
else if (*val == 'Y' || *val == 'y')
|
|
|
|
rc = 1;
|
|
|
|
else if (*val == 'N' || *val == 'n')
|
|
|
|
rc = 0;
|
|
|
|
else {
|
|
|
|
char *end;
|
|
|
|
rc = strtol(val, &end, 0);
|
|
|
|
if (!(end && *end == '\0'))
|
|
|
|
rc = 0;
|
|
|
|
}
|
|
|
|
xfree(val);
|
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return concatenated and expanded path with multiple /'s removed */
|
|
|
|
const char *
|
|
|
|
rpmGetPath(const char *path, ...)
|
|
|
|
{
|
|
|
|
char buf[BUFSIZ], *p, *pe;
|
|
|
|
const char *s;
|
|
|
|
va_list ap;
|
|
|
|
|
|
|
|
if (path == NULL)
|
1999-09-21 11:22:53 +08:00
|
|
|
return xstrdup("");
|
1999-03-28 08:47:40 +08:00
|
|
|
|
|
|
|
p = buf;
|
|
|
|
strcpy(p, path);
|
|
|
|
pe = p + strlen(p);
|
|
|
|
*pe = '\0';
|
|
|
|
|
|
|
|
va_start(ap, path);
|
|
|
|
while ((s = va_arg(ap, const char *)) != NULL) {
|
|
|
|
/* XXX FIXME: this fixes only some of the "...//..." problems */
|
|
|
|
if (pe > p && pe[-1] == '/')
|
|
|
|
while(*s && *s == '/') s++;
|
|
|
|
if (*s != '\0') {
|
|
|
|
strcpy(pe, s);
|
|
|
|
pe += strlen(pe);
|
|
|
|
*pe = '\0';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
va_end(ap);
|
1999-04-02 06:26:44 +08:00
|
|
|
expandMacros(NULL, NULL, buf, sizeof(buf));
|
1999-09-21 11:22:53 +08:00
|
|
|
return xstrdup(buf);
|
1999-03-28 08:47:40 +08:00
|
|
|
}
|
|
|
|
|
1998-08-01 04:11:49 +08:00
|
|
|
/* =============================================================== */
|
|
|
|
|
1999-07-03 04:56:04 +08:00
|
|
|
#if defined(DEBUG_MACROS)
|
|
|
|
|
|
|
|
#if defined(EVAL_MACROS)
|
|
|
|
|
1999-07-03 05:15:25 +08:00
|
|
|
char *macrofiles = "/usr/lib/rpm/macros:/etc/rpm/macros:~/.rpmmacros";
|
1999-07-03 04:56:04 +08:00
|
|
|
|
|
|
|
int
|
|
|
|
main(int argc, char *argv[])
|
|
|
|
{
|
|
|
|
int c;
|
|
|
|
int errflg = 0;
|
|
|
|
extern char *optarg;
|
|
|
|
extern int optind;
|
|
|
|
|
|
|
|
while ((c = getopt(argc, argv, "f:")) != EOF ) {
|
|
|
|
switch (c) {
|
|
|
|
case 'f':
|
|
|
|
macrofiles = optarg;
|
|
|
|
break;
|
|
|
|
case '?':
|
|
|
|
default:
|
|
|
|
errflg++;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (errflg || optind >= argc) {
|
|
|
|
fprintf(stderr, "Usage: %s [-f macropath ] macro ...\n", argv[0]);
|
|
|
|
exit(1);
|
|
|
|
}
|
|
|
|
|
|
|
|
initMacros(NULL, macrofiles);
|
|
|
|
for ( ; optind < argc; optind++) {
|
|
|
|
const char *val;
|
|
|
|
|
|
|
|
val = rpmGetPath(argv[optind], NULL);
|
|
|
|
if (val) {
|
|
|
|
fprintf(stdout, "%s:\t%s\n", argv[optind], val);
|
|
|
|
xfree(val);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
#else /* !EVAL_MACROS */
|
1998-07-09 01:50:48 +08:00
|
|
|
|
1999-04-21 06:45:52 +08:00
|
|
|
char *macrofiles = "../macros:./testmacros";
|
1998-07-09 01:50:48 +08:00
|
|
|
char *testfile = "./test";
|
|
|
|
|
|
|
|
int
|
|
|
|
main(int argc, char *argv[])
|
1998-01-13 05:31:29 +08:00
|
|
|
{
|
1998-07-09 01:50:48 +08:00
|
|
|
char buf[BUFSIZ];
|
|
|
|
FILE *fp;
|
|
|
|
int x;
|
1998-01-13 05:31:29 +08:00
|
|
|
|
1999-04-21 06:45:52 +08:00
|
|
|
initMacros(NULL, macrofiles);
|
|
|
|
dumpMacroTable(NULL, NULL);
|
1998-07-09 01:50:48 +08:00
|
|
|
|
|
|
|
if ((fp = fopen(testfile, "r")) != NULL) {
|
1999-08-17 04:14:34 +08:00
|
|
|
while(rdcl(buf, sizeof(buf), fp, 1)) {
|
1999-04-21 06:45:52 +08:00
|
|
|
x = expandMacros(NULL, NULL, buf, sizeof(buf));
|
1998-07-09 01:50:48 +08:00
|
|
|
fprintf(stderr, "%d->%s\n", x, buf);
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
}
|
|
|
|
fclose(fp);
|
|
|
|
}
|
1998-01-13 05:31:29 +08:00
|
|
|
|
1999-08-17 00:18:25 +08:00
|
|
|
while(rdcl(buf, sizeof(buf), stdin, 1)) {
|
1999-04-21 06:45:52 +08:00
|
|
|
x = expandMacros(NULL, NULL, buf, sizeof(buf));
|
1998-07-09 01:50:48 +08:00
|
|
|
fprintf(stderr, "%d->%s\n <-\n", x, buf);
|
|
|
|
memset(buf, 0, sizeof(buf));
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
1999-07-03 04:56:04 +08:00
|
|
|
#endif /* EVAL_MACROS */
|
1998-07-09 01:50:48 +08:00
|
|
|
#endif /* DEBUG_MACROS */
|