1 /* parser config.in
2 *
3 * Version 1.0
4 * Eric Youngdale
5 * 10/95
6 *
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.
10 *
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.
18 *
19 * This file contains the code to further process the conditions from
20 * the "ifdef" clauses.
21 *
22 * The conditions are assumed to be one of the following formats
23 *
24 * simple_condition:= "$VARIABLE" == y/n/m
25 * simple_condition:= "$VARIABLE != y/n/m
26 *
27 * simple_condition -a simple_condition
28 *
29 * If the input condition contains '(' or ')' it would screw us up, but for now
30 * this is not a problem.
31 */
32 #include <stdlib.h>
33 #include <stdio.h>
34 #include <string.h>
35 #include "tkparse.h"
36
37
38 /*
39 * Walk a condition chain and invert it so that the logical result is
40 * inverted.
41 */
42 static void invert_condition(struct condition * cnd)
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
43 {
44 /*
45 * This is simple. Just walk through the list, and invert
46 * all of the operators.
47 */
48 for(;cnd; cnd = cnd->next)
49 {
50 switch(cnd->op)
51 {
52 case op_and:
53 cnd->op = op_or;
54 break;
55 case op_or:
56 /*
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.
63 */
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;
74 }
75 }
76 }
77
78 /*
79 * Walk a condition chain, and free the memory associated with it.
80 */
81 static void free_condition(struct condition * cnd)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
82 {
83 struct condition * next;
84 for(;cnd; cnd = next)
85 {
86 next = cnd->next;
87
88 if( cnd->variable.str != NULL )
89 free(cnd->variable.str);
90
91 free(cnd);
92 }
93 }
94
95 /*
96 * Walk all of the conditions, and look for choice values. Convert
97 * the tokens into something more digestible.
98 */
99 void fix_choice_cond()
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
100 {
101 struct condition * cond;
102 struct condition * cond2;
103 struct kconfig * cfg;
104 char tmpbuf[10];
105
106 for(cfg = config;cfg != NULL; cfg = cfg->next)
107 {
108 if( cfg->cond == NULL )
109 {
110 continue;
111 }
112
113 for(cond = cfg->cond; cond != NULL; cond = cond->next)
114 {
115 if( cond->op != op_kvariable )
116 continue;
117
118 if( cond->variable.cfg->tok != tok_choice )
119 continue;
120
121 /*
122 * Look ahead for what we are comparing this to. There should
123 * be one operator in between.
124 */
125 cond2 = cond->next->next;
126 strcpy(tmpbuf, cond->variable.cfg->label);
127
128 if( strcmp(cond2->variable.str, "y") == 0 )
129 {
130 cond->variable.cfg = cond->variable.cfg->choice_label;
131 cond2->variable.str = strdup(tmpbuf);
132 }
133 else
134 {
135 fprintf(stderr,"Ooops\n");
136 exit(0);
137 }
138 }
139
140 }
141 }
142
143 /*
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.
148 */
149 struct condition * get_token_cond(struct condition ** cond, int depth)
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
150 {
151 int i;
152 struct condition * newcond;
153 struct condition * tail;
154 struct condition * new;
155 struct condition * ocond;
156 struct kconfig * cfg;
157
158 newcond = tail = NULL;
159 for(i=0; i<depth; i++, cond++)
160 {
161 /*
162 * First insert the left parenthesis
163 */
164 new = (struct condition *) malloc(sizeof(struct condition));
165 memset(new, 0, sizeof(*new));
166 new->op = op_lparen;
167 if( tail == NULL )
168 {
169 newcond = tail = new;
170 }
171 else
172 {
173 tail->next = new;
174 tail = new;
175 }
176
177 /*
178 * Now duplicate the chain.
179 */
180 ocond = *cond;
181 for(;ocond != NULL; ocond = ocond->next)
182 {
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 )
187 {
188 if( ocond->op == op_variable )
189 {
190 /*
191 * Search for structure to insert here.
192 */
193 for(cfg = config;cfg != NULL; cfg = cfg->next)
194 {
195 if( cfg->tok != tok_bool
196 && cfg->tok != tok_int
197 && cfg->tok != tok_hex
198 && cfg->tok != tok_tristate
199 && cfg->tok != tok_choice
200 && cfg->tok != tok_dep_tristate)
201 {
202 continue;
203 }
204 if( strcmp(cfg->optionname, ocond->variable.str) == 0)
205 {
206 new->variable.cfg = cfg;
207 new->op = op_kvariable;
208 break;
209 }
210 }
211 if( cfg == NULL )
212 {
213 new->variable.str = strdup(ocond->variable.str);
214 }
215 }
216 else
217 {
218 new->variable.str = strdup(ocond->variable.str);
219 }
220 }
221 tail->next = new;
222 tail = new;
223 }
224
225 /*
226 * Next insert the left parenthesis
227 */
228 new = (struct condition *) malloc(sizeof(struct condition));
229 memset(new, 0, sizeof(*new));
230 new->op = op_rparen;
231 tail->next = new;
232 tail = new;
233
234 /*
235 * Insert an and operator, if we have another condition.
236 */
237 if( i < depth - 1 )
238 {
239 new = (struct condition *) malloc(sizeof(struct condition));
240 memset(new, 0, sizeof(*new));
241 new->op = op_and;
242 tail->next = new;
243 tail = new;
244 }
245
246 }
247
248 return newcond;
249 }
250
251 /*
252 * Walk a single chain of conditions and clone it. These are assumed
253 * to be created/processed by get_token_cond in a previous pass.
254 */
255 struct condition * get_token_cond_frag(struct condition * cond,
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
256 struct condition ** last)
257 {
258 struct condition * newcond;
259 struct condition * tail;
260 struct condition * new;
261 struct condition * ocond;
262
263 newcond = tail = NULL;
264
265 /*
266 * Now duplicate the chain.
267 */
268 for(ocond = cond;ocond != NULL; ocond = ocond->next)
269 {
270 new = (struct condition *) malloc(sizeof(struct condition));
271 memset(new, 0, sizeof(*new));
272 new->op = ocond->op;
273 new->variable.cfg = ocond->variable.cfg;
274 if( tail == NULL )
275 {
276 newcond = tail = new;
277 }
278 else
279 {
280 tail->next = new;
281 tail = new;
282 }
283 }
284
285 new = (struct condition *) malloc(sizeof(struct condition));
286 memset(new, 0, sizeof(*new));
287 new->op = op_and;
288 tail->next = new;
289 tail = new;
290
291 *last = tail;
292 return newcond;
293 }
294
295 /*
296 * Walk through the if conditionals and maintain a chain.
297 */
298 void fix_conditionals(struct kconfig * scfg)
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
299 {
300 int depth = 0;
301 int i;
302 struct kconfig * cfg;
303 struct kconfig * cfg1;
304 struct condition * conditions[25];
305 struct condition * cnd;
306 struct condition * cnd1;
307 struct condition * cnd2;
308 struct condition * cnd3;
309 struct condition * newcond;
310 struct condition * last;
311
312 /*
313 * Start by walking the chain. Every time we see an ifdef, push
314 * the condition chain on the stack. When we see an "else", we invert
315 * the condition at the top of the stack, and when we see an "endif"
316 * we free all of the memory for the condition at the top of the stack
317 * and remove the condition from the top of the stack.
318 *
319 * For any other type of token (i.e. a bool), we clone a new condition chain
320 * by anding together all of the conditions that are currently stored on
321 * the stack. In this way, we have a correct representation of whatever
322 * conditions govern the usage of each option.
323 */
324 memset(conditions, 0, sizeof(conditions));
325 for(cfg=scfg;cfg != NULL; cfg = cfg->next)
326 {
327 switch(cfg->tok)
328 {
329 case tok_if:
330 /*
331 * Push this condition on the stack, and nuke the token
332 * representing the ifdef, since we no longer need it.
333 */
334 conditions[depth] = cfg->cond;
335 depth++;
336 cfg->tok = tok_nop;
337 cfg->cond = NULL;
338 break;
339 case tok_else:
340 /*
341 * For an else, we just invert the condition at the top of
342 * the stack. This is done in place with no reallocation
343 * of memory taking place.
344 */
345 invert_condition(conditions[depth-1]);
346 cfg->tok = tok_nop;
347 break;
348 case tok_fi:
349 depth--;
350 free_condition(conditions[depth]);
351 conditions[depth] = NULL;
352 cfg->tok = tok_nop;
353 break;
354 case tok_comment:
355 case tok_define:
356 case tok_menuoption:
357 case tok_bool:
358 case tok_tristate:
359 case tok_int:
360 case tok_hex:
361 case tok_choice:
362 case tok_make:
363 /*
364 * We need to duplicate the chain of conditions and attach them to
365 * this token.
366 */
367 cfg->cond = get_token_cond(&conditions[0], depth);
368 break;
369 case tok_dep_tristate:
370 /*
371 * Same as tok_tristate et al except we have a temporary
372 * conditional. (Sort of a hybrid tok_if, tok_tristate, tok_fi
373 * option)
374 */
375 conditions[depth] = cfg->cond;
376 depth++;
377 cfg->cond = get_token_cond(&conditions[0], depth);
378 depth--;
379 free_condition(conditions[depth]);
380 conditions[depth] = NULL;
381 default:
382 break;
383 }
384 }
385
386 /*
387 * Fix any conditions involving the "choice" operator.
388 */
389 fix_choice_cond();
390
391 /*
392 * Walk through and see if there are multiple options that control the
393 * same kvariable. If there are we need to treat them a little bit
394 * special.
395 */
396 for(cfg=scfg;cfg != NULL; cfg = cfg->next)
397 {
398 switch(cfg->tok)
399 {
400 case tok_bool:
401 case tok_tristate:
402 case tok_dep_tristate:
403 case tok_int:
404 case tok_hex:
405 for(cfg1=cfg;cfg1 != NULL; cfg1 = cfg1->next)
406 {
407 switch(cfg1->tok)
408 {
409 case tok_define:
410 case tok_bool:
411 case tok_tristate:
412 case tok_dep_tristate:
413 case tok_int:
414 case tok_hex:
415 if( strcmp(cfg->optionname, cfg1->optionname) == 0)
416 {
417 cfg->flags |= CFG_DUP;
418 cfg1->flags |= CFG_DUP;
419 }
420 break;
421 default:
422 break;
423 }
424 }
425 break;
426 default:
427 break;
428 }
429 }
430
431 /*
432 * Now go through the list, and every time we see a kvariable, check
433 * to see whether it also has some dependencies. If so, then
434 * append it to our list. The reason we do this is that we might have
435 * option CONFIG_FOO which is only used if CONFIG_BAR is set. It may
436 * turn out that in config.in that the default value for CONFIG_BAR is
437 * set to "y", but that CONFIG_BAR is not enabled because CONFIG_XYZZY
438 * is not set. The current condition chain does not reflect this, but
439 * we can fix this by searching for the tokens that this option depends
440 * upon and cloning the conditions and merging them with the list.
441 */
442 for(cfg=scfg;cfg != NULL; cfg = cfg->next)
443 {
444 /*
445 * Search for a token that has a condition list.
446 */
447 if(cfg->cond == NULL) continue;
448 for(cnd = cfg->cond; cnd; cnd=cnd->next)
449 {
450 /*
451 * Now search the condition list for a known configuration variable
452 * that has conditions of it's own.
453 */
454 if(cnd->op != op_kvariable) continue;
455 if(cnd->variable.cfg->cond == NULL) continue;
456
457 if(cnd->variable.cfg->flags & CFG_DUP) continue;
458 /*
459 * OK, we have some conditions to append to cfg. Make a clone
460 * of the conditions,
461 */
462 newcond = get_token_cond_frag(cnd->variable.cfg->cond, &last);
463
464 /*
465 * Finally, we splice it into our list.
466 */
467 last->next = cfg->cond;
468 cfg->cond = newcond;
469
470 }
471 }
472
473 /*
474 * There is a strong possibility that we have duplicate conditions
475 * in here. It would make the script more efficient and readable to
476 * remove these. Here is where we assume here that there are no
477 * parenthesis in the input script.
478 */
479 for(cfg=scfg;cfg != NULL; cfg = cfg->next)
480 {
481 /*
482 * Search for configuration options that have conditions.
483 */
484 if(cfg->cond == NULL) continue;
485 for(cnd = cfg->cond; cnd; cnd=cnd->next)
486 {
487 /*
488 * Search for a left parenthesis.
489 */
490 if(cnd->op != op_lparen) continue;
491 for(cnd1 = cnd->next; cnd1; cnd1=cnd1->next)
492 {
493 /*
494 * Search after the previous left parenthesis, and try
495 * and find a second left parenthesis.
496 */
497 if(cnd1->op != op_lparen) continue;
498
499 /*
500 * Now compare the next 5 tokens to see if they are
501 * identical. We are looking for two chains that
502 * are like: '(' $VARIABLE operator constant ')'.
503 */
504 cnd2 = cnd;
505 cnd3 = cnd1;
506 for(i=0; i<5; i++, cnd2=cnd2->next, cnd3=cnd3->next)
507 {
508 if(!cnd2 || !cnd3) break;
509 if(cnd2->op != cnd3->op) break;
510 if(i == 1 && (cnd2->op != op_kvariable
511 || cnd2->variable.cfg != cnd3->variable.cfg) ) break;
512 if(i==2 && cnd2->op != op_eq && cnd2->op != op_neq) break;
513 if(i == 3 && cnd2->op != op_constant &&
514 strcmp(cnd2->variable.str, cnd3->variable.str) != 0)
515 break;
516 if(i==4 && cnd2->op != op_rparen) break;
517 }
518 /*
519 * If these match, and there is an and gluing these together,
520 * then we can nuke the second one.
521 */
522 if(i==5 && ((cnd3 && cnd3->op == op_and)
523 ||(cnd2 && cnd2->op == op_and)))
524 {
525 /*
526 * We have a duplicate. Nuke 5 ops.
527 */
528 cnd3 = cnd1;
529 for(i=0; i<5; i++, cnd3=cnd3->next)
530 {
531 cnd3->op = op_nuked;
532 }
533 /*
534 * Nuke the and that glues the conditions together.
535 */
536 if(cnd3 && cnd3->op == op_and) cnd3->op = op_nuked;
537 else if(cnd2 && cnd2->op == op_and) cnd2->op = op_nuked;
538 }
539 }
540 }
541 }
542 }