From f9343feac8314427583210aa64cbdde958db9030 Mon Sep 17 00:00:00 2001 From: jsg Date: Sun, 2 Sep 2018 08:28:05 +0000 Subject: [PATCH] update tradcpp to 0.5.2 ok miko@ bcallah@ deraadt@ --- libexec/tradcpp/array.h | 2 +- libexec/tradcpp/bool.h | 41 +++++++ libexec/tradcpp/directive.c | 204 ++++++++++++++++++++++++-------- libexec/tradcpp/directive.h | 14 ++- libexec/tradcpp/eval.c | 2 + libexec/tradcpp/eval.h | 2 +- libexec/tradcpp/files.c | 42 ++++--- libexec/tradcpp/macro.c | 229 ++++++++++++++++++++++++++---------- libexec/tradcpp/macro.h | 8 +- libexec/tradcpp/main.c | 33 +++++- libexec/tradcpp/mode.h | 3 +- libexec/tradcpp/output.c | 12 +- libexec/tradcpp/place.c | 130 +++++++++++++++++++- libexec/tradcpp/place.h | 12 +- libexec/tradcpp/tradcpp.1 | 12 +- libexec/tradcpp/union.h | 36 ++++++ libexec/tradcpp/utils.h | 10 +- libexec/tradcpp/version.h | 6 +- 18 files changed, 650 insertions(+), 148 deletions(-) create mode 100644 libexec/tradcpp/bool.h create mode 100644 libexec/tradcpp/union.h diff --git a/libexec/tradcpp/array.h b/libexec/tradcpp/array.h index 8d1b98b3273..2fa474183e3 100644 --- a/libexec/tradcpp/array.h +++ b/libexec/tradcpp/array.h @@ -253,7 +253,7 @@ array_add(struct array *a, void *val, unsigned *index_ret) #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) \ diff --git a/libexec/tradcpp/bool.h b/libexec/tradcpp/bool.h new file mode 100644 index 00000000000..cf86ffb2cb9 --- /dev/null +++ b/libexec/tradcpp/bool.h @@ -0,0 +1,41 @@ +/*- + * 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 +#else +typedef int bool; +#define true 1 +#define false 0 +#endif + +#endif /* BOOL_H */ diff --git a/libexec/tradcpp/directive.c b/libexec/tradcpp/directive.c index 5c81de24008..0d5c98916b5 100644 --- a/libexec/tradcpp/directive.c +++ b/libexec/tradcpp/directive.c @@ -28,10 +28,12 @@ */ #include -#include #include #include +#include +#include +#include "bool.h" #include "utils.h" #include "mode.h" #include "place.h" @@ -175,13 +177,16 @@ ifstate_pop(void) 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); @@ -194,41 +199,67 @@ d_if(struct place *p, struct place *p2, char *line) } 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 { @@ -243,36 +274,52 @@ d_elif(struct place *p, struct place *p2, char *line) 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(); } } @@ -282,12 +329,12 @@ d_endif(struct place *p, struct place *p2, char *line) 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: @@ -337,22 +384,25 @@ d_define(struct place *p, struct place *p2, char *line) 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); } @@ -368,13 +418,17 @@ tryinclude(struct place *p, char *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; } @@ -383,13 +437,13 @@ tryinclude(struct place *p, char *line) 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); @@ -399,26 +453,78 @@ d_include(struct place *p, struct place *p2, char *line) /* 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); } //////////////////////////////////////////////////////////// @@ -426,12 +532,12 @@ d_line(struct place *p, struct place *p2, char *line) 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(); } @@ -440,12 +546,12 @@ d_warning(struct place *p, struct place *p2, char *line) 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); } @@ -455,11 +561,11 @@ d_error(struct place *p, struct place *p2, char *line) 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(); } @@ -469,7 +575,7 @@ d_pragma(struct place *p, struct place *p2, char *line) 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 }, @@ -489,13 +595,13 @@ static const unsigned numdirectives = HOWMANY(directives); 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; icurrent, "Unknown directive #%.*s", (int)skip, line); complain_fail(); } @@ -532,13 +638,13 @@ directive_gotdirective(struct place *p, char *line) */ 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] == '*') { @@ -574,25 +680,25 @@ directive_scancomments(const struct place *p, char *line, size_t len) } 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; } } diff --git a/libexec/tradcpp/directive.h b/libexec/tradcpp/directive.h index d4d5676e95f..7491a7a0fc5 100644 --- a/libexec/tradcpp/directive.h +++ b/libexec/tradcpp/directive.h @@ -29,11 +29,21 @@ #include -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); diff --git a/libexec/tradcpp/eval.c b/libexec/tradcpp/eval.c index cb5db991364..870ac6cf14d 100644 --- a/libexec/tradcpp/eval.c +++ b/libexec/tradcpp/eval.c @@ -642,6 +642,7 @@ wordval(struct place *p, char *word) complain_fail(); } } + debuglog(p, "Undefined symbol %s; substituting 0", word); return 0; } @@ -744,6 +745,7 @@ eval(struct place *p, char *expr) #ifdef DEBUG fprintf(stderr, "eval: %s\n", expr); #endif + debuglog(p, "eval: %s", expr); tokenarray_init(&tokens); tokenize(p, expr); diff --git a/libexec/tradcpp/eval.h b/libexec/tradcpp/eval.h index 0694fb4f9f7..d9193de0f06 100644 --- a/libexec/tradcpp/eval.h +++ b/libexec/tradcpp/eval.h @@ -27,6 +27,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include +#include "bool.h" bool eval(struct place *p, char *expr); diff --git a/libexec/tradcpp/files.c b/libexec/tradcpp/files.c index e5e945581bb..e59388f0abb 100644 --- a/libexec/tradcpp/files.c +++ b/libexec/tradcpp/files.c @@ -27,7 +27,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include #include #include #include @@ -35,6 +34,7 @@ #include #include +#include "bool.h" #include "array.h" #include "mode.h" #include "place.h" @@ -172,14 +172,21 @@ static 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; @@ -223,9 +230,15 @@ file_read(const struct placefile *pf, int fd, const char *name, bool toplevel) } 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(); } @@ -244,7 +257,7 @@ file_read(const struct placefile *pf, int fd, const char *name, bool toplevel) 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') { @@ -271,21 +284,18 @@ file_read(const struct placefile *pf, int fd, const char *name, bool toplevel) 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); } @@ -396,7 +406,7 @@ file_readabsolute(struct place *place, const char *name) assert(place != NULL); - if ((name == NULL) || !strcmp(name, "-")) { + if (name == NULL) { fd = STDIN_FILENO; pf = place_addfile(place, "", false); } else { diff --git a/libexec/tradcpp/macro.c b/libexec/tradcpp/macro.c index 8fe1e372aeb..147dfebb377 100644 --- a/libexec/tradcpp/macro.c +++ b/libexec/tradcpp/macro.c @@ -28,9 +28,11 @@ */ #include +#include #include #include +#include "union.h" #include "array.h" #include "mode.h" #include "place.h" @@ -38,15 +40,21 @@ #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; @@ -76,8 +84,8 @@ expansionitem_create_string(const char *string) 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; } @@ -88,8 +96,8 @@ expansionitem_create_stringlen(const char *string, size_t len) 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; } @@ -100,8 +108,30 @@ expansionitem_create_param(unsigned param) 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; } @@ -109,8 +139,14 @@ static 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)); } @@ -120,17 +156,23 @@ bool 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; } @@ -298,7 +340,7 @@ macrotable_cleanup(void) 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; @@ -319,7 +361,7 @@ macrotable_findlen(const char *name, size_t len, bool remove) } 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); @@ -335,9 +377,9 @@ macrotable_findlen(const char *name, size_t len, bool remove) 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 @@ -586,6 +628,24 @@ macro_define_params(struct place *p1, const char *macro, 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) { @@ -624,7 +684,7 @@ struct expstate { 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 @@ -705,7 +765,7 @@ expand_send_eof(struct expstate *es, struct place *p) 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; @@ -715,7 +775,7 @@ expand_newarg(struct expstate *es, char *buf, size_t len) 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; @@ -742,6 +802,7 @@ expand_substitute(struct place *p, struct expstate *es) char *arg; char *ret; unsigned numargs, numparams; + char numbuf[64]; numargs = stringarray_num(&es->args); numparams = stringarray_num(&es->curmacro->params); @@ -766,11 +827,20 @@ expand_substitute(struct place *p, struct expstate *es) num = expansionitemarray_num(&es->curmacro->expansion); for (i=0; icurmacro->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; } } @@ -778,11 +848,23 @@ expand_substitute(struct place *p, struct expstate *es) *ret = '\0'; for (i=0; icurmacro->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; } } @@ -794,6 +876,7 @@ void expand_domacro(struct expstate *es, struct place *p) { struct macro *m; + const char *name, *val; char *newbuf, *newbuf2; if (es->curmacro == NULL) { @@ -804,23 +887,32 @@ expand_domacro(struct expstate *es, struct place *p) 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; } /* @@ -846,13 +938,16 @@ expand_missingargs(struct expstate *es, struct place *p, bool needspace) 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); @@ -866,11 +961,10 @@ expand_got_ws(struct expstate *es, struct place *p, char *buf, size_t 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: @@ -884,15 +978,8 @@ expand_got_word(struct expstate *es, struct place *p, char *buf, size_t len) 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; @@ -923,7 +1010,8 @@ expand_got_word(struct expstate *es, struct place *p, char *buf, size_t len) 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: @@ -946,7 +1034,8 @@ expand_got_lparen(struct expstate *es, struct place *p, char *buf, size_t len) 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: @@ -981,7 +1070,8 @@ expand_got_rparen(struct expstate *es, struct place *p, char *buf, size_t len) 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: @@ -1009,7 +1099,8 @@ expand_got_comma(struct expstate *es, struct place *p, char *buf, size_t len) 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: @@ -1061,7 +1152,7 @@ expand_got_eof(struct expstate *es, struct place *p) 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; @@ -1150,7 +1241,7 @@ doexpand(struct expstate *es, struct place *p, char *buf, size_t len) } 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; @@ -1172,10 +1263,30 @@ macroexpand(struct place *p, char *buf, size_t len, bool honordefined) } 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 diff --git a/libexec/tradcpp/macro.h b/libexec/tradcpp/macro.h index 98671e63bc9..76938a39548 100644 --- a/libexec/tradcpp/macro.h +++ b/libexec/tradcpp/macro.h @@ -27,8 +27,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include #include +#include "bool.h" struct place; @@ -40,10 +40,12 @@ void macro_define_plain(struct place *, const char *macro, 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 *); diff --git a/libexec/tradcpp/main.c b/libexec/tradcpp/main.c index 267c279be5e..9ce2ba1c76c 100644 --- a/libexec/tradcpp/main.c +++ b/libexec/tradcpp/main.c @@ -27,7 +27,6 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include #include #include #include @@ -35,6 +34,7 @@ #include #include +#include "bool.h" #include "version.h" #include "config.h" #include "utils.h" @@ -56,6 +56,7 @@ struct mode mode = { .do_output = true, .output_linenumbers = true, + .output_cheaplinenumbers = false, .output_retain_comments = false, .output_file = NULL, @@ -167,7 +168,7 @@ void 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); @@ -194,6 +195,16 @@ apply_commandline_macros(void) 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) @@ -210,6 +221,9 @@ apply_builtin_macros(void) { unsigned n = 1; + apply_magic_macro(n++, "__FILE__"); + apply_magic_macro(n++, "__LINE__"); + #ifdef CONFIG_OS apply_builtin_macro(n++, CONFIG_OS, "1"); #endif @@ -782,6 +796,7 @@ static const struct flag_option flag_options[] = { { "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); @@ -815,6 +830,7 @@ static const struct arg_option arg_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 }, @@ -935,7 +951,7 @@ check_arg_option(const char *opt, const struct place *argplace, char *arg) return false; } -DEAD static +DEAD PF(2, 3) static void usage(const char *progname, const char *fmt, ...) { @@ -947,7 +963,7 @@ 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"); @@ -1000,6 +1016,7 @@ cleanup(void) commandline_files_cleanup(); commandline_macros_cleanup(); incpath_cleanup(); + debuglog_close(); num = stringarray_num(&freestrings); for (i=0; i +#include "bool.h" struct mode { bool werror; @@ -37,6 +37,7 @@ struct mode { bool do_stddef; bool do_output; bool output_linenumbers; + bool output_cheaplinenumbers; bool output_retain_comments; const char *output_file; bool do_depend; diff --git a/libexec/tradcpp/output.c b/libexec/tradcpp/output.c index 5cc7165892c..d706a3180f6 100644 --- a/libexec/tradcpp/output.c +++ b/libexec/tradcpp/output.c @@ -27,6 +27,7 @@ * POSSIBILITY OF SUCH DAMAGE. */ +#include #include #include #include @@ -47,7 +48,7 @@ static 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, @@ -172,6 +173,15 @@ output(const struct place *p, const char *buf, size_t len) 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); diff --git a/libexec/tradcpp/place.c b/libexec/tradcpp/place.c index 267104875c5..72ab47ccb04 100644 --- a/libexec/tradcpp/place.c +++ b/libexec/tradcpp/place.c @@ -32,6 +32,7 @@ #include #include #include +#include #include "utils.h" #include "array.h" @@ -52,8 +53,10 @@ static bool overall_failure; static const char *myprogname; +static FILE *debuglogfile; + //////////////////////////////////////////////////////////// -// seenfiles +// placefiles static struct placefile * @@ -101,6 +104,42 @@ place_getparsedir(const struct place *place) 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; iincludedfrom) && + !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) { @@ -154,7 +193,6 @@ place_setfilestart(struct place *p, const struct placefile *pf) p->column = 1; } -static const char * place_getname(const struct place *p) { @@ -168,6 +206,30 @@ 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) @@ -224,6 +286,70 @@ complain_failed(void) 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 diff --git a/libexec/tradcpp/place.h b/libexec/tradcpp/place.h index 311645be145..d18dd82cbf2 100644 --- a/libexec/tradcpp/place.h +++ b/libexec/tradcpp/place.h @@ -27,7 +27,10 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include +#ifndef PLACE_H +#define PLACE_H + +#include "bool.h" enum places { P_NOWHERE, @@ -50,7 +53,14 @@ void place_setbuiltin(struct place *p, unsigned num); 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 */ diff --git a/libexec/tradcpp/tradcpp.1 b/libexec/tradcpp/tradcpp.1 index c726dc44370..d4cf5355183 100644 --- a/libexec/tradcpp/tradcpp.1 +++ b/libexec/tradcpp/tradcpp.1 @@ -1,4 +1,4 @@ -.\" $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. @@ -27,7 +27,7 @@ .\" 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 @@ -261,6 +261,14 @@ but adds the result as if it were specified with .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. diff --git a/libexec/tradcpp/union.h b/libexec/tradcpp/union.h new file mode 100644 index 00000000000..74113a5a8cb --- /dev/null +++ b/libexec/tradcpp/union.h @@ -0,0 +1,36 @@ +/*- + * 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 diff --git a/libexec/tradcpp/utils.h b/libexec/tradcpp/utils.h index e6f1ae7286f..06d5f024d2c 100644 --- a/libexec/tradcpp/utils.h +++ b/libexec/tradcpp/utils.h @@ -27,8 +27,8 @@ * POSSIBILITY OF SUCH DAMAGE. */ -#include #include +#include "bool.h" struct place; @@ -63,10 +63,16 @@ bool is_identifier(const char *str); /* 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); diff --git a/libexec/tradcpp/version.h b/libexec/tradcpp/version.h index b278c662d11..3e0c5ca8531 100644 --- a/libexec/tradcpp/version.h +++ b/libexec/tradcpp/version.h @@ -28,6 +28,6 @@ */ #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" -- 2.20.1