root/scripts/tkcond.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. invert_condition
  2. free_condition
  3. fix_choice_cond
  4. get_token_cond
  5. get_token_cond_frag
  6. fix_conditionals

   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 static int invert_condition(struct condition * cnd)
     /* [previous][next][first][last][top][bottom][index][help] */
  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         }
  73     }
  74 }
  75 
  76 /*
  77  * Walk a condition chain, and free the memory associated with it.
  78  */
  79 static int free_condition(struct condition * cnd)
     /* [previous][next][first][last][top][bottom][index][help] */
  80 {
  81   struct condition * 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 void fix_choice_cond()
     /* [previous][next][first][last][top][bottom][index][help] */
  98 {
  99   struct condition * cond;
 100   struct condition * cond2;
 101   struct kconfig * cfg;
 102   char tmpbuf[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 struct condition * get_token_cond(struct condition ** cond, int depth)
     /* [previous][next][first][last][top][bottom][index][help] */
 148 {
 149   int i;
 150   struct condition * newcond;
 151   struct condition * tail;
 152   struct condition * new;
 153   struct condition * ocond;
 154   struct kconfig * 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 = (struct condition *) malloc(sizeof(struct condition));
 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 = (struct condition *) malloc(sizeof(struct condition));
 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 = (struct condition *) malloc(sizeof(struct condition));
 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 = (struct condition *) malloc(sizeof(struct condition));
 236           memset(new, 0, sizeof(*new));
 237           new->op = op_and;
 238           tail->next = new;
 239           tail = new;
 240         }
 241 
 242     }
 243 
 244   return newcond;
 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 struct condition * get_token_cond_frag(struct condition * cond, 
     /* [previous][next][first][last][top][bottom][index][help] */
 252                                        struct condition ** last)
 253 {
 254   int i;
 255   struct condition * newcond;
 256   struct condition * tail;
 257   struct condition * new;
 258   struct condition * ocond;
 259   struct kconfig * 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 = (struct condition *) malloc(sizeof(struct condition));
 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 = (struct condition *) malloc(sizeof(struct condition));
 284   memset(new, 0, sizeof(*new));
 285   new->op = op_and;
 286   tail->next = new;
 287   tail = new;
 288   
 289   *last = tail;
 290   return newcond;
 291 }
 292 
 293 /*
 294  * Walk through the if conditionals and maintain a chain.
 295  */
 296 int fix_conditionals(struct kconfig * scfg)
     /* [previous][next][first][last][top][bottom][index][help] */
 297 {
 298   int depth = 0;
 299   int i;
 300   struct kconfig * cfg;
 301   struct kconfig * cfg1;
 302   struct condition * conditions[25];
 303   struct condition * cnd;
 304   struct condition * cnd1;
 305   struct condition * cnd2;
 306   struct condition * cnd3;
 307   struct condition * newcond;
 308   struct condition * 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         case tok_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         case tok_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         case tok_fi:
 347           depth--;
 348           free_condition(conditions[depth]);
 349           conditions[depth] = NULL;
 350           cfg->tok = tok_nop;
 351           break;
 352         case tok_comment:
 353         case tok_define:
 354         case tok_menuoption:
 355         case tok_bool:
 356         case tok_tristate:
 357         case tok_dep_tristate:
 358         case tok_int:
 359         case tok_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         case tok_bool:
 386         case tok_tristate:
 387         case tok_dep_tristate:
 388         case tok_int:
 389           for(cfg1=cfg;cfg1 != NULL; cfg1 = cfg1->next)
 390             {
 391               switch(cfg1->tok)
 392                 {
 393                 case tok_define:
 394                 case tok_bool:
 395                 case tok_tristate:
 396                 case tok_dep_tristate:
 397                 case tok_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                   else if(cnd2 && cnd2->op == op_and) cnd2->op = op_nuked;
 521                 }
 522             }
 523         }
 524     }
 525 }

/* [previous][next][first][last][top][bottom][index][help] */