MFC 199813, 199817, 199842, 199867:
Update unifdef to latest upstream version.
This commit is contained in:
parent
ab4ca9d195
commit
cb0593b42c
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/stable/8/; revision=200031
@ -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
|
||||
|
@ -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
|
||||
@ -24,27 +24,20 @@
|
||||
*/
|
||||
|
||||
/*
|
||||
* This code is derived from software contributed to Berkeley by Dave Yost.
|
||||
* This code was derived from software contributed to Berkeley by Dave Yost.
|
||||
* It was rewritten to support ANSI C by Tony Finch. The original version
|
||||
* of unifdef carried the 4-clause BSD copyright licence. None of its code
|
||||
* remains in this version (though some of the names remain) so it now
|
||||
* carries a more liberal licence.
|
||||
*
|
||||
* The latest version is available from http://dotat.at/prog/unifdef
|
||||
*/
|
||||
|
||||
#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.190 2009/11/27 17:21:26 fanf2 Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
#ifdef __FBSDID
|
||||
__FBSDID("$FreeBSD$");
|
||||
#endif
|
||||
@ -88,6 +81,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 +92,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 +160,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 +190,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 +202,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 +217,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 +227,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 +252,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 +268,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 +288,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 +308,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 +389,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 */
|
||||
};
|
||||
|
||||
/*
|
||||
@ -454,9 +462,11 @@ keywordedit(const char *replacement)
|
||||
static void
|
||||
nest(void)
|
||||
{
|
||||
depth += 1;
|
||||
if (depth >= MAXDEPTH)
|
||||
if (depth > MAXDEPTH-1)
|
||||
abort(); /* bug */
|
||||
if (depth == MAXDEPTH-1)
|
||||
error("Too many levels of nesting");
|
||||
depth += 1;
|
||||
stifline[depth] = linenum;
|
||||
}
|
||||
static void
|
||||
@ -481,15 +491,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 +519,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 +538,7 @@ process(void)
|
||||
* help from skipcomment().
|
||||
*/
|
||||
static Linetype
|
||||
getline(void)
|
||||
parseline(void)
|
||||
{
|
||||
const char *cp;
|
||||
int cursym;
|
||||
@ -613,17 +634,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 +676,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 +696,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 +711,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 +721,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 +760,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 +808,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 +824,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 +848,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 +962,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.
|
||||
*/
|
||||
|
@ -1,29 +1,61 @@
|
||||
#!/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.24 2009/11/26 12:54:39 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
|
||||
# list of all controlling macros
|
||||
unifdef -s "$@" | sort | uniq >"$tmp/ctrl"
|
||||
# list of all macro definitions
|
||||
cpp -dM "$@" | sort | sed 's/^#define //' >"$tmp/hashdefs"
|
||||
# list of defined macro names
|
||||
sed 's/[^A-Za-z0-9_].*$//' <"$tmp/hashdefs" >"$tmp/alldef"
|
||||
# list of undefined and defined controlling macros
|
||||
comm -23 "$tmp/ctrl" "$tmp/alldef" >"$tmp/undef"
|
||||
comm -12 "$tmp/ctrl" "$tmp/alldef" >"$tmp/def"
|
||||
# create a sed script that extracts the controlling macro definitions
|
||||
# and converts them to unifdef command-line arguments
|
||||
sed 's|.*|s/^&\\(([^)]*)\\)\\{0,1\\} /-D&=/p|' <"$tmp/def" >"$tmp/script"
|
||||
# create the final unifdef command
|
||||
{ echo unifdef -k \\
|
||||
# convert the controlling undefined macros to -U arguments
|
||||
sed 's/.*/-U& \\/' <"$tmp/undef"
|
||||
# convert the controlling defined macros to quoted -D arguments
|
||||
sed -nf "$tmp/script" <"$tmp/hashdefs" |
|
||||
sed "s/'/'\\\\''/g;s/.*/'&' \\\\/"
|
||||
echo '"$@"'
|
||||
} >"$tmp/cmd"
|
||||
# run the command we just created
|
||||
sh "$tmp/cmd" "$@"
|
||||
|
Loading…
Reference in New Issue
Block a user