2000-08-28 02:34:02 +08:00
|
|
|
/** \ingroup rpmrc rpmio
|
|
|
|
* \file rpmio/macro.c
|
|
|
|
*/
|
|
|
|
|
2000-12-13 04:03:45 +08:00
|
|
|
#include "system.h"
|
1999-03-28 08:47:40 +08:00
|
|
|
#include <stdarg.h>
|
2009-12-23 20:02:19 +08:00
|
|
|
#ifdef HAVE_GETOPT_H
|
|
|
|
#include <getopt.h>
|
|
|
|
#else
|
|
|
|
extern char *optarg;
|
|
|
|
extern int optind;
|
|
|
|
#endif
|
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')
|
|
|
|
|
2009-08-31 16:15:16 +08:00
|
|
|
#define STREQ(_t, _f, _fn) ((_fn) == (sizeof(_t)-1) && rstreqn((_t), (_f), (_fn)))
|
1997-03-31 22:13:21 +08:00
|
|
|
|
2008-02-01 17:36:13 +08:00
|
|
|
#define MACROBUFSIZ (BUFSIZ * 2)
|
|
|
|
|
2007-12-08 20:02:32 +08:00
|
|
|
#include <rpm/rpmio.h>
|
|
|
|
#include <rpm/rpmstring.h>
|
|
|
|
#include <rpm/rpmfileutil.h>
|
|
|
|
#include <rpm/rpmurl.h>
|
|
|
|
#include <rpm/rpmlog.h>
|
2008-01-30 23:05:29 +08:00
|
|
|
#include <rpm/rpmmacro.h>
|
2008-04-18 19:54:58 +08:00
|
|
|
#include <rpm/argv.h>
|
2004-10-10 01:29:22 +08:00
|
|
|
|
|
|
|
#ifdef WITH_LUA
|
2007-11-23 18:41:29 +08:00
|
|
|
#include "rpmio/rpmlua.h"
|
2004-10-10 01:29:22 +08:00
|
|
|
#endif
|
1999-11-13 01:20:49 +08:00
|
|
|
|
2000-12-13 04:03:45 +08:00
|
|
|
#include "debug.h"
|
|
|
|
|
2007-11-02 16:40:45 +08:00
|
|
|
/*! The structure used to store a macro. */
|
|
|
|
struct rpmMacroEntry_s {
|
|
|
|
struct rpmMacroEntry_s *prev;/*!< Macro entry stack. */
|
2007-12-17 03:28:37 +08:00
|
|
|
char *name; /*!< Macro name. */
|
|
|
|
char *opts; /*!< Macro parameters (a la getopt) */
|
|
|
|
char *body; /*!< Macro body. */
|
2007-11-02 16:40:45 +08:00
|
|
|
int used; /*!< No. of expansions. */
|
|
|
|
int level; /*!< Scoping level. */
|
|
|
|
};
|
|
|
|
|
|
|
|
/*! The structure used to store the set of macros in a context. */
|
|
|
|
struct rpmMacroContext_s {
|
|
|
|
rpmMacroEntry *macroTable; /*!< Macro entry table for context. */
|
|
|
|
int macrosAllocated;/*!< No. of allocated macros. */
|
|
|
|
int firstFree; /*!< No. of macros. */
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2007-09-20 20:52:03 +08:00
|
|
|
static struct rpmMacroContext_s rpmGlobalMacroContext_s;
|
|
|
|
rpmMacroContext rpmGlobalMacroContext = &rpmGlobalMacroContext_s;
|
2001-10-15 11:22:10 +08:00
|
|
|
|
2007-09-20 20:52:03 +08:00
|
|
|
static struct rpmMacroContext_s rpmCLIMacroContext_s;
|
|
|
|
rpmMacroContext rpmCLIMacroContext = &rpmCLIMacroContext_s;
|
1999-04-02 06:26:44 +08:00
|
|
|
|
2000-09-02 05:15:40 +08:00
|
|
|
/**
|
2000-09-30 03:50:29 +08:00
|
|
|
* Macro expansion state.
|
2000-09-02 05:15:40 +08:00
|
|
|
*/
|
2007-09-11 22:48:54 +08:00
|
|
|
typedef struct MacroBuf_s {
|
2010-09-27 17:19:13 +08:00
|
|
|
char * buf; /*!< Expansion buffer. */
|
|
|
|
size_t tpos; /*!< Current position in expansion buffer */
|
2001-06-06 03:26:22 +08:00
|
|
|
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? */
|
2007-09-20 20:52:03 +08:00
|
|
|
rpmMacroContext mc;
|
2001-06-06 03:26:22 +08:00
|
|
|
} * MacroBuf;
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2004-03-02 09:31:01 +08:00
|
|
|
#define _MAX_MACRO_DEPTH 16
|
2008-02-27 04:24:28 +08:00
|
|
|
static int max_macro_depth = _MAX_MACRO_DEPTH;
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2004-03-02 09:31:01 +08:00
|
|
|
#define _PRINT_MACRO_TRACE 0
|
2008-02-27 04:24:28 +08:00
|
|
|
static int print_macro_trace = _PRINT_MACRO_TRACE;
|
2004-03-02 09:31:01 +08:00
|
|
|
|
|
|
|
#define _PRINT_EXPAND_TRACE 0
|
2008-02-27 04:24:28 +08:00
|
|
|
static int print_expand_trace = _PRINT_EXPAND_TRACE;
|
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
|
|
|
|
2001-10-18 00:43:36 +08:00
|
|
|
/* forward ref */
|
2010-09-27 22:15:15 +08:00
|
|
|
static int expandMacro(MacroBuf mb, const char *src, size_t slen);
|
2001-10-18 00:43:36 +08:00
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
/* =============================================================== */
|
1997-03-31 22:13:21 +08:00
|
|
|
|
2000-09-30 03:50:29 +08:00
|
|
|
/**
|
|
|
|
* Compare macro entries by name (qsort/bsearch).
|
|
|
|
* @param ap 1st macro entry
|
|
|
|
* @param bp 2nd macro entry
|
|
|
|
* @return result of comparison
|
|
|
|
*/
|
1998-07-09 01:50:48 +08:00
|
|
|
static int
|
2001-06-06 03:26:22 +08:00
|
|
|
compareMacroName(const void * ap, const void * bp)
|
1997-03-31 22:13:21 +08:00
|
|
|
{
|
2007-12-19 18:49:52 +08:00
|
|
|
rpmMacroEntry ame = *((const rpmMacroEntry *)ap);
|
|
|
|
rpmMacroEntry bme = *((const rpmMacroEntry *)bp);
|
2001-06-06 03:26:22 +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);
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
1997-03-31 22:13:21 +08:00
|
|
|
|
2000-09-30 03:50:29 +08:00
|
|
|
/**
|
|
|
|
* Enlarge macro table.
|
|
|
|
* @param mc macro context
|
|
|
|
*/
|
1998-07-09 01:50:48 +08:00
|
|
|
static void
|
2007-09-20 20:52:03 +08:00
|
|
|
expandMacroTable(rpmMacroContext mc)
|
1998-07-09 01:50:48 +08:00
|
|
|
{
|
2001-06-06 03:26:22 +08:00
|
|
|
if (mc->macroTable == NULL) {
|
|
|
|
mc->macrosAllocated = MACRO_CHUNK_SIZE;
|
2007-09-20 20:52:03 +08:00
|
|
|
mc->macroTable = (rpmMacroEntry *)
|
2001-06-06 03:26:22 +08:00
|
|
|
xmalloc(sizeof(*(mc->macroTable)) * mc->macrosAllocated);
|
|
|
|
mc->firstFree = 0;
|
|
|
|
} else {
|
|
|
|
mc->macrosAllocated += MACRO_CHUNK_SIZE;
|
2007-09-20 20:52:03 +08:00
|
|
|
mc->macroTable = (rpmMacroEntry *)
|
2001-06-06 03:26:22 +08:00
|
|
|
xrealloc(mc->macroTable, sizeof(*(mc->macroTable)) *
|
|
|
|
mc->macrosAllocated);
|
|
|
|
}
|
|
|
|
memset(&mc->macroTable[mc->firstFree], 0, MACRO_CHUNK_SIZE * sizeof(*(mc->macroTable)));
|
1997-03-31 22:13:21 +08:00
|
|
|
}
|
|
|
|
|
2000-09-30 03:50:29 +08:00
|
|
|
/**
|
|
|
|
* Sort entries in macro table.
|
|
|
|
* @param mc macro context
|
|
|
|
*/
|
1998-07-09 01:50:48 +08:00
|
|
|
static void
|
2007-09-20 20:52:03 +08:00
|
|
|
sortMacroTable(rpmMacroContext mc)
|
1997-03-31 22:13:21 +08:00
|
|
|
{
|
2001-05-04 05:00:18 +08:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if (mc == NULL || mc->macroTable == NULL)
|
|
|
|
return;
|
1999-08-17 00:18:25 +08:00
|
|
|
|
2001-05-04 05:00:18 +08:00
|
|
|
qsort(mc->macroTable, mc->firstFree, sizeof(*(mc->macroTable)),
|
1998-07-09 01:50:48 +08:00
|
|
|
compareMacroName);
|
1999-08-17 00:18:25 +08:00
|
|
|
|
2001-05-04 05:00:18 +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
|
2007-09-20 20:52:03 +08:00
|
|
|
rpmDumpMacroTable(rpmMacroContext mc, FILE * fp)
|
1998-07-09 01:50:48 +08:00
|
|
|
{
|
2001-05-04 05:00:18 +08:00
|
|
|
int nempty = 0;
|
|
|
|
int nactive = 0;
|
1999-03-28 08:47:40 +08:00
|
|
|
|
2001-10-15 11:22:10 +08:00
|
|
|
if (mc == NULL) mc = rpmGlobalMacroContext;
|
2001-05-04 05:00:18 +08:00
|
|
|
if (fp == NULL) fp = stderr;
|
1997-03-31 22:13:21 +08:00
|
|
|
|
2001-05-04 05:00:18 +08:00
|
|
|
fprintf(fp, "========================\n");
|
|
|
|
if (mc->macroTable != NULL) {
|
|
|
|
int i;
|
1998-07-09 01:50:48 +08:00
|
|
|
for (i = 0; i < mc->firstFree; i++) {
|
2007-09-20 20:52:03 +08:00
|
|
|
rpmMacroEntry me;
|
2001-05-04 05:00:18 +08:00
|
|
|
if ((me = mc->macroTable[i]) == NULL) {
|
|
|
|
/* XXX this should never happen */
|
|
|
|
nempty++;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
fprintf(fp, "%3d%c %s", me->level,
|
1998-07-09 01:50:48 +08:00
|
|
|
(me->used > 0 ? '=' : ':'), me->name);
|
2001-05-04 05:00:18 +08:00
|
|
|
if (me->opts && *me->opts)
|
|
|
|
fprintf(fp, "(%s)", me->opts);
|
|
|
|
if (me->body && *me->body)
|
|
|
|
fprintf(fp, "\t%s", me->body);
|
|
|
|
fprintf(fp, "\n");
|
|
|
|
nactive++;
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
2001-05-04 05:00:18 +08:00
|
|
|
}
|
|
|
|
fprintf(fp, _("======================== active %d empty %d\n"),
|
1998-07-09 01:50:48 +08:00
|
|
|
nactive, nempty);
|
|
|
|
}
|
1997-03-31 22:13:21 +08:00
|
|
|
|
2000-09-30 03:50:29 +08:00
|
|
|
/**
|
|
|
|
* Find entry in macro table.
|
|
|
|
* @param mc macro context
|
|
|
|
* @param name macro name
|
2004-03-02 09:31:01 +08:00
|
|
|
* @param namelen no. of bytes
|
2000-09-30 03:50:29 +08:00
|
|
|
* @return address of slot in macro table with name (or NULL)
|
|
|
|
*/
|
2007-09-20 20:52:03 +08:00
|
|
|
static rpmMacroEntry *
|
|
|
|
findEntry(rpmMacroContext mc, const char * name, size_t namelen)
|
1998-07-09 01:50:48 +08:00
|
|
|
{
|
2007-09-20 20:52:03 +08:00
|
|
|
rpmMacroEntry key, *ret;
|
|
|
|
struct rpmMacroEntry_s keybuf;
|
2010-09-27 14:33:35 +08:00
|
|
|
char namebuf[namelen+1];
|
|
|
|
const char *mname = name;
|
2001-05-04 05:00:18 +08:00
|
|
|
|
2001-10-15 11:22:10 +08:00
|
|
|
if (mc == NULL) mc = rpmGlobalMacroContext;
|
2001-05-04 05:00:18 +08:00
|
|
|
if (mc->macroTable == NULL || mc->firstFree == 0)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (namelen > 0) {
|
|
|
|
strncpy(namebuf, name, namelen);
|
|
|
|
namebuf[namelen] = '\0';
|
2010-09-27 14:33:35 +08:00
|
|
|
mname = namebuf;
|
2001-05-04 05:00:18 +08:00
|
|
|
}
|
1997-03-31 22:13:21 +08:00
|
|
|
|
2001-05-04 05:00:18 +08:00
|
|
|
key = &keybuf;
|
|
|
|
memset(key, 0, sizeof(*key));
|
2010-09-27 14:33:35 +08:00
|
|
|
key->name = (char *)mname;
|
2007-09-20 20:52:03 +08:00
|
|
|
ret = (rpmMacroEntry *) bsearch(&key, mc->macroTable, mc->firstFree,
|
1998-07-09 01:50:48 +08:00
|
|
|
sizeof(*(mc->macroTable)), compareMacroName);
|
2001-05-04 05:00:18 +08:00
|
|
|
/* XXX TODO: find 1st empty slot and return that */
|
|
|
|
return ret;
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
1997-03-31 22:13:21 +08:00
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
/* =============================================================== */
|
|
|
|
|
2000-09-30 03:50:29 +08:00
|
|
|
/**
|
|
|
|
* fgets(3) analogue that reads \ continuations. Last newline always trimmed.
|
2002-06-22 02:00:50 +08:00
|
|
|
* @param buf input buffer
|
|
|
|
* @param size inbut buffer size (bytes)
|
|
|
|
* @param fd file handle
|
|
|
|
* @return buffer, or NULL on end-of-file
|
2000-09-30 03:50:29 +08:00
|
|
|
*/
|
2002-06-22 02:00:50 +08:00
|
|
|
static char *
|
2008-04-18 21:14:15 +08:00
|
|
|
rdcl(char * buf, size_t size, FILE *f)
|
1998-07-09 01:50:48 +08:00
|
|
|
{
|
2002-06-22 02:00:50 +08:00
|
|
|
char *q = buf - 1; /* initialize just before buffer. */
|
2001-05-04 05:00:18 +08:00
|
|
|
size_t nb = 0;
|
|
|
|
size_t nread = 0;
|
2004-04-09 04:27:53 +08:00
|
|
|
int pc = 0, bc = 0;
|
|
|
|
char *p = buf;
|
2001-05-04 05:00:18 +08:00
|
|
|
|
|
|
|
if (f != NULL)
|
|
|
|
do {
|
2002-06-22 02:00:50 +08:00
|
|
|
*(++q) = '\0'; /* terminate and move forward. */
|
|
|
|
if (fgets(q, size, f) == NULL) /* read next line. */
|
2001-05-04 05:00:18 +08:00
|
|
|
break;
|
|
|
|
nb = strlen(q);
|
2002-06-22 02:00:50 +08:00
|
|
|
nread += nb; /* trim trailing \r and \n */
|
2001-05-04 05:00:18 +08:00
|
|
|
for (q += nb - 1; nb > 0 && iseol(*q); q--)
|
|
|
|
nb--;
|
2004-04-09 04:27:53 +08:00
|
|
|
for (; p <= q; p++) {
|
|
|
|
switch (*p) {
|
|
|
|
case '\\':
|
|
|
|
switch (*(p+1)) {
|
2007-09-11 22:48:54 +08:00
|
|
|
case '\0': break;
|
|
|
|
default: p++; break;
|
2004-04-09 04:27:53 +08:00
|
|
|
}
|
2007-09-11 22:48:54 +08:00
|
|
|
break;
|
2004-04-09 04:27:53 +08:00
|
|
|
case '%':
|
|
|
|
switch (*(p+1)) {
|
2007-09-11 22:48:54 +08:00
|
|
|
case '{': p++, bc++; break;
|
|
|
|
case '(': p++, pc++; break;
|
|
|
|
case '%': p++; break;
|
2004-04-09 04:27:53 +08:00
|
|
|
}
|
2007-09-11 22:48:54 +08:00
|
|
|
break;
|
|
|
|
case '{': if (bc > 0) bc++; break;
|
|
|
|
case '}': if (bc > 0) bc--; break;
|
|
|
|
case '(': if (pc > 0) pc++; break;
|
|
|
|
case ')': if (pc > 0) pc--; break;
|
2004-04-09 04:27:53 +08:00
|
|
|
}
|
|
|
|
}
|
2004-04-19 20:12:12 +08:00
|
|
|
if (nb == 0 || (*q != '\\' && !bc && !pc) || *(q+1) == '\0') {
|
2001-05-04 05:00:18 +08:00
|
|
|
*(++q) = '\0'; /* trim trailing \r, \n */
|
|
|
|
break;
|
|
|
|
}
|
2004-04-09 04:27:53 +08:00
|
|
|
q++; p++; nb++; /* copy newline too */
|
2001-05-04 05:00:18 +08:00
|
|
|
size -= nb;
|
|
|
|
if (*q == '\r') /* XXX avoid \r madness */
|
|
|
|
*q = '\n';
|
|
|
|
} while (size > 0);
|
2002-06-22 02:00:50 +08:00
|
|
|
return (nread > 0 ? buf : NULL);
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
|
|
|
|
2000-09-30 03:50:29 +08:00
|
|
|
/**
|
2000-11-01 00:18:34 +08:00
|
|
|
* Return text between pl and matching pr characters.
|
2000-09-30 03:50:29 +08:00
|
|
|
* @param p start of text
|
|
|
|
* @param pl left char, i.e. '[', '(', '{', etc.
|
|
|
|
* @param pr right char, i.e. ']', ')', '}', etc.
|
|
|
|
* @return address of last char before pr (or NULL)
|
|
|
|
*/
|
1998-07-09 01:50:48 +08:00
|
|
|
static const char *
|
2001-06-06 03:26:22 +08:00
|
|
|
matchchar(const char * p, char pl, char pr)
|
1998-07-09 01:50:48 +08:00
|
|
|
{
|
2001-06-06 03:26:22 +08:00
|
|
|
int lvl = 0;
|
|
|
|
char c;
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2001-06-06 03:26:22 +08:00
|
|
|
while ((c = *p++) != '\0') {
|
|
|
|
if (c == '\\') { /* Ignore escaped chars */
|
|
|
|
p++;
|
|
|
|
continue;
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
2001-06-06 03:26:22 +08:00
|
|
|
if (c == pr) {
|
|
|
|
if (--lvl <= 0) return --p;
|
|
|
|
} else if (c == pl)
|
|
|
|
lvl++;
|
|
|
|
}
|
|
|
|
return (const char *)NULL;
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
|
|
|
|
2000-09-30 03:50:29 +08:00
|
|
|
/**
|
|
|
|
* Pre-print macro expression to be expanded.
|
|
|
|
* @param mb macro expansion state
|
|
|
|
* @param s current expansion string
|
|
|
|
* @param se end of string
|
|
|
|
*/
|
1998-07-09 01:50:48 +08:00
|
|
|
static void
|
2001-06-06 03:26:22 +08:00
|
|
|
printMacro(MacroBuf mb, const char * s, const char * se)
|
1998-07-09 01:50:48 +08:00
|
|
|
{
|
2001-06-06 03:26:22 +08:00
|
|
|
const char *senl;
|
|
|
|
const char *ellipsis;
|
|
|
|
int choplen;
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2001-06-06 03:26:22 +08:00
|
|
|
if (s >= se) { /* XXX just in case */
|
|
|
|
fprintf(stderr, _("%3d>%*s(empty)"), mb->depth,
|
|
|
|
(2 * mb->depth + 1), "");
|
|
|
|
return;
|
|
|
|
}
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2001-06-06 03:26:22 +08:00
|
|
|
if (s[-1] == '{')
|
|
|
|
s--;
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2001-06-06 03:26:22 +08:00
|
|
|
/* Print only to first end-of-line (or end-of-string). */
|
|
|
|
for (senl = se; *senl && !iseol(*senl); senl++)
|
|
|
|
{};
|
|
|
|
|
|
|
|
/* 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");
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
|
|
|
|
2000-09-30 03:50:29 +08:00
|
|
|
/**
|
|
|
|
* Post-print expanded macro expression.
|
|
|
|
* @param mb macro expansion state
|
|
|
|
* @param t current expansion string result
|
|
|
|
* @param te end of string
|
|
|
|
*/
|
1998-07-09 01:50:48 +08:00
|
|
|
static void
|
2001-06-06 03:26:22 +08:00
|
|
|
printExpansion(MacroBuf mb, const char * t, const char * te)
|
1998-07-09 01:50:48 +08:00
|
|
|
{
|
2001-06-06 03:26:22 +08:00
|
|
|
const char *ellipsis;
|
|
|
|
int choplen;
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2001-06-06 03:26:22 +08:00
|
|
|
if (!(te > t)) {
|
2010-07-13 19:35:22 +08:00
|
|
|
rpmlog(RPMLOG_DEBUG, _("%3d<%*s(empty)\n"), mb->depth, (2 * mb->depth + 1), "");
|
2001-06-06 03:26:22 +08:00
|
|
|
return;
|
|
|
|
}
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2001-06-06 03:26:22 +08:00
|
|
|
/* Shorten output which contains newlines */
|
|
|
|
while (te > t && iseol(te[-1]))
|
|
|
|
te--;
|
|
|
|
ellipsis = "";
|
|
|
|
if (mb->depth > 0) {
|
|
|
|
const char *tenl;
|
|
|
|
|
|
|
|
/* Skip to last line of expansion */
|
|
|
|
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 = "...";
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
2001-06-06 03:26:22 +08:00
|
|
|
}
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2010-07-13 19:35:22 +08:00
|
|
|
rpmlog(RPMLOG_DEBUG,"%3d<%*s", mb->depth, (2 * mb->depth + 1), "");
|
2001-06-06 03:26:22 +08:00
|
|
|
if (te > t)
|
2010-07-13 19:35:22 +08:00
|
|
|
rpmlog(RPMLOG_DEBUG, "%.*s%s", (int)(te - t), t, ellipsis);
|
|
|
|
rpmlog(RPMLOG_DEBUG, "\n");
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
#define SKIPBLANK(_s, _c) \
|
|
|
|
while (((_c) = *(_s)) && isblank(_c)) \
|
2002-06-22 02:00:50 +08:00
|
|
|
(_s)++; \
|
1998-07-09 01:50:48 +08:00
|
|
|
|
|
|
|
#define SKIPNONBLANK(_s, _c) \
|
1999-08-17 02:57:37 +08:00
|
|
|
while (((_c) = *(_s)) && !(isblank(_c) || iseol(_c))) \
|
2002-06-22 02:00:50 +08:00
|
|
|
(_s)++; \
|
1998-07-09 01:50:48 +08:00
|
|
|
|
|
|
|
#define COPYNAME(_ne, _s, _c) \
|
|
|
|
{ SKIPBLANK(_s,_c); \
|
2008-03-18 15:10:13 +08:00
|
|
|
while(((_c) = *(_s)) && (risalnum(_c) || (_c) == '_')) \
|
1998-07-09 01:50:48 +08:00
|
|
|
*(_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) \
|
2007-09-12 01:23:32 +08:00
|
|
|
{ \
|
2002-06-24 03:47:08 +08:00
|
|
|
while(((_c) = *(_s)) && (_c) != ')') \
|
1998-07-09 01:50:48 +08:00
|
|
|
*(_oe)++ = *(_s)++; \
|
|
|
|
*(_oe) = '\0'; \
|
1997-03-31 22:13:21 +08:00
|
|
|
}
|
|
|
|
|
2000-09-30 03:50:29 +08:00
|
|
|
/**
|
2010-09-27 21:03:56 +08:00
|
|
|
* Macro-expand string src, return result in dynamically allocated buffer.
|
2000-09-30 03:50:29 +08:00
|
|
|
* @param mb macro expansion state
|
2010-09-27 21:03:56 +08:00
|
|
|
* @param src string to expand
|
|
|
|
* @param slen input string length (or 0 for strlen())
|
|
|
|
* @retval target pointer to expanded string (malloced)
|
2000-09-30 03:50:29 +08:00
|
|
|
* @return result of expansion
|
|
|
|
*/
|
1998-07-09 01:50:48 +08:00
|
|
|
static int
|
2010-09-27 21:03:56 +08:00
|
|
|
expandThis(MacroBuf mb, const char * src, size_t slen, char **target)
|
1998-07-09 01:50:48 +08:00
|
|
|
{
|
2010-09-27 19:22:56 +08:00
|
|
|
struct MacroBuf_s umb;
|
2001-06-06 03:26:22 +08:00
|
|
|
int rc;
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2010-09-27 19:22:56 +08:00
|
|
|
/* Copy other state from "parent", but we want a buffer of our own */
|
|
|
|
umb = *mb;
|
|
|
|
umb.buf = NULL;
|
2010-09-27 22:15:15 +08:00
|
|
|
rc = expandMacro(&umb, src, slen);
|
2010-09-27 21:03:56 +08:00
|
|
|
*target = umb.buf;
|
2008-02-01 18:11:03 +08:00
|
|
|
|
2001-06-06 03:26:22 +08:00
|
|
|
return rc;
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
|
|
|
|
2010-09-27 19:05:37 +08:00
|
|
|
static void mbAppend(MacroBuf mb, char c)
|
|
|
|
{
|
|
|
|
if (mb->nb < 1) {
|
2012-05-10 16:28:39 +08:00
|
|
|
mb->buf = xrealloc(mb->buf, mb->tpos + MACROBUFSIZ + 1);
|
2010-09-27 19:05:37 +08:00
|
|
|
mb->nb += MACROBUFSIZ;
|
|
|
|
}
|
|
|
|
mb->buf[mb->tpos++] = c;
|
2012-05-10 16:49:24 +08:00
|
|
|
mb->buf[mb->tpos] = '\0';
|
2010-09-27 19:05:37 +08:00
|
|
|
mb->nb--;
|
|
|
|
}
|
|
|
|
|
2010-09-27 21:32:15 +08:00
|
|
|
static void mbAppendStr(MacroBuf mb, const char *str)
|
|
|
|
{
|
|
|
|
size_t len = strlen(str);
|
|
|
|
if (len > mb->nb) {
|
2012-05-10 16:28:39 +08:00
|
|
|
mb->buf = xrealloc(mb->buf, mb->tpos + mb->nb + MACROBUFSIZ + len + 1);
|
2010-09-27 21:32:15 +08:00
|
|
|
mb->nb += MACROBUFSIZ + len;
|
|
|
|
}
|
2012-05-10 16:49:24 +08:00
|
|
|
memcpy(mb->buf+mb->tpos, str, len + 1);
|
2010-09-27 21:32:15 +08:00
|
|
|
mb->tpos += len;
|
|
|
|
mb->nb -= len;
|
|
|
|
}
|
2000-09-30 03:50:29 +08:00
|
|
|
/**
|
|
|
|
* Expand output of shell command into target buffer.
|
|
|
|
* @param mb macro expansion state
|
|
|
|
* @param cmd shell command
|
|
|
|
* @param clen no. bytes in shell command
|
|
|
|
* @return result of expansion
|
|
|
|
*/
|
1998-07-09 01:50:48 +08:00
|
|
|
static int
|
2001-06-06 03:26:22 +08:00
|
|
|
doShellEscape(MacroBuf mb, const char * cmd, size_t clen)
|
1998-07-09 01:50:48 +08:00
|
|
|
{
|
2010-09-27 21:03:56 +08:00
|
|
|
char *buf = NULL;
|
2001-06-06 03:26:22 +08:00
|
|
|
FILE *shf;
|
2008-02-01 19:00:40 +08:00
|
|
|
int rc = 0;
|
2001-06-06 03:26:22 +08:00
|
|
|
int c;
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2010-09-27 21:03:56 +08:00
|
|
|
rc = expandThis(mb, cmd, clen, &buf);
|
2001-06-06 03:26:22 +08:00
|
|
|
if (rc)
|
2008-02-01 19:00:40 +08:00
|
|
|
goto exit;
|
2001-06-06 03:26:22 +08:00
|
|
|
|
2008-02-01 19:00:40 +08:00
|
|
|
if ((shf = popen(buf, "r")) == NULL) {
|
|
|
|
rc = 1;
|
|
|
|
goto exit;
|
|
|
|
}
|
2013-02-07 11:44:41 +08:00
|
|
|
|
|
|
|
size_t tpos = mb->tpos;
|
2008-02-01 17:09:13 +08:00
|
|
|
while((c = fgetc(shf)) != EOF) {
|
2010-09-27 19:05:37 +08:00
|
|
|
mbAppend(mb, c);
|
2008-02-01 17:09:13 +08:00
|
|
|
}
|
2001-06-06 03:26:22 +08:00
|
|
|
(void) pclose(shf);
|
|
|
|
|
2013-02-07 11:44:41 +08:00
|
|
|
/* Delete trailing \r \n */
|
|
|
|
while (mb->tpos > tpos && iseol(mb->buf[mb->tpos-1])) {
|
|
|
|
mb->buf[--mb->tpos] = '\0';
|
2001-06-06 03:26:22 +08:00
|
|
|
mb->nb++;
|
|
|
|
}
|
2008-02-01 19:00:40 +08:00
|
|
|
|
|
|
|
exit:
|
|
|
|
_free(buf);
|
|
|
|
return rc;
|
1997-03-31 22:13:21 +08:00
|
|
|
}
|
|
|
|
|
2000-09-30 03:50:29 +08:00
|
|
|
/**
|
|
|
|
* Parse (and execute) new macro definition.
|
|
|
|
* @param mb macro expansion state
|
|
|
|
* @param se macro definition to parse
|
|
|
|
* @param level macro recursion level
|
|
|
|
* @param expandbody should body be expanded?
|
|
|
|
* @return address to continue parsing
|
|
|
|
*/
|
2007-09-11 22:48:54 +08:00
|
|
|
static const char *
|
|
|
|
doDefine(MacroBuf mb, const char * se, int level, int expandbody)
|
1997-03-31 22:13:21 +08:00
|
|
|
{
|
2001-06-06 03:26:22 +08:00
|
|
|
const char *s = se;
|
2008-02-01 19:00:40 +08:00
|
|
|
size_t blen = MACROBUFSIZ;
|
|
|
|
char *buf = xmalloc(blen);
|
|
|
|
char *n = buf, *ne = n;
|
2001-06-06 03:26:22 +08:00
|
|
|
char *o = NULL, *oe;
|
2010-09-27 21:03:56 +08:00
|
|
|
char *b, *be, *ebody = NULL;
|
2001-06-06 03:26:22 +08:00
|
|
|
int c;
|
|
|
|
int oc = ')';
|
2013-01-19 20:11:11 +08:00
|
|
|
const char *sbody; /* as-is body start */
|
2001-06-06 03:26:22 +08:00
|
|
|
|
|
|
|
/* Copy name */
|
|
|
|
COPYNAME(ne, s, c);
|
|
|
|
|
|
|
|
/* Copy opts (if present) */
|
|
|
|
oe = ne + 1;
|
|
|
|
if (*s == '(') {
|
|
|
|
s++; /* skip ( */
|
|
|
|
o = oe;
|
|
|
|
COPYOPTS(oe, s, oc);
|
|
|
|
s++; /* skip ) */
|
|
|
|
}
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2001-06-06 03:26:22 +08:00
|
|
|
/* Copy body, skipping over escaped newlines */
|
|
|
|
b = be = oe + 1;
|
2013-01-19 20:11:11 +08:00
|
|
|
sbody = s;
|
2001-06-06 03:26:22 +08:00
|
|
|
SKIPBLANK(s, c);
|
|
|
|
if (c == '{') { /* XXX permit silent {...} grouping */
|
|
|
|
if ((se = matchchar(s, c, '}')) == NULL) {
|
2007-11-19 22:25:24 +08:00
|
|
|
rpmlog(RPMLOG_ERR,
|
2001-06-06 03:26:22 +08:00
|
|
|
_("Macro %%%s has unterminated body\n"), n);
|
|
|
|
se = s; /* XXX W2DO? */
|
2011-03-17 21:35:42 +08:00
|
|
|
goto exit;
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
2001-06-06 03:26:22 +08:00
|
|
|
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 */
|
2004-04-09 04:27:53 +08:00
|
|
|
int bc = 0, pc = 0;
|
|
|
|
while (*s && (bc || pc || !iseol(*s))) {
|
|
|
|
switch (*s) {
|
|
|
|
case '\\':
|
|
|
|
switch (*(s+1)) {
|
2007-09-11 22:48:54 +08:00
|
|
|
case '\0': break;
|
|
|
|
default: s++; break;
|
2004-04-09 04:27:53 +08:00
|
|
|
}
|
2007-09-11 22:48:54 +08:00
|
|
|
break;
|
2004-04-09 04:27:53 +08:00
|
|
|
case '%':
|
|
|
|
switch (*(s+1)) {
|
2007-09-11 22:48:54 +08:00
|
|
|
case '{': *be++ = *s++; bc++; break;
|
|
|
|
case '(': *be++ = *s++; pc++; break;
|
|
|
|
case '%': *be++ = *s++; break;
|
2004-04-09 04:27:53 +08:00
|
|
|
}
|
2007-09-11 22:48:54 +08:00
|
|
|
break;
|
|
|
|
case '{': if (bc > 0) bc++; break;
|
|
|
|
case '}': if (bc > 0) bc--; break;
|
|
|
|
case '(': if (pc > 0) pc++; break;
|
|
|
|
case ')': if (pc > 0) pc--; break;
|
2004-04-09 04:27:53 +08:00
|
|
|
}
|
|
|
|
*be++ = *s++;
|
|
|
|
}
|
|
|
|
*be = '\0';
|
|
|
|
|
|
|
|
if (bc || pc) {
|
2007-11-19 22:25:24 +08:00
|
|
|
rpmlog(RPMLOG_ERR,
|
2004-04-09 04:27:53 +08:00
|
|
|
_("Macro %%%s has unterminated body\n"), n);
|
|
|
|
se = s; /* XXX W2DO? */
|
2011-03-17 21:35:42 +08:00
|
|
|
goto exit;
|
2004-04-09 04:27:53 +08:00
|
|
|
}
|
|
|
|
|
2001-06-06 03:26:22 +08:00
|
|
|
/* Trim trailing blanks/newlines */
|
|
|
|
while (--be >= b && (c = *be) && (isblank(c) || iseol(c)))
|
|
|
|
{};
|
|
|
|
*(++be) = '\0'; /* one too far */
|
|
|
|
}
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2001-06-06 03:26:22 +08:00
|
|
|
/* Move scan over body */
|
|
|
|
while (iseol(*s))
|
|
|
|
s++;
|
|
|
|
se = s;
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2001-06-06 03:26:22 +08:00
|
|
|
/* Names must start with alphabetic or _ and be at least 3 chars */
|
2008-03-18 15:10:13 +08:00
|
|
|
if (!((c = *n) && (risalpha(c) || c == '_') && (ne - n) > 2)) {
|
2007-11-19 22:25:24 +08:00
|
|
|
rpmlog(RPMLOG_ERR,
|
2001-06-06 03:26:22 +08:00
|
|
|
_("Macro %%%s has illegal name (%%define)\n"), n);
|
2011-03-17 21:35:42 +08:00
|
|
|
goto exit;
|
2001-06-06 03:26:22 +08:00
|
|
|
}
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2001-06-06 03:26:22 +08:00
|
|
|
/* Options must be terminated with ')' */
|
|
|
|
if (o && oc != ')') {
|
2007-11-19 22:25:24 +08:00
|
|
|
rpmlog(RPMLOG_ERR, _("Macro %%%s has unterminated opts\n"), n);
|
2008-02-01 19:00:40 +08:00
|
|
|
goto exit;
|
2001-06-06 03:26:22 +08:00
|
|
|
}
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2001-06-06 03:26:22 +08:00
|
|
|
if ((be - b) < 1) {
|
2007-11-19 22:25:24 +08:00
|
|
|
rpmlog(RPMLOG_ERR, _("Macro %%%s has empty body\n"), n);
|
2008-02-01 19:00:40 +08:00
|
|
|
goto exit;
|
2001-06-06 03:26:22 +08:00
|
|
|
}
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2013-01-19 20:11:11 +08:00
|
|
|
if (!isblank(*sbody) && !(*sbody == '\\' && iseol(sbody[1])))
|
|
|
|
rpmlog(RPMLOG_WARNING, _("Macro %%%s needs whitespace before body\n"), n);
|
|
|
|
|
2010-09-27 21:03:56 +08:00
|
|
|
if (expandbody) {
|
|
|
|
if (expandThis(mb, b, 0, &ebody)) {
|
|
|
|
rpmlog(RPMLOG_ERR, _("Macro %%%s failed to expand\n"), n);
|
|
|
|
goto exit;
|
|
|
|
}
|
|
|
|
b = ebody;
|
2001-06-06 03:26:22 +08:00
|
|
|
}
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2001-06-06 03:26:22 +08:00
|
|
|
addMacro(mb->mc, n, o, b, (level - 1));
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2008-02-01 19:00:40 +08:00
|
|
|
exit:
|
|
|
|
_free(buf);
|
2010-09-27 21:03:56 +08:00
|
|
|
_free(ebody);
|
2002-06-22 02:00:50 +08:00
|
|
|
return se;
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
|
|
|
|
2000-09-30 03:50:29 +08:00
|
|
|
/**
|
|
|
|
* Parse (and execute) macro undefinition.
|
|
|
|
* @param mc macro context
|
|
|
|
* @param se macro name to undefine
|
|
|
|
* @return address to continue parsing
|
|
|
|
*/
|
2007-09-11 22:48:54 +08:00
|
|
|
static const char *
|
2007-09-20 20:52:03 +08:00
|
|
|
doUndefine(rpmMacroContext mc, const char * se)
|
1998-07-09 01:50:48 +08:00
|
|
|
{
|
2001-06-06 03:26:22 +08:00
|
|
|
const char *s = se;
|
2008-02-01 19:00:40 +08:00
|
|
|
char *buf = xmalloc(MACROBUFSIZ);
|
|
|
|
char *n = buf, *ne = n;
|
2001-06-06 03:26:22 +08:00
|
|
|
int c;
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2001-06-06 03:26:22 +08:00
|
|
|
COPYNAME(ne, s, c);
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2001-06-06 03:26:22 +08:00
|
|
|
/* Move scan over body */
|
|
|
|
while (iseol(*s))
|
|
|
|
s++;
|
|
|
|
se = s;
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2001-06-06 03:26:22 +08:00
|
|
|
/* Names must start with alphabetic or _ and be at least 3 chars */
|
2008-03-18 15:10:13 +08:00
|
|
|
if (!((c = *n) && (risalpha(c) || c == '_') && (ne - n) > 2)) {
|
2007-11-19 22:25:24 +08:00
|
|
|
rpmlog(RPMLOG_ERR,
|
2001-06-06 03:26:22 +08:00
|
|
|
_("Macro %%%s has illegal name (%%undefine)\n"), n);
|
2008-02-01 19:00:40 +08:00
|
|
|
goto exit;
|
2001-06-06 03:26:22 +08:00
|
|
|
}
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2001-06-06 03:26:22 +08:00
|
|
|
delMacro(mc, n);
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2008-02-01 19:00:40 +08:00
|
|
|
exit:
|
|
|
|
_free(buf);
|
2002-06-22 02:00:50 +08:00
|
|
|
return se;
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
|
|
|
|
2000-09-30 03:50:29 +08:00
|
|
|
/**
|
|
|
|
* Push new macro definition onto macro entry stack.
|
|
|
|
* @param mep address of macro entry slot
|
|
|
|
* @param n macro name
|
|
|
|
* @param o macro parameters (NULL if none)
|
|
|
|
* @param b macro body (NULL becomes "")
|
|
|
|
* @param level macro recursion level
|
|
|
|
*/
|
1998-07-09 01:50:48 +08:00
|
|
|
static void
|
2007-09-20 20:52:03 +08:00
|
|
|
pushMacro(rpmMacroEntry * mep,
|
2007-09-11 22:48:54 +08:00
|
|
|
const char * n, const char * o,
|
|
|
|
const char * b, int level)
|
1998-07-09 01:50:48 +08:00
|
|
|
{
|
2007-09-20 20:52:03 +08:00
|
|
|
rpmMacroEntry prev = (mep && *mep ? *mep : NULL);
|
|
|
|
rpmMacroEntry me = (rpmMacroEntry) xmalloc(sizeof(*me));
|
2001-05-04 05:00:18 +08:00
|
|
|
|
|
|
|
me->prev = prev;
|
|
|
|
me->name = (prev ? prev->name : xstrdup(n));
|
|
|
|
me->opts = (o ? xstrdup(o) : NULL);
|
|
|
|
me->body = xstrdup(b ? b : "");
|
|
|
|
me->used = 0;
|
|
|
|
me->level = level;
|
|
|
|
if (mep)
|
1998-07-09 01:50:48 +08:00
|
|
|
*mep = me;
|
2001-05-04 05:00:18 +08:00
|
|
|
else
|
|
|
|
me = _free(me);
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
|
|
|
|
2000-09-30 03:50:29 +08:00
|
|
|
/**
|
|
|
|
* Pop macro definition from macro entry stack.
|
|
|
|
* @param mep address of macro entry slot
|
|
|
|
*/
|
1998-07-09 01:50:48 +08:00
|
|
|
static void
|
2007-09-20 20:52:03 +08:00
|
|
|
popMacro(rpmMacroEntry * mep)
|
1998-07-09 01:50:48 +08:00
|
|
|
{
|
2011-05-31 16:38:38 +08:00
|
|
|
if (mep && *mep) {
|
|
|
|
rpmMacroEntry me = *mep;
|
|
|
|
|
|
|
|
/* restore previous definition of the macro */
|
|
|
|
*mep = me->prev;
|
|
|
|
|
|
|
|
/* name is shared between entries, only free if last of its kind */
|
|
|
|
if (me->prev == NULL)
|
|
|
|
free(me->name);
|
|
|
|
free(me->opts);
|
|
|
|
free(me->body);
|
|
|
|
|
|
|
|
memset(me, 0, sizeof(*me)); /* trash and burn */
|
|
|
|
free(me);
|
|
|
|
}
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
|
|
|
|
2000-09-30 03:50:29 +08:00
|
|
|
/**
|
|
|
|
* Free parsed arguments for parameterized macro.
|
|
|
|
* @param mb macro expansion state
|
|
|
|
*/
|
1998-07-09 01:50:48 +08:00
|
|
|
static void
|
2001-06-06 03:26:22 +08:00
|
|
|
freeArgs(MacroBuf mb)
|
1998-07-09 01:50:48 +08:00
|
|
|
{
|
2007-09-20 20:52:03 +08:00
|
|
|
rpmMacroContext mc = mb->mc;
|
2001-05-04 05:00:18 +08:00
|
|
|
int ndeleted = 0;
|
|
|
|
int i;
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2001-05-04 05:00:18 +08:00
|
|
|
if (mc == NULL || mc->macroTable == NULL)
|
|
|
|
return;
|
1999-08-17 00:18:25 +08:00
|
|
|
|
2001-05-04 05:00:18 +08:00
|
|
|
/* Delete dynamic macro definitions */
|
|
|
|
for (i = 0; i < mc->firstFree; i++) {
|
2007-09-20 20:52:03 +08:00
|
|
|
rpmMacroEntry *mep, me;
|
2001-05-04 05:00:18 +08:00
|
|
|
int skiptest = 0;
|
|
|
|
mep = &mc->macroTable[i];
|
|
|
|
me = *mep;
|
|
|
|
|
|
|
|
if (me == NULL) /* XXX this should never happen */
|
|
|
|
continue;
|
|
|
|
if (me->level < mb->depth)
|
|
|
|
continue;
|
|
|
|
if (strlen(me->name) == 1 && strchr("#*0", *me->name)) {
|
|
|
|
if (*me->name == '*' && me->used > 0)
|
|
|
|
skiptest = 1; /* XXX skip test for %# %* %0 */
|
|
|
|
} else if (!skiptest && me->used <= 0) {
|
1998-07-09 01:50:48 +08:00
|
|
|
#if NOTYET
|
2007-11-19 22:25:24 +08:00
|
|
|
rpmlog(RPMLOG_ERR,
|
2001-05-04 05:00:18 +08:00
|
|
|
_("Macro %%%s (%s) was not used below level %d\n"),
|
|
|
|
me->name, me->body, me->level);
|
1998-07-09 01:50:48 +08:00
|
|
|
#endif
|
|
|
|
}
|
2001-05-04 05:00:18 +08:00
|
|
|
popMacro(mep);
|
|
|
|
if (!(mep && *mep))
|
|
|
|
ndeleted++;
|
|
|
|
}
|
1999-08-17 00:18:25 +08:00
|
|
|
|
2001-05-04 05:00:18 +08:00
|
|
|
/* If any deleted macros, sort macro table */
|
|
|
|
if (ndeleted)
|
|
|
|
sortMacroTable(mc);
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
|
|
|
|
2000-09-30 03:50:29 +08:00
|
|
|
/**
|
|
|
|
* Parse arguments (to next new line) for parameterized macro.
|
2001-09-15 21:49:11 +08:00
|
|
|
* @todo Use popt rather than getopt to parse args.
|
2000-09-30 03:50:29 +08:00
|
|
|
* @param mb macro expansion state
|
|
|
|
* @param me macro entry slot
|
|
|
|
* @param se arguments to parse
|
|
|
|
* @param lastc stop parsing at lastc
|
|
|
|
* @return address to continue parsing
|
|
|
|
*/
|
2007-09-11 22:48:54 +08:00
|
|
|
static const char *
|
2007-09-20 20:52:03 +08:00
|
|
|
grabArgs(MacroBuf mb, const rpmMacroEntry me, const char * se,
|
2003-12-30 23:12:50 +08:00
|
|
|
const char * lastc)
|
1998-07-09 01:50:48 +08:00
|
|
|
{
|
2009-09-07 22:50:43 +08:00
|
|
|
const char *opts;
|
2008-04-18 19:54:58 +08:00
|
|
|
char *args = NULL;
|
|
|
|
ARGV_t argv = NULL;
|
1998-07-09 01:50:48 +08:00
|
|
|
int argc = 0;
|
|
|
|
int c;
|
|
|
|
|
2008-04-18 19:54:58 +08:00
|
|
|
/* Copy macro name as argv[0] */
|
|
|
|
argvAdd(&argv, me->name);
|
|
|
|
addMacro(mb->mc, "0", NULL, me->name, mb->depth);
|
1997-03-31 22:13:21 +08:00
|
|
|
|
2008-04-18 19:54:58 +08:00
|
|
|
/*
|
|
|
|
* Make a copy of se up to lastc string that we can pass to argvSplit().
|
2008-09-11 21:56:50 +08:00
|
|
|
* Append the results to main argv.
|
2008-04-18 19:54:58 +08:00
|
|
|
*/
|
|
|
|
{ ARGV_t av = NULL;
|
|
|
|
char *s = xcalloc((lastc-se)+1, sizeof(*s));
|
2008-07-16 14:40:10 +08:00
|
|
|
memcpy(s, se, (lastc-se));
|
|
|
|
|
2008-10-19 06:53:03 +08:00
|
|
|
argvSplit(&av, s, " \t");
|
2008-04-18 19:54:58 +08:00
|
|
|
argvAppend(&argv, av);
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2008-04-18 19:54:58 +08:00
|
|
|
argvFree(av);
|
|
|
|
free(s);
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
2001-09-15 21:49:11 +08:00
|
|
|
|
2008-04-18 19:54:58 +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 %{**} ...
|
|
|
|
*/
|
|
|
|
args = argvJoin(argv + 1, " ");
|
|
|
|
addMacro(mb->mc, "**", NULL, args, mb->depth);
|
|
|
|
free(args);
|
|
|
|
|
|
|
|
/*
|
|
|
|
* POSIX states optind must be 1 before any call but glibc uses 0
|
|
|
|
* to (re)initialize getopt structures, eww.
|
|
|
|
*/
|
2001-09-15 21:49:11 +08:00
|
|
|
#ifdef __GLIBC__
|
2008-04-18 19:54:58 +08:00
|
|
|
optind = 0;
|
2003-12-27 09:37:56 +08:00
|
|
|
#else
|
|
|
|
optind = 1;
|
2001-09-15 21:49:11 +08:00
|
|
|
#endif
|
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
opts = me->opts;
|
2008-04-18 19:54:58 +08:00
|
|
|
argc = argvCount(argv);
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2000-06-22 07:28:50 +08:00
|
|
|
/* Define option macros. */
|
2007-12-19 18:49:52 +08:00
|
|
|
while((c = getopt(argc, argv, opts)) != -1)
|
2003-04-02 06:20:45 +08:00
|
|
|
{
|
2008-04-18 19:54:58 +08:00
|
|
|
char *name = NULL, *body = NULL;
|
2009-09-07 22:50:43 +08:00
|
|
|
if (c == '?' || strchr(opts, c) == NULL) {
|
2007-11-19 22:25:24 +08:00
|
|
|
rpmlog(RPMLOG_ERR, _("Unknown option %c in %s(%s)\n"),
|
2012-12-17 20:58:44 +08:00
|
|
|
(char)optopt, me->name, opts);
|
2008-02-01 19:00:40 +08:00
|
|
|
goto exit;
|
1997-03-31 22:13:21 +08:00
|
|
|
}
|
2008-04-18 20:15:05 +08:00
|
|
|
|
|
|
|
rasprintf(&name, "-%c", c);
|
2008-04-18 19:54:58 +08:00
|
|
|
if (optarg) {
|
|
|
|
rasprintf(&body, "-%c %s", c, optarg);
|
|
|
|
} else {
|
|
|
|
rasprintf(&body, "-%c", c);
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
2008-04-18 19:54:58 +08:00
|
|
|
addMacro(mb->mc, name, NULL, body, mb->depth);
|
|
|
|
free(name);
|
2008-04-18 20:15:05 +08:00
|
|
|
free(body);
|
2008-04-18 19:54:58 +08:00
|
|
|
|
|
|
|
if (optarg) {
|
|
|
|
rasprintf(&name, "-%c*", c);
|
|
|
|
addMacro(mb->mc, name, NULL, optarg, mb->depth);
|
|
|
|
free(name);
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
1998-05-21 01:05:26 +08:00
|
|
|
}
|
1997-03-31 22:13:21 +08:00
|
|
|
|
2008-04-18 19:54:58 +08:00
|
|
|
/* Add argument count (remaining non-option items) as macro. */
|
|
|
|
{ char *ac = NULL;
|
|
|
|
rasprintf(&ac, "%d", (argc - optind));
|
|
|
|
addMacro(mb->mc, "#", NULL, ac, mb->depth);
|
|
|
|
free(ac);
|
|
|
|
}
|
2000-06-22 07:28:50 +08:00
|
|
|
|
2008-04-18 19:54:58 +08:00
|
|
|
/* Add macro for each argument */
|
|
|
|
if (argc - optind) {
|
2001-05-04 05:00:18 +08:00
|
|
|
for (c = optind; c < argc; c++) {
|
2008-04-18 19:54:58 +08:00
|
|
|
char *name = NULL;
|
|
|
|
rasprintf(&name, "%d", (c - optind + 1));
|
|
|
|
addMacro(mb->mc, name, NULL, argv[c], mb->depth);
|
|
|
|
free(name);
|
2001-05-04 05:00:18 +08:00
|
|
|
}
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
1999-04-21 06:45:52 +08:00
|
|
|
|
2008-04-18 19:54:58 +08:00
|
|
|
/* Add concatenated unexpanded arguments as yet another macro. */
|
|
|
|
args = argvJoin(argv + optind, " ");
|
|
|
|
addMacro(mb->mc, "*", NULL, args ? args : "", mb->depth);
|
|
|
|
free(args);
|
1999-04-21 06:45:52 +08:00
|
|
|
|
2008-02-01 19:00:40 +08:00
|
|
|
exit:
|
2008-04-18 19:54:58 +08:00
|
|
|
argvFree(argv);
|
2008-09-11 21:56:50 +08:00
|
|
|
return *lastc ? lastc + 1 : lastc;
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
1997-03-31 22:13:21 +08:00
|
|
|
|
2000-09-30 03:50:29 +08:00
|
|
|
/**
|
|
|
|
* Perform macro message output
|
|
|
|
* @param mb macro expansion state
|
2007-10-09 19:06:06 +08:00
|
|
|
* @param waserror use rpmlog()?
|
2000-09-30 03:50:29 +08:00
|
|
|
* @param msg message to ouput
|
|
|
|
* @param msglen no. of bytes in message
|
|
|
|
*/
|
1998-07-09 01:50:48 +08:00
|
|
|
static void
|
2001-06-06 03:26:22 +08:00
|
|
|
doOutput(MacroBuf mb, int waserror, const char * msg, size_t msglen)
|
1998-01-13 05:31:29 +08:00
|
|
|
{
|
2010-09-27 21:03:56 +08:00
|
|
|
char *buf = NULL;
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2010-09-27 21:03:56 +08:00
|
|
|
(void) expandThis(mb, msg, msglen, &buf);
|
2001-06-06 03:26:22 +08:00
|
|
|
if (waserror)
|
2007-11-19 22:25:24 +08:00
|
|
|
rpmlog(RPMLOG_ERR, "%s\n", buf);
|
2001-06-06 03:26:22 +08:00
|
|
|
else
|
|
|
|
fprintf(stderr, "%s", buf);
|
2008-02-01 19:00:40 +08:00
|
|
|
_free(buf);
|
1998-01-13 05:31:29 +08:00
|
|
|
}
|
|
|
|
|
2000-09-30 03:50:29 +08:00
|
|
|
/**
|
|
|
|
* Execute macro primitives.
|
|
|
|
* @param mb macro expansion state
|
|
|
|
* @param negate should logic be inverted?
|
|
|
|
* @param f beginning of field f
|
|
|
|
* @param fn length of field f
|
|
|
|
* @param g beginning of field g
|
|
|
|
* @param gn length of field g
|
|
|
|
*/
|
1998-07-09 01:50:48 +08:00
|
|
|
static void
|
2001-06-06 03:26:22 +08:00
|
|
|
doFoo(MacroBuf mb, int negate, const char * f, size_t fn,
|
2007-09-11 22:48:54 +08:00
|
|
|
const char * g, size_t gn)
|
1997-03-31 22:13:21 +08:00
|
|
|
{
|
2010-09-27 21:03:56 +08:00
|
|
|
char *buf = NULL;
|
2008-02-01 19:00:40 +08:00
|
|
|
char *b = NULL, *be;
|
2001-06-06 03:26:22 +08:00
|
|
|
int c;
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2003-04-02 06:20:45 +08:00
|
|
|
if (g != NULL) {
|
2010-09-27 21:03:56 +08:00
|
|
|
(void) expandThis(mb, g, gn, &buf);
|
|
|
|
} else {
|
|
|
|
buf = xmalloc(MACROBUFSIZ + fn + gn);
|
|
|
|
buf[0] = '\0';
|
2001-06-06 03:26:22 +08:00
|
|
|
}
|
|
|
|
if (STREQ("basename", f, fn)) {
|
|
|
|
if ((b = strrchr(buf, '/')) == NULL)
|
|
|
|
b = buf;
|
2002-08-16 02:50:46 +08:00
|
|
|
else
|
|
|
|
b++;
|
2001-06-06 03:26:22 +08:00
|
|
|
} else if (STREQ("dirname", f, fn)) {
|
|
|
|
if ((b = strrchr(buf, '/')) != NULL)
|
|
|
|
*b = '\0';
|
|
|
|
b = buf;
|
|
|
|
} else if (STREQ("suffix", f, fn)) {
|
|
|
|
if ((b = strrchr(buf, '.')) != NULL)
|
|
|
|
b++;
|
|
|
|
} else if (STREQ("expand", f, fn)) {
|
|
|
|
b = buf;
|
|
|
|
} else if (STREQ("verbose", f, fn)) {
|
|
|
|
if (negate)
|
|
|
|
b = (rpmIsVerbose() ? NULL : buf);
|
|
|
|
else
|
|
|
|
b = (rpmIsVerbose() ? buf : NULL);
|
|
|
|
} else if (STREQ("url2path", f, fn) || STREQ("u2p", f, fn)) {
|
|
|
|
(void)urlPath(buf, (const char **)&b);
|
|
|
|
if (*b == '\0') b = "/";
|
|
|
|
} else if (STREQ("uncompress", f, fn)) {
|
|
|
|
rpmCompressedMagic compressed = COMPRESSED_OTHER;
|
|
|
|
for (b = buf; (c = *b) && isblank(c);)
|
|
|
|
b++;
|
|
|
|
for (be = b; (c = *be) && !isblank(c);)
|
|
|
|
be++;
|
|
|
|
*be++ = '\0';
|
2008-01-27 22:39:40 +08:00
|
|
|
(void) rpmFileIsCompressed(b, &compressed);
|
2001-06-06 03:26:22 +08:00
|
|
|
switch(compressed) {
|
|
|
|
default:
|
2007-10-09 16:02:49 +08:00
|
|
|
case COMPRESSED_NOT:
|
2008-01-23 13:56:51 +08:00
|
|
|
sprintf(be, "%%__cat %s", b);
|
2001-06-06 03:26:22 +08:00
|
|
|
break;
|
2007-10-09 16:02:49 +08:00
|
|
|
case COMPRESSED_OTHER:
|
2008-01-23 13:56:51 +08:00
|
|
|
sprintf(be, "%%__gzip -dc %s", b);
|
2001-06-06 03:26:22 +08:00
|
|
|
break;
|
2007-10-09 16:02:49 +08:00
|
|
|
case COMPRESSED_BZIP2:
|
2008-04-04 20:52:52 +08:00
|
|
|
sprintf(be, "%%__bzip2 -dc %s", b);
|
2001-06-06 03:26:22 +08:00
|
|
|
break;
|
2007-10-09 16:02:49 +08:00
|
|
|
case COMPRESSED_ZIP:
|
2008-01-23 13:56:51 +08:00
|
|
|
sprintf(be, "%%__unzip %s", b);
|
2001-06-06 03:26:22 +08:00
|
|
|
break;
|
2007-10-10 14:39:01 +08:00
|
|
|
case COMPRESSED_LZMA:
|
2009-03-27 20:11:43 +08:00
|
|
|
case COMPRESSED_XZ:
|
|
|
|
sprintf(be, "%%__xz -dc %s", b);
|
|
|
|
break;
|
2011-04-24 20:56:11 +08:00
|
|
|
case COMPRESSED_LZIP:
|
|
|
|
sprintf(be, "%%__lzip -dc %s", b);
|
|
|
|
break;
|
2011-04-24 20:57:23 +08:00
|
|
|
case COMPRESSED_LRZIP:
|
|
|
|
sprintf(be, "%%__lrzip -dqo- %s", b);
|
|
|
|
break;
|
2012-05-11 05:27:56 +08:00
|
|
|
case COMPRESSED_7ZIP:
|
|
|
|
sprintf(be, "%%__7zip x %s", b);
|
|
|
|
break;
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
2001-06-06 03:26:22 +08:00
|
|
|
b = be;
|
2009-01-16 15:09:40 +08:00
|
|
|
} else if (STREQ("getenv", f, fn)) {
|
|
|
|
b = getenv(buf);
|
2009-03-27 20:01:47 +08:00
|
|
|
} else if (STREQ("getconfdir", f, fn)) {
|
|
|
|
sprintf(buf, "%s", rpmConfigDir());
|
|
|
|
b = buf;
|
2001-06-06 03:26:22 +08:00
|
|
|
} else if (STREQ("S", f, fn)) {
|
2008-03-18 15:10:13 +08:00
|
|
|
for (b = buf; (c = *b) && risdigit(c);)
|
2001-06-06 03:26:22 +08:00
|
|
|
b++;
|
|
|
|
if (!c) { /* digit index */
|
|
|
|
b++;
|
|
|
|
sprintf(b, "%%SOURCE%s", buf);
|
|
|
|
} else
|
|
|
|
b = buf;
|
|
|
|
} else if (STREQ("P", f, fn)) {
|
2008-03-18 15:10:13 +08:00
|
|
|
for (b = buf; (c = *b) && risdigit(c);)
|
2001-06-06 03:26:22 +08:00
|
|
|
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);
|
|
|
|
}
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2001-06-06 03:26:22 +08:00
|
|
|
if (b) {
|
2010-09-27 22:15:15 +08:00
|
|
|
(void) expandMacro(mb, b, 0);
|
2001-06-06 03:26:22 +08:00
|
|
|
}
|
2008-04-29 22:04:08 +08:00
|
|
|
free(buf);
|
1997-03-31 22:13:21 +08:00
|
|
|
}
|
|
|
|
|
Stricter macro substitution syntax
This change introduces a separate routine to parse for valid macro
names. Valid macro names are either regular 3+ character identifiers,
or special names: "S", "P", "0", "#", "*", "**", macro options such as
"-o" and "-o*", and macro arguments such as "1". Other names are not
valid. This fixes a number of bugs seen earlier due to sloppy name
parsing: "%_libdir*" and "%01" were not expanded (these are now expanded
to e.g. "/usr/lib64*" and "<name>1", as expected). This also fixes
bugs in as-is substitution: "%!foo" was expanded to "%foo", and likewise
"%!!!" was expanded to "%" (and to "%<garbage>" at EOL).
Also, bad names in %name and %{name...} substitutions are now handled
differently. In %name form, the name is parsed tentatively; a silent
fall-back to as-is substitution is provisioned when no valid name can
be obtain. In %{name...} form, a failure to obtain a valid name is now
a syntax error. Furthermore, only 3 variants are syntactically valid:
%{name} proper, %{name:...}, and %{name ...}. This renders invalid
ambiguous macro substitutions such as the one found in FC18 lvm2.spec:
Requires: util-linux >= %{util-linux_version}
error: Invalid macro syntax: %{util-linux_version}
Signed-off-by: Panu Matilainen <pmatilai@redhat.com>
2013-01-21 04:45:30 +08:00
|
|
|
/**
|
|
|
|
* Parse for flags before macro name, such as in %{?!name:subst}.
|
|
|
|
* @param s macro flags start
|
|
|
|
* @param negate flipped by each '!' flag
|
|
|
|
* @param chkexist increased by each '?' flag
|
|
|
|
* @return macro flags end
|
|
|
|
*/
|
|
|
|
static const char *
|
|
|
|
parseMacroFlags(const char *s, int *negate, int *chkexist)
|
|
|
|
{
|
|
|
|
while (1) {
|
|
|
|
switch (*s) {
|
|
|
|
case '!':
|
|
|
|
*negate = !*negate;
|
|
|
|
s++;
|
|
|
|
break;
|
|
|
|
case '?':
|
|
|
|
(*chkexist)++;
|
|
|
|
s++;
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* not reached */
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Parse for valid macro name (during expansion).
|
|
|
|
* @param s macro name start
|
|
|
|
* @return macro name end, NULL on error
|
|
|
|
*/
|
|
|
|
static const char *
|
|
|
|
parseMacroName(const char *s)
|
|
|
|
{
|
|
|
|
/* alnum identifiers */
|
|
|
|
if (risalpha(*s) || *s == '_') {
|
|
|
|
const char *se = s + 1;
|
|
|
|
while (risalnum(*se) || *se == '_')
|
|
|
|
se++;
|
|
|
|
switch (se - s) {
|
|
|
|
case 1:
|
|
|
|
/* recheck for [SPF] */
|
|
|
|
break;
|
|
|
|
case 2:
|
|
|
|
return NULL;
|
|
|
|
default:
|
|
|
|
return se;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/* simple special names */
|
|
|
|
switch (*s) {
|
|
|
|
case '0':
|
|
|
|
case '#':
|
|
|
|
case 'S':
|
|
|
|
case 'P':
|
|
|
|
case 'F':
|
|
|
|
s++;
|
|
|
|
return s;
|
|
|
|
case '*':
|
|
|
|
s++;
|
|
|
|
if (*s == '*')
|
|
|
|
s++;
|
|
|
|
return s;
|
|
|
|
/* option names */
|
|
|
|
case '-':
|
|
|
|
s++;
|
|
|
|
if (risalnum(*s))
|
|
|
|
s++;
|
|
|
|
else
|
|
|
|
return NULL;
|
|
|
|
if (*s == '*')
|
|
|
|
s++;
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
/* argument names */
|
|
|
|
if (risdigit(*s)) {
|
|
|
|
s++;
|
|
|
|
while (risdigit(*s))
|
|
|
|
s++;
|
|
|
|
return s;
|
|
|
|
}
|
|
|
|
/* invalid macro name */
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2000-09-02 05:15:40 +08:00
|
|
|
/**
|
2000-09-30 03:50:29 +08:00
|
|
|
* The main macro recursion loop.
|
|
|
|
* @param mb macro expansion state
|
2010-09-24 15:42:38 +08:00
|
|
|
* @param src string to expand
|
2000-09-30 03:50:29 +08:00
|
|
|
* @return 0 on success, 1 on failure
|
2000-09-02 05:15:40 +08:00
|
|
|
*/
|
1998-07-09 01:50:48 +08:00
|
|
|
static int
|
2010-09-27 22:15:15 +08:00
|
|
|
expandMacro(MacroBuf mb, const char *src, size_t slen)
|
1997-03-31 22:13:21 +08:00
|
|
|
{
|
2007-09-20 20:52:03 +08:00
|
|
|
rpmMacroEntry *mep;
|
|
|
|
rpmMacroEntry me;
|
2010-09-24 15:42:38 +08:00
|
|
|
const char *s = src, *se;
|
1998-07-09 01:50:48 +08:00
|
|
|
const char *f, *fe;
|
|
|
|
const char *g, *ge;
|
2010-09-27 18:05:37 +08:00
|
|
|
size_t fn, gn, tpos;
|
1998-07-09 01:50:48 +08:00
|
|
|
int c;
|
|
|
|
int rc = 0;
|
|
|
|
int negate;
|
2003-12-30 23:12:50 +08:00
|
|
|
const char * lastc;
|
1998-09-06 07:13:35 +08:00
|
|
|
int chkexist;
|
2010-09-27 22:15:15 +08:00
|
|
|
char *source = NULL;
|
|
|
|
|
|
|
|
/* Handle non-terminated substrings by creating a terminated copy */
|
2011-05-18 14:04:40 +08:00
|
|
|
if (!slen)
|
|
|
|
slen = strlen(src);
|
|
|
|
source = xmalloc(slen + 1);
|
|
|
|
strncpy(source, src, slen);
|
|
|
|
source[slen] = '\0';
|
|
|
|
s = source;
|
1997-03-31 22:13:21 +08:00
|
|
|
|
2010-09-27 18:05:37 +08:00
|
|
|
if (mb->buf == NULL) {
|
2010-09-27 22:15:15 +08:00
|
|
|
size_t blen = MACROBUFSIZ + strlen(s);
|
2010-09-27 18:05:37 +08:00
|
|
|
mb->buf = xcalloc(blen + 1, sizeof(*mb->buf));
|
|
|
|
mb->tpos = 0;
|
|
|
|
mb->nb = blen;
|
|
|
|
}
|
|
|
|
tpos = mb->tpos; /* save expansion pointer for printExpand */
|
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
if (++mb->depth > max_macro_depth) {
|
2007-11-19 22:25:24 +08:00
|
|
|
rpmlog(RPMLOG_ERR,
|
2010-07-13 19:34:05 +08:00
|
|
|
_("Too many levels of recursion in macro expansion. It is likely caused by recursive macro declaration.\n"));
|
1998-07-09 01:50:48 +08:00
|
|
|
mb->depth--;
|
|
|
|
mb->expand_trace = 1;
|
2010-09-27 22:15:15 +08:00
|
|
|
_free(source);
|
1998-07-09 01:50:48 +08:00
|
|
|
return 1;
|
1997-03-31 22:13:21 +08:00
|
|
|
}
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2010-09-27 19:05:37 +08:00
|
|
|
while (rc == 0 && (c = *s) != '\0') {
|
1998-07-09 01:50:48 +08:00
|
|
|
s++;
|
|
|
|
/* Copy text until next macro */
|
|
|
|
switch(c) {
|
|
|
|
case '%':
|
2005-07-13 17:52:45 +08:00
|
|
|
if (*s) { /* Ensure not end-of-string. */
|
|
|
|
if (*s != '%')
|
2007-09-11 22:48:54 +08:00
|
|
|
break;
|
2005-07-13 17:52:45 +08:00
|
|
|
s++; /* skip first % in %% */
|
|
|
|
}
|
1998-07-09 01:50:48 +08:00
|
|
|
default:
|
2010-09-27 19:05:37 +08:00
|
|
|
mbAppend(mb, c);
|
1998-07-09 01:50:48 +08:00
|
|
|
continue;
|
2007-09-11 22:48:54 +08:00
|
|
|
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 */
|
2010-09-27 17:19:13 +08:00
|
|
|
tpos = mb->tpos; /* save expansion pointer for printExpand */
|
1998-07-09 01:50:48 +08:00
|
|
|
negate = 0;
|
2003-12-30 23:12:50 +08:00
|
|
|
lastc = NULL;
|
1998-09-06 07:13:35 +08:00
|
|
|
chkexist = 0;
|
1998-07-09 01:50:48 +08:00
|
|
|
switch ((c = *s)) {
|
|
|
|
default: /* %name substitution */
|
Stricter macro substitution syntax
This change introduces a separate routine to parse for valid macro
names. Valid macro names are either regular 3+ character identifiers,
or special names: "S", "P", "0", "#", "*", "**", macro options such as
"-o" and "-o*", and macro arguments such as "1". Other names are not
valid. This fixes a number of bugs seen earlier due to sloppy name
parsing: "%_libdir*" and "%01" were not expanded (these are now expanded
to e.g. "/usr/lib64*" and "<name>1", as expected). This also fixes
bugs in as-is substitution: "%!foo" was expanded to "%foo", and likewise
"%!!!" was expanded to "%" (and to "%<garbage>" at EOL).
Also, bad names in %name and %{name...} substitutions are now handled
differently. In %name form, the name is parsed tentatively; a silent
fall-back to as-is substitution is provisioned when no valid name can
be obtain. In %{name...} form, a failure to obtain a valid name is now
a syntax error. Furthermore, only 3 variants are syntactically valid:
%{name} proper, %{name:...}, and %{name ...}. This renders invalid
ambiguous macro substitutions such as the one found in FC18 lvm2.spec:
Requires: util-linux >= %{util-linux_version}
error: Invalid macro syntax: %{util-linux_version}
Signed-off-by: Panu Matilainen <pmatilai@redhat.com>
2013-01-21 04:45:30 +08:00
|
|
|
f = parseMacroFlags(s, &negate, &chkexist);
|
|
|
|
fe = parseMacroName(f);
|
|
|
|
/* no valid name? assume as-is substitution */
|
|
|
|
if (fe == NULL) {
|
|
|
|
mbAppend(mb, '%');
|
|
|
|
continue;
|
1999-07-29 20:36:03 +08:00
|
|
|
}
|
Stricter macro substitution syntax
This change introduces a separate routine to parse for valid macro
names. Valid macro names are either regular 3+ character identifiers,
or special names: "S", "P", "0", "#", "*", "**", macro options such as
"-o" and "-o*", and macro arguments such as "1". Other names are not
valid. This fixes a number of bugs seen earlier due to sloppy name
parsing: "%_libdir*" and "%01" were not expanded (these are now expanded
to e.g. "/usr/lib64*" and "<name>1", as expected). This also fixes
bugs in as-is substitution: "%!foo" was expanded to "%foo", and likewise
"%!!!" was expanded to "%" (and to "%<garbage>" at EOL).
Also, bad names in %name and %{name...} substitutions are now handled
differently. In %name form, the name is parsed tentatively; a silent
fall-back to as-is substitution is provisioned when no valid name can
be obtain. In %{name...} form, a failure to obtain a valid name is now
a syntax error. Furthermore, only 3 variants are syntactically valid:
%{name} proper, %{name:...}, and %{name ...}. This renders invalid
ambiguous macro substitutions such as the one found in FC18 lvm2.spec:
Requires: util-linux >= %{util-linux_version}
error: Invalid macro syntax: %{util-linux_version}
Signed-off-by: Panu Matilainen <pmatilai@redhat.com>
2013-01-21 04:45:30 +08:00
|
|
|
se = fe;
|
1998-07-09 01:50:48 +08:00
|
|
|
/* For "%name " macros ... */
|
|
|
|
if ((c = *fe) && isblank(c))
|
2003-12-30 23:12:50 +08:00
|
|
|
if ((lastc = strchr(fe,'\n')) == NULL)
|
|
|
|
lastc = strchr(fe, '\0');
|
2007-09-11 22:48:54 +08:00
|
|
|
break;
|
1998-07-09 01:50:48 +08:00
|
|
|
case '(': /* %(...) shell escape */
|
|
|
|
if ((se = matchchar(s, c, ')')) == NULL) {
|
2007-11-19 22:25:24 +08:00
|
|
|
rpmlog(RPMLOG_ERR,
|
2001-05-01 06:32:22 +08:00
|
|
|
_("Unterminated %c: %s\n"), (char)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;
|
2007-09-11 22:48:54 +08:00
|
|
|
break;
|
1998-07-09 01:50:48 +08:00
|
|
|
case '{': /* %{...}/%{...:...} substitution */
|
|
|
|
if ((se = matchchar(s, c, '}')) == NULL) {
|
2007-11-19 22:25:24 +08:00
|
|
|
rpmlog(RPMLOG_ERR,
|
2001-05-01 06:32:22 +08:00
|
|
|
_("Unterminated %c: %s\n"), (char)c, s);
|
1998-07-09 01:50:48 +08:00
|
|
|
rc = 1;
|
|
|
|
continue;
|
|
|
|
}
|
Stricter macro substitution syntax
This change introduces a separate routine to parse for valid macro
names. Valid macro names are either regular 3+ character identifiers,
or special names: "S", "P", "0", "#", "*", "**", macro options such as
"-o" and "-o*", and macro arguments such as "1". Other names are not
valid. This fixes a number of bugs seen earlier due to sloppy name
parsing: "%_libdir*" and "%01" were not expanded (these are now expanded
to e.g. "/usr/lib64*" and "<name>1", as expected). This also fixes
bugs in as-is substitution: "%!foo" was expanded to "%foo", and likewise
"%!!!" was expanded to "%" (and to "%<garbage>" at EOL).
Also, bad names in %name and %{name...} substitutions are now handled
differently. In %name form, the name is parsed tentatively; a silent
fall-back to as-is substitution is provisioned when no valid name can
be obtain. In %{name...} form, a failure to obtain a valid name is now
a syntax error. Furthermore, only 3 variants are syntactically valid:
%{name} proper, %{name:...}, and %{name ...}. This renders invalid
ambiguous macro substitutions such as the one found in FC18 lvm2.spec:
Requires: util-linux >= %{util-linux_version}
error: Invalid macro syntax: %{util-linux_version}
Signed-off-by: Panu Matilainen <pmatilai@redhat.com>
2013-01-21 04:45:30 +08:00
|
|
|
f = parseMacroFlags(s + 1 /* skip { */, &negate, &chkexist);
|
|
|
|
fe = parseMacroName(f);
|
1998-07-09 01:50:48 +08:00
|
|
|
se++; /* skip } */
|
Stricter macro substitution syntax
This change introduces a separate routine to parse for valid macro
names. Valid macro names are either regular 3+ character identifiers,
or special names: "S", "P", "0", "#", "*", "**", macro options such as
"-o" and "-o*", and macro arguments such as "1". Other names are not
valid. This fixes a number of bugs seen earlier due to sloppy name
parsing: "%_libdir*" and "%01" were not expanded (these are now expanded
to e.g. "/usr/lib64*" and "<name>1", as expected). This also fixes
bugs in as-is substitution: "%!foo" was expanded to "%foo", and likewise
"%!!!" was expanded to "%" (and to "%<garbage>" at EOL).
Also, bad names in %name and %{name...} substitutions are now handled
differently. In %name form, the name is parsed tentatively; a silent
fall-back to as-is substitution is provisioned when no valid name can
be obtain. In %{name...} form, a failure to obtain a valid name is now
a syntax error. Furthermore, only 3 variants are syntactically valid:
%{name} proper, %{name:...}, and %{name ...}. This renders invalid
ambiguous macro substitutions such as the one found in FC18 lvm2.spec:
Requires: util-linux >= %{util-linux_version}
error: Invalid macro syntax: %{util-linux_version}
Signed-off-by: Panu Matilainen <pmatilai@redhat.com>
2013-01-21 04:45:30 +08:00
|
|
|
/* no valid name? syntax error */
|
|
|
|
if (fe == NULL) {
|
|
|
|
rpmlog(RPMLOG_ERR,
|
|
|
|
_("Invalid macro name: %%%.*s\n"), (int)(se - s), s);
|
|
|
|
rc = 1;
|
|
|
|
continue;
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
Stricter macro substitution syntax
This change introduces a separate routine to parse for valid macro
names. Valid macro names are either regular 3+ character identifiers,
or special names: "S", "P", "0", "#", "*", "**", macro options such as
"-o" and "-o*", and macro arguments such as "1". Other names are not
valid. This fixes a number of bugs seen earlier due to sloppy name
parsing: "%_libdir*" and "%01" were not expanded (these are now expanded
to e.g. "/usr/lib64*" and "<name>1", as expected). This also fixes
bugs in as-is substitution: "%!foo" was expanded to "%foo", and likewise
"%!!!" was expanded to "%" (and to "%<garbage>" at EOL).
Also, bad names in %name and %{name...} substitutions are now handled
differently. In %name form, the name is parsed tentatively; a silent
fall-back to as-is substitution is provisioned when no valid name can
be obtain. In %{name...} form, a failure to obtain a valid name is now
a syntax error. Furthermore, only 3 variants are syntactically valid:
%{name} proper, %{name:...}, and %{name ...}. This renders invalid
ambiguous macro substitutions such as the one found in FC18 lvm2.spec:
Requires: util-linux >= %{util-linux_version}
error: Invalid macro syntax: %{util-linux_version}
Signed-off-by: Panu Matilainen <pmatilai@redhat.com>
2013-01-21 04:45:30 +08:00
|
|
|
switch (*fe) {
|
1999-07-29 20:36:03 +08:00
|
|
|
case ':':
|
1998-07-09 01:50:48 +08:00
|
|
|
g = fe + 1;
|
|
|
|
ge = se - 1;
|
2007-09-11 22:48:54 +08:00
|
|
|
break;
|
1999-07-29 20:36:03 +08:00
|
|
|
case ' ':
|
Stricter macro substitution syntax
This change introduces a separate routine to parse for valid macro
names. Valid macro names are either regular 3+ character identifiers,
or special names: "S", "P", "0", "#", "*", "**", macro options such as
"-o" and "-o*", and macro arguments such as "1". Other names are not
valid. This fixes a number of bugs seen earlier due to sloppy name
parsing: "%_libdir*" and "%01" were not expanded (these are now expanded
to e.g. "/usr/lib64*" and "<name>1", as expected). This also fixes
bugs in as-is substitution: "%!foo" was expanded to "%foo", and likewise
"%!!!" was expanded to "%" (and to "%<garbage>" at EOL).
Also, bad names in %name and %{name...} substitutions are now handled
differently. In %name form, the name is parsed tentatively; a silent
fall-back to as-is substitution is provisioned when no valid name can
be obtain. In %{name...} form, a failure to obtain a valid name is now
a syntax error. Furthermore, only 3 variants are syntactically valid:
%{name} proper, %{name:...}, and %{name ...}. This renders invalid
ambiguous macro substitutions such as the one found in FC18 lvm2.spec:
Requires: util-linux >= %{util-linux_version}
error: Invalid macro syntax: %{util-linux_version}
Signed-off-by: Panu Matilainen <pmatilai@redhat.com>
2013-01-21 04:45:30 +08:00
|
|
|
case '\t':
|
2003-12-30 23:12:50 +08:00
|
|
|
lastc = se-1;
|
2007-09-11 22:48:54 +08:00
|
|
|
break;
|
Stricter macro substitution syntax
This change introduces a separate routine to parse for valid macro
names. Valid macro names are either regular 3+ character identifiers,
or special names: "S", "P", "0", "#", "*", "**", macro options such as
"-o" and "-o*", and macro arguments such as "1". Other names are not
valid. This fixes a number of bugs seen earlier due to sloppy name
parsing: "%_libdir*" and "%01" were not expanded (these are now expanded
to e.g. "/usr/lib64*" and "<name>1", as expected). This also fixes
bugs in as-is substitution: "%!foo" was expanded to "%foo", and likewise
"%!!!" was expanded to "%" (and to "%<garbage>" at EOL).
Also, bad names in %name and %{name...} substitutions are now handled
differently. In %name form, the name is parsed tentatively; a silent
fall-back to as-is substitution is provisioned when no valid name can
be obtain. In %{name...} form, a failure to obtain a valid name is now
a syntax error. Furthermore, only 3 variants are syntactically valid:
%{name} proper, %{name:...}, and %{name ...}. This renders invalid
ambiguous macro substitutions such as the one found in FC18 lvm2.spec:
Requires: util-linux >= %{util-linux_version}
error: Invalid macro syntax: %{util-linux_version}
Signed-off-by: Panu Matilainen <pmatilai@redhat.com>
2013-01-21 04:45:30 +08:00
|
|
|
case '}':
|
2007-09-11 22:48:54 +08:00
|
|
|
break;
|
Stricter macro substitution syntax
This change introduces a separate routine to parse for valid macro
names. Valid macro names are either regular 3+ character identifiers,
or special names: "S", "P", "0", "#", "*", "**", macro options such as
"-o" and "-o*", and macro arguments such as "1". Other names are not
valid. This fixes a number of bugs seen earlier due to sloppy name
parsing: "%_libdir*" and "%01" were not expanded (these are now expanded
to e.g. "/usr/lib64*" and "<name>1", as expected). This also fixes
bugs in as-is substitution: "%!foo" was expanded to "%foo", and likewise
"%!!!" was expanded to "%" (and to "%<garbage>" at EOL).
Also, bad names in %name and %{name...} substitutions are now handled
differently. In %name form, the name is parsed tentatively; a silent
fall-back to as-is substitution is provisioned when no valid name can
be obtain. In %{name...} form, a failure to obtain a valid name is now
a syntax error. Furthermore, only 3 variants are syntactically valid:
%{name} proper, %{name:...}, and %{name ...}. This renders invalid
ambiguous macro substitutions such as the one found in FC18 lvm2.spec:
Requires: util-linux >= %{util-linux_version}
error: Invalid macro syntax: %{util-linux_version}
Signed-off-by: Panu Matilainen <pmatilai@redhat.com>
2013-01-21 04:45:30 +08:00
|
|
|
default:
|
|
|
|
rpmlog(RPMLOG_ERR,
|
|
|
|
_("Invalid macro syntax: %%%.*s\n"), (int)(se - s), s);
|
|
|
|
rc = 1;
|
|
|
|
continue;
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
2007-09-11 22:48:54 +08:00
|
|
|
break;
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
|
|
|
|
Stricter macro substitution syntax
This change introduces a separate routine to parse for valid macro
names. Valid macro names are either regular 3+ character identifiers,
or special names: "S", "P", "0", "#", "*", "**", macro options such as
"-o" and "-o*", and macro arguments such as "1". Other names are not
valid. This fixes a number of bugs seen earlier due to sloppy name
parsing: "%_libdir*" and "%01" were not expanded (these are now expanded
to e.g. "/usr/lib64*" and "<name>1", as expected). This also fixes
bugs in as-is substitution: "%!foo" was expanded to "%foo", and likewise
"%!!!" was expanded to "%" (and to "%<garbage>" at EOL).
Also, bad names in %name and %{name...} substitutions are now handled
differently. In %name form, the name is parsed tentatively; a silent
fall-back to as-is substitution is provisioned when no valid name can
be obtain. In %{name...} form, a failure to obtain a valid name is now
a syntax error. Furthermore, only 3 variants are syntactically valid:
%{name} proper, %{name:...}, and %{name ...}. This renders invalid
ambiguous macro substitutions such as the one found in FC18 lvm2.spec:
Requires: util-linux >= %{util-linux_version}
error: Invalid macro syntax: %{util-linux_version}
Signed-off-by: Panu Matilainen <pmatilai@redhat.com>
2013-01-21 04:45:30 +08:00
|
|
|
assert(fe > f);
|
1998-07-09 01:50:48 +08:00
|
|
|
fn = (fe - f);
|
|
|
|
gn = (ge - g);
|
|
|
|
|
|
|
|
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;
|
2003-04-02 06:20:45 +08:00
|
|
|
if (g != NULL && g < ge)
|
1998-07-09 01:50:48 +08:00
|
|
|
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-12-13 05:14:05 +08:00
|
|
|
rpmDumpMacroTable(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;
|
|
|
|
}
|
|
|
|
|
2004-10-10 01:29:22 +08:00
|
|
|
#ifdef WITH_LUA
|
2004-03-20 04:08:20 +08:00
|
|
|
if (STREQ("lua", f, fn)) {
|
2004-03-25 03:47:11 +08:00
|
|
|
rpmlua lua = NULL; /* Global state. */
|
2004-03-20 04:08:20 +08:00
|
|
|
const char *ls = s+sizeof("{lua:")-1;
|
|
|
|
const char *lse = se-sizeof("}")+1;
|
|
|
|
char *scriptbuf = (char *)xmalloc((lse-ls)+1);
|
2011-05-25 01:28:16 +08:00
|
|
|
char *printbuf;
|
2004-03-20 04:08:20 +08:00
|
|
|
memcpy(scriptbuf, ls, lse-ls);
|
|
|
|
scriptbuf[lse-ls] = '\0';
|
2011-05-25 01:28:16 +08:00
|
|
|
rpmluaPushPrintBuffer(lua);
|
2004-03-20 04:08:20 +08:00
|
|
|
if (rpmluaRunScript(lua, scriptbuf, NULL) == -1)
|
|
|
|
rc = 1;
|
2011-05-25 01:28:16 +08:00
|
|
|
printbuf = rpmluaPopPrintBuffer(lua);
|
2004-03-20 04:08:20 +08:00
|
|
|
if (printbuf) {
|
2010-09-27 21:32:15 +08:00
|
|
|
mbAppendStr(mb, printbuf);
|
2011-05-25 01:28:16 +08:00
|
|
|
free(printbuf);
|
2004-03-20 04:08:20 +08:00
|
|
|
}
|
|
|
|
free(scriptbuf);
|
|
|
|
s = se;
|
|
|
|
continue;
|
|
|
|
}
|
2004-10-10 01:29:22 +08:00
|
|
|
#endif
|
2004-03-20 04:08:20 +08:00
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
/* XXX necessary but clunky */
|
|
|
|
if (STREQ("basename", f, fn) ||
|
2012-11-01 18:09:30 +08:00
|
|
|
STREQ("dirname", f, fn) ||
|
1998-07-09 01:50:48 +08:00
|
|
|
STREQ("suffix", f, fn) ||
|
|
|
|
STREQ("expand", f, fn) ||
|
1999-11-20 02:19:41 +08:00
|
|
|
STREQ("verbose", f, fn) ||
|
1998-07-09 01:50:48 +08:00
|
|
|
STREQ("uncompress", f, fn) ||
|
1999-11-20 02:19:41 +08:00
|
|
|
STREQ("url2path", f, fn) ||
|
|
|
|
STREQ("u2p", f, fn) ||
|
2009-01-16 15:09:40 +08:00
|
|
|
STREQ("getenv", f, fn) ||
|
2009-03-27 20:01:47 +08:00
|
|
|
STREQ("getconfdir", f, fn) ||
|
1998-07-09 01:50:48 +08:00
|
|
|
STREQ("S", f, fn) ||
|
|
|
|
STREQ("P", f, fn) ||
|
|
|
|
STREQ("F", f, fn)) {
|
2007-09-11 22:48:54 +08:00
|
|
|
/* FIX: verbose may be set */
|
1999-11-20 02:19:41 +08:00
|
|
|
doFoo(mb, negate, f, fn, g, gn);
|
1998-07-09 01:50:48 +08:00
|
|
|
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} */
|
2010-09-27 22:15:15 +08:00
|
|
|
rc = expandMacro(mb, g, gn);
|
1998-07-09 01:50:48 +08:00
|
|
|
} else
|
2001-05-04 05:00:18 +08:00
|
|
|
if (me && me->body && *me->body) {/* Expand %{-f}/%{-f*} */
|
2010-09-27 22:15:15 +08:00
|
|
|
rc = expandMacro(mb, me->body, 0);
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
|
|
|
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} */
|
2010-09-27 22:15:15 +08:00
|
|
|
rc = expandMacro(mb, g, gn);
|
1998-09-06 07:13:35 +08:00
|
|
|
} else
|
2000-02-21 18:32:01 +08:00
|
|
|
if (me && me->body && *me->body) { /* Expand %{?f}/%{?f*} */
|
2010-09-27 22:15:15 +08:00
|
|
|
rc = expandMacro(mb, me->body, 0);
|
1998-09-06 07:13:35 +08:00
|
|
|
}
|
|
|
|
s = se;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
if (me == NULL) { /* leave unknown %... as is */
|
|
|
|
/* XXX hack to permit non-overloaded %foo to be passed */
|
|
|
|
c = '%'; /* XXX only need to save % */
|
2010-09-27 19:05:37 +08:00
|
|
|
mbAppend(mb, c);
|
1998-07-09 01:50:48 +08:00
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Setup args for "%name " macros with opts */
|
|
|
|
if (me && me->opts != NULL) {
|
2003-12-30 23:12:50 +08:00
|
|
|
if (lastc != NULL) {
|
|
|
|
se = grabArgs(mb, me, fe, lastc);
|
1999-07-29 20:36:03 +08:00
|
|
|
} 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) {
|
2010-09-27 22:15:15 +08:00
|
|
|
rc = expandMacro(mb, me->body, 0);
|
1999-03-28 08:47:40 +08:00
|
|
|
if (rc == 0)
|
|
|
|
me->used++; /* Mark macro as used */
|
|
|
|
}
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2010-01-07 18:04:53 +08:00
|
|
|
/* Free args for "%name " macros with opts */
|
|
|
|
if (me->opts != NULL)
|
|
|
|
freeArgs(mb);
|
1998-07-09 01:50:48 +08:00
|
|
|
|
|
|
|
s = se;
|
1997-03-31 22:13:21 +08:00
|
|
|
}
|
|
|
|
|
2010-09-27 17:19:13 +08:00
|
|
|
mb->buf[mb->tpos] = '\0';
|
1998-07-09 01:50:48 +08:00
|
|
|
mb->depth--;
|
|
|
|
if (rc != 0 || mb->expand_trace)
|
2010-09-27 17:19:13 +08:00
|
|
|
printExpansion(mb, mb->buf+tpos, mb->buf+mb->tpos);
|
2010-09-27 22:15:15 +08:00
|
|
|
_free(source);
|
1998-07-09 01:50:48 +08:00
|
|
|
return rc;
|
|
|
|
}
|
1997-03-31 22:13:21 +08:00
|
|
|
|
2004-03-02 09:31:01 +08:00
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
/* =============================================================== */
|
1999-03-28 08:47:40 +08:00
|
|
|
|
2010-09-24 17:48:15 +08:00
|
|
|
static int doExpandMacros(rpmMacroContext mc, const char *src, char **target)
|
1997-03-31 22:13:21 +08:00
|
|
|
{
|
2008-02-01 18:11:03 +08:00
|
|
|
MacroBuf mb = xcalloc(1, sizeof(*mb));
|
|
|
|
int rc = 0;
|
1997-03-31 22:13:21 +08:00
|
|
|
|
2001-10-15 11:22:10 +08:00
|
|
|
if (mc == NULL) mc = rpmGlobalMacroContext;
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2010-09-27 18:05:37 +08:00
|
|
|
mb->buf = NULL;
|
2001-06-06 03:26:22 +08:00
|
|
|
mb->depth = 0;
|
|
|
|
mb->macro_trace = print_macro_trace;
|
|
|
|
mb->expand_trace = print_expand_trace;
|
|
|
|
mb->mc = mc;
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2010-09-27 22:15:15 +08:00
|
|
|
rc = expandMacro(mb, src, 0);
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2010-09-27 18:05:37 +08:00
|
|
|
mb->buf[mb->tpos] = '\0'; /* XXX just in case */
|
2010-09-24 17:48:15 +08:00
|
|
|
/* expanded output is usually much less than alloced buffer, downsize */
|
2010-09-27 18:05:37 +08:00
|
|
|
*target = xrealloc(mb->buf, mb->tpos + 1);
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2008-02-01 18:11:03 +08:00
|
|
|
_free(mb);
|
2010-09-24 17:48:15 +08:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
|
|
|
int expandMacros(void * spec, rpmMacroContext mc, char * sbuf, size_t slen)
|
|
|
|
{
|
|
|
|
char *target = NULL;
|
|
|
|
int rc = doExpandMacros(mc, sbuf, &target);
|
|
|
|
rstrlcpy(sbuf, target, slen);
|
|
|
|
free(target);
|
2001-06-06 03:26:22 +08:00
|
|
|
return rc;
|
1997-03-31 22:13:21 +08:00
|
|
|
}
|
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
void
|
2007-09-20 20:52:03 +08:00
|
|
|
addMacro(rpmMacroContext mc,
|
2001-06-06 03:26:22 +08:00
|
|
|
const char * n, const char * o, const char * b, int level)
|
1997-03-31 22:13:21 +08:00
|
|
|
{
|
2007-09-20 20:52:03 +08:00
|
|
|
rpmMacroEntry * mep;
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2001-10-15 11:22:10 +08:00
|
|
|
if (mc == NULL) mc = rpmGlobalMacroContext;
|
1999-04-02 06:26:44 +08:00
|
|
|
|
2001-06-06 03:26:22 +08:00
|
|
|
/* If new name, expand macro table */
|
|
|
|
if ((mep = findEntry(mc, n, 0)) == NULL) {
|
|
|
|
if (mc->firstFree == mc->macrosAllocated)
|
|
|
|
expandMacroTable(mc);
|
|
|
|
if (mc->macroTable != NULL)
|
|
|
|
mep = mc->macroTable + mc->firstFree++;
|
|
|
|
}
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2001-06-06 03:26:22 +08:00
|
|
|
if (mep != NULL) {
|
1998-07-09 01:50:48 +08:00
|
|
|
/* Push macro over previous definition */
|
|
|
|
pushMacro(mep, n, o, b, level);
|
|
|
|
|
|
|
|
/* If new name, sort macro table */
|
|
|
|
if ((*mep)->prev == NULL)
|
2001-06-06 03:26:22 +08:00
|
|
|
sortMacroTable(mc);
|
|
|
|
}
|
1997-03-31 22:13:21 +08:00
|
|
|
}
|
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
void
|
2007-09-20 20:52:03 +08:00
|
|
|
delMacro(rpmMacroContext mc, const char * n)
|
1997-03-31 22:13:21 +08:00
|
|
|
{
|
2007-09-20 20:52:03 +08:00
|
|
|
rpmMacroEntry * mep;
|
2001-06-06 03:26:22 +08:00
|
|
|
|
2001-10-15 11:22:10 +08:00
|
|
|
if (mc == NULL) mc = rpmGlobalMacroContext;
|
2001-06-06 03:26:22 +08:00
|
|
|
/* If name exists, pop entry */
|
|
|
|
if ((mep = findEntry(mc, n, 0)) != NULL) {
|
|
|
|
popMacro(mep);
|
|
|
|
/* 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
|
2007-09-20 20:52:03 +08:00
|
|
|
rpmDefineMacro(rpmMacroContext mc, const char * macro, int level)
|
1999-03-28 08:47:40 +08:00
|
|
|
{
|
2008-02-01 18:11:03 +08:00
|
|
|
MacroBuf mb = xcalloc(1, sizeof(*mb));
|
2001-06-06 03:26:22 +08:00
|
|
|
|
|
|
|
/* XXX just enough to get by */
|
2001-10-15 11:22:10 +08:00
|
|
|
mb->mc = (mc ? mc : rpmGlobalMacroContext);
|
2001-10-19 09:24:21 +08:00
|
|
|
(void) doDefine(mb, macro, level, 0);
|
2008-02-01 18:11:03 +08:00
|
|
|
_free(mb);
|
2001-06-06 03:26:22 +08:00
|
|
|
return 0;
|
1999-03-28 08:47:40 +08:00
|
|
|
}
|
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
void
|
2007-09-20 20:52:03 +08:00
|
|
|
rpmLoadMacros(rpmMacroContext mc, int level)
|
1999-12-13 05:14:05 +08:00
|
|
|
{
|
|
|
|
|
2001-10-15 11:22:10 +08:00
|
|
|
if (mc == NULL || mc == rpmGlobalMacroContext)
|
2001-05-04 05:00:18 +08:00
|
|
|
return;
|
1999-12-13 05:14:05 +08:00
|
|
|
|
2001-05-04 05:00:18 +08:00
|
|
|
if (mc->macroTable != NULL) {
|
|
|
|
int i;
|
1999-12-13 05:14:05 +08:00
|
|
|
for (i = 0; i < mc->firstFree; i++) {
|
2007-09-20 20:52:03 +08:00
|
|
|
rpmMacroEntry *mep, me;
|
2001-05-04 05:00:18 +08:00
|
|
|
mep = &mc->macroTable[i];
|
|
|
|
me = *mep;
|
1999-12-13 05:14:05 +08:00
|
|
|
|
2001-05-04 05:00:18 +08:00
|
|
|
if (me == NULL) /* XXX this should never happen */
|
|
|
|
continue;
|
|
|
|
addMacro(NULL, me->name, me->opts, me->body, (level - 1));
|
1999-12-13 05:14:05 +08:00
|
|
|
}
|
2001-05-04 05:00:18 +08:00
|
|
|
}
|
1999-12-13 05:14:05 +08:00
|
|
|
}
|
|
|
|
|
2004-03-02 09:31:01 +08:00
|
|
|
int
|
2007-09-20 20:52:03 +08:00
|
|
|
rpmLoadMacroFile(rpmMacroContext mc, const char * fn)
|
2004-03-02 09:31:01 +08:00
|
|
|
{
|
2008-04-18 21:14:15 +08:00
|
|
|
FILE *fd = fopen(fn, "r");
|
2008-02-01 19:00:40 +08:00
|
|
|
size_t blen = MACROBUFSIZ;
|
|
|
|
char *buf = xmalloc(blen);
|
2004-03-02 09:31:01 +08:00
|
|
|
int rc = -1;
|
|
|
|
|
2011-05-18 15:59:54 +08:00
|
|
|
if (fd == NULL)
|
2008-02-01 19:00:40 +08:00
|
|
|
goto exit;
|
2004-03-02 09:31:01 +08:00
|
|
|
|
|
|
|
/* XXX Assume new fangled macro expansion */
|
|
|
|
max_macro_depth = 16;
|
|
|
|
|
2004-03-23 15:18:55 +08:00
|
|
|
buf[0] = '\0';
|
2008-02-01 19:00:40 +08:00
|
|
|
while(rdcl(buf, blen, fd) != NULL) {
|
2004-03-02 09:31:01 +08:00
|
|
|
char c, *n;
|
|
|
|
|
|
|
|
n = buf;
|
|
|
|
SKIPBLANK(n, c);
|
|
|
|
|
|
|
|
if (c != '%')
|
2004-03-23 15:18:55 +08:00
|
|
|
continue;
|
2004-03-02 09:31:01 +08:00
|
|
|
n++; /* skip % */
|
|
|
|
rc = rpmDefineMacro(mc, n, RMIL_MACROFILES);
|
|
|
|
}
|
2008-04-18 21:14:15 +08:00
|
|
|
rc = fclose(fd);
|
2008-02-01 19:00:40 +08:00
|
|
|
|
|
|
|
exit:
|
|
|
|
_free(buf);
|
2004-03-02 09:31:01 +08:00
|
|
|
return rc;
|
|
|
|
}
|
|
|
|
|
1999-12-13 05:14:05 +08:00
|
|
|
void
|
2007-09-20 20:52:03 +08:00
|
|
|
rpmInitMacros(rpmMacroContext mc, const char * macrofiles)
|
1998-07-09 01:50:48 +08:00
|
|
|
{
|
2008-04-19 21:42:56 +08:00
|
|
|
ARGV_t pattern, globs = NULL;
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2001-05-04 05:00:18 +08:00
|
|
|
if (macrofiles == NULL)
|
|
|
|
return;
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2008-04-19 21:42:56 +08:00
|
|
|
argvSplit(&globs, macrofiles, ":");
|
|
|
|
for (pattern = globs; *pattern; pattern++) {
|
|
|
|
ARGV_t path, files = NULL;
|
|
|
|
|
2004-03-02 09:31:01 +08:00
|
|
|
/* Glob expand the macro file path element, expanding ~ to $HOME. */
|
2008-04-19 21:42:56 +08:00
|
|
|
if (rpmGlob(*pattern, NULL, &files) != 0) {
|
2001-05-04 05:00:18 +08:00
|
|
|
continue;
|
2008-04-19 21:42:56 +08:00
|
|
|
}
|
1998-07-09 01:50:48 +08:00
|
|
|
|
2004-03-02 09:31:01 +08:00
|
|
|
/* Read macros from each file. */
|
2008-04-19 21:42:56 +08:00
|
|
|
for (path = files; *path; path++) {
|
|
|
|
if (rpmFileHasSuffix(*path, ".rpmnew") ||
|
|
|
|
rpmFileHasSuffix(*path, ".rpmsave") ||
|
|
|
|
rpmFileHasSuffix(*path, ".rpmorig")) {
|
2007-08-30 18:02:12 +08:00
|
|
|
continue;
|
|
|
|
}
|
2008-04-19 21:42:56 +08:00
|
|
|
(void) rpmLoadMacroFile(mc, *path);
|
2007-07-02 20:02:15 +08:00
|
|
|
}
|
2008-04-19 21:42:56 +08:00
|
|
|
argvFree(files);
|
2001-05-04 05:00:18 +08:00
|
|
|
}
|
2008-04-19 21:42:56 +08:00
|
|
|
argvFree(globs);
|
1999-12-13 05:14:05 +08:00
|
|
|
|
2001-05-04 05:00:18 +08:00
|
|
|
/* Reload cmdline macros */
|
2001-10-15 11:22:10 +08:00
|
|
|
rpmLoadMacros(rpmCLIMacroContext, RMIL_CMDLINE);
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
1998-01-13 05:31:29 +08:00
|
|
|
|
1998-07-09 01:50:48 +08:00
|
|
|
void
|
2007-09-20 20:52:03 +08:00
|
|
|
rpmFreeMacros(rpmMacroContext mc)
|
1998-01-13 05:31:29 +08:00
|
|
|
{
|
|
|
|
|
2001-10-15 11:22:10 +08:00
|
|
|
if (mc == NULL) mc = rpmGlobalMacroContext;
|
1999-04-02 06:26:44 +08:00
|
|
|
|
2001-05-04 05:00:18 +08:00
|
|
|
if (mc->macroTable != NULL) {
|
2011-05-31 15:38:17 +08:00
|
|
|
for (int i = 0; i < mc->firstFree; i++) {
|
|
|
|
while (mc->macroTable[i] != NULL) {
|
|
|
|
popMacro(&mc->macroTable[i]);
|
2001-05-04 05:00:18 +08:00
|
|
|
}
|
1998-07-09 01:50:48 +08:00
|
|
|
}
|
2011-05-31 15:38:17 +08:00
|
|
|
free(mc->macroTable);
|
2001-05-04 05:00:18 +08:00
|
|
|
}
|
|
|
|
memset(mc, 0, sizeof(*mc));
|
1998-01-13 05:31:29 +08:00
|
|
|
}
|
|
|
|
|
1999-03-28 08:47:40 +08:00
|
|
|
char *
|
|
|
|
rpmExpand(const char *arg, ...)
|
|
|
|
{
|
2010-09-24 17:48:15 +08:00
|
|
|
size_t blen = 0;
|
|
|
|
char *buf = NULL, *ret = NULL;
|
2008-07-16 15:33:57 +08:00
|
|
|
char *pe;
|
1999-03-28 08:47:40 +08:00
|
|
|
const char *s;
|
|
|
|
va_list ap;
|
|
|
|
|
2008-02-01 19:00:40 +08:00
|
|
|
if (arg == NULL) {
|
2010-09-24 17:48:15 +08:00
|
|
|
ret = xstrdup("");
|
2008-02-01 19:00:40 +08:00
|
|
|
goto exit;
|
|
|
|
}
|
1999-03-28 08:47:40 +08:00
|
|
|
|
2010-09-24 17:48:15 +08:00
|
|
|
/* precalculate unexpanded size */
|
2008-07-16 15:52:33 +08:00
|
|
|
va_start(ap, arg);
|
|
|
|
for (s = arg; s != NULL; s = va_arg(ap, const char *))
|
|
|
|
blen += strlen(s);
|
|
|
|
va_end(ap);
|
|
|
|
|
|
|
|
buf = xmalloc(blen + 1);
|
2000-11-01 00:18:34 +08:00
|
|
|
buf[0] = '\0';
|
1999-03-28 08:47:40 +08:00
|
|
|
|
|
|
|
va_start(ap, arg);
|
2008-07-16 15:33:57 +08:00
|
|
|
for (pe = buf, s = arg; s != NULL; s = va_arg(ap, const char *))
|
2000-06-22 07:28:50 +08:00
|
|
|
pe = stpcpy(pe, s);
|
1999-03-28 08:47:40 +08:00
|
|
|
va_end(ap);
|
2008-07-16 15:52:33 +08:00
|
|
|
|
2010-09-24 17:48:15 +08:00
|
|
|
(void) doExpandMacros(NULL, buf, &ret);
|
2008-07-16 15:52:33 +08:00
|
|
|
|
2010-09-24 17:48:15 +08:00
|
|
|
free(buf);
|
2008-02-01 19:00:40 +08:00
|
|
|
exit:
|
2010-09-24 17:48:15 +08:00
|
|
|
return ret;
|
1999-03-28 08:47:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
rpmExpandNumeric(const char *arg)
|
|
|
|
{
|
2007-12-14 21:50:17 +08:00
|
|
|
char *val;
|
1999-03-28 08:47:40 +08:00
|
|
|
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;
|
|
|
|
}
|
2011-05-29 00:43:52 +08:00
|
|
|
free(val);
|
1999-03-28 08:47:40 +08:00
|
|
|
|
|
|
|
return rc;
|
|
|
|
}
|