[PATCH] unifdef: teach it about defined(FOO) syntax

From: Denys Vlasenko
Date: Sun Jun 21 2009 - 14:21:46 EST


Hi,

uclibc project patched unifdef.c (which we stole from kernel)
so that it understands defined(FOO) in addition to defined FOO,
and also taught it to understand short-circuited evaluation
of && and ||

The patch is attached. (Sorry, not inline, I fear Google
web mail interface may mangle it).

I ran these commands in unpatched and patched tree:

make ARCH=i386 CROSS_COMPILE=i486-linux-uclibc- defconfig
ln -s asm-x86 include/asm
make ARCH=i386 CROSS_COMPILE=i486-linux-uclibc- headers_install

and then diffed usr/*. The difference clearly shows that
new unifdef works better than old one:


linux-2.6.30.test/usr/include/linux/acct.h:
@@ -59,9 +59,7 @@ struct acct
comp_t ac_majflt; /* Major Pagefaults */
comp_t ac_swaps; /* Number of Swaps */
/* m68k had no padding here. */
-#if !defined(CONFIG_M68K) || !defined(__KERNEL__)
__u16 ac_ahz; /* AHZ */
-#endif
__u32 ac_exitcode; /* Exitcode */
char ac_comm[ACCT_COMM + 1]; /* Command Name */
__u8 ac_etime_hi; /* Elapsed Time MSB */


linux-2.6.30.test/usr/include/linux/soundcard.h:
@@ -1033,7 +1033,6 @@ typedef struct mixer_vol_table {
*/
#define LOCL_STARTAUDIO 1

-#if !defined(__KERNEL__) || defined(USE_SEQ_MACROS)
/*
* Some convenience macros to simplify programming of the
* /dev/sequencer interface
@@ -1275,4 +1274,3 @@ void seqbuf_dump(void); /* This function
(SEQ_DUMPBUF(), write(seqfd, (char*)(patchx), len))

#endif
-#endif


linux-2.6.30.test/usr/include/linux/videodev.h:
@@ -16,24 +16,6 @@
#include <linux/ioctl.h>
#include <linux/videodev2.h>

-#if defined(__MIN_V4L1) && defined (__KERNEL__)
-
-/*
- * Used by those V4L2 core functions that need a minimum V4L1 support,
- * in order to allow V4L1 Compatibilty code compilation.
- */
-
-struct video_mbuf
-{
- int size; /* Total memory to map */
- int frames; /* Frames */
- int offsets[VIDEO_MAX_FRAME];
-};
-
-#define VIDIOCGMBUF _IOR('v',20, struct video_mbuf) /* Memory map
buffer info */
-
-#else
-#if defined(CONFIG_VIDEO_V4L1_COMPAT) || !defined (__KERNEL__)

#define VID_TYPE_CAPTURE 1 /* Can capture */
#define VID_TYPE_TUNER 2 /* Can tune */
@@ -328,8 +310,6 @@ struct video_code
#define VID_PLAY_RESET 13
#define VID_PLAY_END_MARK 14

-#endif /* CONFIG_VIDEO_V4L1_COMPAT */
-#endif /* __MIN_V4L1 */

#endif /* __LINUX_VIDEODEV_H */


+++ linux-2.6.30.test/usr/include/video/edid.h:
@@ -1,13 +1,11 @@
#ifndef __linux_video_edid_h__
#define __linux_video_edid_h__

-#if !defined(__KERNEL__) || defined(CONFIG_X86)

struct edid_info {
unsigned char dummy[128];
};


-#endif

#endif /* __linux_video_edid_h__ */



Please apply.

Signed-off-by: Denys Vlasenko <vda.linux@xxxxxxxxxxxxxx>
--
vda
diff -urpN linux-2.6.30.org/scripts/unifdef.c linux-2.6.30/scripts/unifdef.c
--- linux-2.6.30.org/scripts/unifdef.c 2009-06-10 05:05:27.000000000 +0200
+++ linux-2.6.30/scripts/unifdef.c 2009-06-21 20:05:02.000000000 +0200
@@ -296,6 +296,7 @@ main(int argc, char *argv[])
input = stdin;
}
process();
+ debug("bug at line %d", __LINE__);
abort(); /* bug */
}

