Commit d8379ab1dde371f13d7fdddf05346840a82c2b61

Authored by Tony Finch
Committed by Michal Marek
1 parent eb8f844c0a

unifdef: update to upstream revision 1.190

Fix handling of input files (e.g. with no newline at EOF) that could
make unifdef get into an unexpected state and call abort().

The new -B option compresses blank lines around a deleted section
so that blank lines around "paragraphs" of code don't get doubled.

The evaluator can now handle macros with arguments, and unbracketed
arguments to the "defined" operator.

Add myself to MAINTAINERS for unifdef.

Signed-off-by: Tony Finch <dot@dotat.at>
Acked-by: Sam Ravnborg <sam@ravnborg.org>
Signed-off-by: Michal Marek <mmarek@suse.cz>

Showing 2 changed files with 213 additions and 134 deletions Side-by-side Diff

... ... @@ -5407,6 +5407,12 @@
5407 5407 F: include/linux/uwb.h
5408 5408 F: include/linux/uwb/
5409 5409  
  5410 +UNIFDEF
  5411 +M: Tony Finch <dot@dotat.at>
  5412 +W: http://dotat.at/prog/unifdef
  5413 +S: Maintained
  5414 +F: scripts/unifdef.c
  5415 +
5410 5416 UNIFORM CDROM DRIVER
5411 5417 M: Jens Axboe <axboe@kernel.dk>
5412 5418 W: http://www.kernel.dk
1 1 /*
2   - * Copyright (c) 2002 - 2005 Tony Finch <dot@dotat.at>. All rights reserved.
  2 + * Copyright (c) 2002 - 2009 Tony Finch <dot@dotat.at>
3 3 *
4   - * This code is derived from software contributed to Berkeley by Dave Yost.
5   - * It was rewritten to support ANSI C by Tony Finch. The original version of
6   - * unifdef carried the following copyright notice. None of its code remains
7   - * in this version (though some of the names remain).
8   - *
9   - * Copyright (c) 1985, 1993
10   - * The Regents of the University of California. All rights reserved.
11   - *
12 4 * Redistribution and use in source and binary forms, with or without
13 5 * modification, are permitted provided that the following conditions
14 6 * are met:
15 7  
... ... @@ -31,23 +23,20 @@
31 23 * SUCH DAMAGE.
32 24 */
33 25  
34   -#include <sys/cdefs.h>
  26 +/*
  27 + * This code was derived from software contributed to Berkeley by Dave Yost.
  28 + * It was rewritten to support ANSI C by Tony Finch. The original version
  29 + * of unifdef carried the 4-clause BSD copyright licence. None of its code
  30 + * remains in this version (though some of the names remain) so it now
  31 + * carries a more liberal licence.
  32 + *
  33 + * The latest version is available from http://dotat.at/prog/unifdef
  34 + */
35 35  
36   -#ifndef lint
37   -#if 0
38   -static const char copyright[] =
39   -"@(#) Copyright (c) 1985, 1993\n\
40   - The Regents of the University of California. All rights reserved.\n";
41   -#endif
42   -#ifdef __IDSTRING
43   -__IDSTRING(Berkeley, "@(#)unifdef.c 8.1 (Berkeley) 6/6/93");
44   -__IDSTRING(NetBSD, "$NetBSD: unifdef.c,v 1.8 2000/07/03 02:51:36 matt Exp $");
45   -__IDSTRING(dotat, "$dotat: things/unifdef.c,v 1.171 2005/03/08 12:38:48 fanf2 Exp $");
46   -#endif
47   -#endif /* not lint */
48   -#ifdef __FBSDID
49   -__FBSDID("$FreeBSD: /repoman/r/ncvs/src/usr.bin/unifdef/unifdef.c,v 1.20 2005/05/21 09:55:09 ru Exp $");
50   -#endif
  36 +static const char * const copyright[] = {
  37 + "@(#) Copyright (c) 2002 - 2009 Tony Finch <dot@dotat.at>\n",
  38 + "$dotat: unifdef/unifdef.c,v 1.190 2009/11/27 17:21:26 fanf2 Exp $",
  39 +};
