summaryrefslogtreecommitdiffstats
path: root/usr.bin
diff options
context:
space:
mode:
authorfanf <fanf@FreeBSD.org>2003-01-20 12:41:41 +0000
committerfanf <fanf@FreeBSD.org>2003-01-20 12:41:41 +0000
commitd707a4320db2fa86d34e3eb17eb2780b92c9930e (patch)
treea64f180e864037a5027e56b50cf24216f4837cd4 /usr.bin
parentb222781a3d7a2ebc9d8dadaf47aecae9a8582200 (diff)
downloadFreeBSD-src-d707a4320db2fa86d34e3eb17eb2780b92c9930e.zip
FreeBSD-src-d707a4320db2fa86d34e3eb17eb2780b92c9930e.tar.gz
Sync with upstream again:
* Be less strict about multi-line preprocessor directives (e.g. those with comments hanging off the right-hand end) since they're more of a problem in practise than I expected. Prompted by phk. * Fix the handling of "ignore" symbols. * Style pedantry from OpenBSD and Ted Unangst <tedu@stanford.edu>, including some whitespace fixes and removal of strcpy() (and not including excessively strict KNF enforcement). * Fix some typos and terminological inconsistencies.
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/unifdef/Makefile1
-rw-r--r--usr.bin/unifdef/unifdef.124
-rw-r--r--usr.bin/unifdef/unifdef.c182
3 files changed, 148 insertions, 59 deletions
diff --git a/usr.bin/unifdef/Makefile b/usr.bin/unifdef/Makefile
index e3817d1..de6c53a 100644
--- a/usr.bin/unifdef/Makefile
+++ b/usr.bin/unifdef/Makefile
@@ -6,5 +6,6 @@ MAINTAINER= fanf@FreeBSD.org
PROG= unifdef
SCRIPTS=unifdefall.sh
MLINKS= unifdef.1 unifdefall.1
+WARNS?= 5
.include <bsd.prog.mk>
diff --git a/usr.bin/unifdef/unifdef.1 b/usr.bin/unifdef/unifdef.1
index 6bc771c..fd76e14 100644
--- a/usr.bin/unifdef/unifdef.1
+++ b/usr.bin/unifdef/unifdef.1
@@ -33,7 +33,7 @@
.\" SUCH DAMAGE.
.\"
.\" @(#)unifdef.1 8.2 (Berkeley) 4/1/94
-.\" $dotat: things/unifdef.1,v 1.40 2002/12/13 11:33:34 fanf2 Exp $
+.\" $dotat: things/unifdef.1,v 1.43 2003/01/20 11:36:12 fanf2 Exp $
.\" $FreeBSD$
.\"
.Dd September 24, 2002
@@ -44,7 +44,7 @@
.Nd remove preprocessor conditionals from code
.Sh SYNOPSIS
.Nm
-.Op Fl cklst
+.Op Fl ceklst
.Oo
.Fl I Ns Ar path
.Fl D Ns Ar sym Ns Op = Ns Ar val
@@ -157,6 +157,24 @@ is complemented,
i.e., the lines that would have been removed or blanked
are retained and vice versa.
.Pp
+.It Fl e
+Because
+.Nm
+processes its input one line at a time,
+it cannot remove preprocessor directives that span more than one line.
+The most common example of this is a directive with a multi-line
+comment hanging off its right hand end.
+By default,
+if
+.Nm
+has to process such a directive,
+it will complain that the line is too obfuscated.
+The
+.Fl e
+option changes the behaviour so that,
+where possible,
+such lines are left unprocessed instead of reporting an error.
+.Pp
.It Fl k
Process
.Ic #if
@@ -285,7 +303,7 @@ Expression evaluation is very limited.
.Pp
Preprocessor control lines split across more than one physical line
(because of comments or backslash-newline)
-cannot be handled.
+cannot be handled in every situation.
.Pp
Trigraphs are not recognized.
.Pp
diff --git a/usr.bin/unifdef/unifdef.c b/usr.bin/unifdef/unifdef.c
index 01d4e9e..66f65d8 100644
--- a/usr.bin/unifdef/unifdef.c
+++ b/usr.bin/unifdef/unifdef.c
@@ -44,7 +44,7 @@ static const char copyright[] =
#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.133 2003/01/17 19:04:36 fanf2 Exp $");
+__IDSTRING(dotat, "$dotat: things/unifdef.c,v 1.148 2003/01/20 12:05:41 fanf2 Exp $");
#endif
#ifdef __FBSDID
__FBSDID("$FreeBSD$");
@@ -61,6 +61,9 @@ __FBSDID("$FreeBSD$");
* #else's and #endif's to see that they match their
* corresponding #ifdef or #ifndef
* generate #line directives in place of deleted code
+ *
+ * The first two items above require better buffer handling, which would
+ * also make it possible to handle all "dodgy" directives correctly.
*/
#include <ctype.h>
@@ -74,7 +77,6 @@ __FBSDID("$FreeBSD$");
/* types of input lines: */
typedef enum {
- LT_PLAIN, /* ordinary line */
LT_TRUEI, /* a true #if with ignore flag */
LT_FALSEI, /* a false #if with ignore flag */
LT_IF, /* an unknown #if */
@@ -85,13 +87,21 @@ typedef enum {
LT_ELFALSE, /* a false #elif */
LT_ELSE, /* #else */
LT_ENDIF, /* #endif */
+ LT_DODGY, /* flag: directive is not on one line */
+ LT_DODGY_LAST = LT_DODGY + LT_ENDIF,
+ LT_PLAIN, /* ordinary line */
LT_EOF, /* end of file */
LT_COUNT
} Linetype;
static char const * const linetype_name[] = {
- "PLAIN", "TRUEI", "FALSEI", "IF", "TRUE", "FALSE",
- "ELIF", "ELTRUE", "ELFALSE", "ELSE", "ENDIF", "EOF"
+ "TRUEI", "FALSEI", "IF", "TRUE", "FALSE",
+ "ELIF", "ELTRUE", "ELFALSE", "ELSE", "ENDIF",
+ "DODGY TRUEI", "DODGY FALSEI",
+ "DODGY IF", "DODGY TRUE", "DODGY FALSE",
+ "DODGY ELIF", "DODGY ELTRUE", "DODGY ELFALSE",
+ "DODGY ELSE", "DODGY ENDIF",
+ "PLAIN", "EOF"
};
/* state of #if processing */
@@ -111,8 +121,8 @@ typedef enum {
static char const * const ifstate_name[] = {
"OUTSIDE", "FALSE_PREFIX", "TRUE_PREFIX",
- "PASS_MIDDLE", "FALSE_MIDDLE", "TRUE_MIDDLE",
- "PASS_ELSE", "FALSE_ELSE", "TRUE_ELSE",
+ "PASS_MIDDLE", "FALSE_MIDDLE", "TRUE_MIDDLE",
+ "PASS_ELSE", "FALSE_ELSE", "TRUE_ELSE",
"FALSE_TRAILER"
};
@@ -148,11 +158,18 @@ static char const * const linestate_name[] = {
#define MAXSYMS 4096 /* maximum number of symbols */
/*
+ * Sometimes when editing a keyword the replacement text is longer, so
+ * we leave some space at the end of the tline buffer to accommodate this.
+ */
+#define EDITSLOP 10
+
+/*
* Globals.
*/
static bool complement; /* -c: do the complement */
static bool debugging; /* -d: debugging reports */
+static bool iocccok; /* -e: fewer IOCCC errors */
static bool killconsts; /* -k: eval constant #ifs */
static bool lnblank; /* -l: blank deleted lines */
static bool symlist; /* -s: output symbol list */
@@ -167,7 +184,7 @@ static FILE *input; /* input file pointer */
static const char *filename; /* input file name */
static int linenum; /* current line number */
-static char tline[MAXLINE+10]; /* input buffer plus space */
+static char tline[MAXLINE+EDITSLOP];/* input buffer plus space */
static char *keyword; /* used for editing #elif's */
static Comment_state incomment; /* comment parser state */
@@ -187,13 +204,15 @@ static int findsym(const char *);
static void flushline(bool);
static Linetype getline(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 *skipcomment(const char *);
static const char *skipsym(const char *);
static void state(Ifstate);
static int strlcmp(const char *, const char *, size_t);
-static void unignore(void);
static void usage(void);
#define endsym(c) (!isalpha((unsigned char)c) && !isdigit((unsigned char)c) && c != '_')
@@ -206,7 +225,7 @@ main(int argc, char *argv[])
{
int opt;
- while ((opt = getopt(argc, argv, "i:D:U:I:cdklst")) != -1)
+ while ((opt = getopt(argc, argv, "i:D:U:I:cdeklst")) != -1)
switch (opt) {
case 'i': /* treat stuff controlled by these symbols as text */
/*
@@ -237,6 +256,9 @@ main(int argc, char *argv[])
case 'd':
debugging = true;
break;
+ case 'e': /* fewer errors from dodgy lines */
+ iocccok = true;
+ break;
case 'k': /* process constant #ifs */
killconsts = true;
break;
@@ -279,9 +301,9 @@ main(int argc, char *argv[])
static void
usage(void)
{
- fprintf(stderr, "usage: %s",
-"unifdef [-cdklst] [[-Dsym[=val]] [-Usym] [-iDsym[=val]] [-iUsym]] ... [file]\n");
- exit (2);
+ fprintf(stderr, "usage: unifdef [-cdeklst]"
+ " [[-Dsym[=val]] [-Usym] [-iDsym[=val]] [-iUsym]] ... [file]\n");
+ exit(2);
}
/*
@@ -291,19 +313,28 @@ usage(void)
* indicate that processing is complete.
*
* Nesting is handled by keeping a stack of states; some transition
- * functions increase or decrease the depth. They also maintin the
+ * functions increase or decrease the depth. They also maintain the
* ignore state on a stack. In some complicated cases they have to
* alter the preprocessor directive, as follows.
*
* When we have processed a group that starts off with a known-false
* #if/#elif sequence (which has therefore been deleted) followed by a
- * #elif that we don't understand and therefore must keep, we turn the
+ * #elif that we don't understand and therefore must keep, we edit the
* latter into a #if to keep the nesting correct.
*
* When we find a true #elif in a group, the following block will
* always be kept and the rest of the sequence after the next #elif or
- * #else will be discarded. We change the #elif to #else and the
+ * #else will be discarded. We edit the #elif into a #else and the
* following directive to #endif since this has the desired behaviour.
+ *
+ * "Dodgy" directives are split across multiple lines, the most common
+ * example being a multi-line comment hanging off the right of the
+ * directive. We can handle them correctly only if there is no change
+ * from printing to dropping (or vice versa) caused by that directive.
+ * If the directive is the first of a group we have a choice between
+ * failing with an error, or passing it through unchanged instead of
+ * evaluating it. The latter is not the default to avoid questions from
+ * users about unifdef unexpectedly leaving behind preprocessor directives.
*/
typedef void state_fn(void);
@@ -317,65 +348,103 @@ static void Eioccc(void) { error("Obfuscated preprocessor control line"); }
static void print (void) { flushline(true); }
static void drop (void) { flushline(false); }
/* output lacks group's start line */
-static void Strue (void) { drop(); unignore(); state(IS_TRUE_PREFIX); }
-static void Sfalse(void) { drop(); unignore(); state(IS_FALSE_PREFIX); }
-static void Selse (void) { drop(); state(IS_TRUE_ELSE); }
+static void Strue (void) { drop(); ignoreoff(); state(IS_TRUE_PREFIX); }
+static void Sfalse(void) { drop(); ignoreoff(); state(IS_FALSE_PREFIX); }
+static void Selse (void) { drop(); state(IS_TRUE_ELSE); }
/* print/pass this block */
-static void Pelif (void) { print(); unignore(); state(IS_PASS_MIDDLE); }
-static void Pelse (void) { print(); state(IS_PASS_ELSE); }
+static void Pelif (void) { print(); ignoreoff(); state(IS_PASS_MIDDLE); }
+static void Pelse (void) { print(); state(IS_PASS_ELSE); }
static void Pendif(void) { print(); --depth; }
/* discard this block */
-static void Dfalse(void) { drop(); unignore(); state(IS_FALSE_TRAILER); }
-static void Delif (void) { drop(); unignore(); state(IS_FALSE_MIDDLE); }
-static void Delse (void) { drop(); state(IS_FALSE_ELSE); }
+static void Dfalse(void) { drop(); ignoreoff(); state(IS_FALSE_TRAILER); }
+static void Delif (void) { drop(); ignoreoff(); state(IS_FALSE_MIDDLE); }
+static void Delse (void) { drop(); state(IS_FALSE_ELSE); }
static void Dendif(void) { drop(); --depth; }
/* first line of group */
static void Fdrop (void) { nest(); Dfalse(); }
static void Fpass (void) { nest(); Pelif(); }
static void Ftrue (void) { nest(); Strue(); }
static void Ffalse(void) { nest(); Sfalse(); }
+/* variable pedantry for obfuscated lines */
+static void Oiffy (void) { if (iocccok) Fpass(); else Eioccc(); ignoreon(); }
+static void Oif (void) { if (iocccok) Fpass(); else Eioccc(); }
+static void Oelif (void) { if (iocccok) Pelif(); else Eioccc(); }
/* ignore comments in this block */
-static void Idrop (void) { Fdrop(); ignore[depth] = true; }
-static void Itrue (void) { Ftrue(); ignore[depth] = true; }
-static void Ifalse(void) { Ffalse(); ignore[depth] = true; }
-/* modify this line */
-static void
-Mpass (void) { strncpy(keyword, "if ", 4); Pelif(); }
-static void
-Mtrue (void) { strcpy(keyword, "else\n"); print(); state(IS_TRUE_MIDDLE); }
-static void
-Melif (void) { strcpy(keyword, "endif\n"); print(); state(IS_FALSE_TRAILER); }
-static void
-Melse (void) { strcpy(keyword, "endif\n"); print(); state(IS_FALSE_ELSE); }
+static void Idrop (void) { Fdrop(); ignoreon(); }
+static void Itrue (void) { Ftrue(); ignoreon(); }
+static void Ifalse(void) { Ffalse(); ignoreon(); }
+/* edit this line */
+static void Mpass (void) { strncpy(keyword, "if ", 4); Pelif(); }
+static void Mtrue (void) { keywordedit("else\n"); state(IS_TRUE_MIDDLE); }
+static void Melif (void) { keywordedit("endif\n"); state(IS_FALSE_TRAILER); }
+static void Melse (void) { keywordedit("endif\n"); state(IS_FALSE_ELSE); }
static state_fn * const trans_table[IS_COUNT][LT_COUNT] = {
/* IS_OUTSIDE */
-{print,Itrue,Ifalse,Fpass,Ftrue,Ffalse,Eelif, Eelif, Eelif, Eelse,Eendif,NULL},
+{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Eendif,
+ Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Eendif,
+ print, NULL },
/* IS_FALSE_PREFIX */
-{drop, Idrop,Idrop, Fdrop,Fdrop,Fdrop, Mpass, Strue, Sfalse,Selse,Dendif,Eeof},
+{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Mpass, Strue, Sfalse,Selse, Dendif,
+ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Mpass, Eioccc,Eioccc,Eioccc,Eioccc,
+ drop, Eeof },
/* IS_TRUE_PREFIX */
-{print,Itrue,Ifalse,Fpass,Ftrue,Ffalse,Dfalse,Dfalse,Dfalse,Delse,Dendif,Eeof},
+{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Dfalse,Dfalse,Dfalse,Delse, Dendif,
+ Oiffy, Oiffy, Fpass, Oif, Oif, Eioccc,Eioccc,Eioccc,Eioccc,Eioccc,
+ print, Eeof },
/* IS_PASS_MIDDLE */
-{print,Itrue,Ifalse,Fpass,Ftrue,Ffalse,Pelif, Mtrue, Delif, Pelse,Pendif,Eeof},
+{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Pelif, Mtrue, Delif, Pelse, Pendif,
+ Oiffy, Oiffy, Fpass, Oif, Oif, Pelif, Oelif, Oelif, Pelse, Pendif,
+ print, Eeof },
/* IS_FALSE_MIDDLE */
-{drop, Idrop,Idrop, Fdrop,Fdrop,Fdrop, Pelif, Mtrue, Delif, Pelse,Pendif,Eeof},
+{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Pelif, Mtrue, Delif, Pelse, Pendif,
+ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eioccc,Eioccc,Eioccc,Eioccc,Eioccc,
+ drop, Eeof },
/* IS_TRUE_MIDDLE */
-{print,Itrue,Ifalse,Fpass,Ftrue,Ffalse,Melif, Melif, Melif, Melse,Pendif,Eeof},
+{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Melif, Melif, Melif, Melse, Pendif,
+ Oiffy, Oiffy, Fpass, Oif, Oif, Eioccc,Eioccc,Eioccc,Eioccc,Pendif,
+ print, Eeof },
/* IS_PASS_ELSE */
-{print,Itrue,Ifalse,Fpass,Ftrue,Ffalse,Eelif, Eelif, Eelif, Eelse,Pendif,Eeof},
+{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Pendif,
+ Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Pendif,
+ print, Eeof },
/* IS_FALSE_ELSE */
-{drop, Idrop,Idrop, Fdrop,Fdrop,Fdrop, Eelif, Eelif, Eelif, Eelse,Dendif,Eeof},
+{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eelif, Eelif, Eelif, Eelse, Dendif,
+ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eelif, Eelif, Eelif, Eelse, Eioccc,
+ drop, Eeof },
/* IS_TRUE_ELSE */
-{print,Itrue,Ifalse,Fpass,Ftrue,Ffalse,Eelif, Eelif, Eelif, Eelse,Dendif,Eeof},
+{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Dendif,
+ Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Eioccc,
+ print, Eeof },
/* IS_FALSE_TRAILER */
-{drop, Idrop,Idrop, Fdrop,Fdrop,Fdrop, Dfalse,Dfalse,Dfalse,Delse,Dendif,Eeof}
-/*PLAIN TRUEI FALSEI IF TRUE FALSE ELIF ELTRUE ELFALSE ELSE ENDIF EOF*/
+{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Dfalse,Dfalse,Dfalse,Delse, Dendif,
+ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Dfalse,Dfalse,Dfalse,Delse, Eioccc,
+ drop, Eeof }
+/*TRUEI FALSEI IF TRUE FALSE ELIF ELTRUE ELFALSE ELSE ENDIF
+ TRUEI FALSEI IF TRUE FALSE ELIF ELTRUE ELFALSE ELSE ENDIF (DODGY)
+ PLAIN EOF */
};
/*
* State machine utility functions
*/
static void
+ignoreoff(void)
+{
+ ignoring[depth] = ignoring[depth-1];
+}
+static void
+ignoreon(void)
+{
+ ignoring[depth] = true;
+}
+static void
+keywordedit(const char *replacement)
+{
+ strlcpy(keyword, replacement, tline + sizeof(tline) - keyword);
+ print();
+}
+static void
nest(void)
{
depth += 1;
@@ -388,11 +457,6 @@ state(Ifstate is)
{
ifstate[depth] = is;
}
-static void
-unignore(void)
-{
- ignore[depth] = ignore[depth-1];
-}
/*
* Write a line to the output or not, according to command line options.
@@ -464,6 +528,7 @@ getline(void)
keyword = tline + (cp - tline);
cp = skipsym(cp);
kwlen = cp - keyword;
+ /* no way can we deal with a continuation inside a keyword */
if (strncmp(cp, "\\\n", 2) == 0)
Eioccc();
if (strlcmp("ifdef", keyword, kwlen) == 0 ||
@@ -503,8 +568,12 @@ getline(void)
if (retval == LT_ELTRUE || retval == LT_ELFALSE)
retval = LT_ELIF;
}
- if (retval != LT_PLAIN && (wascomment || incomment))
- Eioccc();
+ if (retval != LT_PLAIN && (wascomment || incomment)) {
+ retval += LT_DODGY;
+ if (incomment)
+ linestate = LS_DIRTY;
+ }
+ /* skipcomment should have changed the state */
if (linestate == LS_HASH)
abort(); /* bug */
}
@@ -582,7 +651,7 @@ eval_unary(const struct ops *ops, int *valp, const char **cpp)
int sym;
cp = skipcomment(*cpp);
- if(*cp == '!') {
+ if (*cp == '!') {
debug("eval%d !", ops - eval_ops);
cp++;
if (eval_unary(ops, valp, &cp) == LT_IF)
@@ -869,8 +938,9 @@ static void
error(const char *msg)
{
if (depth == 0)
- errx(2, "%s: %d: %s", filename, linenum, msg);
+ warnx("%s: %d: %s", filename, linenum, msg);
else
- errx(2, "%s: %d: %s (#if line %d depth %d)",
+ warnx("%s: %d: %s (#if line %d depth %d)",
filename, linenum, msg, stifline[depth], depth);
+ errx(2, "output may be truncated");
}
OpenPOWER on IntegriCloud