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 staticvoidinvert_condition(structcondition * cnd)
/* */ 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 caseop_and:
53 cnd->op = op_or;
54 break;
55 caseop_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 caseop_neq:
67 cnd->op = op_eq;
68 break;
69 caseop_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 staticvoidfree_condition(structcondition * cnd)
/* */ 82 { 83 structcondition * 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 voidfix_choice_cond()
/* */ 100 { 101 structcondition * cond;
102 structcondition * cond2;
103 structkconfig * cfg;
104 chartmpbuf[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 structcondition * get_token_cond(structcondition ** cond, intdepth)
/* */ 150 { 151 inti;
152 structcondition * newcond;
153 structcondition * tail;
154 structcondition * new;
155 structcondition * ocond;
156 structkconfig * 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 = (structcondition *) malloc(sizeof(structcondition));
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 = (structcondition *) malloc(sizeof(structcondition));
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 = (structcondition *) malloc(sizeof(structcondition));
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 = (structcondition *) malloc(sizeof(structcondition));
240 memset(new, 0, sizeof(*new));
241 new->op = op_and;
242 tail->next = new;
243 tail = new;
244 } 245
246 } 247
248 returnnewcond;
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 structcondition * get_token_cond_frag(structcondition * cond,
/* */ 256 structcondition ** last)
257 { 258 structcondition * newcond;
259 structcondition * tail;
260 structcondition * new;
261 structcondition * 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 = (structcondition *) malloc(sizeof(structcondition));
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 = (structcondition *) malloc(sizeof(structcondition));
286 memset(new, 0, sizeof(*new));
287 new->op = op_and;
288 tail->next = new;
289 tail = new;
290
291 *last = tail;
292 returnnewcond;
293 } 294
295 /* 296 * Walk through the if conditionals and maintain a chain. 297 */ 298 voidfix_conditionals(structkconfig * scfg)
/* */ 299 { 300 intdepth = 0;
301 inti;
302 structkconfig * cfg;
303 structkconfig * cfg1;
304 structcondition * conditions[25];
305 structcondition * cnd;
306 structcondition * cnd1;
307 structcondition * cnd2;
308 structcondition * cnd3;
309 structcondition * newcond;
310 structcondition * 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 casetok_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 casetok_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 casetok_fi:
349 depth--;
350 free_condition(conditions[depth]);
351 conditions[depth] = NULL;
352 cfg->tok = tok_nop;
353 break;
354 casetok_comment:
355 casetok_define:
356 casetok_menuoption:
357 casetok_bool:
358 casetok_tristate:
359 casetok_int:
360 casetok_hex:
361 casetok_choice:
362 casetok_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 casetok_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 casetok_bool:
401 casetok_tristate:
402 casetok_dep_tristate:
403 casetok_int:
404 casetok_hex:
405 for(cfg1=cfg;cfg1 != NULL; cfg1 = cfg1->next)
406 { 407 switch(cfg1->tok)
408 { 409 casetok_define:
410 casetok_bool:
411 casetok_tristate:
412 casetok_dep_tristate:
413 casetok_int:
414 casetok_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 elseif(cnd2 && cnd2->op == op_and) cnd2->op = op_nuked;
538 } 539 } 540 } 541 } 542 }