51 40  
52 41 /*
53 42 * unifdef - remove ifdef'ed lines
... ... @@ -72,8 +61,6 @@
72 61 #include <string.h>
73 62 #include <unistd.h>
74 63  
75   -size_t strlcpy(char *dst, const char *src, size_t siz);
76   -
77 64 /* types of input lines: */
78 65 typedef enum {
79 66 LT_TRUEI, /* a true #if with ignore flag */
... ... @@ -90,6 +77,7 @@
90 77 LT_DODGY_LAST = LT_DODGY + LT_ENDIF,
91 78 LT_PLAIN, /* ordinary line */
92 79 LT_EOF, /* end of file */
  80 + LT_ERROR, /* unevaluable #if */
93 81 LT_COUNT
94 82 } Linetype;
95 83  
... ... @@ -100,7 +88,7 @@
100 88 "DODGY IF", "DODGY TRUE", "DODGY FALSE",
101 89 "DODGY ELIF", "DODGY ELTRUE", "DODGY ELFALSE",
102 90 "DODGY ELSE", "DODGY ENDIF",
103   - "PLAIN", "EOF"
  91 + "PLAIN", "EOF", "ERROR"
104 92 };
105 93  
106 94 /* state of #if processing */
107 95  
108 96  
... ... @@ -168,11 +156,13 @@
168 156 * Globals.
169 157 */
170 158  
  159 +static bool compblank; /* -B: compress blank lines */
  160 +static bool lnblank; /* -b: blank deleted lines */
171 161 static bool complement; /* -c: do the complement */
172 162 static bool debugging; /* -d: debugging reports */
173 163 static bool iocccok; /* -e: fewer IOCCC errors */
  164 +static bool strictlogic; /* -K: keep ambiguous #ifs */
174 165 static bool killconsts; /* -k: eval constant #ifs */
175   -static bool lnblank; /* -l: blank deleted lines */
176 166 static bool lnnum; /* -n: add #line directives */
177 167 static bool symlist; /* -s: output symbol list */
178 168 static bool text; /* -t: this is a text file */
... ... @@ -196,7 +186,9 @@
196 186 static int stifline[MAXDEPTH]; /* start of current #if */
197 187 static int depth; /* current #if nesting */
198 188 static int delcount; /* count of deleted lines */
199   -static bool keepthis; /* don't delete constant #if */
  189 +static unsigned blankcount; /* count of blank lines */
  190 +static unsigned blankmax; /* maximum recent blankcount */
  191 +static bool constexpr; /* constant #if expression */
200 192  
201 193 static int exitstat; /* program exit status */
202 194  
203 195  
... ... @@ -206,13 +198,14 @@
206 198 static void error(const char *);
207 199 static int findsym(const char *);
208 200 static void flushline(bool);
209   -static Linetype get_line(void);
  201 +static Linetype parseline(void);
210 202 static Linetype ifeval(const char **);
211 203 static void ignoreoff(void);
212 204 static void ignoreon(void);
213 205 static void keywordedit(const char *);
214 206 static void nest(void);
215 207 static void process(void);
  208 +static const char *skipargs(const char *);
216 209 static const char *skipcomment(const char *);
217 210 static const char *skipsym(const char *);
218 211 static void state(Ifstate);
... ... @@ -220,7 +213,7 @@
220 213 static void unnest(void);
221 214 static void usage(void);
222 215  
223   -#define endsym(c) (!isalpha((unsigned char)c) && !isdigit((unsigned char)c) && c != '_')
  216 +#define endsym(c) (!isalnum((unsigned char)c) && c != '_')
224 217  
225 218 /*
226 219 * The main program.
... ... @@ -230,7 +223,7 @@
230 223 {
231 224 int opt;
232 225  
233   - while ((opt = getopt(argc, argv, "i:D:U:I:cdeklnst")) != -1)
  226 + while ((opt = getopt(argc, argv, "i:D:U:I:BbcdeKklnst")) != -1)
234 227 switch (opt) {
235 228 case 'i': /* treat stuff controlled by these symbols as text */
236 229 /*
... ... @@ -255,6 +248,13 @@
255 248 case 'I':
256 249 /* no-op for compatibility with cpp */
257 250 break;
  251 + case 'B': /* compress blank lines around removed section */
  252 + compblank = true;
  253 + break;
  254 + case 'b': /* blank deleted lines instead of omitting them */
  255 + case 'l': /* backwards compatibility */
  256 + lnblank = true;
  257 + break;
