Author: fanf
Date: Thu Dec  3 14:21:55 2015
New Revision: 291696
URL: https://svnweb.freebsd.org/changeset/base/291696

Log:
  Update to upstream version 2.11
  
  Improved #if expression evaluator and safer modify-in-place.
  
  Obtained from:        http://dotat.at/prog/unifdef
  MFC after:    1 week

Modified:
  head/usr.bin/unifdef/unifdef.1
  head/usr.bin/unifdef/unifdef.c
  head/usr.bin/unifdef/unifdef.h

Modified: head/usr.bin/unifdef/unifdef.1
==============================================================================
--- head/usr.bin/unifdef/unifdef.1      Thu Dec  3 14:17:28 2015        
(r291695)
+++ head/usr.bin/unifdef/unifdef.1      Thu Dec  3 14:21:55 2015        
(r291696)
@@ -1,6 +1,6 @@
 .\" Copyright (c) 1985, 1991, 1993
 .\"    The Regents of the University of California.  All rights reserved.
-.\" Copyright (c) 2002 - 2013 Tony Finch <d...@dotat.at>.  All rights reserved.
+.\" Copyright (c) 2002 - 2015 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.
@@ -31,7 +31,7 @@
 .\"
 .\" $FreeBSD$
 .\"
-.Dd January 7, 2014
+.Dd December 3, 2015
 .Dt UNIFDEF 1 PRM
 .Os " "
 .Sh NAME
@@ -122,10 +122,13 @@ the
 .Fn defined
 operator,
 the operators
-.Ic \&! , < , > ,
-.Ic <= , >= , == , != ,
+.Ic \&! , ~ , -
+(unary),
+.Ic * , / , % , + , - ,
+.Ic < , <= , > , >= , == , != , & , ^ , \&| ,
 .Ic && , || ,
 and parenthesized expressions.
+Division by zero is treated as an unknown value.
 A kind of
 .Dq "short circuit"
 evaluation is used for the
@@ -253,6 +256,11 @@ are set to the given value.
 Function-like macro definitions (with arguments)
 are treated as if they are set to 1.
 .Pp
+.Em Warning:
+string literals and character constants are not parsed correctly in
+.Fl f
+files.
+.Pp
 .It Fl b
 Replace removed lines with blank lines
 instead of deleting them.
@@ -325,12 +333,19 @@ It would be rude to strip them out, just
 .Pp
 .It Fl m
 Modify one or more input files in place.
+If an input file is not modified,
+the original is preserved instead of being overwritten with an identical copy.
 .Pp
 .It Fl M Ar backext
 Modify input files in place, and keep backups of the original files by
 appending the
 .Ar backext
 to the input filenames.
+A zero length
+.Ar backext
+behaves the same as the
+.Fl m
+option.
 .Pp
 .It Fl n
 Add
@@ -433,23 +448,29 @@ command line options are given.
 .Sh DIAGNOSTICS
 .Bl -item
 .It
-Too many levels of nesting.
+.Tn EOF
+in comment
 .It
 Inappropriate
 .Ic #elif ,
 .Ic #else
 or
-.Ic #endif .
+.Ic #endif
+.It
+Missing macro name in #define or #undef
 .It
