Import 2.3.13pre3
[davej-history.git] / scripts / tkcond.c
blob89069daad8382ae64d8592903af09e9a065f0570
1 /*
2 * tkcond.c
4 * Eric Youngdale was the original author of xconfig.
5 * Michael Elizabeth Chastain (mec@shout.net) is the current maintainer.
7 * This file takes the tokenized statement list and transforms 'if ...'
8 * statements. For each simple statement, I find all of the 'if' statements
9 * that enclose it, and attach the aggregate conditionals of those 'if'
10 * statements to the cond list of the simple statement.
12 * 14 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
13 * - Steam-clean this file. I tested this by generating kconfig.tk for
14 * every architecture and comparing it character-for-character against
15 * the output of the old tkparse.
17 * TO DO:
18 * - xconfig is at the end of its life cycle. Contact <mec@shout.net> if
19 * you are interested in working on the replacement.
22 #include <stdio.h>
23 #include <stdlib.h>
24 #include <string.h>
26 #include "tkparse.h"
31 * Transform op_variable to op_kvariable.
33 * This works, but it's gross, speed-wise. It would benefit greatly
34 * from a simple hash table that maps names to cfg.
36 * Note well: this is actually better than the loop structure xconfig
37 * has been staggering along with for three years, which performs
38 * this whole procedure inside *another* loop on active conditionals.
40 void transform_to_kvariable( struct kconfig * scfg )
42 struct kconfig * cfg;
44 for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
46 struct condition * cond;
48 for ( cond = cfg->cond; cond != NULL; cond = cond->next )
50 if ( cond->op == op_variable )
52 /* Here's where it gets DISGUSTING. */
53 struct kconfig * cfg1;
55 for ( cfg1 = scfg; cfg1 != NULL; cfg1 = cfg1->next )
57 if ( cfg1->token == token_bool
58 || cfg1->token == token_choice_item
59 || cfg1->token == token_dep_tristate
60 || cfg1->token == token_hex
61 || cfg1->token == token_int
62 || cfg1->token == token_string
63 || cfg1->token == token_tristate )
65 if ( strcmp( cond->str, cfg1->optionname ) == 0 )
67 cond->op = op_kvariable;
68 cond->str = NULL;
69 cond->cfg = cfg1;
70 break;
76 #if 0
78 * Maybe someday this will be useful, but right now it
79 * gives a lot of false positives on files like
80 * drivers/video/Config.in that are meant for more
81 * than one architecture. Turn it on if you want to play
82 * with it though; it does work. -- mec
84 if ( cond->op == op_variable )
86 if ( strcmp( cond->str, "ARCH" ) != 0
87 && strcmp( cond->str, "CONSTANT_Y" ) != 0
88 && strcmp( cond->str, "CONSTANT_M" ) != 0
89 && strcmp( cond->str, "CONSTANT_N" ) != 0 )
91 fprintf( stderr, "warning: $%s used but not defined\n",
92 cond->str );
95 #endif
103 * Make a new condition chain by joining the current condition stack with
104 * the "&&" operator for glue.
106 struct condition * join_condition_stack( struct condition * conditions [],
107 int depth )
109 struct condition * cond_list;
110 struct condition * cond_last;
111 int i;
113 cond_list = cond_last = NULL;
114 for ( i = 0; i < depth; i++ )
116 struct condition * cond;
117 struct condition * cnew;
119 /* add a '(' */
120 cnew = malloc( sizeof(*cnew) );
121 memset( cnew, 0, sizeof(*cnew) );
122 cnew->op = op_lparen;
123 if ( cond_last == NULL )
124 { cond_list = cond_last = cnew; }
125 else
126 { cond_last->next = cnew; cond_last = cnew; }
128 /* duplicate the chain */
129 for ( cond = conditions [i]; cond != NULL; cond = cond->next )
131 cnew = malloc( sizeof(*cnew) );
132 cnew->next = NULL;
133 cnew->op = cond->op;
134 cnew->str = cond->str ? strdup( cond->str ) : NULL;
135 cnew->cfg = cond->cfg;
136 cond_last->next = cnew;
137 cond_last = cnew;
140 /* add a ')' */
141 cnew = malloc( sizeof(*cnew) );
142 memset( cnew, 0, sizeof(*cnew) );
143 cnew->op = op_rparen;
144 cond_last->next = cnew;
145 cond_last = cnew;
147 /* if i have another condition, add an '&&' operator */
148 if ( i < depth - 1 )
150 cnew = malloc( sizeof(*cnew) );
151 memset( cnew, 0, sizeof(*cnew) );
152 cnew->op = op_and;
153 cond_last->next = cnew;
154 cond_last = cnew;
159 * Remove duplicate conditions.
162 struct condition *cond1, *cond1b, *cond1c, *cond1d, *cond1e, *cond1f;
164 for ( cond1 = cond_list; cond1 != NULL; cond1 = cond1->next )
166 if ( cond1->op == op_lparen )
168 cond1b = cond1 ->next; if ( cond1b == NULL ) break;
169 cond1c = cond1b->next; if ( cond1c == NULL ) break;
170 cond1d = cond1c->next; if ( cond1d == NULL ) break;
171 cond1e = cond1d->next; if ( cond1e == NULL ) break;
172 cond1f = cond1e->next; if ( cond1f == NULL ) break;
174 if ( cond1b->op == op_kvariable
175 && ( cond1c->op == op_eq || cond1c->op == op_neq )
176 && cond1d->op == op_constant
177 && cond1e->op == op_rparen )
179 struct condition *cond2, *cond2b, *cond2c, *cond2d, *cond2e, *cond2f;
181 for ( cond2 = cond1f->next; cond2 != NULL; cond2 = cond2->next )
183 if ( cond2->op == op_lparen )
185 cond2b = cond2 ->next; if ( cond2b == NULL ) break;
186 cond2c = cond2b->next; if ( cond2c == NULL ) break;
187 cond2d = cond2c->next; if ( cond2d == NULL ) break;
188 cond2e = cond2d->next; if ( cond2e == NULL ) break;
189 cond2f = cond2e->next;
191 /* look for match */
192 if ( cond2b->op == op_kvariable
193 && cond2b->cfg == cond1b->cfg
194 && cond2c->op == cond1c->op
195 && cond2d->op == op_constant
196 && strcmp( cond2d->str, cond1d->str ) == 0
197 && cond2e->op == op_rparen )
199 /* one of these must be followed by && */
200 if ( cond1f->op == op_and
201 || ( cond2f != NULL && cond2f->op == op_and ) )
203 /* nuke the first duplicate */
204 cond1 ->op = op_nuked;
205 cond1b->op = op_nuked;
206 cond1c->op = op_nuked;
207 cond1d->op = op_nuked;
208 cond1e->op = op_nuked;
209 if ( cond1f->op == op_and )
210 cond1f->op = op_nuked;
211 else
212 cond2f->op = op_nuked;
222 return cond_list;
228 * This is the main transformation function.
230 void fix_conditionals( struct kconfig * scfg )
232 struct kconfig * cfg;
235 * Transform op_variable to op_kvariable.
237 transform_to_kvariable( scfg );
240 * Transform conditions that use variables from "choice" statements.
241 * Choice values appear to the user as a collection of booleans, and the
242 * script can test the individual booleans. But internally, all I have is
243 * the N-way value of an unnamed temporary for the whole statement. So I
244 * have to tranform '"$CONFIG_M386" != "y"'
245 * into '"$tmpvar_N" != "CONFIG_M386"'.
247 for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
249 struct condition * cond;
251 for ( cond = cfg->cond; cond != NULL; cond = cond->next )
253 if ( cond->op == op_kvariable && cond->cfg->token == token_choice_item )
256 * Look two more tokens down for the comparison token.
257 * It has to be "y" for this trick to work.
259 * If you get this error, don't even think about relaxing the
260 * strcmp test. You will produce incorrect TK code. Instead,
261 * look for the place in your Config.in script where you are
262 * comparing a 'choice' variable to a value other than 'y',
263 * and rewrite the comparison to be '= "y"' or '!= "y"'.
265 struct condition * cond2 = cond->next->next;
266 const char * label;
268 if ( strcmp( cond2->str, "y" ) != 0 )
270 fprintf( stderr, "tkparse choked in fix_choice_cond\n" );
271 exit( 1 );
274 label = cond->cfg->label;
275 cond->cfg = cond->cfg->cfg_parent;
276 cond2->str = strdup( label );
282 * Walk the statement list, maintaining a stack of current conditions.
283 * token_if push its condition onto the stack.
284 * token_else invert the condition on the top of the stack.
285 * token_endif pop the stack.
287 * For a simple statement, create a condition chain by joining together
288 * all of the conditions on the stack.
291 struct condition * cond_stack [32];
292 int depth = 0;
294 for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
296 switch ( cfg->token )
298 default:
299 break;
301 case token_if:
302 cond_stack [depth++] = cfg->cond;
303 cfg->cond = NULL;
304 break;
306 case token_else:
309 * Invert the condition chain.
311 * Be careful to transfrom op_or to op_and1, not op_and.
312 * I will need this later in the code that removes
313 * duplicate conditions.
315 struct condition * cond;
317 for ( cond = cond_stack [depth-1];
318 cond != NULL;
319 cond = cond->next )
321 switch( cond->op )
323 default: break;
324 case op_and: cond->op = op_or; break;
325 case op_or: cond->op = op_and1; break;
326 case op_neq: cond->op = op_eq; break;
327 case op_eq: cond->op = op_neq; break;
331 break;
333 case token_fi:
334 --depth;
335 break;
337 case token_bool:
338 case token_choice_item:
339 case token_comment:
340 case token_define_bool:
341 case token_hex:
342 case token_int:
343 case token_mainmenu_option:
344 case token_string:
345 case token_tristate:
346 cfg->cond = join_condition_stack( cond_stack, depth );
347 break;
349 case token_dep_tristate:
351 * Same as the other simple statements, plus an additional
352 * condition for the dependency.
354 cond_stack [depth] = cfg->cond;
355 cfg->cond = join_condition_stack( cond_stack, depth+1 );
356 break;