#include <unistd.h>
#include <errno.h>
+#include "hash.h"
#include "macros.h"
#include "mem.h"
#include "vector.h"
#include "log.h"
-#include "hash.h"
#include "sink.h"
#include "syscalls.h"
#include "printf.h"
if(!(e = hash_find(expansions, m->name))) {
error(0, "%s:%d: unknown expansion name '%s'",
m->filename, m->line, m->name);
- if(sink_printf(output, "[[%s unknown]]", m->name) < 0)
+ if(sink_printf(output, "[['%s' unknown]]", m->name) < 0)
return -1;
} else if(m->nargs < e->min) {
error(0, "%s:%d: expansion '%s' requires %d args, only %d given",
m->filename, m->line, m->name, e->min, m->nargs);
- if(sink_printf(output, "[[%s too few args]]", m->name) < 0)
+ if(sink_printf(output, "[['%s' too few args]]", m->name) < 0)
return -1;
} else if(m->nargs > e->max) {
error(0, "%s:%d: expansion '%s' takes at most %d args, but %d given",
m->filename, m->line, m->name, e->max, m->nargs);
- if(sink_printf(output, "[[%s too many args]]", m->name) < 0)
+ if(sink_printf(output, "[['%s' too many args]]", m->name) < 0)
return -1;
} else switch(e->flags & EXP_TYPE_MASK) {
case EXP_MAGIC: {
if(rc) {
/* For non-IO errors we generate some backtrace */
if(rc != -1)
- error(0, " ...in '%s' at %s:%d",
+ error(0, " ...in @%s at %s:%d",
m->name, m->filename, m->line);
return rc;
}
return rc;
}
-/** @brief Rewrite a parse tree substituting in macro arguments
+/* Macros ------------------------------------------------------------------- */
+
+/** @brief Rewrite a parse tree substituting sub-expansions
* @param m Parse tree to rewrite (from macro definition)
+ * @param ... Name/value pairs to rewrite
+ * @return Rewritten parse tree
+ *
+ * The name/value pair list consists of pairs of strings and is terminated by
+ * (char *)0. Names and values are both copied so need not survive the call.
+ */
+const struct mx_node *mx_rewritel(const struct mx_node *m,
+ ...) {
+ va_list ap;
+ hash *h = hash_new(sizeof (struct mx_node *));
+ const char *n, *v;
+ struct mx_node *e;
+
+ va_start(ap, m);
+ while((n = va_arg(ap, const char *))) {
+ v = va_arg(ap, const char *);
+ e = xmalloc(sizeof *e);
+ e->next = 0;
+ e->filename = m->filename;
+ e->line = m->line;
+ e->type = MX_TEXT;
+ e->text = xstrdup(v);
+ hash_add(h, n, &e, HASH_INSERT);
+ /* hash_add() copies n */
+ }
+ return mx_rewrite(m, h);
+}
+
+/** @brief Rewrite a parse tree substituting in macro arguments
+ * @param definition Parse tree to rewrite (from macro definition)
* @param h Hash mapping argument names to argument values
* @return Rewritten parse tree
*/
-static const struct mx_node *mx__rewrite(const struct mx_node *m,
- hash *h) {
- const struct mx_node *head = 0, **tailp = &head, *argvalue, *mm;
+const struct mx_node *mx_rewrite(const struct mx_node *definition,
+ hash *h) {
+ const struct mx_node *head = 0, **tailp = &head, *argvalue, *m, *mm;
struct mx_node *nm;
int n;
- for(; m; m = m->next) {
+ for(m = definition; m; m = m->next) {
switch(m->type) {
case MX_TEXT:
nm = xmalloc(sizeof *nm);
* values according to h. */
nm = xmalloc(sizeof *nm);
*nm = *m;
+ nm->args = xcalloc(nm->nargs, sizeof (struct mx_node *));
for(n = 0; n < nm->nargs; ++n)
- nm->args[n] = mx__rewrite(m->args[n], h);
+ nm->args[n] = mx_rewrite(m->args[n], h);
nm->next = 0;
*tailp = nm;
tailp = (const struct mx_node **)&nm->next;
for(n = 0; n < m->nargs; ++n)
hash_add(h, e->args[n], &m->args[n], HASH_INSERT);
/* Generate a rewritten parse tree */
- m = mx__rewrite(e->definition, h);
+ m = mx_rewrite(e->definition, h);
/* Expand the result */
return mx_expand(m, output, u);
/* mx_expand() will update the backtrace */