summaryrefslogtreecommitdiffstats
path: root/meta/recipes-devtools/unifdef
diff options
context:
space:
mode:
authorRichard Purdie <rpurdie@linux.intel.com>2010-08-27 15:14:24 +0100
committerRichard Purdie <rpurdie@linux.intel.com>2010-08-27 15:29:45 +0100
commit29d6678fd546377459ef75cf54abeef5b969b5cf (patch)
tree8edd65790e37a00d01c3f203f773fe4b5012db18 /meta/recipes-devtools/unifdef
parentda49de6885ee1bc424e70bc02f21f6ab920efb55 (diff)
downloadpoky-29d6678fd546377459ef75cf54abeef5b969b5cf.tar.gz
Major layout change to the packages directory
Having one monolithic packages directory makes it hard to find things and is generally overwhelming. This commit splits it into several logical sections roughly based on function, recipes.txt gives more information about the classifications used. The opportunity is also used to switch from "packages" to "recipes" as used in OpenEmbedded as the term "packages" can be confusing to people and has many different meanings. Not all recipes have been classified yet, this is just a first pass at separating things out. Some packages are moved to meta-extras as they're no longer actively used or maintained. Signed-off-by: Richard Purdie <rpurdie@linux.intel.com>
Diffstat (limited to 'meta/recipes-devtools/unifdef')
-rw-r--r--meta/recipes-devtools/unifdef/files/unifdef.c1005
-rw-r--r--meta/recipes-devtools/unifdef/unifdef-native_2.6.18+git.bb17
2 files changed, 1022 insertions, 0 deletions
diff --git a/meta/recipes-devtools/unifdef/files/unifdef.c b/meta/recipes-devtools/unifdef/files/unifdef.c
new file mode 100644
index 0000000000..5cbac15608
--- /dev/null
+++ b/meta/recipes-devtools/unifdef/files/unifdef.c
@@ -0,0 +1,1005 @@
1/*
2 * Copyright (c) 2002 - 2005 Tony Finch <dot@dotat.at>. All rights reserved.
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 * Redistribution and use in source and binary forms, with or without
13 * modification, are permitted provided that the following conditions
14 * are met:
15 * 1. Redistributions of source code must retain the above copyright
16 * notice, this list of conditions and the following disclaimer.
17 * 2. Redistributions in binary form must reproduce the above copyright
18 * notice, this list of conditions and the following disclaimer in the
19 * documentation and/or other materials provided with the distribution.
20 *
21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 * SUCH DAMAGE.
32 */
33
34#include <sys/cdefs.h>
35
36#ifndef lint
37#if 0
38static 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
51
52/*
53 * unifdef - remove ifdef'ed lines
54 *
55 * Wishlist:
56 * provide an option which will append the name of the
57 * appropriate symbol after #else's and #endif's
58 * provide an option which will check symbols after
59 * #else's and #endif's to see that they match their
60 * corresponding #ifdef or #ifndef
61 *
62 * The first two items above require better buffer handling, which would
63 * also make it possible to handle all "dodgy" directives correctly.
64 */
65
66#include <ctype.h>
67#include <err.h>
68#include <stdarg.h>
69#include <stdbool.h>
70#include <stdio.h>
71#include <stdlib.h>
72#include <string.h>
73#include <unistd.h>
74
75size_t strlcpy(char *dst, const char *src, size_t siz);
76
77/* types of input lines: */
78typedef enum {
79 LT_TRUEI, /* a true #if with ignore flag */
80 LT_FALSEI, /* a false #if with ignore flag */
81 LT_IF, /* an unknown #if */
82 LT_TRUE, /* a true #if */
83 LT_FALSE, /* a false #if */
84 LT_ELIF, /* an unknown #elif */
85 LT_ELTRUE, /* a true #elif */
86 LT_ELFALSE, /* a false #elif */
87 LT_ELSE, /* #else */
88 LT_ENDIF, /* #endif */
89 LT_DODGY, /* flag: directive is not on one line */
90 LT_DODGY_LAST = LT_DODGY + LT_ENDIF,
91 LT_PLAIN, /* ordinary line */
92 LT_EOF, /* end of file */
93 LT_COUNT
94} Linetype;
95
96static char const * const linetype_name[] = {
97 "TRUEI", "FALSEI", "IF", "TRUE", "FALSE",
98 "ELIF", "ELTRUE", "ELFALSE", "ELSE", "ENDIF",
99 "DODGY TRUEI", "DODGY FALSEI",
100 "DODGY IF", "DODGY TRUE", "DODGY FALSE",
101 "DODGY ELIF", "DODGY ELTRUE", "DODGY ELFALSE",
102 "DODGY ELSE", "DODGY ENDIF",
103 "PLAIN", "EOF"
104};
105
106/* state of #if processing */
107typedef enum {
108 IS_OUTSIDE,
109 IS_FALSE_PREFIX, /* false #if followed by false #elifs */
110 IS_TRUE_PREFIX, /* first non-false #(el)if is true */
111 IS_PASS_MIDDLE, /* first non-false #(el)if is unknown */
112 IS_FALSE_MIDDLE, /* a false #elif after a pass state */
113 IS_TRUE_MIDDLE, /* a true #elif after a pass state */
114 IS_PASS_ELSE, /* an else after a pass state */
115 IS_FALSE_ELSE, /* an else after a true state */
116 IS_TRUE_ELSE, /* an else after only false states */
117 IS_FALSE_TRAILER, /* #elifs after a true are false */
118 IS_COUNT
119} Ifstate;
120
121static char const * const ifstate_name[] = {
122 "OUTSIDE", "FALSE_PREFIX", "TRUE_PREFIX",
123 "PASS_MIDDLE", "FALSE_MIDDLE", "TRUE_MIDDLE",
124 "PASS_ELSE", "FALSE_ELSE", "TRUE_ELSE",
125 "FALSE_TRAILER"
126};
127
128/* state of comment parser */
129typedef enum {
130 NO_COMMENT = false, /* outside a comment */
131 C_COMMENT, /* in a comment like this one */
132 CXX_COMMENT, /* between // and end of line */
133 STARTING_COMMENT, /* just after slash-backslash-newline */
134 FINISHING_COMMENT, /* star-backslash-newline in a C comment */
135 CHAR_LITERAL, /* inside '' */
136 STRING_LITERAL /* inside "" */
137} Comment_state;
138
139static char const * const comment_name[] = {
140 "NO", "C", "CXX", "STARTING", "FINISHING", "CHAR", "STRING"
141};
142
143/* state of preprocessor line parser */
144typedef enum {
145 LS_START, /* only space and comments on this line */
146 LS_HASH, /* only space, comments, and a hash */
147 LS_DIRTY /* this line can't be a preprocessor line */
148} Line_state;
149
150static char const * const linestate_name[] = {
151 "START", "HASH", "DIRTY"
152};
153
154/*
155 * Minimum translation limits from ISO/IEC 9899:1999 5.2.4.1
156 */
157#define MAXDEPTH 64 /* maximum #if nesting */
158#define MAXLINE 4096 /* maximum length of line */
159#define MAXSYMS 4096 /* maximum number of symbols */
160
161/*
162 * Sometimes when editing a keyword the replacement text is longer, so
163 * we leave some space at the end of the tline buffer to accommodate this.
164 */
165#define EDITSLOP 10
166
167/*
168 * Globals.
169 */
170
171static bool complement; /* -c: do the complement */
172static bool debugging; /* -d: debugging reports */
173static bool iocccok; /* -e: fewer IOCCC errors */
174static bool killconsts; /* -k: eval constant #ifs */
175static bool lnblank; /* -l: blank deleted lines */
176static bool lnnum; /* -n: add #line directives */
177static bool symlist; /* -s: output symbol list */
178static bool text; /* -t: this is a text file */
179
180static const char *symname[MAXSYMS]; /* symbol name */
181static const char *value[MAXSYMS]; /* -Dsym=value */
182static bool ignore[MAXSYMS]; /* -iDsym or -iUsym */
183static int nsyms; /* number of symbols */
184
185static FILE *input; /* input file pointer */
186static const char *filename; /* input file name */
187static int linenum; /* current line number */
188
189static char tline[MAXLINE+EDITSLOP];/* input buffer plus space */
190static char *keyword; /* used for editing #elif's */
191
192static Comment_state incomment; /* comment parser state */
193static Line_state linestate; /* #if line parser state */
194static Ifstate ifstate[MAXDEPTH]; /* #if processor state */
195static bool ignoring[MAXDEPTH]; /* ignore comments state */
196static int stifline[MAXDEPTH]; /* start of current #if */
197static int depth; /* current #if nesting */
198static int delcount; /* count of deleted lines */
199static bool keepthis; /* don't delete constant #if */
200
201static int exitstat; /* program exit status */
202
203static void addsym(bool, bool, char *);
204static void debug(const char *, ...);
205static void done(void);
206static void error(const char *);
207static int findsym(const char *);
208static void flushline(bool);
209static Linetype getline34(void);
210static Linetype ifeval(const char **);
211static void ignoreoff(void);
212static void ignoreon(void);
213static void keywordedit(const char *);
214static void nest(void);
215static void process(void);
216static const char *skipcomment(const char *);
217static const char *skipsym(const char *);
218static void state(Ifstate);
219static int strlcmp(const char *, const char *, size_t);
220static void unnest(void);
221static void usage(void);
222
223#define endsym(c) (!isalpha((unsigned char)c) && !isdigit((unsigned char)c) && c != '_')
224
225/*
226 * The main program.
227 */
228int
229main(int argc, char *argv[])
230{
231 int opt;
232
233 while ((opt = getopt(argc, argv, "i:D:U:I:cdeklnst")) != -1)
234 switch (opt) {
235 case 'i': /* treat stuff controlled by these symbols as text */
236 /*
237 * For strict backwards-compatibility the U or D
238 * should be immediately after the -i but it doesn't
239 * matter much if we relax that requirement.
240 */
241 opt = *optarg++;
242 if (opt == 'D')
243 addsym(true, true, optarg);
244 else if (opt == 'U')
245 addsym(true, false, optarg);
246 else
247 usage();
248 break;
249 case 'D': /* define a symbol */
250 addsym(false, true, optarg);
251 break;
252 case 'U': /* undef a symbol */
253 addsym(false, false, optarg);
254 break;
255 case 'I':
256 /* no-op for compatibility with cpp */
257 break;
258 case 'c': /* treat -D as -U and vice versa */
259 complement = true;
260 break;
261 case 'd':
262 debugging = true;
263 break;
264 case 'e': /* fewer errors from dodgy lines */
265 iocccok = true;
266 break;
267 case 'k': /* process constant #ifs */
268 killconsts = true;
269 break;
270 case 'l': /* blank deleted lines instead of omitting them */
271 lnblank = true;
272 break;
273 case 'n': /* add #line directive after deleted lines */
274 lnnum = true;
275 break;
276 case 's': /* only output list of symbols that control #ifs */
277 symlist = true;
278 break;
279 case 't': /* don't parse C comments */
280 text = true;
281 break;
282 default:
283 usage();
284 }
285 argc -= optind;
286 argv += optind;
287 if (argc > 1) {
288 errx(2, "can only do one file");
289 } else if (argc == 1 && strcmp(*argv, "-") != 0) {
290 filename = *argv;
291 input = fopen(filename, "r");
292 if (input == NULL)
293 err(2, "can't open %s", filename);
294 } else {
295 filename = "[stdin]";
296 input = stdin;
297 }
298 process();
299 abort(); /* bug */
300}
301
302static void
303usage(void)
304{
305 fprintf(stderr, "usage: unifdef [-cdeklnst] [-Ipath]"
306 " [-Dsym[=val]] [-Usym] [-iDsym[=val]] [-iUsym] ... [file]\n");
307 exit(2);
308}
309
310/*
311 * A state transition function alters the global #if processing state
312 * in a particular way. The table below is indexed by the current
313 * processing state and the type of the current line.
314 *
315 * Nesting is handled by keeping a stack of states; some transition
316 * functions increase or decrease the depth. They also maintain the
317 * ignore state on a stack. In some complicated cases they have to
318 * alter the preprocessor directive, as follows.
319 *
320 * When we have processed a group that starts off with a known-false
321 * #if/#elif sequence (which has therefore been deleted) followed by a
322 * #elif that we don't understand and therefore must keep, we edit the
323 * latter into a #if to keep the nesting correct.
324 *
325 * When we find a true #elif in a group, the following block will
326 * always be kept and the rest of the sequence after the next #elif or
327 * #else will be discarded. We edit the #elif into a #else and the
328 * following directive to #endif since this has the desired behaviour.
329 *
330 * "Dodgy" directives are split across multiple lines, the most common
331 * example being a multi-line comment hanging off the right of the
332 * directive. We can handle them correctly only if there is no change
333 * from printing to dropping (or vice versa) caused by that directive.
334 * If the directive is the first of a group we have a choice between
335 * failing with an error, or passing it through unchanged instead of
336 * evaluating it. The latter is not the default to avoid questions from
337 * users about unifdef unexpectedly leaving behind preprocessor directives.
338 */
339typedef void state_fn(void);
340
341/* report an error */
342static void Eelif (void) { error("Inappropriate #elif"); }
343static void Eelse (void) { error("Inappropriate #else"); }
344static void Eendif(void) { error("Inappropriate #endif"); }
345static void Eeof (void) { error("Premature EOF"); }
346static void Eioccc(void) { error("Obfuscated preprocessor control line"); }
347/* plain line handling */
348static void print (void) { flushline(true); }
349static void drop (void) { flushline(false); }
350/* output lacks group's start line */
351static void Strue (void) { drop(); ignoreoff(); state(IS_TRUE_PREFIX); }
352static void Sfalse(void) { drop(); ignoreoff(); state(IS_FALSE_PREFIX); }
353static void Selse (void) { drop(); state(IS_TRUE_ELSE); }
354/* print/pass this block */
355static void Pelif (void) { print(); ignoreoff(); state(IS_PASS_MIDDLE); }
356static void Pelse (void) { print(); state(IS_PASS_ELSE); }
357static void Pendif(void) { print(); unnest(); }
358/* discard this block */
359static void Dfalse(void) { drop(); ignoreoff(); state(IS_FALSE_TRAILER); }
360static void Delif (void) { drop(); ignoreoff(); state(IS_FALSE_MIDDLE); }
361static void Delse (void) { drop(); state(IS_FALSE_ELSE); }
362static void Dendif(void) { drop(); unnest(); }
363/* first line of group */
364static void Fdrop (void) { nest(); Dfalse(); }
365static void Fpass (void) { nest(); Pelif(); }
366static void Ftrue (void) { nest(); Strue(); }
367static void Ffalse(void) { nest(); Sfalse(); }
368/* variable pedantry for obfuscated lines */
369static void Oiffy (void) { if (!iocccok) Eioccc(); Fpass(); ignoreon(); }
370static void Oif (void) { if (!iocccok) Eioccc(); Fpass(); }
371static void Oelif (void) { if (!iocccok) Eioccc(); Pelif(); }
372/* ignore comments in this block */
373static void Idrop (void) { Fdrop(); ignoreon(); }
374static void Itrue (void) { Ftrue(); ignoreon(); }
375static void Ifalse(void) { Ffalse(); ignoreon(); }
376/* edit this line */
377static void Mpass (void) { strncpy(keyword, "if ", 4); Pelif(); }
378static void Mtrue (void) { keywordedit("else\n"); state(IS_TRUE_MIDDLE); }
379static void Melif (void) { keywordedit("endif\n"); state(IS_FALSE_TRAILER); }
380static void Melse (void) { keywordedit("endif\n"); state(IS_FALSE_ELSE); }
381
382static state_fn * const trans_table[IS_COUNT][LT_COUNT] = {
383/* IS_OUTSIDE */
384{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Eendif,
385 Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Eendif,
386 print, done },
387/* IS_FALSE_PREFIX */
388{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Mpass, Strue, Sfalse,Selse, Dendif,
389 Idrop, Idrop, Fdrop, Fdrop, Fdrop, Mpass, Eioccc,Eioccc,Eioccc,Eioccc,
390 drop, Eeof },
391/* IS_TRUE_PREFIX */
392{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Dfalse,Dfalse,Dfalse,Delse, Dendif,
393 Oiffy, Oiffy, Fpass, Oif, Oif, Eioccc,Eioccc,Eioccc,Eioccc,Eioccc,
394 print, Eeof },
395/* IS_PASS_MIDDLE */
396{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Pelif, Mtrue, Delif, Pelse, Pendif,
397 Oiffy, Oiffy, Fpass, Oif, Oif, Pelif, Oelif, Oelif, Pelse, Pendif,
398 print, Eeof },
399/* IS_FALSE_MIDDLE */
400{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Pelif, Mtrue, Delif, Pelse, Pendif,
401 Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eioccc,Eioccc,Eioccc,Eioccc,Eioccc,
402 drop, Eeof },
403/* IS_TRUE_MIDDLE */
404{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Melif, Melif, Melif, Melse, Pendif,
405 Oiffy, Oiffy, Fpass, Oif, Oif, Eioccc,Eioccc,Eioccc,Eioccc,Pendif,
406 print, Eeof },
407/* IS_PASS_ELSE */
408{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Pendif,
409 Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Pendif,
410 print, Eeof },
411/* IS_FALSE_ELSE */
412{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eelif, Eelif, Eelif, Eelse, Dendif,
413 Idrop, Idrop, Fdrop, Fdrop, Fdrop, Eelif, Eelif, Eelif, Eelse, Eioccc,
414 drop, Eeof },
415/* IS_TRUE_ELSE */
416{ Itrue, Ifalse,Fpass, Ftrue, Ffalse,Eelif, Eelif, Eelif, Eelse, Dendif,
417 Oiffy, Oiffy, Fpass, Oif, Oif, Eelif, Eelif, Eelif, Eelse, Eioccc,
418 print, Eeof },
419/* IS_FALSE_TRAILER */
420{ Idrop, Idrop, Fdrop, Fdrop, Fdrop, Dfalse,Dfalse,Dfalse,Delse, Dendif,
421 Idrop, Idrop, Fdrop, Fdrop, Fdrop, Dfalse,Dfalse,Dfalse,Delse, Eioccc,
422 drop, Eeof }
423/*TRUEI FALSEI IF TRUE FALSE ELIF ELTRUE ELFALSE ELSE ENDIF
424 TRUEI FALSEI IF TRUE FALSE ELIF ELTRUE ELFALSE ELSE ENDIF (DODGY)
425 PLAIN EOF */
426};
427
428/*
429 * State machine utility functions
430 */
431static void
432done(void)
433{
434 if (incomment)
435 error("EOF in comment");
436 exit(exitstat);
437}
438static void
439ignoreoff(void)
440{
441 if (depth == 0)
442 abort(); /* bug */
443 ignoring[depth] = ignoring[depth-1];
444}
445static void
446ignoreon(void)
447{
448 ignoring[depth] = true;
449}
450static void
451keywordedit(const char *replacement)
452{
453 size_t size = tline + sizeof(tline) - keyword;
454 char *dst = keyword;
455 const char *src = replacement;
456 if (size != 0) {
457 while ((--size != 0) && (*src != '\0'))
458 *dst++ = *src++;
459 *dst = '\0';
460 }
461 print();
462}
463static void
464nest(void)
465{
466 depth += 1;
467 if (depth >= MAXDEPTH)
468 error("Too many levels of nesting");
469 stifline[depth] = linenum;
470}
471static void
472unnest(void)
473{
474 if (depth == 0)
475 abort(); /* bug */
476 depth -= 1;
477}
478static void
479state(Ifstate is)
480{
481 ifstate[depth] = is;
482}
483
484/*
485 * Write a line to the output or not, according to command line options.
486 */
487static void
488flushline(bool keep)
489{
490 if (symlist)
491 return;
492 if (keep ^ complement) {
493 if (lnnum && delcount > 0)
494 printf("#line %d\n", linenum);
495 fputs(tline, stdout);
496 delcount = 0;
497 } else {
498 if (lnblank)
499 putc('\n', stdout);
500 exitstat = 1;
501 delcount += 1;
502 }
503}
504
505/*
506 * The driver for the state machine.
507 */
508static void
509process(void)
510{
511 Linetype lineval;
512
513 for (;;) {
514 linenum++;
515 lineval = getline34();
516 trans_table[ifstate[depth]][lineval]();
517 debug("process %s -> %s depth %d",
518 linetype_name[lineval],
519 ifstate_name[ifstate[depth]], depth);
520 }
521}
522
523/*
524 * Parse a line and determine its type. We keep the preprocessor line
525 * parser state between calls in the global variable linestate, with
526 * help from skipcomment().
527 */
528static Linetype
529getline34(void)
530{
531 const char *cp;
532 int cursym;
533 int kwlen;
534 Linetype retval;
535 Comment_state wascomment;
536
537 if (fgets(tline, MAXLINE, input) == NULL)
538 return (LT_EOF);
539 retval = LT_PLAIN;
540 wascomment = incomment;
541 cp = skipcomment(tline);
542 if (linestate == LS_START) {
543 if (*cp == '#') {
544 linestate = LS_HASH;
545 cp = skipcomment(cp + 1);
546 } else if (*cp != '\0')
547 linestate = LS_DIRTY;
548 }
549 if (!incomment && linestate == LS_HASH) {
550 keyword = tline + (cp - tline);
551 cp = skipsym(cp);
552 kwlen = cp - keyword;
553 /* no way can we deal with a continuation inside a keyword */
554 if (strncmp(cp, "\\\n", 2) == 0)
555 Eioccc();
556 if (strlcmp("ifdef", keyword, kwlen) == 0 ||
557 strlcmp("ifndef", keyword, kwlen) == 0) {
558 cp = skipcomment(cp);
559 if ((cursym = findsym(cp)) < 0)
560 retval = LT_IF;
561 else {
562 retval = (keyword[2] == 'n')
563 ? LT_FALSE : LT_TRUE;
564 if (value[cursym] == NULL)
565 retval = (retval == LT_TRUE)
566 ? LT_FALSE : LT_TRUE;
567 if (ignore[cursym])
568 retval = (retval == LT_TRUE)
569 ? LT_TRUEI : LT_FALSEI;
570 }
571 cp = skipsym(cp);
572 } else if (strlcmp("if", keyword, kwlen) == 0)
573 retval = ifeval(&cp);
574 else if (strlcmp("elif", keyword, kwlen) == 0)
575 retval = ifeval(&cp) - LT_IF + LT_ELIF;
576 else if (strlcmp("else", keyword, kwlen) == 0)
577 retval = LT_ELSE;
578 else if (strlcmp("endif", keyword, kwlen) == 0)
579 retval = LT_ENDIF;
580 else {
581 linestate = LS_DIRTY;
582 retval = LT_PLAIN;
583 }
584 cp = skipcomment(cp);
585 if (*cp != '\0') {
586 linestate = LS_DIRTY;
587 if (retval == LT_TRUE || retval == LT_FALSE ||
588 retval == LT_TRUEI || retval == LT_FALSEI)
589 retval = LT_IF;
590 if (retval == LT_ELTRUE || retval == LT_ELFALSE)
591 retval = LT_ELIF;
592 }
593 if (retval != LT_PLAIN && (wascomment || incomment)) {
594 retval += LT_DODGY;
595 if (incomment)
596 linestate = LS_DIRTY;
597 }
598 /* skipcomment should have changed the state */
599 if (linestate == LS_HASH)
600 abort(); /* bug */
601 }
602 if (linestate == LS_DIRTY) {
603 while (*cp != '\0')
604 cp = skipcomment(cp + 1);
605 }
606 debug("parser %s comment %s line",
607 comment_name[incomment], linestate_name[linestate]);
608 return (retval);
609}
610
611/*
612 * 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.
615 */
616static int op_lt(int a, int b) { return (a < b); }
617static int op_gt(int a, int b) { return (a > b); }
618static int op_le(int a, int b) { return (a <= b); }
619static int op_ge(int a, int b) { return (a >= b); }
620static int op_eq(int a, int b) { return (a == b); }
621static int op_ne(int a, int b) { return (a != b); }
622static int op_or(int a, int b) { return (a || b); }
623static int op_and(int a, int b) { return (a && b); }
624
625/*
626 * An evaluation function takes three arguments, as follows: (1) a pointer to
627 * an element of the precedence table which lists the operators at the current
628 * level of precedence; (2) a pointer to an integer which will receive the
629 * value of the expression; and (3) a pointer to a char* that points to the
630 * expression to be evaluated and that is updated to the end of the expression
631 * 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.
634 */
635struct ops;
636
637typedef Linetype eval_fn(const struct ops *, int *, const char **);
638
639static eval_fn eval_table, eval_unary;
640
641/*
642 * The precedence table. Expressions involving binary operators are evaluated
643 * in a table-driven way by eval_table. When it evaluates a subexpression it
644 * calls the inner function with its first argument pointing to the next
645 * element of the table. Innermost expressions have special non-table-driven
646 * handling.
647 */
648static const struct ops {
649 eval_fn *inner;
650 struct op {
651 const char *str;
652 int (*fn)(int, int);
653 } op[5];
654} eval_ops[] = {
655 { eval_table, { { "||", op_or } } },
656 { eval_table, { { "&&", op_and } } },
657 { eval_table, { { "==", op_eq },
658 { "!=", op_ne } } },
659 { eval_unary, { { "<=", op_le },
660 { ">=", op_ge },
661 { "<", op_lt },
662 { ">", op_gt } } }
663};
664
665/*
666 * 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.
669 */
670static Linetype
671eval_unary(const struct ops *ops, int *valp, const char **cpp)
672{
673 const char *cp;
674 char *ep;
675 int sym;
676
677 cp = skipcomment(*cpp);
678 if (*cp == '!') {
679 debug("eval%d !", ops - eval_ops);
680 cp++;
681 if (eval_unary(ops, valp, &cp) == LT_IF)
682 return (LT_IF);
683 *valp = !*valp;
684 } else if (*cp == '(') {
685 cp++;
686 debug("eval%d (", ops - eval_ops);
687 if (eval_table(eval_ops, valp, &cp) == LT_IF)
688 return (LT_IF);
689 cp = skipcomment(cp);
690 if (*cp++ != ')')
691 return (LT_IF);
692 } else if (isdigit((unsigned char)*cp)) {
693 debug("eval%d number", ops - eval_ops);
694 *valp = strtol(cp, &ep, 0);
695 cp = skipsym(cp);
696 } else if (strncmp(cp, "defined", 7) == 0 && endsym(cp[7])) {
697 cp = skipcomment(cp+7);
698 debug("eval%d defined", ops - eval_ops);
699 if (*cp++ != '(')
700 return (LT_IF);
701 cp = skipcomment(cp);
702 sym = findsym(cp);
703 if (sym < 0)
704 return (LT_IF);
705 *valp = (value[sym] != NULL);
706 cp = skipsym(cp);
707 cp = skipcomment(cp);
708 if (*cp++ != ')')
709 return (LT_IF);
710 keepthis = false;
711 } else if (!endsym(*cp)) {
712 debug("eval%d symbol", ops - eval_ops);
713 sym = findsym(cp);
714 if (sym < 0)
715 return (LT_IF);
716 if (value[sym] == NULL)
717 *valp = 0;
718 else {
719 *valp = strtol(value[sym], &ep, 0);
720 if (*ep != '\0' || ep == value[sym])
721 return (LT_IF);
722 }
723 cp = skipsym(cp);
724 keepthis = false;
725 } else {
726 debug("eval%d bad expr", ops - eval_ops);
727 return (LT_IF);
728 }
729
730 *cpp = cp;
731 debug("eval%d = %d", ops - eval_ops, *valp);
732 return (*valp ? LT_TRUE : LT_FALSE);
733}
734
735/*
736 * Table-driven evaluation of binary operators.
737 */
738static Linetype
739eval_table(const struct ops *ops, int *valp, const char **cpp)
740{
741 const struct op *op;
742 const char *cp;
743 int val;
744
745 debug("eval%d", ops - eval_ops);
746 cp = *cpp;
747 if (ops->inner(ops+1, valp, &cp) == LT_IF)
748 return (LT_IF);
749 for (;;) {
750 cp = skipcomment(cp);
751 for (op = ops->op; op->str != NULL; op++)
752 if (strncmp(cp, op->str, strlen(op->str)) == 0)
753 break;
754 if (op->str == NULL)
755 break;
756 cp += strlen(op->str);
757 debug("eval%d %s", ops - eval_ops, op->str);
758 if (ops->inner(ops+1, &val, &cp) == LT_IF)
759 return (LT_IF);
760 *valp = op->fn(*valp, val);
761 }
762
763 *cpp = cp;
764 debug("eval%d = %d", ops - eval_ops, *valp);
765 return (*valp ? LT_TRUE : LT_FALSE);
766}
767
768/*
769 * Evaluate the expression on a #if or #elif line. If we can work out
770 * the result we return LT_TRUE or LT_FALSE accordingly, otherwise we
771 * return just a generic LT_IF.
772 */
773static Linetype
774ifeval(const char **cpp)
775{
776 int ret;
777 int val;
778
779 debug("eval %s", *cpp);
780 keepthis = killconsts ? false : true;
781 ret = eval_table(eval_ops, &val, cpp);
782 debug("eval = %d", val);
783 return (keepthis ? LT_IF : ret);
784}
785
786/*
787 * Skip over comments, strings, and character literals and stop at the
788 * next character position that is not whitespace. Between calls we keep
789 * the comment state in the global variable incomment, and we also adjust
790 * the global variable linestate when we see a newline.
791 * XXX: doesn't cope with the buffer splitting inside a state transition.
792 */
793static const char *
794skipcomment(const char *cp)
795{
796 if (text || ignoring[depth]) {
797 for (; isspace((unsigned char)*cp); cp++)
798 if (*cp == '\n')
799 linestate = LS_START;
800 return (cp);
801 }
802 while (*cp != '\0')
803 /* don't reset to LS_START after a line continuation */
804 if (strncmp(cp, "\\\n", 2) == 0)
805 cp += 2;
806 else switch (incomment) {
807 case NO_COMMENT:
808 if (strncmp(cp, "/\\\n", 3) == 0) {
809 incomment = STARTING_COMMENT;
810 cp += 3;
811 } else if (strncmp(cp, "/*", 2) == 0) {
812 incomment = C_COMMENT;
813 cp += 2;
814 } else if (strncmp(cp, "//", 2) == 0) {
815 incomment = CXX_COMMENT;
816 cp += 2;
817 } else if (strncmp(cp, "\'", 1) == 0) {
818 incomment = CHAR_LITERAL;
819 linestate = LS_DIRTY;
820 cp += 1;
821 } else if (strncmp(cp, "\"", 1) == 0) {
822 incomment = STRING_LITERAL;
823 linestate = LS_DIRTY;
824 cp += 1;
825 } else if (strncmp(cp, "\n", 1) == 0) {
826 linestate = LS_START;
827 cp += 1;
828 } else if (strchr(" \t", *cp) != NULL) {
829 cp += 1;
830 } else
831 return (cp);
832 continue;
833 case CXX_COMMENT:
834 if (strncmp(cp, "\n", 1) == 0) {
835 incomment = NO_COMMENT;
836 linestate = LS_START;
837 }
838 cp += 1;
839 continue;
840 case CHAR_LITERAL:
841 case STRING_LITERAL:
842 if ((incomment == CHAR_LITERAL && cp[0] == '\'') ||
843 (incomment == STRING_LITERAL && cp[0] == '\"')) {
844 incomment = NO_COMMENT;
845 cp += 1;
846 } else if (cp[0] == '\\') {
847 if (cp[1] == '\0')
848 cp += 1;
849 else
850 cp += 2;
851 } else if (strncmp(cp, "\n", 1) == 0) {
852 if (incomment == CHAR_LITERAL)
853 error("unterminated char literal");
854 else
855 error("unterminated string literal");
856 } else
857 cp += 1;
858 continue;
859 case C_COMMENT:
860 if (strncmp(cp, "*\\\n", 3) == 0) {
861 incomment = FINISHING_COMMENT;
862 cp += 3;
863 } else if (strncmp(cp, "*/", 2) == 0) {
864 incomment = NO_COMMENT;
865 cp += 2;
866 } else
867 cp += 1;
868 continue;
869 case STARTING_COMMENT:
870 if (*cp == '*') {
871 incomment = C_COMMENT;
872 cp += 1;
873 } else if (*cp == '/') {
874 incomment = CXX_COMMENT;
875 cp += 1;
876 } else {
877 incomment = NO_COMMENT;
878 linestate = LS_DIRTY;
879 }
880 continue;
881 case FINISHING_COMMENT:
882 if (*cp == '/') {
883 incomment = NO_COMMENT;
884 cp += 1;
885 } else
886 incomment = C_COMMENT;
887 continue;
888 default:
889 abort(); /* bug */
890 }
891 return (cp);
892}
893
894/*
895 * Skip over an identifier.
896 */
897static const char *
898skipsym(const char *cp)
899{
900 while (!endsym(*cp))
901 ++cp;
902 return (cp);
903}
904
905/*
906 * Look for the symbol in the symbol table. If is is found, we return
907 * the symbol table index, else we return -1.
908 */
909static int
910findsym(const char *str)
911{
912 const char *cp;
913 int symind;
914
915 cp = skipsym(str);
916 if (cp == str)
917 return (-1);
918 if (symlist) {
919 printf("%.*s\n", (int)(cp-str), str);
920 /* we don't care about the value of the symbol */
921 return (0);
922 }
923 for (symind = 0; symind < nsyms; ++symind) {
924 if (strlcmp(symname[symind], str, cp-str) == 0) {
925 debug("findsym %s %s", symname[symind],
926 value[symind] ? value[symind] : "");
927 return (symind);
928 }
929 }
930 return (-1);
931}
932
933/*
934 * Add a symbol to the symbol table.
935 */
936static void
937addsym(bool ignorethis, bool definethis, char *sym)
938{
939 int symind;
940 char *val;
941
942 symind = findsym(sym);
943 if (symind < 0) {
944 if (nsyms >= MAXSYMS)
945 errx(2, "too many symbols");
946 symind = nsyms++;
947 }
948 symname[symind] = sym;
949 ignore[symind] = ignorethis;
950 val = sym + (skipsym(sym) - sym);
951 if (definethis) {
952 if (*val == '=') {
953 value[symind] = val+1;
954 *val = '\0';
955 } else if (*val == '\0')
956 value[symind] = "";
957 else
958 usage();
959 } else {
960 if (*val != '\0')
961 usage();
962 value[symind] = NULL;
963 }
964}
965
966/*
967 * Compare s with n characters of t.
968 * The same as strncmp() except that it checks that s[n] == '\0'.
969 */
970static int
971strlcmp(const char *s, const char *t, size_t n)
972{
973 while (n-- && *t != '\0')
974 if (*s != *t)
975 return ((unsigned char)*s - (unsigned char)*t);
976 else
977 ++s, ++t;
978 return ((unsigned char)*s);
979}
980
981/*
982 * Diagnostics.
983 */
984static void
985debug(const char *msg, ...)
986{
987 va_list ap;
988
989 if (debugging) {
990 va_start(ap, msg);
991 vwarnx(msg, ap);
992 va_end(ap);
993 }
994}
995
996static void
997error(const char *msg)
998{
999 if (depth == 0)
1000 warnx("%s: %d: %s", filename, linenum, msg);
1001 else
1002 warnx("%s: %d: %s (#if line %d depth %d)",
1003 filename, linenum, msg, stifline[depth], depth);
1004 errx(2, "output may be truncated");
1005}
diff --git a/meta/recipes-devtools/unifdef/unifdef-native_2.6.18+git.bb b/meta/recipes-devtools/unifdef/unifdef-native_2.6.18+git.bb
new file mode 100644
index 0000000000..d879782b29
--- /dev/null
+++ b/meta/recipes-devtools/unifdef/unifdef-native_2.6.18+git.bb
@@ -0,0 +1,17 @@
1DESCRIPTION = "Kernel header preprocessor"
2SECTION = "devel"
3LICENSE = "GPL"
4
5SRC_URI = "file://unifdef.c"
6
7inherit native
8
9do_compile() {
10 ${CC} ${CFLAGS} ${LDFLAGS} -o unifdef ${WORKDIR}/unifdef.c
11}
12
13do_install() {
14 install -d ${D}${bindir}
15 install -m 0755 unifdef ${D}${bindir}
16}
17