#define DEFARRAY(T, INLINE) DEFARRAY_BYTYPE(T##array, struct T, INLINE)
#define DESTROYALL_ARRAY(T, INLINE) \
- void T##array_destroyall(struct T##array *arr); \
+ INLINE void T##array_destroyall(struct T##array *arr); \
\
INLINE void \
T##array_destroyall(struct T##array *arr) \
--- /dev/null
+/*-
+ * Copyright (c) 2015 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by David A. Holland.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef BOOL_H
+#define BOOL_H
+
+#if __STDC__ > 199901
+#include <stdbool.h>
+#else
+typedef int bool;
+#define true 1
+#define false 0
+#endif
+
+#endif /* BOOL_H */
*/
#include <assert.h>
-#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
+#include <limits.h>
+#include <errno.h>
+#include "bool.h"
#include "utils.h"
#include "mode.h"
#include "place.h"
static
void
-d_if(struct place *p, struct place *p2, char *line)
+d_if(struct lineplace *lp, struct place *p2, char *line)
{
+ bool doprint;
char *expr;
bool val;
struct place p3 = *p2;
size_t oldlen;
+ doprint = ifstate->curtrue;
+
expr = macroexpand(p2, line, strlen(line), true);
oldlen = strlen(expr);
} else {
val = 0;
}
- ifstate_push(p, val);
+ ifstate_push(&lp->current, val);
dostrfree(expr);
+
+ if (doprint) {
+ debuglog(&lp->current, "#if: %s",
+ ifstate->curtrue ? "taken" : "not taken");
+ }
}
static
void
-d_ifdef(struct place *p, struct place *p2, char *line)
+d_ifdef(struct lineplace *lp, struct place *p2, char *line)
{
+ bool doprint;
+
+ doprint = ifstate->curtrue;
+
uncomment(line);
oneword("#ifdef", p2, line);
- ifstate_push(p, macro_isdefined(line));
+ ifstate_push(&lp->current, macro_isdefined(line));
+
+ if (doprint) {
+ debuglog(&lp->current, "#ifdef %s: %s",
+ line, ifstate->curtrue ? "taken" : "not taken");
+ }
}
static
void
-d_ifndef(struct place *p, struct place *p2, char *line)
+d_ifndef(struct lineplace *lp, struct place *p2, char *line)
{
+ bool doprint;
+
+ doprint = ifstate->curtrue;
+
uncomment(line);
oneword("#ifndef", p2, line);
- ifstate_push(p, !macro_isdefined(line));
+ ifstate_push(&lp->current, !macro_isdefined(line));
+
+ if (doprint) {
+ debuglog(&lp->current, "#ifndef %s: %s",
+ line, ifstate->curtrue ? "taken" : "not taken");
+ }
}
static
void
-d_elif(struct place *p, struct place *p2, char *line)
+d_elif(struct lineplace *lp, struct place *p2, char *line)
{
+ bool doprint;
char *expr;
struct place p3 = *p2;
size_t oldlen;
if (ifstate->seenelse) {
- complain(p, "#elif after #else");
+ complain(&lp->current, "#elif after #else");
complain_fail();
}
+ doprint = ifstate->curtrue;
+
if (ifstate->evertrue) {
ifstate->curtrue = false;
} else {
ifstate->evertrue = ifstate->curtrue;
dostrfree(expr);
}
+
+ if (doprint) {
+ debuglog2(&lp->current, &ifstate->startplace, "#elif: %s",
+ ifstate->curtrue ? "taken" : "not taken");
+ }
}
static
void
-d_else(struct place *p, struct place *p2, char *line)
+d_else(struct lineplace *lp, struct place *p2, char *line)
{
+ bool doprint;
+
(void)p2;
(void)line;
if (ifstate->seenelse) {
- complain(p, "Multiple #else directives in one conditional");
+ complain(&lp->current,
+ "Multiple #else directives in one conditional");
complain_fail();
}
+ doprint = ifstate->curtrue;
+
ifstate->curtrue = !ifstate->evertrue;
ifstate->evertrue = true;
ifstate->seenelse = true;
+
+ if (doprint) {
+ debuglog2(&lp->current, &ifstate->startplace, "#else: %s",
+ ifstate->curtrue ? "taken" : "not taken");
+ }
}
static
void
-d_endif(struct place *p, struct place *p2, char *line)
+d_endif(struct lineplace *lp, struct place *p2, char *line)
{
(void)p2;
(void)line;
if (ifstate->prev == NULL) {
- complain(p, "Unmatched #endif");
+ complain(&lp->current, "Unmatched #endif");
complain_fail();
} else {
+ debuglog2(&lp->current, &ifstate->startplace, "#endif");
ifstate_pop();
}
}
static
void
-d_define(struct place *p, struct place *p2, char *line)
+d_define(struct lineplace *lp, struct place *p2, char *line)
{
size_t pos, argpos;
struct place p3, p4;
- (void)p;
+ (void)lp;
/*
* line may be:
p4.column += pos;
if (argpos) {
+ debuglog(&lp->current, "Defining %s()", line);
macro_define_params(p2, line, &p3,
line + argpos, &p4,
line + pos);
} else {
+ debuglog(&lp->current, "Defining %s", line);
macro_define_plain(p2, line, &p4, line + pos);
}
}
static
void
-d_undef(struct place *p, struct place *p2, char *line)
+d_undef(struct lineplace *lp, struct place *p2, char *line)
{
- (void)p;
+ (void)lp;
uncomment(line);
oneword("#undef", p2, line);
+ debuglog(&lp->current, "Undef %s", line);
macro_undef(line);
}
len = strlen(line);
if (len > 2 && line[0] == '"' && line[len-1] == '"') {
line[len-1] = '\0';
+ debuglog(p, "Entering include file \"%s\"", line+1);
file_readquote(p, line+1);
+ debuglog(p, "Leaving include file \"%s\"", line+1);
line[len-1] = '"';
return true;
}
if (len > 2 && line[0] == '<' && line[len-1] == '>') {
line[len-1] = '\0';
+ debuglog(p, "Entering include file <%s>", line+1);
file_readbracket(p, line+1);
+ debuglog(p, "Leaving include file <%s>", line+1);
line[len-1] = '>';
return true;
}
static
void
-d_include(struct place *p, struct place *p2, char *line)
+d_include(struct lineplace *lp, struct place *p2, char *line)
{
char *text;
size_t oldlen;
uncomment(line);
- if (tryinclude(p, line)) {
+ if (tryinclude(&lp->current, line)) {
return;
}
text = macroexpand(p2, line, strlen(line), false);
/* trim to fit, so the malloc debugging won't complain */
text = dorealloc(text, oldlen + 1, strlen(text) + 1);
- if (tryinclude(p, text)) {
+ if (tryinclude(&lp->current, text)) {
dostrfree(text);
return;
}
- complain(p, "Illegal #include directive");
- complain(p, "Before macro expansion: #include %s", line);
- complain(p, "After macro expansion: #include %s", text);
+ complain(&lp->current, "Illegal #include directive");
+ complain(&lp->current, "Before macro expansion: #include %s", line);
+ complain(&lp->current, "After macro expansion: #include %s", text);
dostrfree(text);
complain_fail();
}
static
void
-d_line(struct place *p, struct place *p2, char *line)
+d_line(struct lineplace *lp, struct place *p2, char *line)
{
- (void)p2;
- (void)line;
+ char *text;
+ size_t oldlen;
+ unsigned long val;
+ char *moretext;
+ size_t moretextlen;
+ char *filename;
+
+ text = macroexpand(p2, line, strlen(line), true);
+
+ oldlen = strlen(text);
+ uncomment(text);
+ /* trim to fit, so the malloc debugging won't complain */
+ text = dorealloc(text, oldlen + 1, strlen(text) + 1);
+
+ /*
+ * What we should have here: either 1234 "file.c",
+ * or just 1234.
+ */
- /* XXX */
- complain(p, "Sorry, no #line yet");
+ errno = 0;
+ val = strtoul(text, &moretext, 10);
+ if (errno) {
+ complain(&lp->current, "No line number in #line directive");
+ goto fail;
+ }
+#if UINT_MAX < ULONG_MAX
+ if (val > UINT_MAX) {
+ complain(&lp->current,
+ "Line number in #line directive too large");
+ goto fail;
+ }
+#endif
+ moretext += strspn(moretext, ws);
+ moretextlen = strlen(moretext);
+ lp->current.column += (moretext - text);
+
+ if (moretextlen > 2 &&
+ moretext[0] == '"' && moretext[moretextlen-1] == '"') {
+ filename = dostrndup(moretext+1, moretextlen-2);
+ place_changefile(&lp->nextline, filename);
+ dostrfree(filename);
+ }
+ else if (moretextlen > 0) {
+ complain(&lp->current,
+ "Invalid file name in #line directive");
+ goto fail;
+ }
+
+ lp->nextline.line = val;
+ dostrfree(text);
+ return;
+
+fail:
+ complain(&lp->current, "Before macro expansion: #line %s", line);
+ complain(&lp->current, "After macro expansion: #line %s", text);
+ complain_fail();
+ dostrfree(text);
}
////////////////////////////////////////////////////////////
static
void
-d_warning(struct place *p, struct place *p2, char *line)
+d_warning(struct lineplace *lp, struct place *p2, char *line)
{
char *msg;
msg = macroexpand(p2, line, strlen(line), false);
- complain(p, "#warning: %s", msg);
+ complain(&lp->current, "#warning: %s", msg);
if (mode.werror) {
complain_fail();
}
static
void
-d_error(struct place *p, struct place *p2, char *line)
+d_error(struct lineplace *lp, struct place *p2, char *line)
{
char *msg;
msg = macroexpand(p2, line, strlen(line), false);
- complain(p, "#error: %s", msg);
+ complain(&lp->current, "#error: %s", msg);
complain_fail();
dostrfree(msg);
}
static
void
-d_pragma(struct place *p, struct place *p2, char *line)
+d_pragma(struct lineplace *lp, struct place *p2, char *line)
{
(void)p2;
- complain(p, "#pragma %s", line);
+ complain(&lp->current, "#pragma %s", line);
complain_fail();
}
static const struct {
const char *name;
bool ifskip;
- void (*func)(struct place *, struct place *, char *line);
+ void (*func)(struct lineplace *, struct place *, char *line);
} directives[] = {
{ "define", true, d_define },
{ "elif", false, d_elif },
static
void
-directive_gotdirective(struct place *p, char *line)
+directive_gotdirective(struct lineplace *lp, char *line)
{
struct place p2;
size_t len, skip;
unsigned i;
- p2 = *p;
+ p2 = lp->current;
for (i=0; i<numdirectives; i++) {
len = strlen(directives[i].name);
if (!strncmp(line, directives[i].name, len) &&
if (len < strlen(line)) {
line[len] = '\0';
}
- directives[i].func(p, &p2, line);
+ directives[i].func(lp, &p2, line);
return;
}
}
}
skip = strcspn(line, ws);
- complain(p, "Unknown directive #%.*s", (int)skip, line);
+ complain(&lp->current, "Unknown directive #%.*s", (int)skip, line);
complain_fail();
}
*/
static
size_t
-directive_scancomments(const struct place *p, char *line, size_t len)
+directive_scancomments(const struct lineplace *lp, char *line, size_t len)
{
size_t pos;
bool incomment;
struct place p2;
- p2 = *p;
+ p2 = lp->current;
incomment = 0;
for (pos = 0; pos+1 < len; pos++) {
if (line[pos] == '/' && line[pos+1] == '*') {
}
void
-directive_gotline(struct place *p, char *line, size_t len)
+directive_gotline(struct lineplace *lp, char *line, size_t len)
{
size_t skip;
if (warns.nestcomment) {
- directive_scancomments(p, line, len);
+ directive_scancomments(lp, line, len);
}
/* check if we have a directive line (# exactly in column 0) */
- if (line[0] == '#') {
+ if (len > 0 && line[0] == '#') {
skip = 1 + strspn(line + 1, ws);
assert(skip <= len);
- p->column += skip;
+ lp->current.column += skip;
assert(line[len] == '\0');
- directive_gotdirective(p, line+skip /*, length = len-skip */);
- p->column += len-skip;
+ directive_gotdirective(lp, line+skip /*, length = len-skip */);
+ lp->current.column += len-skip;
} else if (ifstate->curtrue) {
- macro_sendline(p, line, len);
- p->column += len;
+ macro_sendline(&lp->current, line, len);
+ lp->current.column += len;
}
}
#include <stddef.h>
-struct place;
+#include "place.h"
+
+/*
+ * Relevant places while we're processing a line:
+ * the place in the current line
+ * the beginning of the next line
+ */
+struct lineplace {
+ struct place current;
+ struct place nextline;
+};
void directive_init(void);
void directive_cleanup(void);
-void directive_gotline(struct place *p, char *line, size_t len);
+void directive_gotline(struct lineplace *lp, char *line, size_t len);
void directive_goteof(struct place *p);
complain_fail();
}
}
+ debuglog(p, "Undefined symbol %s; substituting 0", word);
return 0;
}
#ifdef DEBUG
fprintf(stderr, "eval: %s\n", expr);
#endif
+ debuglog(p, "eval: %s", expr);
tokenarray_init(&tokens);
tokenize(p, expr);
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <stdbool.h>
+#include "bool.h"
bool eval(struct place *p, char *expr);
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <errno.h>
+#include "bool.h"
#include "array.h"
#include "mode.h"
#include "place.h"
void
file_read(const struct placefile *pf, int fd, const char *name, bool toplevel)
{
- struct place linestartplace, nextlinestartplace, ptmp;
+ struct lineplace places;
+ struct place ptmp;
size_t bufend, bufmax, linestart, lineend, nextlinestart, tmp;
ssize_t result;
bool ateof = false;
char *buf;
- place_setfilestart(&linestartplace, pf);
- nextlinestartplace = linestartplace;
+ place_setfilestart(&places.current, pf);
+ places.nextline = places.current;
+
+ if (name) {
+ debuglog(&places.current, "Reading file %s", name);
+ } else {
+ debuglog(&places.current, "Reading standard input");
+ }
bufmax = 128;
bufend = 0;
} else if (result == 0) {
/* eof in middle of line */
ateof = true;
- ptmp = linestartplace;
+ ptmp = places.current;
ptmp.column += bufend - linestart;
- complain(&ptmp, "No newline at end of file");
+ if (buf[bufend - 1] == '\n') {
+ complain(&ptmp, "Unclosed comment");
+ complain_fail();
+ } else {
+ complain(&ptmp,
+ "No newline at end of file");
+ }
if (mode.werror) {
complain_fail();
}
assert(buf[lineend] == '\n');
buf[lineend] = '\0';
nextlinestart = lineend+1;
- nextlinestartplace.line++;
+ places.nextline.line++;
/* check for CR/NL */
if (lineend > 0 && buf[lineend-1] == '\r') {
assert(buf[lineend] == '\0');
/* count how many commented-out newlines we swallowed */
- nextlinestartplace.line += countnls(buf, linestart, lineend);
+ places.nextline.line += countnls(buf, linestart, lineend);
- /* if the line isn't empty, process it */
- if (lineend > linestart) {
- directive_gotline(&linestartplace,
- buf+linestart, lineend-linestart);
- }
+ /* process the line (even if it's empty) */
+ directive_gotline(&places, buf+linestart, lineend-linestart);
linestart = nextlinestart;
lineend = findeol(buf, linestart, bufend);
- linestartplace = nextlinestartplace;
+ places.current = places.nextline;
}
if (toplevel) {
- directive_goteof(&linestartplace);
+ directive_goteof(&places.current);
}
dofree(buf, bufmax);
}
assert(place != NULL);
- if ((name == NULL) || !strcmp(name, "-")) {
+ if (name == NULL) {
fd = STDIN_FILENO;
pf = place_addfile(place, "<standard-input>", false);
} else {
*/
#include <stdint.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include "union.h"
#include "array.h"
#include "mode.h"
#include "place.h"
#include "output.h"
struct expansionitem {
- bool isstring;
+ enum { EI_STRING, EI_PARAM, EI_FILE, EI_LINE } itemtype;
union {
- char *string;
- unsigned param;
- };
+ char *ei_string; /* for EI_STRING */
+ unsigned ei_param; /* for EI_PARAM */
+ } UN;
};
DECLARRAY(expansionitem, static UNUSED);
DEFARRAY(expansionitem, static);
+#ifdef NEED_UNION_ACCESSORS
+#define ei_string un.ei_string
+#define ei_param un.ei_param
+#endif
+
+
struct macro {
struct place defplace;
struct place expansionplace;
struct expansionitem *ei;
ei = domalloc(sizeof(*ei));
- ei->isstring = true;
- ei->string = dostrdup(string);
+ ei->itemtype = EI_STRING;
+ ei->ei_string = dostrdup(string);
return ei;
}
struct expansionitem *ei;
ei = domalloc(sizeof(*ei));
- ei->isstring = true;
- ei->string = dostrndup(string, len);
+ ei->itemtype = EI_STRING;
+ ei->ei_string = dostrndup(string, len);
return ei;
}
struct expansionitem *ei;
ei = domalloc(sizeof(*ei));
- ei->isstring = false;
- ei->param = param;
+ ei->itemtype = EI_PARAM;
+ ei->ei_param = param;
+ return ei;
+}
+
+static
+struct expansionitem *
+expansionitem_create_file(void)
+{
+ struct expansionitem *ei;
+
+ ei = domalloc(sizeof(*ei));
+ ei->itemtype = EI_FILE;
+ return ei;
+}
+
+static
+struct expansionitem *
+expansionitem_create_line(void)
+{
+ struct expansionitem *ei;
+
+ ei = domalloc(sizeof(*ei));
+ ei->itemtype = EI_LINE;
return ei;
}
void
expansionitem_destroy(struct expansionitem *ei)
{
- if (ei->isstring) {
- dostrfree(ei->string);
+ switch (ei->itemtype) {
+ case EI_STRING:
+ dostrfree(ei->ei_string);
+ break;
+ case EI_PARAM:
+ case EI_FILE:
+ case EI_LINE:
+ break;
}
dofree(ei, sizeof(*ei));
}
expansionitem_eq(const struct expansionitem *ei1,
const struct expansionitem *ei2)
{
- if (ei1->isstring != ei2->isstring) {
+ if (ei1->itemtype != ei2->itemtype) {
return false;
}
- if (ei1->isstring) {
- if (strcmp(ei1->string, ei2->string) != 0) {
+ switch (ei1->itemtype) {
+ case EI_STRING:
+ if (strcmp(ei1->ei_string, ei2->ei_string) != 0) {
return false;
}
- } else {
- if (ei1->param != ei2->param) {
+ break;
+ case EI_PARAM:
+ if (ei1->ei_param != ei2->ei_param) {
return false;
}
+ break;
+ case EI_FILE:
+ case EI_LINE:
+ break;
}
return true;
}
static
struct macro *
-macrotable_findlen(const char *name, size_t len, bool remove)
+macrotable_findlen(const char *name, size_t len, bool remove_it)
{
unsigned hash;
struct macroarray *bucket;
}
mlen = strlen(m->name);
if (len == mlen && !memcmp(name, m->name, len)) {
- if (remove) {
+ if (remove_it) {
if (i < num-1) {
m2 = macroarray_get(bucket, num-1);
macroarray_set(bucket, i, m2);
static
struct macro *
-macrotable_find(const char *name, bool remove)
+macrotable_find(const char *name, bool remove_it)
{
- return macrotable_findlen(name, strlen(name), remove);
+ return macrotable_findlen(name, strlen(name), remove_it);
}
static
macro_define_common_end(m);
}
+void
+macro_define_magic(struct place *p, const char *macro)
+{
+ struct macro *m;
+ struct expansionitem *ei;
+
+ m = macro_define_common_start(p, macro, p);
+ if (!strcmp(macro, "__FILE__")) {
+ ei = expansionitem_create_file();
+ }
+ else {
+ assert(!strcmp(macro, "__LINE__"));
+ ei = expansionitem_create_line();
+ }
+ expansionitemarray_add(&m->expansion, ei, NULL);
+ macro_define_common_end(m);
+}
+
void
macro_undef(const char *macro)
{
static struct expstate mainstate;
static void doexpand(struct expstate *es, struct place *p,
- char *buf, size_t len);
+ const char *buf, size_t len);
static
void
static
void
-expand_newarg(struct expstate *es, char *buf, size_t len)
+expand_newarg(struct expstate *es, const char *buf, size_t len)
{
char *text;
static
void
-expand_appendarg(struct expstate *es, char *buf, size_t len)
+expand_appendarg(struct expstate *es, const char *buf, size_t len)
{
unsigned num;
char *text;
char *arg;
char *ret;
unsigned numargs, numparams;
+ char numbuf[64];
numargs = stringarray_num(&es->args);
numparams = stringarray_num(&es->curmacro->params);
num = expansionitemarray_num(&es->curmacro->expansion);
for (i=0; i<num; i++) {
ei = expansionitemarray_get(&es->curmacro->expansion, i);
- if (ei->isstring) {
- len += strlen(ei->string);
- } else {
- arg = stringarray_get(&es->args, ei->param);
+ switch (ei->itemtype) {
+ case EI_STRING:
+ len += strlen(ei->ei_string);
+ break;
+ case EI_PARAM:
+ arg = stringarray_get(&es->args, ei->ei_param);
len += strlen(arg);
+ break;
+ case EI_FILE:
+ len += strlen(place_getname(p)) + 2;
+ break;
+ case EI_LINE:
+ len += snprintf(numbuf, sizeof(numbuf), "%u", p->line);
+ break;
}
}
*ret = '\0';
for (i=0; i<num; i++) {
ei = expansionitemarray_get(&es->curmacro->expansion, i);
- if (ei->isstring) {
- strlcat(ret, ei->string, len+1);
- } else {
- arg = stringarray_get(&es->args, ei->param);
- strlcat(ret, arg, len+1);
+ switch (ei->itemtype) {
+ case EI_STRING:
+ strlcat(ret, ei->ei_string, len + 1);
+ break;
+ case EI_PARAM:
+ arg = stringarray_get(&es->args, ei->ei_param);
+ strlcat(ret, arg, len + 1);
+ break;
+ case EI_FILE:
+ strlcat(ret, "\"", len + 1);
+ strlcat(ret, place_getname(p), len + 1);
+ strlcat(ret, "\"", len + 1);
+ break;
+ case EI_LINE:
+ snprintf(numbuf, sizeof(numbuf), "%u", p->line);
+ strlcat(ret, numbuf, len + 1);
+ break;
}
}
expand_domacro(struct expstate *es, struct place *p)
{
struct macro *m;
+ const char *name, *val;
char *newbuf, *newbuf2;
if (es->curmacro == NULL) {
expand_send(es, p, "0", 1);
return;
}
- m = macrotable_find(stringarray_get(&es->args, 0), false);
- expand_send(es, p, (m != NULL) ? "1" : "0", 1);
+ name = stringarray_get(&es->args, 0);
+ m = macrotable_find(name, false);
+ val = (m != NULL) ? "1" : "0";
+ debuglog(p, "defined(%s): %s", name, val);
+ expand_send(es, p, val, 1);
expstate_destroyargs(es);
return;
}
- assert(es->curmacro->inuse == false);
- es->curmacro->inuse = true;
+ m = es->curmacro;
+ assert(m->inuse == false);
+ m->inuse = true;
+ debuglog(p, "Expanding macro %s", m->name);
newbuf = expand_substitute(p, es);
+ debuglog(p, "Substituting for %s: %s", m->name, newbuf);
+
newbuf2 = macroexpand(p, newbuf, strlen(newbuf), false);
dostrfree(newbuf);
expstate_destroyargs(es);
+ debuglog(p, "Complete expansion for %s: %s", m->name, newbuf2);
+
doexpand(es, p, newbuf2, strlen(newbuf2));
dostrfree(newbuf2);
- es->curmacro->inuse = false;
+ m->inuse = false;
}
/*
static
void
-expand_got_ws(struct expstate *es, struct place *p, char *buf, size_t len)
+expand_got_ws(struct expstate *es, struct place *p,
+ const char *buf, size_t len)
{
switch (es->state) {
case ES_NORMAL:
expand_send(es, p, buf, len);
break;
case ES_WANTLPAREN:
+ /* XXX notyet */
+ //expand_send(es, p, buf, len);
break;
case ES_NOARG:
expand_newarg(es, buf, len);
static
void
-expand_got_word(struct expstate *es, struct place *p, char *buf, size_t len)
+expand_got_word(struct expstate *es, struct place *p,
+ const char *buf, size_t len)
{
struct macro *m;
- struct expansionitem *ei;
- char *newbuf;
switch (es->state) {
case ES_NORMAL:
if (m == NULL || m->inuse) {
expand_send(es, p, buf, len);
} else if (!m->hasparams) {
- m->inuse = true;
- assert(expansionitemarray_num(&m->expansion) == 1);
- ei = expansionitemarray_get(&m->expansion, 0);
- assert(ei->isstring);
- newbuf = macroexpand(p, ei->string,
- strlen(ei->string), false);
- doexpand(es, p, newbuf, strlen(newbuf));
- dostrfree(newbuf);
- m->inuse = false;
+ es->curmacro = m;
+ expand_domacro(es, p);
} else {
es->curmacro = m;
es->state = ES_WANTLPAREN;
static
void
-expand_got_lparen(struct expstate *es, struct place *p, char *buf, size_t len)
+expand_got_lparen(struct expstate *es, struct place *p,
+ const char *buf, size_t len)
{
switch (es->state) {
case ES_NORMAL:
static
void
-expand_got_rparen(struct expstate *es, struct place *p, char *buf, size_t len)
+expand_got_rparen(struct expstate *es, struct place *p,
+ const char *buf, size_t len)
{
switch (es->state) {
case ES_NORMAL:
static
void
-expand_got_comma(struct expstate *es, struct place *p, char *buf, size_t len)
+expand_got_comma(struct expstate *es, struct place *p,
+ const char *buf, size_t len)
{
switch (es->state) {
case ES_NORMAL:
static
void
-expand_got_other(struct expstate *es, struct place *p, char *buf, size_t len)
+expand_got_other(struct expstate *es, struct place *p,
+ const char *buf, size_t len)
{
switch (es->state) {
case ES_NORMAL:
static
void
-doexpand(struct expstate *es, struct place *p, char *buf, size_t len)
+doexpand(struct expstate *es, struct place *p, const char *buf, size_t len)
{
char *s;
size_t x;
}
char *
-macroexpand(struct place *p, char *buf, size_t len, bool honordefined)
+macroexpand(struct place *p, const char *buf, size_t len, bool honordefined)
{
struct expstate es;
char *ret;
}
void
-macro_sendline(struct place *p, char *buf, size_t len)
+macro_sendline(struct place *p, const char *buf, size_t len)
{
doexpand(&mainstate, p, buf, len);
- output(p, "\n", 1);
+ switch (mainstate.state) {
+ case ES_NORMAL:
+ /*
+ * If we were sent a blank line, don't emit a newline
+ * for it. This matches the prior behavior of tradcpp.
+ */
+ if (len > 0) {
+ output(p, "\n", 1);
+ }
+ break;
+ case ES_WANTLPAREN:
+ case ES_NOARG:
+ case ES_HAVEARG:
+ /*
+ * Apparently to match gcc's -traditional behavior we
+ * need to emit a space for each newline that appears
+ * while processing macro args.
+ */
+ expand_got_ws(&mainstate, p, " ", 1);
+ break;
+ }
}
void
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <stdbool.h>
#include <stddef.h>
+#include "bool.h"
struct place;
void macro_define_params(struct place *, const char *macro,
struct place *, const char *params,
struct place *, const char *expansion);
+void macro_define_magic(struct place *, const char *macro);
void macro_undef(const char *macro);
bool macro_isdefined(const char *macro);
-char *macroexpand(struct place *, char *buf, size_t len, bool honordefined);
+char *macroexpand(struct place *, const char *buf, size_t len,
+ bool honordefined);
-void macro_sendline(struct place *, char *buf, size_t len);
+void macro_sendline(struct place *, const char *buf, size_t len);
void macro_sendeof(struct place *);
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <stdbool.h>
#include <stdio.h>
#include <stdarg.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
+#include "bool.h"
#include "version.h"
#include "config.h"
#include "utils.h"
.do_output = true,
.output_linenumbers = true,
+ .output_cheaplinenumbers = false,
.output_retain_comments = false,
.output_file = NULL,
commandline_undef(const struct place *p, char *str)
{
if (*str == '\0') {
- complain(NULL, "-D: macro name expected");
+ complain(NULL, "-U: macro name expected");
die();
}
commandline_macro_add(p, str, p, NULL);
array_setsize(&commandline_macros, 0);
}
+static
+void
+apply_magic_macro(unsigned num, const char *name)
+{
+ struct place p;
+
+ place_setbuiltin(&p, num);
+ macro_define_magic(&p, name);
+}
+
static
void
apply_builtin_macro(unsigned num, const char *name, const char *val)
{
unsigned n = 1;
+ apply_magic_macro(n++, "__FILE__");
+ apply_magic_macro(n++, "__LINE__");
+
#ifdef CONFIG_OS
apply_builtin_macro(n++, CONFIG_OS, "1");
#endif
{ "fdollars-in-identifiers", &mode.input_allow_dollars, true },
{ "fno-dollars-in-identifiers", &mode.input_allow_dollars, false },
{ "nostdinc", &mode.do_stdinc, false },
+ { "p", &mode.output_cheaplinenumbers, true },
{ "undef", &mode.do_stddef, false },
};
static const unsigned num_flag_options = HOWMANY(flag_options);
{ "MF", commandline_setdependoutput },
{ "MQ", commandline_setdependtarget_quoted },
{ "MT", commandline_setdependtarget },
+ { "debuglog", debuglog_open },
{ "idirafter", commandline_addincpath_late },
{ "imacros", commandline_addfile_nooutput },
{ "include", commandline_addfile_output },
return false;
}
-DEAD static
+DEAD PF(2, 3) static
void
usage(const char *progname, const char *fmt, ...)
{
va_end(ap);
fprintf(stderr, "\n");
- fprintf(stderr, "Usage: %s [options] [infile [outfile]]\n", progname);
+ fprintf(stderr, "usage: %s [options] [infile [outfile]]\n", progname);
fprintf(stderr, "Common options:\n");
fprintf(stderr, " -C Retain comments\n");
fprintf(stderr, " -Dmacro[=def] Predefine macro\n");
commandline_files_cleanup();
commandline_macros_cleanup();
incpath_cleanup();
+ debuglog_close();
num = stringarray_num(&freestrings);
for (i=0; i<num; i++) {
init();
for (i=1; i<argc; i++) {
- if ((argv[i][0] != '-') || !strcmp(argv[i], "-")) {
+ if (argv[i][0] != '-' || argv[i][1] == 0) {
break;
}
place_setcommandline(&cmdplace, i, 1);
}
if (i < argc) {
inputfile = argv[i++];
+ if (!strcmp(inputfile, "-")) {
+ inputfile = NULL;
+ }
}
if (i < argc) {
outputfile = argv[i++];
+ if (!strcmp(outputfile, "-")) {
+ outputfile = NULL;
+ }
}
if (i < argc) {
usage(progname, "Extra non-option argument %s", argv[i]);
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <stdbool.h>
+#include "bool.h"
struct mode {
bool werror;
bool do_stddef;
bool do_output;
bool output_linenumbers;
+ bool output_cheaplinenumbers;
bool output_retain_comments;
const char *output_file;
bool do_depend;
* POSSIBILITY OF SUCH DAMAGE.
*/
+#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
void
output_open(void)
{
- if ((mode.output_file == NULL) || !strcmp(mode.output_file, "-")) {
+ if (mode.output_file == NULL) {
outputfd = STDOUT_FILENO;
} else {
outputfd = open(mode.output_file, O_WRONLY|O_CREAT|O_TRUNC,
linebuf = dorealloc(linebuf, oldmax, linebufmax);
}
if (linebufpos == 0) {
+ if (!place_samefile(&linebufplace, p)) {
+ if (mode.output_cheaplinenumbers) {
+ char str[256];
+
+ snprintf(str, sizeof(str), "# %u \"%s\"\n",
+ p->line, place_getname(p));
+ dowrite(str, strlen(str));
+ }
+ }
linebufplace = *p;
}
memcpy(linebuf + linebufpos, buf, len);
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <errno.h>
#include "utils.h"
#include "array.h"
static const char *myprogname;
+static FILE *debuglogfile;
+
////////////////////////////////////////////////////////////
-// seenfiles
+// placefiles
static
struct placefile *
return place->file->dir;
}
+static
+struct placefile *
+placefile_find(const struct place *incfrom, const char *name)
+{
+ unsigned i, num;
+ struct placefile *pf;
+
+ num = placefilearray_num(&placefiles);
+ for (i=0; i<num; i++) {
+ pf = placefilearray_get(&placefiles, i);
+ if (place_eq(incfrom, &pf->includedfrom) &&
+ !strcmp(name, pf->name)) {
+ return pf;
+ }
+ }
+ return NULL;
+}
+
+void
+place_changefile(struct place *p, const char *name)
+{
+ struct placefile *pf;
+
+ assert(p->type == P_FILE);
+ if (!strcmp(name, p->file->name)) {
+ return;
+ }
+ pf = placefile_find(&p->file->includedfrom, name);
+ if (pf == NULL) {
+ pf = placefile_create(&p->file->includedfrom, name,
+ p->file->fromsystemdir);
+ placefilearray_add(&placefiles, pf, NULL);
+ }
+ p->file = pf;
+}
+
const struct placefile *
place_addfile(const struct place *place, const char *file, bool issystem)
{
p->column = 1;
}
-static
const char *
place_getname(const struct place *p)
{
return NULL;
}
+bool
+place_samefile(const struct place *a, const struct place *b)
+{
+ if (a->type != b->type) {
+ return false;
+ }
+ if (a->file != b->file) {
+ return false;
+ }
+ return true;
+}
+
+bool
+place_eq(const struct place *a, const struct place *b)
+{
+ if (!place_samefile(a, b)) {
+ return false;
+ }
+ if (a->line != b->line || a->column != b->column) {
+ return false;
+ }
+ return true;
+}
+
static
void
place_printfrom(const struct place *p)
return overall_failure;
}
+////////////////////////////////////////////////////////////
+// debug logging
+
+void
+debuglog_open(const struct place *p, /*const*/ char *file)
+{
+ assert(debuglogfile == NULL);
+ debuglogfile = fopen(file, "w");
+ if (debuglogfile == NULL) {
+ complain(p, "%s: %s", file, strerror(errno));
+ die();
+ }
+}
+
+void
+debuglog_close(void)
+{
+ if (debuglogfile != NULL) {
+ fclose(debuglogfile);
+ debuglogfile = NULL;
+ }
+}
+
+PF(2, 3) void
+debuglog(const struct place *p, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (debuglogfile == NULL) {
+ return;
+ }
+
+ fprintf(debuglogfile, "%s:%u: ", place_getname(p), p->line);
+ va_start(ap, fmt);
+ vfprintf(debuglogfile, fmt, ap);
+ va_end(ap);
+ fprintf(debuglogfile, "\n");
+ fflush(debuglogfile);
+}
+
+PF(3, 4) void
+debuglog2(const struct place *p, const struct place *p2, const char *fmt, ...)
+{
+ va_list ap;
+
+ if (debuglogfile == NULL) {
+ return;
+ }
+
+ fprintf(debuglogfile, "%s:%u: ", place_getname(p), p->line);
+ if (place_samefile(p, p2)) {
+ fprintf(debuglogfile, "(block began at line %u) ",
+ p2->line);
+ } else {
+ fprintf(debuglogfile, "(block began at %s:%u)",
+ place_getname(p2), p2->line);
+ }
+ va_start(ap, fmt);
+ vfprintf(debuglogfile, fmt, ap);
+ va_end(ap);
+ fprintf(debuglogfile, "\n");
+ fflush(debuglogfile);
+}
+
////////////////////////////////////////////////////////////
// module init and cleanup
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <stdbool.h>
+#ifndef PLACE_H
+#define PLACE_H
+
+#include "bool.h"
enum places {
P_NOWHERE,
void place_setcommandline(struct place *p, unsigned word, unsigned column);
void place_setfilestart(struct place *p, const struct placefile *pf);
+const char *place_getname(const struct place *);
const char *place_getparsedir(const struct place *incplace);
+bool place_eq(const struct place *, const struct place *);
+bool place_samefile(const struct place *, const struct place *);
+
+void place_changefile(struct place *p, const char *name);
const struct placefile *place_addfile(const struct place *incplace,
const char *name, bool fromsystemdir);
+
+#endif /* PLACE_H */
-.\" $OpenBSD: tradcpp.1,v 1.4 2016/12/28 22:47:11 schwarze Exp $
+.\" $OpenBSD: tradcpp.1,v 1.5 2018/09/02 08:28:05 jsg Exp $
.\"
.\" Copyright (c) 2013 The NetBSD Foundation, Inc.
.\" All rights reserved.
.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
.\" POSSIBILITY OF SUCH DAMAGE.
.\"
-.Dd $Mdocdate: December 28 2016 $
+.Dd $Mdocdate: September 2 2018 $
.Dt TRADCPP 1
.Os
.Sh NAME
.El
.Ss Diagnostic Options
.Bl -tag -width bubblebabble
+.It Fl debuglog Ar file
+Write a trace of actions and operations to
+.Ar file
+as the input is processed.
+Meant for debugging problems in complex substitution schemes fed to
+.Nm ,
+such as those used by
+.Sy imake .
.It Fl dD
Dump all macro definitions, except for the predefined macros, after
the normal preprocessing output.
--- /dev/null
+/*-
+ * Copyright (c) 2015 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by David A. Holland.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#if defined(__clang__) || defined(__GNUC__) || __STDC__ > 201101
+#define UN
+#undef NEED_UNION_ACCESSORS
+#else
+#define UN un
+#define NEED_UNION_ACCESSORS
+#endif
* POSSIBILITY OF SUCH DAMAGE.
*/
-#include <stdbool.h>
#include <stddef.h>
+#include "bool.h"
struct place;
/* in place.c */
void complain_init(const char *progname);
-void complain(const struct place *, const char *fmt, ...) PF(2, 3);
+PF(2, 3) void complain(const struct place *, const char *fmt, ...);
void complain_fail(void);
bool complain_failed(void);
+void debuglog_open(const struct place *p, /*const*/ char *file);
+void debuglog_close(void);
+PF(2, 3) void debuglog(const struct place *p, const char *fmt, ...);
+PF(3, 4) void debuglog2(const struct place *p, const struct place *p2,
+ const char *fmt, ...);
+
/* in main.c */
void freestringlater(char *s);
DEAD void die(void);
*/
#define VERSION_MAJOR "0"
-#define VERSION_MINOR "4"
-#define VERSION_STRING "0.4"
-#define VERSION_LONG "NetBSD tradcpp 0.4"
+#define VERSION_MINOR "5"
+#define VERSION_STRING "0.5.2"
+#define VERSION_LONG "NetBSD tradcpp 0.5.2"