Author: fanf
Date: Wed Dec  2 15:34:13 2009
New Revision: 200032
URL: http://svn.freebsd.org/changeset/base/200032

Log:
  MFC 199813, 199817, 199842, 199867:
  
  Update unifdef to latest upstream version.

Modified:
  stable/7/usr.bin/unifdef/unifdef.1
  stable/7/usr.bin/unifdef/unifdef.c
  stable/7/usr.bin/unifdef/unifdefall.sh
Directory Properties:
  stable/7/usr.bin/unifdef/   (props changed)

Modified: stable/7/usr.bin/unifdef/unifdef.1
==============================================================================
--- stable/7/usr.bin/unifdef/unifdef.1  Wed Dec  2 15:30:53 2009        
(r200031)
+++ stable/7/usr.bin/unifdef/unifdef.1  Wed Dec  2 15:34:13 2009        
(r200032)
@@ -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 <d...@dotat.at>.  All rights reserved.
+.\" Copyright (c) 2002 - 2009 Tony Finch <d...@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 d...@yost.com .
 .An Tony Finch Aq d...@dotat.at
 rewrote it to support

Modified: stable/7/usr.bin/unifdef/unifdef.c
==============================================================================
--- stable/7/usr.bin/unifdef/unifdef.c  Wed Dec  2 15:30:53 2009        
(r200031)
+++ stable/7/usr.bin/unifdef/unifdef.c  Wed Dec  2 15:34:13 2009        
(r200032)
@@ -1,13 +1,5 @@
 /*
- * Copyright (c) 2002 - 2005 Tony Finch <d...@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. The original version of
- * unifdef carried the following copyright notice. None of its code remains
- * in this version (though some of the names remain).
- *
- * Copyright (c) 1985, 1993
- *     The Regents of the University of California.  All rights reserved.
+ * Copyright (c) 2002 - 2009 Tony Finch <d...@dotat.at>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -31,20 +23,21 @@
  * SUCH DAMAGE.
  */
 
+/*
+ * 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.171 2005/03/08 12:38:48 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[MAXDEPT
 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 ch
 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_C
 /* 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;
@@ -586,9 +607,21 @@ getline(void)
                        if (incomment)
                                linestate = LS_DIRTY;
                }
-               /* skipcomment should have changed the state */
-               if (linestate == LS_HASH)
-                       abort(); /* bug */
+               /* skipcomment normally changes the state, except
+                  if the last line of the file lacks a newline, or
+                  if there is too much whitespace in a directive */
+               if (linestate == LS_HASH) {
+                       size_t len = cp - tline;
+                       if (fgets(tline + len, MAXLINE - len, input) == NULL) {
+                               /* append the missing newline */
+                               tline[len+0] = '\n';
+                               tline[len+1] = '\0';
+                               cp++;
+                               linestate = LS_START;
+                       } else {
+                               linestate = LS_DIRTY;
+                       }
+               }
        }
        if (linestate == LS_DIRTY) {
                while (*cp != '\0')
@@ -601,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
@@ -620,8 +676,8 @@ static int op_and(int a, int b) { return
  * 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;
 
@@ -640,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 } } },
@@ -655,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)
@@ -664,63 +720,83 @@ eval_unary(const struct ops *ops, int *v
        const char *cp;
        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);
                debug("eval%d defined", ops - eval_ops);
-               if (*cp++ != '(')
-                       return (LT_IF);
-               cp = skipcomment(cp);
+               if (*cp == '(') {
+                       cp = skipcomment(cp+1);
+                       defparen = true;
+               } else {
+                       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 (*cp++ != ')')
-                       return (LT_IF);
-               keepthis = false;
+               if (defparen && *cp++ != ')')
+                       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);
 }
 
 /*
@@ -732,11 +808,13 @@ eval_table(const struct ops *ops, int *v
        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++)
@@ -746,14 +824,16 @@ eval_table(const struct ops *ops, int *v
                        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);
 }
 
 /*
@@ -765,13 +845,13 @@ static Linetype
 ifeval(const char **cpp)
 {
        int ret;
-       int val;
+       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);
 }
 
 /*
@@ -883,6 +963,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 *
@@ -894,7 +999,7 @@ skipsym(const char *cp)
 }
 
 /*
- * Look for the symbol in the symbol table. If is is found, we return
+ * Look for the symbol in the symbol table. If it is found, we return
  * the symbol table index, else we return -1.
  */
 static int

Modified: stable/7/usr.bin/unifdef/unifdefall.sh
==============================================================================
--- stable/7/usr.bin/unifdef/unifdefall.sh      Wed Dec  2 15:30:53 2009        
(r200031)
+++ stable/7/usr.bin/unifdef/unifdefall.sh      Wed Dec  2 15:34:13 2009        
(r200032)
@@ -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 <d...@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
-
-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
+basename=$(basename $0)
+tmp=$(mktemp -d "${TMPDIR:-/tmp}/$basename.XXXXXXXXXX") || exit 2
+trap 'rm -r "$tmp" || exit 1' EXIT
 
-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 "$@"
+export LC_ALL=C
 
-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" "$@"
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to