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 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 static void 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         default:
  73           break;
  74         }
  75     }
  76 }
  77 
  78 /*
  79  * Walk a condition chain, and free the memory associated with it.
  80  */
  81 static void free_condition(struct condition * cnd)
     /* [previous][next][first][last][top][bottom][index][help] */
  82 {
  83   struct condition * 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 void fix_choice_cond()
     /* [previous][next][first][last][top][bottom][index][help] */
 100 {
 101   struct condition * cond;
 102   struct condition * cond2;
 103   struct kconfig * cfg;
 104   char tmpbuf[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 struct condition * get_token_cond(struct condition ** cond, int depth)
     /* [previous][next][first][last][top][bottom][index][help] */
 150 {
 151   int i;
 152   struct condition * newcond;
 153   struct condition * tail;
 154   struct condition * new;
 155   struct condition * ocond;
 156   struct kconfig * 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 = (struct condition *) malloc(sizeof(struct condition));
 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 = (struct condition *) malloc(sizeof(struct condition));
 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 = (struct condition *) malloc(sizeof(struct condition));
 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 = (struct condition *) malloc(sizeof(struct condition));
 240           memset(new, 0, sizeof(*new));
 241           new->op = op_and;
 242           tail->next = new;
 243           tail = new;
 244         }
 245 
 246     }
 247 
 248   return newcond;
 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 struct condition * get_token_cond_frag(struct condition * cond, 
     /* [previous][next][first][last][top][bottom][index][help] */
 256                                        struct condition ** last)
 257 {
 258   struct condition * newcond;
 259   struct condition * tail;
 260   struct condition * new;
 261   struct condition * 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 = (struct condition *) malloc(sizeof(struct condition));
 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 = (struct condition *) malloc(sizeof(struct condition));
 286   memset(new, 0, sizeof(*new));
 287   new->op = op_and;
 288   tail->next = new;
 289   tail = new;
 290   
 291   *last = tail;
 292   return newcond;
 293 }
 294 
 295 /*
 296  * Walk through the if conditionals and maintain a chain.
 297  */
 298 void fix_conditionals(struct kconfig * scfg)
     /* [previous][next][first][last][top][bottom][index][help] */
 299 {
 300   int depth = 0;
 301   int i;
 302   struct kconfig * cfg;
 303   struct kconfig * cfg1;
 304   struct condition * conditions[25];
 305   struct condition * cnd;
 306   struct condition * cnd1;
 307   struct condition * cnd2;
 308   struct condition * cnd3;
 309   struct condition * newcond;
 310   struct condition * 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         case tok_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         case tok_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         case tok_fi:
 349           depth--;
 350           free_condition(conditions[depth]);
 351           conditions[depth] = NULL;
 352           cfg->tok = tok_nop;
 353           break;
 354         case tok_comment:
 355         case tok_define:
 356         case tok_menuoption:
 357         case tok_bool:
 358         case tok_tristate:
 359         case tok_int:
 360         case tok_hex:
 361         case tok_choice:
 362         case tok_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         case tok_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         case tok_bool:
 401         case tok_tristate:
 402         case tok_dep_tristate:
 403         case tok_int:
 404         case tok_hex:
 405           for(cfg1=cfg;cfg1 != NULL; cfg1 = cfg1->next)
 406             {
 407               switch(cfg1->tok)
 408                 {
 409                 case tok_define:
 410                 case tok_bool:
 411                 case tok_tristate:
 412                 case tok_dep_tristate:
 413                 case tok_int:
 414                 case tok_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                   else if(cnd2 && cnd2->op == op_and) cnd2->op = op_nuked;
 538                 }
 539             }
 540         }
 541     }
 542 }

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