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