258 258 case 'c': /* treat -D as -U and vice versa */
259 259 complement = true;
260 260 break;
261 261  
... ... @@ -264,12 +264,12 @@
264 264 case 'e': /* fewer errors from dodgy lines */
265 265 iocccok = true;
266 266 break;
  267 + case 'K': /* keep ambiguous #ifs */
  268 + strictlogic = true;
  269 + break;
267 270 case 'k': /* process constant #ifs */
268 271 killconsts = true;
269 272 break;
270   - case 'l': /* blank deleted lines instead of omitting them */
271   - lnblank = true;
272   - break;
273 273 case 'n': /* add #line directive after deleted lines */
274 274 lnnum = true;
275 275 break;
... ... @@ -284,6 +284,8 @@
284 284 }
285 285 argc -= optind;
286 286 argv += optind;
  287 + if (compblank && lnblank)
  288 + errx(2, "-B and -b are mutually exclusive");
287 289 if (argc > 1) {
288 290 errx(2, "can only do one file");
289 291 } else if (argc == 1 && strcmp(*argv, "-") != 0) {
... ... @@ -302,7 +304,7 @@
302 304 static void
303 305 usage(void)
304 306 {
305   - fprintf(stderr, "usage: unifdef [-cdeklnst] [-Ipath]"
  307 + fprintf(stderr, "usage: unifdef [-BbcdeKknst] [-Ipath]"
306 308 " [-Dsym[=val]] [-Usym] [-iDsym[=val]] [-iUsym] ... [file]\n");
307 309 exit(2);
308 310 }
309 311  
310 312  
311 313  
312 314  
313 315  
314 316  
315 317  
316 318  
317 319  
318 320  
... ... @@ -383,46 +385,46 @@
383 385 /* IS_OUTSIDE */
384 386 { Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Eendif,
385 387 Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Eendif,
386   - print, done },
  388 + print, done, abort },
387 389 /* IS_FALSE_PREFIX */
388 390 { Idrop, Idrop, Fdrop, Fdrop, Fdrop, Mpass, Strue, Sfalse,Selse, Dendif,
389 391 Idrop, Idrop, Fdrop, Fdrop, Fdrop, Mpass, Eioccc,Eioccc,Eioccc,Eioccc,
390   - drop, Eeof },
  392 + drop, Eeof, abort },
391 393 /* IS_TRUE_PREFIX */
392 394 { Itrue, Ifalse,Fpass, Ftrue, Ffalse,Dfalse,Dfalse,Dfalse,Delse, Dendif,
393 395 Oiffy, Oiffy, Fpass, Oif, Oif, Eioccc,Eioccc,Eioccc,Eioccc,Eioccc,
394   - print, Eeof },
  396 + print, Eeof, abort },
395 397 /* IS_PASS_MIDDLE */
396 398 { Itrue, Ifalse,Fpass, Ftrue, Ffalse,Pelif, Mtrue, Delif, Pelse, Pendif,
397 399 Oiffy, Oiffy, Fpass, Oif, Oif, Pelif, Oelif, Oelif, Pelse, Pendif,
398   - print, Eeof },
  400 + print, Eeof, abort },
399 401 /* IS_FALSE_MIDDLE */
400 402 { Idrop, Idrop, Fdrop, Fdrop, Fdrop, Pelif, Mtrue, Delif, Pelse, Pendif,
401 403 Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eioccc,Eioccc,Eioccc,Eioccc,Eioccc,
402   - drop, Eeof },
  404 + drop, Eeof, abort },
403 405 /* IS_TRUE_MIDDLE */
404 406 { Itrue, Ifalse,Fpass, Ftrue, Ffalse,Melif, Melif, Melif, Melse, Pendif,
405 407 Oiffy, Oiffy, Fpass, Oif, Oif, Eioccc,Eioccc,Eioccc,Eioccc,Pendif,
406   - print, Eeof },
  408 + print, Eeof, abort },
407 409 /* IS_PASS_ELSE */
408 410 { Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Pendif,
409 411 Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Pendif,
410   - print, Eeof },
  412 + print, Eeof, abort },
411 413 /* IS_FALSE_ELSE */
412 414 { Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eelif, Eelif, Eelif, Eelse, Dendif,
413 415 Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eelif, Eelif, Eelif, Eelse, Eioccc,
414   - drop, Eeof },
  416 + drop, Eeof, abort },
415 417 /* IS_TRUE_ELSE */
416 418 { Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Dendif,
417 419 Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Eioccc,
418   - print, Eeof },
  420 + print, Eeof, abort },
