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/
This commit is contained in:
Tony Finch 2009-11-25 20:23:18 +00:00
parent 5c2d577a21
commit f6f85e213e
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/head/; revision=199813
3 changed files with 300 additions and 134 deletions

View File

@ -1,6 +1,6 @@
.\" Copyright (c) 1985, 1991, 1993
.\" The Regents of the University of California. All rights reserved.
.\" Copyright (c) 2002 - 2005 Tony Finch <dot@dotat.at>. All rights reserved.
.\" Copyright (c) 2002 - 2009 Tony Finch <dot@dotat.at>. All rights reserved.
.\"
.\" This code is derived from software contributed to Berkeley by
.\" Dave Yost. It was rewritten to support ANSI C by Tony Finch.
@ -30,7 +30,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)unifdef.1 8.2 (Berkeley) 4/1/94
.\" $dotat: things/unifdef.1,v 1.51 2005/03/08 12:39:01 fanf2 Exp $
.\" $dotat: unifdef/unifdef.1,v 1.60 2009/11/25 00:11:02 fanf2 Exp $
.\" $FreeBSD$
.\"
.Dd September 24, 2002
@ -41,7 +41,7 @@
.Nd remove preprocessor conditionals from code
.Sh SYNOPSIS
.Nm
.Op Fl cdeklnst
.Op Fl BbcdeKknst
.Op Fl I Ns Ar path
.Op Fl D Ns Ar sym Ns Op = Ns Ar val
.Op Fl U Ns Ar sym
@ -70,46 +70,85 @@ utility acts on
.Ic #if , #ifdef , #ifndef , #elif , #else ,
and
.Ic #endif
lines,
and it understands only the commonly-used subset
lines.
A directive is only processed
if the symbols specified on the command line are sufficient to allow
.Nm
to get a definite value for its control expression.
If the result is false,
the directive and the following lines under its control are removed.
If the result is true,
only the directive is removed.
An
.Ic #ifdef
or
.Ic #ifndef
directive is passed through unchanged
if its controlling symbol is not specified on the command line.
Any
.Ic #if
or
.Ic #elif
control expression that has an unknown value or that
.Nm
cannot parse is passed through unchanged.
By default,
.Nm
ignores
.Ic #if
and
.Ic #elif
lines with constant expressions;
it can be told to process them by specifying the
.Fl k
flag on the command line.
.Pp
It understands a commonly-used subset
of the expression syntax for
.Ic #if
and
.Ic #elif
lines.
It handles
lines:
integer constants,
integer values of symbols defined on the command line,
the
.Fn defined
operator applied to symbols defined or undefined on the command line,
operator,
the operators
.Ic \&! , < , > , <= , >= , == , != , && , || ,
and parenthesized expressions.
Anything that it does not understand is passed through unharmed.
It only processes
.Ic #ifdef
and
.Ic #ifndef
directives if the symbol is specified on the command line,
otherwise they are also passed through unchanged.
By default, it ignores
.Ic #if
and
.Ic #elif
lines with constant expressions,
or they may be processed by specifying the
.Fl k
flag on the command line.
A kind of
.Dq "short circuit"
evaluation is used for the
.Ic &&
operator:
if either operand is definitely false then the result is false,
even if the value of the other operand is unknown.
Similarly,
if either operand of
.Ic ||
is definitely true then the result is true.
.Pp
In most cases, the
.Nm
utility does not distinguish between object-like macros
(without arguments) and function-like arguments (with arguments).
If a macro is not explicitly defined, or is defined with the
.Fl D
flag on the command-line, its arguments are ignored.
If a macro is explicitly undefined on the command line with the
.Fl U
flag, it may not have any arguments since this leads to a syntax error.
.Pp
The
.Nm
utility also understands just enough about C
utility understands just enough about C
to know when one of the directives is inactive
because it is inside
a comment,
or affected by a backslash-continued line.
It spots unusually-formatted preprocessor directives
and knows when the layout is too odd to handle.
and knows when the layout is too odd for it to handle.
.Pp
A script called
.Nm unifdefall
@ -125,8 +164,7 @@ and their definitions (or lack thereof),
then invokes
.Nm
with appropriate arguments to process the file.
.Pp
Available options:
.Sh OPTIONS
.Pp
.Bl -tag -width indent -compact
.It Fl D Ns Ar sym Ns Op = Ns Ar val
@ -143,6 +181,19 @@ Specify that a symbol is undefined.
If the same symbol appears in more than one argument,
the last occurrence dominates.
.Pp
.It Fl B
Compress blank lines around a deleted section.
Mutually exclusive with the
.Fl b
option.
.Pp
.It Fl b
Replace removed lines with blank lines
instead of deleting them.
Mutually exclusive with the
.Fl B
option.
.Pp
.It Fl c
If the
.Fl c
@ -174,6 +225,16 @@ option changes the behaviour so that,
where possible,
such lines are left unprocessed instead of reporting an error.
.Pp
.It Fl K
Always treat the result of
.Ic &&
and
.Ic ||
operators as unknown if either operand is unknown,
instead of short-circuiting when unknown operands can't affect the result.
This option is for compatibility with older versions of
.Nm .
.Pp
.It Fl k
Process
.Ic #if
@ -186,10 +247,6 @@ because they typically start
and are used as a kind of comment to sketch out future or past development.
It would be rude to strip them out, just as it would be for normal comments.
.Pp
.It Fl l
Replace removed lines with blank lines
instead of deleting them.
.Pp
.It Fl n
Add
.Li #line
@ -235,7 +292,7 @@ comments
and line continuations
inside those
.Ic #ifdef Ns s .
One specifies ignored symbols with
You can specify ignored symbols with
.Fl iD Ns Ar sym Ns Oo = Ns Ar val Oc
and
.Fl iU Ns Ar sym
@ -313,7 +370,7 @@ command appeared in
support was added in
.Fx 4.7 .
.Sh AUTHORS
This implementation was originally written by
The original implementation was written by
.An Dave Yost Aq Dave@Yost.com .
.An Tony Finch Aq dot@dotat.at
rewrote it to support

