tkcond.c 13 KB

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