@@ -438,8 +439,10 @@ done(void)
static void
ignoreoff(void)
{
- if (depth == 0)
+ if (depth == 0) {
+ debug("bug at line %d", __LINE__);
abort(); /* bug */
+ }
ignoring[depth] = ignoring[depth-1];
}
static void
@@ -471,8 +474,10 @@ nest(void)
static void
unnest(void)
{
- if (depth == 0)
+ if (depth == 0) {
+ debug("bug at line %d", __LINE__);
abort(); /* bug */
+ }
depth -= 1;
}
static void
@@ -596,8 +601,11 @@ get_line(void)
linestate = LS_DIRTY;
}
/* skipcomment should have changed the state */
- if (linestate == LS_HASH)
- abort(); /* bug */
+// Hmm happens sometimes on valid files
+// if (linestate == LS_HASH) {
+// debug("bug at line %d", __LINE__);
+// abort(); /* bug */
+// }
}
if (linestate == LS_DIRTY) {
while (*cp != '\0')
@@ -649,24 +657,31 @@ static const struct ops {
eval_fn *inner;
struct op {
const char *str;
+ int short_circuit_val;
int (*fn)(int, int);
} op[5];
} eval_ops[] = {
- { eval_table, { { "||", op_or } } },
- { eval_table, { { "&&", op_and } } },
- { eval_table, { { "==", op_eq },
- { "!=", op_ne } } },
- { eval_unary, { { "<=", op_le },
- { ">=", op_ge },
- { "<", op_lt },
- { ">", op_gt } } }
+ { eval_table, { { "||", 1, op_or } } },
+ { eval_table, { { "&&", 0, op_and } } },
+ { eval_table, { { "==", -1, op_eq },
+ { "!=", -1, op_ne } } },
+ { eval_unary, { { "<=", -1, op_le },
+ { ">=", -1, op_ge },
+ { "<", -1, op_lt },
+ { ">", -1, op_gt } } }
};

/*
- * Function for evaluating the innermost parts of expressions,
- * viz. !expr (expr) defined(symbol) symbol number
+ * Function for evaluating the innermost parts of expressions, viz.
+ * "!expr", "(expr)", "defined(symbol)", "defined symbol", "symbol", "number".
* We reset the keepthis flag when we find a non-constant subexpression.
*/
+// TODO: we use LT_IF both as "I don't know whether it's false or true"
+// (example: "#if defined FOO") and when we see syntax error
+// (example: "#if (1 || 2" - no closing paren!), but this is wrong.
+// Binary && and || need to distinguish these cases in order to handle this:
+// "#if defined KNOWN_UNDEFINED && FOO" - discard
+// "#if defined KNOWN_UNDEFINED && (syntax_error_here" - do not discard!
static Linetype
eval_unary(const struct ops *ops, int *valp, const char **cpp)
{
@@ -678,39 +693,60 @@ eval_unary(const struct ops *ops, int *v
if (*cp == '!') {
debug("eval%d !", ops - eval_ops);
cp++;
- if (eval_unary(ops, valp, &cp) == LT_IF)
+ if (eval_unary(ops, valp, &cp) == LT_IF) {
+ *cpp = cp;
return (LT_IF);
+ }
*valp = !*valp;
+
} else if (*cp == '(') {
+ Linetype expr_res;
+
cp++;
- debug("eval%d (", ops - eval_ops);
- if (eval_table(eval_ops, valp, &cp) == LT_IF)
- return (LT_IF);
+ debug("eval%d (%s", ops - eval_ops, cp);
+ expr_res = eval_table(eval_ops, valp, &cp);
cp = skipcomment(cp);
+ *cpp = cp;
if (*cp++ != ')')
return (LT_IF);
+ *cpp = cp;
+ if (expr_res == LT_IF)
+ return (LT_IF);
+
} else if (isdigit((unsigned char)*cp)) {
debug("eval%d number", ops - eval_ops);
*valp = strtol(cp, &ep, 0);
cp = skipsym(cp);
+
} else if (strncmp(cp, "defined", 7) == 0 && endsym(cp[7])) {
+ bool parens;
+
cp = skipcomment(cp+7);
- debug("eval%d defined", ops - eval_ops);
- if (*cp++ != '(')
- return (LT_IF);
- cp = skipcomment(cp);
+ debug("eval%d defined '%s'", ops - eval_ops, cp);
+ parens = (*cp == '(');
+ if (parens)
+ cp = skipcomment(cp+1);
sym = findsym(cp);
- if (sym < 0)
- return (LT_IF);
- *valp = (value[sym] != NULL);
cp = skipsym(cp);
cp = skipcomment(cp);
- if (*cp++ != ')')
+ if (parens) {
+ if (*cp != ')')
+ return (LT_IF);
+ cp = skipcomment(cp+1);
+ }
+ *cpp = cp;
+ if (sym < 0) {
+ debug("sym not found, returning LT_IF");
return (LT_IF);
+ }
+ *valp = (value[sym] != NULL);
keepthis = false;
+
} else if (!endsym(*cp)) {
debug("eval%d symbol", ops - eval_ops);
sym = findsym(cp);
+ cp = skipsym(cp);
+ *cpp = cp;
if (sym < 0)
return (LT_IF);
if (value[sym] == NULL)
@@ -720,8 +756,8 @@ eval_unary(const struct ops *ops, int *v
if (*ep != '\0' || ep == value[sym])
return (LT_IF);
}
- cp = skipsym(cp);
keepthis = false;
+
} else {
debug("eval%d bad expr", ops - eval_ops);
return (LT_IF);
@@ -738,15 +774,18 @@ eval_unary(const struct ops *ops, int *v
static Linetype
eval_table(const struct ops *ops, int *valp, const char **cpp)
{
+ Linetype left_side;
const struct op *op;
const char *cp;
int val;

- debug("eval%d", ops - eval_ops);
+ debug("eval%d '%s'", ops - eval_ops, *cpp);
+ left_side = ops->inner(ops+1, valp, cpp);
cp = *cpp;
- if (ops->inner(ops+1, valp, &cp) == LT_IF)
- return (LT_IF);
+
for (;;) {
+ Linetype right_side;
+
cp = skipcomment(cp);
for (op = ops->op; op->str != NULL; op++)
if (strncmp(cp, op->str, strlen(op->str)) == 0)
@@ -754,14 +793,37 @@ eval_table(const struct ops *ops, int *v
if (op->str == NULL)
break;
cp += strlen(op->str);
- debug("eval%d %s", ops - eval_ops, op->str);
- if (ops->inner(ops+1, &val, &cp) == LT_IF)
+ debug("eval%d '%s'", ops - eval_ops, op->str);
+ right_side = ops->inner(ops+1, &val, &cp);
+ *cpp = cp;
+
+ /* If short_circuit_val is 0 or 1, we can ignore
+ * right side if left size is known, and its value
+ * (i.e., *valp) is 0 or !0, respectively */
+ if (left_side != LT_IF && op->short_circuit_val == !!*valp) {
+ debug("op->short_circuit_val:%d *valp:%d cp:'%s'",
+ op->short_circuit_val, *valp, cp);
+ *valp = !!*valp;
+ break;
+ }
+ /* Same for the right side */
+ if (right_side != LT_IF && op->short_circuit_val == !!val) {
+ debug("op->short_circuit_val:%d val:%d cp:'%s'",
+ op->short_circuit_val, val, cp);
+ left_side = right_side;
+ *valp = !!val;
+ break;
+ }
+
+ if (left_side == LT_IF || right_side == LT_IF)
return (LT_IF);
*valp = op->fn(*valp, val);
+ left_side = right_side;
}

- *cpp = cp;
- debug("eval%d = %d", ops - eval_ops, *valp);
+ debug("eval%d = %d LT_IF:%d", ops - eval_ops, *valp, (left_side == LT_IF));
+ if (left_side == LT_IF)
+ return (LT_IF);
return (*valp ? LT_TRUE : LT_FALSE);
}

@@ -779,7 +841,7 @@ ifeval(const char **cpp)
debug("eval %s", *cpp);
keepthis = killconsts ? false : true;
ret = eval_table(eval_ops, &val, cpp);
- debug("eval = %d", val);
+ debug("val:%d ret:%d keepthis:%d", val, ret, keepthis);
return (keepthis ? LT_IF : ret);
}

@@ -886,6 +948,7 @@ skipcomment(const char *cp)
incomment = C_COMMENT;
continue;
default:
+ debug("bug at line %d", __LINE__);
abort(); /* bug */
}
return (cp);