View File

@ -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);
}
/*
@ -898,6 +958,31 @@ skipcomment(const char *cp)
return (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.
*/

View File

@ -1,29 +1,53 @@
#!/bin/sh
#
# remove all the #if's from a source file
# unifdefall: remove all the #if's from a source file
#
# $dotat: things/unifdefall.sh,v 1.9 2002/09/24 19:43:57 fanf2 Exp $
# Copyright (c) 2002 - 2009 Tony Finch <dot@dotat.at>. All rights reserved.
#
# 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 AUTHOR 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 AUTHOR 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.
#
# $dotat: unifdef/unifdefall.sh,v 1.21 2009/11/25 19:54:34 fanf2 Exp $
# $FreeBSD$
set -e
basename=`basename $0`
tmp=`mktemp -d -t $basename` || exit 2
basename=$(basename $0)
tmp=$(mktemp -d "${TMPDIR:-/tmp}/$basename.XXXXXXXXXX") || exit 2
trap 'rm -r "$tmp" || exit 1' EXIT
unifdef -s "$@" | sort | uniq > $tmp/ctrl
cpp -dM "$@" | sort |
sed -Ee 's/^#define[ ]+(.*[^ ])[ ]*$/\1/' > $tmp/hashdefs
sed -Ee 's/^([A-Za-z0-9_]+).*$/\1/' $tmp/hashdefs > $tmp/alldef
comm -23 $tmp/ctrl $tmp/alldef > $tmp/undef
comm -12 $tmp/ctrl $tmp/alldef > $tmp/def
export LC_ALL=C
echo unifdef -k \\ > $tmp/cmd
sed -Ee 's/^(.*)$/-U\1 \\/' $tmp/undef >> $tmp/cmd
while read sym
do sed -Ee '/^('"$sym"')([(][^)]*[)])?([ ]+(.*))?$/!d;s//-D\1=\4/' $tmp/hashdefs
done < $tmp/def |
sed -Ee 's/\\/\\\\/g;s/"/\\"/g;s/^/"/;s/$/" \\/' >> $tmp/cmd
echo '"$@"' >> $tmp/cmd
sh $tmp/cmd "$@"
rm -r $tmp
./unifdef -s "$@" | sort | uniq >"$tmp/ctrl"
cpp -dM "$@" | sort | sed 's/^#define //' >"$tmp/hashdefs"
sed 's/[^A-Za-z0-9_].*$//' "$tmp/hashdefs" >"$tmp/alldef"
comm -23 "$tmp/ctrl" "$tmp/alldef" >"$tmp/undef"
comm -12 "$tmp/ctrl" "$tmp/alldef" >"$tmp/def"
(
echo ./unifdef -k \\
sed 's/.*/-U& \\/' "$tmp/undef"
while read sym
do sed -n 's/^'$sym'\(([^)]*)\)\{0,1\} /-D'$sym'=/p' "$tmp/hashdefs"
done <"$tmp/def" |
sed "s/'/'\\\\''/g;s/.*/'&' \\\\/"
echo '"$@"'
) >"$tmp/cmd"
sh "$tmp/cmd" "$@"