summaryrefslogtreecommitdiffstats
path: root/usr.bin/unifdef/unifdef.c
diff options
context:
space:
mode:
authorfanf <fanf@FreeBSD.org>2009-11-25 20:23:18 +0000
committerfanf <fanf@FreeBSD.org>2009-11-25 20:23:18 +0000
commit0960dfee41a0d4a8397a5ae182649588b7deeba8 (patch)
treeffcdb398b1f42147ff1f433e4bb9d9d0971d0b74 /usr.bin/unifdef/unifdef.c
parentbf4b9dad83a701b57717da855cd3e9d309f7474a (diff)
downloadFreeBSD-src-0960dfee41a0d4a8397a5ae182649588b7deeba8.zip
FreeBSD-src-0960dfee41a0d4a8397a5ae182649588b7deeba8.tar.gz
Update unifdef to my upstream version 1.188
Main highlights: (A) The new -B option compresses blank lines around a deleted section so that blank lines around "paragraphs" of code don't get doubled. (B) Lenient evaluation of && and || so that #if expressions can be evaluated even when some of their sub-expressions cannot be. (C) The evaluator can now handle macros with arguments. (D) Portability fixes, especially for unifdefall. Contributions from: Ben Hutchings at Solarflare Communications (A and B) Anders H Kaseorg <andersk@mit.edu> (A and C) Jonathan Nieder <jrnieder@gmail.com> (D) Obtained from: http://dotat.at/prog/unifdef/
Diffstat (limited to 'usr.bin/unifdef/unifdef.c')
-rw-r--r--usr.bin/unifdef/unifdef.c247
1 files changed, 166 insertions, 81 deletions
diff --git a/usr.bin/unifdef/unifdef.c b/usr.bin/unifdef/unifdef.c
index a8427d1..82e0e6b 100644
--- a/usr.bin/unifdef/unifdef.c
+++ b/usr.bin/unifdef/unifdef.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2002 - 2008 Tony Finch <dot@dotat.at>
+ * Copyright (c) 2002 - 2009 Tony Finch <dot@dotat.at>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -33,18 +33,9 @@
#include <sys/cdefs.h>
-#ifndef lint
-#if 0
-static const char copyright[] =
-"@(#) Copyright (c) 1985, 1993\n\
- The Regents of the University of California. All rights reserved.\n";
-#endif
#ifdef __IDSTRING
-__IDSTRING(Berkeley, "@(#)unifdef.c 8.1 (Berkeley) 6/6/93");
-__IDSTRING(NetBSD, "$NetBSD: unifdef.c,v 1.8 2000/07/03 02:51:36 matt Exp $");
-__IDSTRING(dotat, "$dotat: things/unifdef.c,v 1.178 2008/03/02 22:23:32 fanf2 Exp $");
+__IDSTRING(dotat, "$dotat: unifdef/unifdef.c,v 1.188 2009/11/25 00:11:02 fanf2 Exp $");
#endif
-#endif /* not lint */
#ifdef __FBSDID
__FBSDID("$FreeBSD$");
#endif
@@ -88,6 +79,7 @@ typedef enum {
LT_DODGY_LAST = LT_DODGY + LT_ENDIF,
LT_PLAIN, /* ordinary line */
LT_EOF, /* end of file */
+ LT_ERROR, /* unevaluable #if */
LT_COUNT
} Linetype;
@@ -98,7 +90,7 @@ static char const * const linetype_name[] = {
"DODGY IF", "DODGY TRUE", "DODGY FALSE",
"DODGY ELIF", "DODGY ELTRUE", "DODGY ELFALSE",
"DODGY ELSE", "DODGY ENDIF",
- "PLAIN", "EOF"
+ "PLAIN", "EOF", "ERROR"
};
/* state of #if processing */
@@ -166,11 +158,13 @@ static char const * const linestate_name[] = {
* Globals.
*/
+static bool compblank; /* -B: compress blank lines */
+static bool lnblank; /* -b: blank deleted lines */
static bool complement; /* -c: do the complement */
static bool debugging; /* -d: debugging reports */
static bool iocccok; /* -e: fewer IOCCC errors */
+static bool strictlogic; /* -K: keep ambiguous #ifs */
static bool killconsts; /* -k: eval constant #ifs */
-static bool lnblank; /* -l: blank deleted lines */
static bool lnnum; /* -n: add #line directives */
static bool symlist; /* -s: output symbol list */
static bool text; /* -t: this is a text file */
@@ -194,7 +188,9 @@ static bool ignoring[MAXDEPTH]; /* ignore comments state */
static int stifline[MAXDEPTH]; /* start of current #if */
static int depth; /* current #if nesting */
static int delcount; /* count of deleted lines */
-static bool keepthis; /* don't delete constant #if */
+static unsigned blankcount; /* count of blank lines */
+static unsigned blankmax; /* maximum recent blankcount */
+static bool constexpr; /* constant #if expression */
static int exitstat; /* program exit status */
@@ -204,13 +200,14 @@ static void done(void);
static void error(const char *);
static int findsym(const char *);
static void flushline(bool);
-static Linetype getline(void);
+static Linetype parseline(void);
static Linetype ifeval(const char **);
static void ignoreoff(void);
static void ignoreon(void);
static void keywordedit(const char *);
static void nest(void);
static void process(void);
+static const char *skipargs(const char *);
static const char *skipcomment(const char *);
static const char *skipsym(const char *);
static void state(Ifstate);
@@ -218,7 +215,7 @@ static int strlcmp(const char *, const char *, size_t);
static void unnest(void);
static void usage(void);
-#define endsym(c) (!isalpha((unsigned char)c) && !isdigit((unsigned char)c) && c != '_')
+#define endsym(c) (!isalnum((unsigned char)c) && c != '_')
/*
* The main program.
@@ -228,7 +225,7 @@ main(int argc, char *argv[])
{
int opt;
- while ((opt = getopt(argc, argv, "i:D:U:I:cdeklnst")) != -1)
+ while ((opt = getopt(argc, argv, "i:D:U:I:BbcdeKklnst")) != -1)
switch (opt) {
case 'i': /* treat stuff controlled by these symbols as text */
/*
@@ -253,6 +250,13 @@ main(int argc, char *argv[])
case 'I':
/* no-op for compatibility with cpp */
break;
+ case 'B': /* compress blank lines around removed section */
+ compblank = true;
+ break;
+ case 'b': /* blank deleted lines instead of omitting them */
+ case 'l': /* backwards compatibility */
+ lnblank = true;
+ break;
case 'c': /* treat -D as -U and vice versa */
complement = true;
break;
@@ -262,12 +266,12 @@ main(int argc, char *argv[])
case 'e': /* fewer errors from dodgy lines */
iocccok = true;
break;
+ case 'K': /* keep ambiguous #ifs */
+ strictlogic = true;
+ break;
case 'k': /* process constant #ifs */
killconsts = true;
break;
- case 'l': /* blank deleted lines instead of omitting them */
- lnblank = true;
- break;
case 'n': /* add #line directive after deleted lines */
lnnum = true;
break;
@@ -282,6 +286,8 @@ main(int argc, char *argv[])
}
argc -= optind;
argv += optind;
+ if (compblank && lnblank)
+ errx(2, "-B and -b are mutually exclusive");
if (argc > 1) {
errx(2, "can only do one file");
} else if (argc == 1 && strcmp(*argv, "-") != 0) {
@@ -300,7 +306,7 @@ main(int argc, char *argv[])
static void
usage(void)
{
- fprintf(stderr, "usage: unifdef [-cdeklnst] [-Ipath]"
+ fprintf(stderr, "usage: unifdef [-BbcdeKknst] [-Ipath]"
" [-Dsym[=val]] [-Usym] [-iDsym[=val]] [-iUsym] ... [file]\n");
exit(2);
}
@@ -381,46 +387,46 @@ static state_fn * const trans_table[IS_COUNT][LT_COUNT] = {
/* IS_OUTSIDE */
{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Eendif,
Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Eendif,
- print, done },
+ print, done, abort },
/* IS_FALSE_PREFIX */
{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Mpass, Strue, Sfalse,Selse, Dendif,
Idrop, Idrop, Fdrop, Fdrop, Fdrop, Mpass, Eioccc,Eioccc,Eioccc,Eioccc,
- drop, Eeof },
+ drop, Eeof, abort },
/* IS_TRUE_PREFIX */
{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Dfalse,Dfalse,Dfalse,Delse, Dendif,
Oiffy, Oiffy, Fpass, Oif, Oif, Eioccc,Eioccc,Eioccc,Eioccc,Eioccc,
- print, Eeof },
+ print, Eeof, abort },
/* IS_PASS_MIDDLE */
{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Pelif, Mtrue, Delif, Pelse, Pendif,
Oiffy, Oiffy, Fpass, Oif, Oif, Pelif, Oelif, Oelif, Pelse, Pendif,
- print, Eeof },
+ print, Eeof, abort },
/* IS_FALSE_MIDDLE */
{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Pelif, Mtrue, Delif, Pelse, Pendif,
Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eioccc,Eioccc,Eioccc,Eioccc,Eioccc,
- drop, Eeof },
+ drop, Eeof, abort },
/* IS_TRUE_MIDDLE */
{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Melif, Melif, Melif, Melse, Pendif,
Oiffy, Oiffy, Fpass, Oif, Oif, Eioccc,Eioccc,Eioccc,Eioccc,Pendif,
- print, Eeof },
+ print, Eeof, abort },
/* IS_PASS_ELSE */
{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Pendif,
Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Pendif,
- print, Eeof },
+ print, Eeof, abort },
/* IS_FALSE_ELSE */
{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eelif, Eelif, Eelif, Eelse, Dendif,
Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eelif, Eelif, Eelif, Eelse, Eioccc,
- drop, Eeof },
+ drop, Eeof, abort },
/* IS_TRUE_ELSE */
{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Dendif,
Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Eioccc,
- print, Eeof },
+ print, Eeof, abort },
/* IS_FALSE_TRAILER */
{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Dfalse,Dfalse,Dfalse,Delse, Dendif,
Idrop, Idrop, Fdrop, Fdrop, Fdrop, Dfalse,Dfalse,Dfalse,Delse, Eioccc,
- drop, Eeof }
+ drop, Eeof, abort }
/*TRUEI FALSEI IF TRUE FALSE ELIF ELTRUE ELFALSE ELSE ENDIF
TRUEI FALSEI IF TRUE FALSE ELIF ELTRUE ELFALSE ELSE ENDIF (DODGY)
- PLAIN EOF */
+ PLAIN EOF ERROR */
};
/*
@@ -481,15 +487,23 @@ flushline(bool keep)
if (symlist)
return;
if (keep ^ complement) {
- if (lnnum && delcount > 0)
- printf("#line %d\n", linenum);
- fputs(tline, stdout);
- delcount = 0;
+ bool blankline = tline[strspn(tline, " \t\n")] == '\0';
+ if (blankline && compblank && blankcount != blankmax) {
+ delcount += 1;
+ blankcount += 1;
+ } else {
+ if (lnnum && delcount > 0)
+ printf("#line %d\n", linenum);
+ fputs(tline, stdout);
+ delcount = 0;
+ blankmax = blankcount = blankline ? blankcount + 1 : 0;
+ }
} else {
if (lnblank)
putc('\n', stdout);
exitstat = 1;
delcount += 1;
+ blankcount = 0;
}
}
@@ -501,9 +515,12 @@ process(void)
{
Linetype lineval;
+ /* When compressing blank lines, act as if the file
+ is preceded by a large number of blank lines. */
+ blankmax = blankcount = 1000;
for (;;) {
linenum++;
- lineval = getline();
+ lineval = parseline();
trans_table[ifstate[depth]][lineval]();
debug("process %s -> %s depth %d",
linetype_name[lineval],
@@ -517,7 +534,7 @@ process(void)
* help from skipcomment().
*/
static Linetype
-getline(void)
+parseline(void)
{
const char *cp;
int cursym;
@@ -613,17 +630,40 @@ getline(void)
/*
* These are the binary operators that are supported by the expression
- * evaluator. Note that if support for division is added then we also
- * need short-circuiting booleans because of divide-by-zero.
+ * evaluator.
*/
-static int op_lt(int a, int b) { return (a < b); }
-static int op_gt(int a, int b) { return (a > b); }
-static int op_le(int a, int b) { return (a <= b); }
-static int op_ge(int a, int b) { return (a >= b); }
-static int op_eq(int a, int b) { return (a == b); }
-static int op_ne(int a, int b) { return (a != b); }
-static int op_or(int a, int b) { return (a || b); }
-static int op_and(int a, int b) { return (a && b); }
+static Linetype op_strict(int *p, int v, Linetype at, Linetype bt) {
+ if(at == LT_IF || bt == LT_IF) return (LT_IF);
+ return (*p = v, v ? LT_TRUE : LT_FALSE);
+}
+static Linetype op_lt(int *p, Linetype at, int a, Linetype bt, int b) {
+ return op_strict(p, a < b, at, bt);
+}
+static Linetype op_gt(int *p, Linetype at, int a, Linetype bt, int b) {
+ return op_strict(p, a > b, at, bt);
+}
+static Linetype op_le(int *p, Linetype at, int a, Linetype bt, int b) {
+ return op_strict(p, a <= b, at, bt);
+}
+static Linetype op_ge(int *p, Linetype at, int a, Linetype bt, int b) {
+ return op_strict(p, a >= b, at, bt);
+}
+static Linetype op_eq(int *p, Linetype at, int a, Linetype bt, int b) {
+ return op_strict(p, a == b, at, bt);
+}
+static Linetype op_ne(int *p, Linetype at, int a, Linetype bt, int b) {
+ return op_strict(p, a != b, at, bt);
+}
+static Linetype op_or(int *p, Linetype at, int a, Linetype bt, int b) {
+ if (!strictlogic && (at == LT_TRUE || bt == LT_TRUE))
+ return (*p = 1, LT_TRUE);
+ return op_strict(p, a || b, at, bt);
+}
+static Linetype op_and(int *p, Linetype at, int a, Linetype bt, int b) {
+ if (!strictlogic && (at == LT_FALSE || bt == LT_FALSE))
+ return (*p = 0, LT_FALSE);
+ return op_strict(p, a && b, at, bt);
+}
/*
* An evaluation function takes three arguments, as follows: (1) a pointer to
@@ -632,8 +672,8 @@ static int op_and(int a, int b) { return (a && b); }
* value of the expression; and (3) a pointer to a char* that points to the
* expression to be evaluated and that is updated to the end of the expression
* when evaluation is complete. The function returns LT_FALSE if the value of
- * the expression is zero, LT_TRUE if it is non-zero, or LT_IF if the
- * expression could not be evaluated.
+ * the expression is zero, LT_TRUE if it is non-zero, LT_IF if the expression
+ * depends on an unknown symbol, or LT_ERROR if there is a parse failure.
*/
struct ops;
@@ -652,7 +692,7 @@ static const struct ops {
eval_fn *inner;
struct op {
const char *str;
- int (*fn)(int, int);
+ Linetype (*fn)(int *, Linetype, int, Linetype, int);
} op[5];
} eval_ops[] = {
{ eval_table, { { "||", op_or } } },
@@ -667,8 +707,8 @@ static const struct ops {
/*
* Function for evaluating the innermost parts of expressions,
- * viz. !expr (expr) defined(symbol) symbol number
- * We reset the keepthis flag when we find a non-constant subexpression.
+ * viz. !expr (expr) number defined(symbol) symbol
+ * We reset the constexpr flag in the last two cases.
*/
static Linetype
eval_unary(const struct ops *ops, int *valp, const char **cpp)
@@ -677,25 +717,34 @@ eval_unary(const struct ops *ops, int *valp, const char **cpp)
char *ep;
int sym;
bool defparen;
+ Linetype lt;
cp = skipcomment(*cpp);
if (*cp == '!') {
debug("eval%d !", ops - eval_ops);
cp++;
- if (eval_unary(ops, valp, &cp) == LT_IF)
- return (LT_IF);
- *valp = !*valp;
+ lt = eval_unary(ops, valp, &cp);
+ if (lt == LT_ERROR)
+ return (LT_ERROR);
+ if (lt != LT_IF) {
+ *valp = !*valp;
+ lt = *valp ? LT_TRUE : LT_FALSE;
+ }
} else if (*cp == '(') {
cp++;
debug("eval%d (", ops - eval_ops);
- if (eval_table(eval_ops, valp, &cp) == LT_IF)
- return (LT_IF);
+ lt = eval_table(eval_ops, valp, &cp);
+ if (lt == LT_ERROR)
+ return (LT_ERROR);
cp = skipcomment(cp);
if (*cp++ != ')')
- return (LT_IF);
+ return (LT_ERROR);
} else if (isdigit((unsigned char)*cp)) {
debug("eval%d number", ops - eval_ops);
*valp = strtol(cp, &ep, 0);
+ if (ep == cp)
+ return (LT_ERROR);
+ lt = *valp ? LT_TRUE : LT_FALSE;
cp = skipsym(cp);
} else if (strncmp(cp, "defined", 7) == 0 && endsym(cp[7])) {
cp = skipcomment(cp+7);
@@ -707,36 +756,43 @@ eval_unary(const struct ops *ops, int *valp, const char **cpp)
defparen = false;
}
sym = findsym(cp);
- if (sym < 0)
- return (LT_IF);
- *valp = (value[sym] != NULL);
+ if (sym < 0) {
+ lt = LT_IF;
+ } else {
+ *valp = (value[sym] != NULL);
+ lt = *valp ? LT_TRUE : LT_FALSE;
+ }
cp = skipsym(cp);
cp = skipcomment(cp);
if (defparen && *cp++ != ')')
- return (LT_IF);
- keepthis = false;
+ return (LT_ERROR);
+ constexpr = false;
} else if (!endsym(*cp)) {
debug("eval%d symbol", ops - eval_ops);
sym = findsym(cp);
- if (sym < 0)
- return (LT_IF);
- if (value[sym] == NULL)
+ cp = skipsym(cp);
+ if (sym < 0) {
+ lt = LT_IF;
+ cp = skipargs(cp);
+ } else if (value[sym] == NULL) {
*valp = 0;
- else {
+ lt = LT_FALSE;
+ } else {
*valp = strtol(value[sym], &ep, 0);
if (*ep != '\0' || ep == value[sym])
- return (LT_IF);
+ return (LT_ERROR);
+ lt = *valp ? LT_TRUE : LT_FALSE;
+ cp = skipargs(cp);
}
- cp = skipsym(cp);
- keepthis = false;
+ constexpr = false;
} else {
debug("eval%d bad expr", ops - eval_ops);
- return (LT_IF);
+ return (LT_ERROR);
}
*cpp = cp;
debug("eval%d = %d", ops - eval_ops, *valp);
- return (*valp ? LT_TRUE : LT_FALSE);
+ return (lt);
}
/*
@@ -748,11 +804,13 @@ eval_table(const struct ops *ops, int *valp, const char **cpp)
const struct op *op;
const char *cp;
int val;
+ Linetype lt, rt;
debug("eval%d", ops - eval_ops);
cp = *cpp;
- if (ops->inner(ops+1, valp, &cp) == LT_IF)
- return (LT_IF);
+ lt = ops->inner(ops+1, valp, &cp);
+ if (lt == LT_ERROR)
+ return (LT_ERROR);
for (;;) {
cp = skipcomment(cp);
for (op = ops->op; op->str != NULL; op++)
@@ -762,14 +820,16 @@ eval_table(const struct ops *ops, int *valp, const char **cpp)
break;
cp += strlen(op->str);
debug("eval%d %s", ops - eval_ops, op->str);
- if (ops->inner(ops+1, &val, &cp) == LT_IF)
- return (LT_IF);
- *valp = op->fn(*valp, val);
+ rt = ops->inner(ops+1, &val, &cp);
+ if (rt == LT_ERROR)
+ return (LT_ERROR);
+ lt = op->fn(valp, lt, *valp, rt, val);
}
*cpp = cp;
debug("eval%d = %d", ops - eval_ops, *valp);
- return (*valp ? LT_TRUE : LT_FALSE);
+ debug("eval%d lt = %s", ops - eval_ops, linetype_name[lt]);
+ return (lt);
}
/*
@@ -784,10 +844,10 @@ ifeval(const char **cpp)
int val = 0;
debug("eval %s", *cpp);
- keepthis = killconsts ? false : true;
+ constexpr = killconsts ? false : true;
ret = eval_table(eval_ops, &val, cpp);
debug("eval = %d", val);
- return (keepthis ? LT_IF : ret);
+ return (constexpr ? LT_IF : ret == LT_ERROR ? LT_IF : ret);
}
/*
@@ -899,6 +959,31 @@ skipcomment(const char *cp)
}
/*
+ * Skip macro arguments.
+ */
+static const char *
+skipargs(const char *cp)
+{
+ const char *ocp = cp;
+ int level = 0;
+ cp = skipcomment(cp);
+ if (*cp != '(')
+ return (cp);
+ do {
+ if (*cp == '(')
+ level++;
+ if (*cp == ')')
+ level--;
+ cp = skipcomment(cp+1);
+ } while (level != 0 && *cp != '\0');
+ if (level == 0)
+ return (cp);
+ else
+ /* Rewind and re-detect the syntax error later. */
+ return (ocp);
+}
+
+/*
* Skip over an identifier.
*/
static const char *
OpenPOWER on IntegriCloud