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. get_token_cond
  4. get_token_cond_frag
  5. 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 <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 static int invert_condition(struct condition * cnd)
     /* [previous][next][first][last][top][bottom][index][help] */
  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         case op_and:
  52           cnd->op = op_or;
  53           break;
  54         case op_or:
  55           cnd->op = op_and;
  56           break;
  57         case op_neq:
  58           cnd->op = op_eq;
  59           break;
  60         case op_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 static int free_condition(struct condition * cnd)
     /* [previous][next][first][last][top][bottom][index][help] */
  71 {
  72   struct condition * 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 struct condition * get_token_cond(struct condition ** cond, int depth)
     /* [previous][next][first][last][top][bottom][index][help] */
  91 {
  92   int i;
  93   struct condition * newcond;
  94   struct condition * tail;
  95   struct condition * new;
  96   struct condition * ocond;
  97   struct kconfig * 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 = (struct condition *) malloc(sizeof(struct condition));
 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 = (struct condition *) malloc(sizeof(struct condition));
 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 = (struct condition *) malloc(sizeof(struct condition));
 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 = (struct condition *) malloc(sizeof(struct condition));
 174           memset(new, 0, sizeof(*new));
 175           new->op = op_and;
 176           tail->next = new;
 177           tail = new;
 178         }
 179 
 180     }
 181 
 182   return newcond;
 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 struct condition * get_token_cond_frag(struct condition * cond, 
     /* [previous][next][first][last][top][bottom][index][help] */
 190                                        struct condition ** last)
 191 {
 192   int i;
 193   struct condition * newcond;
 194   struct condition * tail;
 195   struct condition * new;
 196   struct condition * ocond;
 197   struct kconfig * 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 = (struct condition *) malloc(sizeof(struct condition));
 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 = (struct condition *) malloc(sizeof(struct condition));
 222   memset(new, 0, sizeof(*new));
 223   new->op = op_and;
 224   tail->next = new;
 225   tail = new;
 226   
 227   *last = tail;
 228   return newcond;
 229 }
 230 
 231 /*
 232  * Walk through the if conditionals and maintain a chain.
 233  */
 234 int fix_conditionals(struct kconfig * scfg)
     /* [previous][next][first][last][top][bottom][index][help] */
 235 {
 236   int depth = 0;
 237   int i;
 238   struct kconfig * cfg;
 239   struct kconfig * cfg1;
 240   struct condition * conditions[25];
 241   struct condition * cnd;
 242   struct condition * cnd1;
 243   struct condition * cnd2;
 244   struct condition * cnd3;
 245   struct condition * newcond;
 246   struct condition * 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         case tok_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         case tok_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         case tok_fi:
 285           depth--;
 286           free_condition(conditions[depth]);
 287           conditions[depth] = NULL;
 288           cfg->tok = tok_nop;
 289           break;
 290         case tok_comment:
 291         case tok_menuoption:
 292         case tok_bool:
 293         case tok_tristate:
 294         case tok_dep_tristate:
 295         case tok_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         case tok_bool:
 316         case tok_tristate:
 317         case tok_dep_tristate:
 318         case tok_int:
 319           for(cfg1=cfg;cfg1 != NULL; cfg1 = cfg1->next)
 320             {
 321               switch(cfg1->tok)
 322                 {
 323                 case tok_bool:
 324                 case tok_tristate:
 325                 case tok_dep_tristate:
 326                 case tok_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                   else if(cnd2 && cnd2->op == op_and) cnd2->op = op_nuked;
 450                 }
 451             }
 452         }
 453     }
 454 }

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