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 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 digestable.
  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 inbetween.
 124            */
 125           cond2 = cond->next->next;
 126           sprintf(tmpbuf, "%d", cond->variable.cfg->choice_value);
 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           /*
 363            * We need to duplicate the chain of conditions and attach them to
 364            * this token.
 365            */
 366           cfg->cond = get_token_cond(&conditions[0], depth);
 367           break;
 368         case tok_dep_tristate:
 369           /*
 370            * Same as tok_tristate et al except we have a temporary
 371            * conditional. (Sort of a hybrid tok_if, tok_tristate, tok_fi
 372            * option)
 373            */
 374           conditions[depth] = cfg->cond;
 375           depth++;
 376           cfg->cond = get_token_cond(&conditions[0], depth);
 377           depth--;
 378           free_condition(conditions[depth]);
 379           conditions[depth] = NULL;
 380         default:
 381           break;
 382         }
 383     }
 384 
 385   /*
 386    * Fix any conditions involving the "choice" operator.
 387    */
 388   fix_choice_cond();
 389 
 390   /*
 391    * Walk through and see if there are multiple options that control the
 392    * same kvariable.  If there are we need to treat them a little bit
 393    * special.
 394    */
 395   for(cfg=scfg;cfg != NULL; cfg = cfg->next)
 396     {
 397       switch(cfg->tok)
 398         {
 399         case tok_bool:
 400         case tok_tristate:
 401         case tok_dep_tristate:
 402         case tok_int:
 403         case tok_hex:
 404           for(cfg1=cfg;cfg1 != NULL; cfg1 = cfg1->next)
 405             {
 406               switch(cfg1->tok)
 407                 {
 408                 case tok_define:
 409                 case tok_bool:
 410                 case tok_tristate:
 411                 case tok_dep_tristate:
 412                 case tok_int:
 413                 case tok_hex:
 414                   if( strcmp(cfg->optionname, cfg1->optionname) == 0)
 415                     {
 416                       cfg->flags |= CFG_DUP;
 417                       cfg1->flags |= CFG_DUP;
 418                     }
 419                   break;
 420                 default:
 421                   break;
 422                 }
 423             }
 424           break;
 425         default:
 426           break;
 427         }
 428     }
 429 
 430   /*
 431    * Now go through the list, and every time we see a kvariable, check
 432    * to see whether it also has some dependencies.  If so, then
 433    * append it to our list.  The reason we do this is that we might have
 434    * option CONFIG_FOO which is only used if CONFIG_BAR is set.  It may
 435    * turn out that in config.in that the default value for CONFIG_BAR is
 436    * set to "y", but that CONFIG_BAR is not enabled because CONFIG_XYZZY
 437    * is not set.  The current condition chain does not reflect this, but
 438    * we can fix this by searching for the tokens that this option depends
 439    * upon and cloning the conditions and merging them with the list.
 440    */
 441   for(cfg=scfg;cfg != NULL; cfg = cfg->next)
 442     {
 443       /*
 444        * Search for a token that has a condition list.
 445        */
 446       if(cfg->cond == NULL) continue;
 447       for(cnd = cfg->cond; cnd; cnd=cnd->next)
 448         {
 449           /*
 450            * Now search the condition list for a known configuration variable
 451            * that has conditions of it's own.
 452            */
 453           if(cnd->op != op_kvariable) continue;
 454           if(cnd->variable.cfg->cond == NULL) continue;
 455 
 456           if(cnd->variable.cfg->flags & CFG_DUP) continue; 
 457           /*
 458            * OK, we have some conditions to append to cfg.  Make  a clone
 459            * of the conditions,
 460            */
 461           newcond = get_token_cond_frag(cnd->variable.cfg->cond, &last);
 462 
 463           /*
 464            * Finally, we splice it into our list.
 465            */
 466           last->next = cfg->cond;
 467           cfg->cond = newcond;
 468 
 469         }
 470     }
 471 
 472   /*
 473    * There is a strong possibility that we have duplicate conditions
 474    * in here.  It would make the script more efficient and readable to
 475    * remove these.  Here is where we assume here that there are no
 476    * parenthesis in the input script.
 477    */
 478   for(cfg=scfg;cfg != NULL; cfg = cfg->next)
 479     {
 480       /*
 481        * Search for configuration options that have conditions.
 482        */
 483       if(cfg->cond == NULL) continue;
 484       for(cnd = cfg->cond; cnd; cnd=cnd->next)
 485         {
 486           /*
 487            * Search for a left parenthesis.
 488            */
 489           if(cnd->op != op_lparen) continue;
 490           for(cnd1 = cnd->next; cnd1; cnd1=cnd1->next)
 491             {
 492               /*
 493                * Search after the previous left parenthesis, and try
 494                * and find a second left parenthesis.
 495                */
 496               if(cnd1->op != op_lparen) continue;
 497 
 498               /*
 499                * Now compare the next 5 tokens to see if they are
 500                * identical.  We are looking for two chains that
 501                * are like: '(' $VARIABLE operator constant ')'.
 502                */
 503               cnd2 = cnd;
 504               cnd3 = cnd1;
 505               for(i=0; i<5; i++, cnd2=cnd2->next, cnd3=cnd3->next)
 506                 {
 507                   if(!cnd2 || !cnd3) break;
 508                   if(cnd2->op != cnd3->op) break;
 509                   if(i == 1 && (cnd2->op != op_kvariable 
 510                      || cnd2->variable.cfg != cnd3->variable.cfg) ) break;
 511                   if(i==2 && cnd2->op != op_eq && cnd2->op != op_neq) break;
 512                   if(i == 3 && cnd2->op != op_constant &&
 513                      strcmp(cnd2->variable.str, cnd3->variable.str) != 0)
 514                     break;
 515                   if(i==4 && cnd2->op != op_rparen) break;
 516                 }
 517               /*
 518                * If these match, and there is an and gluing these together,
 519                * then we can nuke the second one.
 520                */
 521               if(i==5 && ((cnd3 && cnd3->op == op_and)
 522                           ||(cnd2 && cnd2->op == op_and)))
 523                 {
 524                   /*
 525                    * We have a duplicate.  Nuke 5 ops.
 526                    */
 527                   cnd3 = cnd1;
 528                   for(i=0; i<5; i++, cnd3=cnd3->next)
 529                     {
 530                       cnd3->op = op_nuked;
 531                     }
 532                   /*
 533                    * Nuke the and that glues the conditions together.
 534                    */
 535                   if(cnd3 && cnd3->op == op_and) cnd3->op = op_nuked;
 536                   else if(cnd2 && cnd2->op == op_and) cnd2->op = op_nuked;
 537                 }
 538             }
 539         }
 540     }
 541 }

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