Import 2.1.115pre2
[davej-history.git] / scripts / tkcond.c
blobfc133295d978079943d2c0555658970f5c924208
1 /* parser config.in
3 * Version 1.0
4 * Eric Youngdale
5 * 10/95
7 * The general idea here is that we want to parse a config.in file and
8 * from this, we generate a wish script which gives us effectively the
9 * same functionality that the original config.in script provided.
11 * This task is split roughly into 3 parts. The first parse is the parse
12 * of the input file itself. The second part is where we analyze the
13 * #ifdef clauses, and attach a linked list of tokens to each of the
14 * menu items. In this way, each menu item has a complete list of
15 * dependencies that are used to enable/disable the options.
16 * The third part is to take the configuration database we have build,
17 * and build the actual wish script.
19 * This file contains the code to further process the conditions from
20 * the "ifdef" clauses.
22 * The conditions are assumed to be one of the following formats
24 * simple_condition:= "$VARIABLE" == y/n/m
25 * simple_condition:= "$VARIABLE != y/n/m
27 * simple_condition -a simple_condition
29 * If the input condition contains '(' or ')' it would screw us up, but for now
30 * this is not a problem.
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include "tkparse.h"
39 * Walk a condition chain and invert it so that the logical result is
40 * inverted.
42 static void invert_condition(struct condition * cnd)
45 * This is simple. Just walk through the list, and invert
46 * all of the operators.
48 for(;cnd; cnd = cnd->next)
50 switch(cnd->op)
52 case op_and:
53 cnd->op = op_or;
54 break;
55 case op_or:
57 * This is not turned into op_and - we need to keep track
58 * of what operators were used here since we have an optimization
59 * later on to remove duplicate conditions, and having
60 * inverted ors in there would make it harder if we did not
61 * distinguish an inverted or from an and we inserted because
62 * of nested ifs.
64 cnd->op = op_and1;
65 break;
66 case op_neq:
67 cnd->op = op_eq;
68 break;
69 case op_eq:
70 cnd->op = op_neq;
71 break;
72 default:
73 break;
79 * Walk a condition chain, and free the memory associated with it.
81 static void free_condition(struct condition * cnd)
83 struct condition * next;
84 for(;cnd; cnd = next)
86 next = cnd->next;
88 if( cnd->variable.str != NULL )
89 free(cnd->variable.str);
91 free(cnd);
96 * Walk all of the conditions, and look for choice values. Convert
97 * the tokens into something more digestible.
99 void fix_choice_cond(void)
101 struct condition * cond;
102 struct condition * cond2;
103 struct kconfig * cfg;
104 char tmpbuf[255];
106 for(cfg = config;cfg != NULL; cfg = cfg->next)
108 if( cfg->cond == NULL )
110 continue;
113 for(cond = cfg->cond; cond != NULL; cond = cond->next)
115 if( cond->op != op_kvariable )
116 continue;
118 if( cond->variable.cfg->tok != tok_choice )
119 continue;
122 * Look ahead for what we are comparing this to. There should
123 * be one operator in between.
125 cond2 = cond->next->next;
126 strcpy(tmpbuf, cond->variable.cfg->label);
128 if( strcmp(cond2->variable.str, "y") == 0 )
130 cond->variable.cfg = cond->variable.cfg->choice_label;
131 cond2->variable.str = strdup(tmpbuf);
133 else
135 fprintf(stderr,"Ooops\n");
136 exit(0);
144 * Walk the stack of conditions, and clone all of them with "&&" operators
145 * gluing them together. The conditions from each level of the stack
146 * are wrapped in parenthesis so as to guarantee that the results
147 * are logically correct.
149 struct condition * get_token_cond(struct condition ** cond, int depth)
151 int i;
152 struct condition * newcond;
153 struct condition * tail;
154 struct condition * new;
155 struct condition * ocond;
156 struct kconfig * cfg;
158 newcond = tail = NULL;
159 for(i=0; i<depth; i++, cond++)
162 * First insert the left parenthesis
164 new = (struct condition *) malloc(sizeof(struct condition));
165 memset(new, 0, sizeof(*new));
166 new->op = op_lparen;
167 if( tail == NULL )
169 newcond = tail = new;
171 else
173 tail->next = new;
174 tail = new;
178 * Now duplicate the chain.
180 ocond = *cond;
181 for(;ocond != NULL; ocond = ocond->next)
183 new = (struct condition *) malloc(sizeof(struct condition));
184 memset(new, 0, sizeof(*new));
185 new->op = ocond->op;
186 if( ocond->variable.str != NULL )
188 if( ocond->op == op_variable )
191 * Search for structure to insert here.
193 for(cfg = config;cfg != NULL; cfg = cfg->next)
195 if( cfg->tok != tok_bool
196 && cfg->tok != tok_int
197 && cfg->tok != tok_hex
198 && cfg->tok != tok_string
199 && cfg->tok != tok_tristate
200 && cfg->tok != tok_choice
201 && cfg->tok != tok_dep_tristate)
203 continue;
205 if( strcmp(cfg->optionname, ocond->variable.str) == 0)
207 new->variable.cfg = cfg;
208 new->op = op_kvariable;
209 break;
212 if( cfg == NULL )
214 new->variable.str = strdup(ocond->variable.str);
217 else
219 new->variable.str = strdup(ocond->variable.str);
222 tail->next = new;
223 tail = new;
227 * Next insert the left parenthesis
229 new = (struct condition *) malloc(sizeof(struct condition));
230 memset(new, 0, sizeof(*new));
231 new->op = op_rparen;
232 tail->next = new;
233 tail = new;
236 * Insert an and operator, if we have another condition.
238 if( i < depth - 1 )
240 new = (struct condition *) malloc(sizeof(struct condition));
241 memset(new, 0, sizeof(*new));
242 new->op = op_and;
243 tail->next = new;
244 tail = new;
249 return newcond;
253 * Walk a single chain of conditions and clone it. These are assumed
254 * to be created/processed by get_token_cond in a previous pass.
256 struct condition * get_token_cond_frag(struct condition * cond,
257 struct condition ** last)
259 struct condition * newcond;
260 struct condition * tail;
261 struct condition * new;
262 struct condition * ocond;
264 newcond = tail = NULL;
267 * Now duplicate the chain.
269 for(ocond = cond;ocond != NULL; ocond = ocond->next)
271 new = (struct condition *) malloc(sizeof(struct condition));
272 memset(new, 0, sizeof(*new));
273 new->op = ocond->op;
274 new->variable.cfg = ocond->variable.cfg;
275 if( tail == NULL )
277 newcond = tail = new;
279 else
281 tail->next = new;
282 tail = new;
286 new = (struct condition *) malloc(sizeof(struct condition));
287 memset(new, 0, sizeof(*new));
288 new->op = op_and;
289 tail->next = new;
290 tail = new;
292 *last = tail;
293 return newcond;
297 * Walk through the if conditionals and maintain a chain.
299 void fix_conditionals(struct kconfig * scfg)
301 int depth = 0;
302 int i;
303 struct kconfig * cfg;
304 struct kconfig * cfg1;
305 struct condition * conditions[25];
306 struct condition * cnd;
307 struct condition * cnd1;
308 struct condition * cnd2;
309 struct condition * cnd3;
310 struct condition * newcond;
311 struct condition * last;
314 * Start by walking the chain. Every time we see an ifdef, push
315 * the condition chain on the stack. When we see an "else", we invert
316 * the condition at the top of the stack, and when we see an "endif"
317 * we free all of the memory for the condition at the top of the stack
318 * and remove the condition from the top of the stack.
320 * For any other type of token (i.e. a bool), we clone a new condition chain
321 * by anding together all of the conditions that are currently stored on
322 * the stack. In this way, we have a correct representation of whatever
323 * conditions govern the usage of each option.
325 memset(conditions, 0, sizeof(conditions));
326 for(cfg=scfg;cfg != NULL; cfg = cfg->next)
328 switch(cfg->tok)
330 case tok_if:
332 * Push this condition on the stack, and nuke the token
333 * representing the ifdef, since we no longer need it.
335 conditions[depth] = cfg->cond;
336 depth++;
337 cfg->tok = tok_nop;
338 cfg->cond = NULL;
339 break;
340 case tok_else:
342 * For an else, we just invert the condition at the top of
343 * the stack. This is done in place with no reallocation
344 * of memory taking place.
346 invert_condition(conditions[depth-1]);
347 cfg->tok = tok_nop;
348 break;
349 case tok_fi:
350 depth--;
351 free_condition(conditions[depth]);
352 conditions[depth] = NULL;
353 cfg->tok = tok_nop;
354 break;
355 case tok_comment:
356 case tok_define:
357 case tok_menuoption:
358 case tok_bool:
359 case tok_tristate:
360 case tok_int:
361 case tok_hex:
362 case tok_string:
363 case tok_choice:
365 * We need to duplicate the chain of conditions and attach them to
366 * this token.
368 cfg->cond = get_token_cond(&conditions[0], depth);
369 break;
370 case tok_dep_tristate:
372 * Same as tok_tristate et al except we have a temporary
373 * conditional. (Sort of a hybrid tok_if, tok_tristate, tok_fi
374 * option)
376 conditions[depth] = cfg->cond;
377 depth++;
378 cfg->cond = get_token_cond(&conditions[0], depth);
379 depth--;
380 free_condition(conditions[depth]);
381 conditions[depth] = NULL;
382 default:
383 break;
388 * Fix any conditions involving the "choice" operator.
390 fix_choice_cond();
393 * Walk through and see if there are multiple options that control the
394 * same kvariable. If there are we need to treat them a little bit
395 * special.
397 for(cfg=scfg;cfg != NULL; cfg = cfg->next)
399 switch(cfg->tok)
401 case tok_bool:
402 case tok_tristate:
403 case tok_dep_tristate:
404 case tok_int:
405 case tok_hex:
406 case tok_string:
407 for(cfg1=cfg;cfg1 != NULL; cfg1 = cfg1->next)
409 switch(cfg1->tok)
411 case tok_define:
412 case tok_bool:
413 case tok_tristate:
414 case tok_dep_tristate:
415 case tok_int:
416 case tok_hex:
417 case tok_string:
418 if( strcmp(cfg->optionname, cfg1->optionname) == 0)
420 cfg->flags |= CFG_DUP;
421 cfg1->flags |= CFG_DUP;
423 break;
424 default:
425 break;
428 break;
429 default:
430 break;
435 * Now go through the list, and every time we see a kvariable, check
436 * to see whether it also has some dependencies. If so, then
437 * append it to our list. The reason we do this is that we might have
438 * option CONFIG_FOO which is only used if CONFIG_BAR is set. It may
439 * turn out that in config.in that the default value for CONFIG_BAR is
440 * set to "y", but that CONFIG_BAR is not enabled because CONFIG_XYZZY
441 * is not set. The current condition chain does not reflect this, but
442 * we can fix this by searching for the tokens that this option depends
443 * upon and cloning the conditions and merging them with the list.
445 for(cfg=scfg;cfg != NULL; cfg = cfg->next)
448 * Search for a token that has a condition list.
450 if(cfg->cond == NULL) continue;
451 for(cnd = cfg->cond; cnd; cnd=cnd->next)
454 * Now search the condition list for a known configuration variable
455 * that has conditions of its own.
457 if(cnd->op != op_kvariable) continue;
458 if(cnd->variable.cfg->cond == NULL) continue;
460 if(cnd->variable.cfg->flags & CFG_DUP) continue;
462 * OK, we have some conditions to append to cfg. Make a clone
463 * of the conditions,
465 newcond = get_token_cond_frag(cnd->variable.cfg->cond, &last);
468 * Finally, we splice it into our list.
470 last->next = cfg->cond;
471 cfg->cond = newcond;
477 * There is a strong possibility that we have duplicate conditions
478 * in here. It would make the script more efficient and readable to
479 * remove these. Here is where we assume here that there are no
480 * parenthesis in the input script.
482 for(cfg=scfg;cfg != NULL; cfg = cfg->next)
485 * Search for configuration options that have conditions.
487 if(cfg->cond == NULL) continue;
488 for(cnd = cfg->cond; cnd; cnd=cnd->next)
491 * Search for a left parenthesis.
493 if(cnd->op != op_lparen) continue;
494 for(cnd1 = cnd->next; cnd1; cnd1=cnd1->next)
497 * Search after the previous left parenthesis, and try
498 * and find a second left parenthesis.
500 if(cnd1->op != op_lparen) continue;
503 * Now compare the next 5 tokens to see if they are
504 * identical. We are looking for two chains that
505 * are like: '(' $VARIABLE operator constant ')'.
507 cnd2 = cnd;
508 cnd3 = cnd1;
509 for(i=0; i<5; i++, cnd2=cnd2->next, cnd3=cnd3->next)
511 if(!cnd2 || !cnd3) break;
512 if(cnd2->op != cnd3->op) break;
513 if(i == 1 && (cnd2->op != op_kvariable
514 || cnd2->variable.cfg != cnd3->variable.cfg) ) break;
515 if(i==2 && cnd2->op != op_eq && cnd2->op != op_neq) break;
516 if(i == 3 && cnd2->op != op_constant &&
517 strcmp(cnd2->variable.str, cnd3->variable.str) != 0)
518 break;
519 if(i==4 && cnd2->op != op_rparen) break;
522 * If these match, and there is an and gluing these together,
523 * then we can nuke the second one.
525 if(i==5 && ((cnd3 && cnd3->op == op_and)
526 ||(cnd2 && cnd2->op == op_and)))
529 * We have a duplicate. Nuke 5 ops.
531 cnd3 = cnd1;
532 for(i=0; i<5; i++, cnd3=cnd3->next)
534 cnd3->op = op_nuked;
537 * Nuke the and that glues the conditions together.
539 if(cnd3 && cnd3->op == op_and) cnd3->op = op_nuked;
540 else if(cnd2 && cnd2->op == op_and) cnd2->op = op_nuked;