419 421 /* IS_FALSE_TRAILER */
420 422 { Idrop, Idrop, Fdrop, Fdrop, Fdrop, Dfalse,Dfalse,Dfalse,Delse, Dendif,
421 423 Idrop, Idrop, Fdrop, Fdrop, Fdrop, Dfalse,Dfalse,Dfalse,Delse, Eioccc,
422   - drop, Eeof }
  424 + drop, Eeof, abort }
423 425 /*TRUEI FALSEI IF TRUE FALSE ELIF ELTRUE ELFALSE ELSE ENDIF
424 426 TRUEI FALSEI IF TRUE FALSE ELIF ELTRUE ELFALSE ELSE ENDIF (DODGY)
425   - PLAIN EOF */
  427 + PLAIN EOF ERROR */
426 428 };
427 429  
428 430 /*
429 431  
... ... @@ -463,9 +465,11 @@
463 465 static void
464 466 nest(void)
465 467 {
466   - depth += 1;
467   - if (depth >= MAXDEPTH)
  468 + if (depth > MAXDEPTH-1)
  469 + abort(); /* bug */
  470 + if (depth == MAXDEPTH-1)
468 471 error("Too many levels of nesting");
  472 + depth += 1;
469 473 stifline[depth] = linenum;
470 474 }
471 475 static void
472 476  
... ... @@ -490,15 +494,23 @@
490 494 if (symlist)
491 495 return;
492 496 if (keep ^ complement) {
493   - if (lnnum && delcount > 0)
494   - printf("#line %d\n", linenum);
495   - fputs(tline, stdout);
496   - delcount = 0;
  497 + bool blankline = tline[strspn(tline, " \t\n")] == '\0';
  498 + if (blankline && compblank && blankcount != blankmax) {
  499 + delcount += 1;
  500 + blankcount += 1;
  501 + } else {
  502 + if (lnnum && delcount > 0)
  503 + printf("#line %d\n", linenum);
  504 + fputs(tline, stdout);
  505 + delcount = 0;
  506 + blankmax = blankcount = blankline ? blankcount + 1 : 0;
  507 + }
497 508 } else {
498 509 if (lnblank)
499 510 putc('\n', stdout);
500 511 exitstat = 1;
501 512 delcount += 1;
  513 + blankcount = 0;
502 514 }
503 515 }
504 516  
505 517  
... ... @@ -510,9 +522,12 @@
510 522 {
511 523 Linetype lineval;
512 524  
  525 + /* When compressing blank lines, act as if the file
  526 + is preceded by a large number of blank lines. */
  527 + blankmax = blankcount = 1000;
513 528 for (;;) {
514 529 linenum++;
515   - lineval = get_line();
  530 + lineval = parseline();
516 531 trans_table[ifstate[depth]][lineval]();
517 532 debug("process %s -> %s depth %d",
518 533 linetype_name[lineval],
... ... @@ -526,7 +541,7 @@
526 541 * help from skipcomment().
527 542 */
528 543 static Linetype
529   -get_line(void)
  544 +parseline(void)
530 545 {
531 546 const char *cp;
532 547 int cursym;
... ... @@ -595,9 +610,21 @@
595 610 if (incomment)
596 611 linestate = LS_DIRTY;
597 612 }
598   - /* skipcomment should have changed the state */
599   - if (linestate == LS_HASH)
600   - abort(); /* bug */
  613 + /* skipcomment normally changes the state, except
  614 + if the last line of the file lacks a newline, or
  615 + if there is too much whitespace in a directive */
  616 + if (linestate == LS_HASH) {
  617 + size_t len = cp - tline;
  618 + if (fgets(tline + len, MAXLINE - len, input) == NULL) {
  619 + /* append the missing newline */
  620 + tline[len+0] = '\n';
  621 + tline[len+1] = '\0';
  622 + cp++;
  623 + linestate = LS_START;
  624 + } else {
  625 + linestate = LS_DIRTY;
  626 + }
  627 + }
601 628 }
602 629 if (linestate == LS_DIRTY) {
603 630 while (*cp != '\0')
604 631  
... ... @@ -610,17 +637,40 @@
610 637  
611 638 /*
612 639 * These are the binary operators that are supported by the expression
613   - * evaluator. Note that if support for division is added then we also
614   - * need short-circuiting booleans because of divide-by-zero.
  640 + * evaluator.
615 641 */
616   -static int op_lt(int a, int b) { return (a < b); }
617   -static int op_gt(int a, int b) { return (a > b); }
618   -static int op_le(int a, int b) { return (a <= b); }
619   -static int op_ge(int a, int b) { return (a >= b); }
620   -static int op_eq(int a, int b) { return (a == b); }
621   -static int op_ne(int a, int b) { return (a != b); }
622   -static int op_or(int a, int b) { return (a || b); }
623   -static int op_and(int a, int b) { return (a && b); }
  642 +static Linetype op_strict(int *p, int v, Linetype at, Linetype bt) {
  643 + if(at == LT_IF || bt == LT_IF) return (LT_IF);
  644 + return (*p = v, v ? LT_TRUE : LT_FALSE);
  645 +}
  646 +static Linetype op_lt(int *p, Linetype at, int a, Linetype bt, int b) {
  647 + return op_strict(p, a < b, at, bt);
  648 +}
  649 +static Linetype op_gt(int *p, Linetype at, int a, Linetype bt, int b) {
  650 + return op_strict(p, a > b, at, bt);
  651 +}
  652 +static Linetype op_le(int *p, Linetype at, int a, Linetype bt, int b) {
  653 + return op_strict(p, a <= b, at, bt);
  654 +}
  655 +static Linetype op_ge(int *p, Linetype at, int a, Linetype bt, int b) {
  656 + return op_strict(p, a >= b, at, bt);
  657 +}
  658 +static Linetype op_eq(int *p, Linetype at, int a, Linetype bt, int b) {
  659 + return op_strict(p, a == b, at, bt);
  660 +}
  661 +static Linetype op_ne(int *p, Linetype at, int a, Linetype bt, int b) {
  662 + return op_strict(p, a != b, at, bt);
  663 +}
  664 +static Linetype op_or(int *p, Linetype at, int a, Linetype bt, int b) {
  665 + if (!strictlogic && (at == LT_TRUE || bt == LT_TRUE))
  666 + return (*p = 1, LT_TRUE);
  667 + return op_strict(p, a || b, at, bt);
  668 +}
  669 +static Linetype op_and(int *p, Linetype at, int a, Linetype bt, int b) {
  670 + if (!strictlogic && (at == LT_FALSE || bt == LT_FALSE))
  671 + return (*p = 0, LT_FALSE);
  672 + return op_strict(p, a && b, at, bt);
  673 +}
624 674  
625 675 /*
626 676 * An evaluation function takes three arguments, as follows: (1) a pointer to
... ... @@ -629,8 +679,8 @@
629 679 * value of the expression; and (3) a pointer to a char* that points to the
630 680 * expression to be evaluated and that is updated to the end of the expression
631 681 * when evaluation is complete. The function returns LT_FALSE if the value of
632   - * the expression is zero, LT_TRUE if it is non-zero, or LT_IF if the
633   - * expression could not be evaluated.
  682 + * the expression is zero, LT_TRUE if it is non-zero, LT_IF if the expression
  683 + * depends on an unknown symbol, or LT_ERROR if there is a parse failure.
634 684 */
635 685 struct ops;
636 686  
... ... @@ -649,7 +699,7 @@
649 699 eval_fn *inner;
650 700 struct op {
651 701 const char *str;
652   - int (*fn)(int, int);
  702 + Linetype (*fn)(int *, Linetype, int, Linetype, int);
653 703 } op[5];
654 704 } eval_ops[] = {
655 705 { eval_table, { { "||", op_or } } },
... ... @@ -664,8 +714,8 @@
664 714  
665 715 /*
666 716 * Function for evaluating the innermost parts of expressions,
667   - * viz. !expr (expr) defined(symbol) symbol number
668   - * We reset the keepthis flag when we find a non-constant subexpression.
  717 + * viz. !expr (expr) number defined(symbol) symbol
  718 + * We reset the constexpr flag in the last two cases.
669 719 */
670 720 static Linetype
671 721 eval_unary(const struct ops *ops, int *valp, const char **cpp)
672 722  
673 723  
674 724  
675 725  
676 726  
677 727  
678 728  
679 729  
680 730  
681 731  
682 732  
683 733  
684 734  
685 735  
686 736  
... ... @@ -673,68 +723,83 @@
673 723 const char *cp;
674 724 char *ep;
675 725 int sym;
  726 + bool defparen;
  727 + Linetype lt;
676 728  
677 729 cp = skipcomment(*cpp);
678 730 if (*cp == '!') {
679 731 debug("eval%d !", ops - eval_ops);
680 732 cp++;
681   - if (eval_unary(ops, valp, &cp) == LT_IF) {
682   - *cpp = cp;
683   - return (LT_IF);
  733 + lt = eval_unary(ops, valp, &cp);
  734 + if (lt == LT_ERROR)
  735 + return (LT_ERROR);
  736 + if (lt != LT_IF) {
  737 + *valp = !*valp;
  738 + lt = *valp ? LT_TRUE : LT_FALSE;
684 739 }
685   - *valp = !*valp;
686 740 } else if (*cp == '(') {
687 741 cp++;
688 742 debug("eval%d (", ops - eval_ops);
689   - if (eval_table(eval_ops, valp, &cp) == LT_IF)
690   - return (LT_IF);
  743 + lt = eval_table(eval_ops, valp, &cp);
  744 + if (lt == LT_ERROR)
  745 + return (LT_ERROR);
691 746 cp = skipcomment(cp);
692 747 if (*cp++ != ')')
693   - return (LT_IF);
  748 + return (LT_ERROR);
694 749 } else if (isdigit((unsigned char)*cp)) {
695 750 debug("eval%d number", ops - eval_ops);
696 751 *valp = strtol(cp, &ep, 0);
  752 + if (ep == cp)
  753 + return (LT_ERROR);
  754 + lt = *valp ? LT_TRUE : LT_FALSE;
697 755 cp = skipsym(cp);
698 756 } else if (strncmp(cp, "defined", 7) == 0 && endsym(cp[7])) {
699 757 cp = skipcomment(cp+7);
700 758 debug("eval%d defined", ops - eval_ops);
701   - if (*cp++ != '(')
702   - return (LT_IF);
703   - cp = skipcomment(cp);
  759 + if (*cp == '(') {
  760 + cp = skipcomment(cp+1);
  761 + defparen = true;
  762 + } else {
  763 + defparen = false;
  764 + }
704 765 sym = findsym(cp);
705   - cp = skipsym(cp);
706   - cp = skipcomment(cp);
707   - if (*cp++ != ')')
708   - return (LT_IF);
709   - if (sym >= 0)
  766 + if (sym < 0) {
  767 + lt = LT_IF;
  768 + } else {
710 769 *valp = (value[sym] != NULL);
711   - else {
712   - *cpp = cp;
713   - return (LT_IF);
  770 + lt = *valp ? LT_TRUE : LT_FALSE;
714 771 }
715   - keepthis = false;
  772 + cp = skipsym(cp);
  773 + cp = skipcomment(cp);
  774 + if (defparen && *cp++ != ')')
  775 + return (LT_ERROR);
  776 + constexpr = false;
716 777 } else if (!endsym(*cp)) {
717 778 debug("eval%d symbol", ops - eval_ops);
718 779 sym = findsym(cp);
719   - if (sym < 0)
720   - return (LT_IF);
721   - if (value[sym] == NULL)
  780 + cp = skipsym(cp);
  781 + if (sym < 0) {
  782 + lt = LT_IF;
  783 + cp = skipargs(cp);
  784 + } else if (value[sym] == NULL) {
722 785 *valp = 0;
723   - else {
  786 + lt = LT_FALSE;
  787 + } else {
724 788 *valp = strtol(value[sym], &ep, 0);
725 789 if (*ep != '\0' || ep == value[sym])
726   - return (LT_IF);
  790 + return (LT_ERROR);
  791 + lt = *valp ? LT_TRUE : LT_FALSE;
  792 + cp = skipargs(cp);
727 793 }
728   - cp = skipsym(cp);
729   - keepthis = false;
  794 + constexpr = false;
730 795 } else {
731 796 debug("eval%d bad expr", ops - eval_ops);
732   - return (LT_IF);
  797 + return (LT_ERROR);
733 798 }
734 799  
735 800 *cpp = cp;
736 801 debug("eval%d = %d", ops - eval_ops, *valp);
737   - return (*valp ? LT_TRUE : LT_FALSE);
  802 + return (lt);
738 803 }
739 804  
740 805 /*
741 806  
... ... @@ -746,11 +811,13 @@
746 811 const struct op *op;
747 812 const char *cp;
748 813 int val;
749   - Linetype lhs, rhs;
  814 + Linetype lt, rt;
750 815  
751 816 debug("eval%d", ops - eval_ops);
752 817 cp = *cpp;
753   - lhs = ops->inner(ops+1, valp, &cp);
  818 + lt = ops->inner(ops+1, valp, &cp);
  819 + if (lt == LT_ERROR)
  820 + return (LT_ERROR);
754 821 for (;;) {
755 822 cp = skipcomment(cp);
756 823 for (op = ops->op; op->str != NULL; op++)
757 824  
... ... @@ -760,32 +827,16 @@
760 827 break;
761 828 cp += strlen(op->str);
762 829 debug("eval%d %s", ops - eval_ops, op->str);
763   - rhs = ops->inner(ops+1, &val, &cp);
764   - if (op->fn == op_and && (lhs == LT_FALSE || rhs == LT_FALSE)) {
765   - debug("eval%d: and always false", ops - eval_ops);
766   - if (lhs == LT_IF)
767   - *valp = val;
768   - lhs = LT_FALSE;
769   - continue;
770   - }
771   - if (op->fn == op_or && (lhs == LT_TRUE || rhs == LT_TRUE)) {
772   - debug("eval%d: or always true", ops - eval_ops);
773   - if (lhs == LT_IF)
774   - *valp = val;
775   - lhs = LT_TRUE;
776   - continue;
777   - }
778   - if (rhs == LT_IF)
779   - lhs = LT_IF;
780   - if (lhs != LT_IF)
781   - *valp = op->fn(*valp, val);
  830 + rt = ops->inner(ops+1, &val, &cp);
  831 + if (rt == LT_ERROR)
  832 + return (LT_ERROR);
  833 + lt = op->fn(valp, lt, *valp, rt, val);
782 834 }
783 835  
784 836 *cpp = cp;
785 837 debug("eval%d = %d", ops - eval_ops, *valp);
786   - if (lhs != LT_IF)
787   - lhs = (*valp ? LT_TRUE : LT_FALSE);
788   - return lhs;
  838 + debug("eval%d lt = %s", ops - eval_ops, linetype_name[lt]);
  839 + return (lt);
789 840 }
790 841  
791 842 /*
792 843  
793 844  
794 845  
... ... @@ -796,17 +847,14 @@
796 847 static Linetype
797 848 ifeval(const char **cpp)
798 849 {
799   - const char *cp = *cpp;
800 850 int ret;
801   - int val;
  851 + int val = 0;
802 852  
803 853 debug("eval %s", *cpp);
804   - keepthis = killconsts ? false : true;
805   - ret = eval_table(eval_ops, &val, &cp);
806   - if (ret != LT_IF)
807   - *cpp = cp;
  854 + constexpr = killconsts ? false : true;
  855 + ret = eval_table(eval_ops, &val, cpp);
808 856 debug("eval = %d", val);
809   - return (keepthis ? LT_IF : ret);
  857 + return (constexpr ? LT_IF : ret == LT_ERROR ? LT_IF : ret);
810 858 }
811 859  
812 860 /*
... ... @@ -918,6 +966,31 @@
918 966 }
919 967  
920 968 /*
  969 + * Skip macro arguments.
  970 + */
  971 +static const char *
  972 +skipargs(const char *cp)
  973 +{
  974 + const char *ocp = cp;
  975 + int level = 0;
  976 + cp = skipcomment(cp);
  977 + if (*cp != '(')
  978 + return (cp);
  979 + do {
  980 + if (*cp == '(')
  981 + level++;
  982 + if (*cp == ')')
  983 + level--;
  984 + cp = skipcomment(cp+1);
  985 + } while (level != 0 && *cp != '\0');
  986 + if (level == 0)
  987 + return (cp);
  988 + else
  989 + /* Rewind and re-detect the syntax error later. */
  990 + return (ocp);
  991 +}
  992 +
  993 +/*
921 994 * Skip over an identifier.
922 995 */
923 996 static const char *
... ... @@ -929,7 +1002,7 @@
929 1002 }
930 1003  
931 1004 /*
932   - * Look for the symbol in the symbol table. If is is found, we return
  1005 + * Look for the symbol in the symbol table. If it is found, we return
933 1006 * the symbol table index, else we return -1.
934 1007 */
935 1008 static int