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