-Obfuscated preprocessor control line.
+Obfuscated preprocessor control line
 .It
 Premature
 .Tn EOF
 (with the line number of the most recent unterminated
-.Ic #if ) .
+.Ic #if )
 .It
-.Tn EOF
-in comment.
+Too many levels of nesting
+.It
+Unrecognized preprocessor directive
+.It
+Unterminated char or string literal
 .El
 .Sh SEE ALSO
 .Xr cpp 1 ,
@@ -475,6 +496,12 @@ rewrote it to support
 .Sh BUGS
 Expression evaluation is very limited.
 .Pp
+Character constants are not evaluated.
+String literals and character constants in
+.Fl f
+definition files are ignored rather than parsed as
+part of a macro's replacement tokens.
+.Pp
 Handling one line at a time means
 preprocessor directives split across more than one physical line
 (because of comments or backslash-newline)

Modified: head/usr.bin/unifdef/unifdef.c
==============================================================================
--- head/usr.bin/unifdef/unifdef.c      Thu Dec  3 14:17:28 2015        
(r291695)
+++ head/usr.bin/unifdef/unifdef.c      Thu Dec  3 14:21:55 2015        
(r291696)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2002 - 2014 Tony Finch <d...@dotat.at>
+ * Copyright (c) 2002 - 2015 Tony Finch <d...@dotat.at>
  *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
@@ -46,7 +46,7 @@
 #include "unifdef.h"
 
 static const char copyright[] =
-    "@(#) $Version: unifdef-2.10 $\n"
+    "@(#) $Version: unifdef-2.11 $\n"
     "@(#) $FreeBSD$\n"
     "@(#) $Author: Tony Finch (d...@dotat.at) $\n"
     "@(#) $URL: http://dotat.at/prog/unifdef $\n"
@@ -208,6 +208,7 @@ static bool             firstsym;           /* di
 
 static int              exitmode;              /* exit status mode */
 static int              exitstat;              /* program exit status */
+static bool             altered;               /* was this file modified? */
 
 static void             addsym1(bool, bool, char *);
 static void             addsym2(bool, const char *, const char *);
@@ -312,7 +313,8 @@ main(int argc, char *argv[])
                        break;
                case 'M': /* modify in place and keep backup */
                        inplace = true;
-                       backext = optarg;
+                       if (strlen(optarg) > 0)
+                               backext = optarg;
                        break;
                case 'n': /* add #line directive after deleted lines */
                        lnnum = true;
@@ -350,6 +352,8 @@ main(int argc, char *argv[])
                errx(2, "-o cannot be used with multiple input files");
        if (argc > 1 && !inplace)
                errx(2, "multiple input files require -m or -M");
+       if (argc == 0 && inplace)
+               errx(2, "-m requires an input file");
        if (argc == 0)
                argc = 1;
        if (argc == 1 && !inplace && ofilename == NULL)
@@ -416,7 +420,11 @@ processinout(const char *ifn, const char
                        err(2, "can't rename \"%s\" to \"%s\"", ofn, backname);
                free(backname);
        }
-       if (replace(tempname, ofn) < 0)
+       /* leave file unmodified if unifdef made no changes */
+       if (!altered && backext == NULL) {
+               if (remove(tempname) < 0)
+                       warn("can't remove \"%s\"", tempname);
+       } else if (replace(tempname, ofn) < 0)
                err(2, "can't rename \"%s\" to \"%s\"", tempname, ofn);
        free(tempname);
        tempname = NULL;
@@ -638,6 +646,7 @@ keywordedit(const char *replacement)
 {
        snprintf(keyword, tline + sizeof(tline) - keyword,
            "%s%s", replacement, newline);
+       altered = true;
        print();
 }
 static void
@@ -700,7 +709,7 @@ flushline(bool keep)
        } else {
                if (lnblank && fputs(newline, output) == EOF)
                        closeio();
-               exitstat = 1;
+               altered = true;
                delcount += 1;
                blankcount = 0;
        }
@@ -752,6 +761,7 @@ process(void)
        zerosyms = true;
        newline = NULL;
        linenum = 0;
+       altered = false;
        while (lineval != LT_EOF) {
                lineval = parseline();
                trans_table[ifstate[depth]][lineval]();
@@ -759,6 +769,7 @@ process(void)
                    linenum, linetype_name[lineval],
                    ifstate_name[ifstate[depth]], depth);
        }
+       exitstat |= altered;
 }
 
 /*
@@ -892,6 +903,40 @@ static Linetype op_and(long *p, Linetype
                return (*p = 0, LT_FALSE);
        return op_strict(p, a && b, at, bt);
 }
+static Linetype op_blsh(long *p, Linetype at, long a, Linetype bt, long b) {
+       return op_strict(p, a << b, at, bt);
+}
+static Linetype op_brsh(long *p, Linetype at, long a, Linetype bt, long b) {
+       return op_strict(p, a >> b, at, bt);
+}
+static Linetype op_add(long *p, Linetype at, long a, Linetype bt, long b) {
+       return op_strict(p, a + b, at, bt);
+}
+static Linetype op_sub(long *p, Linetype at, long a, Linetype bt, long b) {
+       return op_strict(p, a - b, at, bt);
+}
+static Linetype op_mul(long *p, Linetype at, long a, Linetype bt, long b) {
+       return op_strict(p, a * b, at, bt);
+}
+static Linetype op_div(long *p, Linetype at, long a, Linetype bt, long b) {
+       if (bt != LT_TRUE) {
+               debug("eval division by zero");
+               return (LT_ERROR);
+       }
+       return op_strict(p, a / b, at, bt);
+}
+static Linetype op_mod(long *p, Linetype at, long a, Linetype bt, long b) {
+       return op_strict(p, a % b, at, bt);
+}
+static Linetype op_bor(long *p, Linetype at, long a, Linetype bt, long b) {
+       return op_strict(p, a | b, at, bt);
+}
+static Linetype op_bxor(long *p, Linetype at, long a, Linetype bt, long b) {
+       return op_strict(p, a ^ b, at, bt);
+}
+static Linetype op_band(long *p, Linetype at, long a, Linetype bt, long b) {
+       return op_strict(p, a & b, at, bt);
+}
 
 /*
  * An evaluation function takes three arguments, as follows: (1) a pointer to
@@ -915,10 +960,15 @@ static eval_fn eval_table, eval_unary;
  * calls the inner function with its first argument pointing to the next
  * element of the table. Innermost expressions have special non-table-driven
  * handling.
+ *
+ * The stop characters help with lexical analysis: an operator is not
+ * recognized if it is followed by one of the stop characters because
+ * that would make it a different operator.
  */
 struct op {
        const char *str;
        Linetype (*fn)(long *, Linetype, long, Linetype, long);
+       const char *stop;
 };
 struct ops {
        eval_fn *inner;
@@ -927,12 +977,22 @@ struct ops {
 static const struct ops eval_ops[] = {
        { eval_table, { { "||", op_or } } },
        { eval_table, { { "&&", op_and } } },
+       { eval_table, { { "|", op_bor, "|" } } },
+       { eval_table, { { "^", op_bxor } } },
+       { eval_table, { { "&", op_band, "&" } } },
        { eval_table, { { "==", op_eq },
                        { "!=", op_ne } } },
-       { eval_unary, { { "<=", op_le },
+       { eval_table, { { "<=", op_le },
                        { ">=", op_ge },
-                       { "<", op_lt },
-                       { ">", op_gt } } }
+                       { "<", op_lt, "<=" },
+                       { ">", op_gt, ">=" } } },
+       { eval_table, { { "<<", op_blsh },
+                       { ">>", op_brsh } } },
+       { eval_table, { { "+", op_add },
+                       { "-", op_sub } } },
+       { eval_unary, { { "*", op_mul },
+                       { "/", op_div },
+                       { "%", op_mod } } },
 };
 
 /* Current operator precedence level */
@@ -966,6 +1026,26 @@ eval_unary(const struct ops *ops, long *
                        *valp = !*valp;
                        lt = *valp ? LT_TRUE : LT_FALSE;
                }
+       } else if (*cp == '~') {
+               debug("eval%d ~", prec(ops));
+               cp++;
+               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 == '-') {
+               debug("eval%d -", prec(ops));
+               cp++;
+               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 (", prec(ops));
@@ -1040,7 +1120,7 @@ eval_table(const struct ops *ops, long *
 {
        const struct op *op;
        const char *cp;
-       long val;
+       long val = 0;
        Linetype lt, rt;
 
        debug("eval%d", prec(ops));
@@ -1050,9 +1130,16 @@ eval_table(const struct ops *ops, long *
                return (LT_ERROR);
        for (;;) {
                cp = skipcomment(cp);
-               for (op = ops->op; op->str != NULL; op++)
-                       if (strncmp(cp, op->str, strlen(op->str)) == 0)
-                               break;
+               for (op = ops->op; op->str != NULL; op++) {
+                       if (strncmp(cp, op->str, strlen(op->str)) == 0) {
+                               /* assume only one-char operators have stop 
chars */
+                               if (op->stop != NULL && cp[1] != '\0' &&
+                                   strchr(op->stop, cp[1]) != NULL)
+                                       continue;
+                               else
+                                       break;
+                       }
+               }
                if (op->str == NULL)
                        break;
                cp += strlen(op->str);
@@ -1123,10 +1210,14 @@ skiphash(void)
 static const char *
 skipline(const char *cp)
 {
+       const char *pcp;
        if (*cp != '\0')
                linestate = LS_DIRTY;
-       while (*cp != '\0')
-               cp = skipcomment(cp + 1);
+       while (*cp != '\0') {
+               cp = skipcomment(pcp = cp);
+               if (pcp == cp)
+                       cp++;
+       }
        return (cp);
 }
 
@@ -1202,9 +1293,9 @@ skipcomment(const char *cp)
                                        cp += 2;
                        } else if (strncmp(cp, "\n", 1) == 0) {
                                if (incomment == CHAR_LITERAL)
-                                       error("unterminated char literal");
+                                       error("Unterminated char literal");
                                else
-                                       error("unterminated string literal");
+                                       error("Unterminated string literal");
                        } else
                                cp += 1;
                        continue;
@@ -1478,7 +1569,7 @@ defundef(void)
        if ((cp = matchsym("define", kw)) != NULL) {
                sym = getsym(&cp);
                if (sym == NULL)
-                       error("missing macro name in #define");
+                       error("Missing macro name in #define");
                if (*cp == '(') {
                        val = "1";
                } else {
@@ -1490,12 +1581,12 @@ defundef(void)
        } else if ((cp = matchsym("undef", kw)) != NULL) {
                sym = getsym(&cp);
                if (sym == NULL)
-                       error("missing macro name in #undef");
+                       error("Missing macro name in #undef");
                cp = skipcomment(cp);
                debug("#undef");
                addsym2(false, sym, NULL);
        } else {
-               error("unrecognized preprocessor directive");
+               error("Unrecognized preprocessor directive");
        }
        skipline(cp);
 done:
@@ -1567,5 +1658,5 @@ error(const char *msg)
                warnx("%s: %d: %s (#if line %d depth %d)",
                    filename, linenum, msg, stifline[depth], depth);
        closeio();
-       errx(2, "output may be truncated");
+       errx(2, "Output may be truncated");
 }

Modified: head/usr.bin/unifdef/unifdef.h
==============================================================================
--- head/usr.bin/unifdef/unifdef.h      Thu Dec  3 14:17:28 2015        
(r291695)
+++ head/usr.bin/unifdef/unifdef.h      Thu Dec  3 14:21:55 2015        
(r291696)
@@ -36,7 +36,7 @@
 #include <string.h>
 #include <unistd.h>
 
-/* portabiity stubs */
+/* portability stubs */
 
 #define fbinmode(fp) (fp)
 
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to