patch-2.2.0-pre9 linux/scripts/tkcond.c

Next file: linux/scripts/tkgen.c
Previous file: linux/net/sunrpc/xprt.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.2.0-pre8/linux/scripts/tkcond.c linux/scripts/tkcond.c
@@ -1,544 +1,359 @@
-/* parser config.in
- *
- * Version 1.0
- * Eric Youngdale
- * 10/95
- *
- * The general idea here is that we want to parse a config.in file and 
- * from this, we generate a wish script which gives us effectively the
- * same functionality that the original config.in script provided.
- *
- * This task is split roughly into 3 parts.  The first parse is the parse
- * of the input file itself.  The second part is where we analyze the 
- * #ifdef clauses, and attach a linked list of tokens to each of the
- * menu items.  In this way, each menu item has a complete list of
- * dependencies that are used to enable/disable the options.
- * The third part is to take the configuration database we have build,
- * and build the actual wish script.
- *
- * This file contains the code to further process the conditions from
- * the "ifdef" clauses.
+/*
+ * tkcond.c
  *
- * The conditions are assumed to be one of the following formats
+ * Eric Youngdale was the original author of xconfig.
+ * Michael Elizabeth Chastain (mec@shout.net) is the current maintainer.
  *
- * simple_condition:= "$VARIABLE" == y/n/m
- * simple_condition:= "$VARIABLE != y/n/m
+ * This file takes the tokenized statement list and transforms 'if ...'
+ * statements.  For each simple statement, I find all of the 'if' statements
+ * that enclose it, and attach the aggregate conditionals of those 'if'
+ * statements to the cond list of the simple statement.
  *
- * simple_condition -a simple_condition
+ * 14 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
+ * - Steam-clean this file.  I tested this by generating kconfig.tk for
+ *   every architecture and comparing it character-for-character against
+ *   the output of the old tkparse.
  *
- * If the input condition contains '(' or ')' it would screw us up, but for now
- * this is not a problem.
+ * TO DO:
+ * - xconfig is at the end of its life cycle.  Contact <mec@shout.net> if
+ *   you are interested in working on the replacement.
  */
-#include <stdlib.h>
+
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
-#include "tkparse.h"
-
-
-/*
- * Walk a condition chain and invert it so that the logical result is
- * inverted.
- */
-static void invert_condition(struct condition * cnd)
-{
-  /*
-   * This is simple.  Just walk through the list, and invert
-   * all of the operators.
-   */
-  for(;cnd; cnd = cnd->next)
-    {
-      switch(cnd->op)
-	{
-	case op_and:
-	  cnd->op = op_or;
-	  break;
-	case op_or:
-	  /*
-	   * This is not turned into op_and - we need to keep track
-	   * of what operators were used here since we have an optimization
-	   * later on to remove duplicate conditions, and having
-	   * inverted ors in there would make it harder if we did not
-	   * distinguish an inverted or from an and we inserted because
-	   * of nested ifs.
-	   */
-	  cnd->op = op_and1;
-	  break;
-	case op_neq:
-	  cnd->op = op_eq;
-	  break;
-	case op_eq:
-	  cnd->op = op_neq;
-	  break;
-	default:
-	  break;
-	}
-    }
-}
 
-/*
- * Walk a condition chain, and free the memory associated with it.
- */
-static void free_condition(struct condition * cnd)
-{
-  struct condition * next;
-  for(;cnd; cnd = next)
-    {
-      next = cnd->next;
+#include "tkparse.h"
 
-      if( cnd->variable.str != NULL )
-	free(cnd->variable.str);
 
-      free(cnd);
-    }
-}
 
 /*
- * Walk all of the conditions, and look for choice values.  Convert
- * the tokens into something more digestible.
+ * Transform op_variable to op_kvariable.
+ *
+ * This works, but it's gross, speed-wise.  It would benefit greatly
+ * from a simple hash table that maps names to cfg.
+ *
+ * Note well: this is actually better than the loop structure xconfig
+ * has been staggering along with for three years, which performs
+ * this whole procedure inside *another* loop on active conditionals.
  */
-void fix_choice_cond(void)
+void transform_to_kvariable( struct kconfig * scfg )
 {
-  struct condition * cond;
-  struct condition * cond2;
-  struct kconfig * cfg;
-  char tmpbuf[255];
+    struct kconfig * cfg;
 
-  for(cfg = config;cfg != NULL; cfg = cfg->next)
+    for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
     {
-      if( cfg->cond == NULL )
-	{
-	  continue;
-	}
+	struct condition * cond;
 
-      for(cond = cfg->cond; cond != NULL; cond = cond->next)
+	for ( cond = cfg->cond; cond != NULL; cond = cond->next )
 	{
-	  if( cond->op != op_kvariable )
-	    continue;
-
-	  if( cond->variable.cfg->tok != tok_choice )
-	    continue;
-
-	  /*
-	   * Look ahead for what we are comparing this to.  There should
-	   * be one operator in between.
-	   */
-	  cond2 = cond->next->next;
-	  strcpy(tmpbuf, cond->variable.cfg->label);
-
-	  if( strcmp(cond2->variable.str, "y") == 0 )
+	    if ( cond->op == op_variable )
 	    {
-	      cond->variable.cfg = cond->variable.cfg->choice_label;
-	      cond2->variable.str = strdup(tmpbuf);
+		/* Here's where it gets DISGUSTING. */
+		struct kconfig * cfg1;
+
+		for ( cfg1 = scfg; cfg1 != NULL; cfg1 = cfg1->next )
+		{
+		    if ( cfg1->token == token_bool
+		    ||   cfg1->token == token_choice_item
+		    ||   cfg1->token == token_dep_tristate
+		    ||   cfg1->token == token_hex
+		    ||   cfg1->token == token_int
+		    ||   cfg1->token == token_string
+		    ||   cfg1->token == token_tristate )
+		    {
+			if ( strcmp( cond->str, cfg1->optionname ) == 0 )
+			{
+			    cond->op  = op_kvariable;
+			    cond->str = NULL;
+			    cond->cfg = cfg1;
+			    break;
+			}
+		    }
+		}
 	    }
-	  else
+
+#if 0
+	    /*
+	     * Maybe someday this will be useful, but right now it
+	     * gives a lot of false positives on files like
+	     * drivers/video/Config.in that are meant for more
+	     * than one architecture.  Turn it on if you want to play
+	     * with it though; it does work.  -- mec
+	     */
+	    if ( cond->op == op_variable )
 	    {
-	      fprintf(stderr,"tkparse can't handle this conditional\n");
-	      exit(1);
+		if ( strcmp( cond->str, "ARCH"       ) != 0
+		&&   strcmp( cond->str, "CONSTANT_Y" ) != 0
+		&&   strcmp( cond->str, "CONSTANT_M" ) != 0
+		&&   strcmp( cond->str, "CONSTANT_N" ) != 0 )
+		{
+		    fprintf( stderr, "warning: $%s used but not defined\n",
+			cond->str );
+		}
 	    }
+#endif
 	}
-
     }
 }
 
+
+
 /*
- * Walk the stack of conditions, and clone all of them with "&&" operators
- * gluing them together.  The conditions from each level of the stack
- * are wrapped in parenthesis so as to guarantee that the results
- * are logically correct.
+ * Make a new condition chain by joining the current condition stack with
+ * the "&&" operator for glue.
  */
-struct condition * get_token_cond(struct condition ** cond, int depth)
+struct condition * join_condition_stack( struct condition * conditions [],
+    int depth )
 {
-  int i;
-  struct condition * newcond;
-  struct condition * tail;
-  struct condition * new;
-  struct condition * ocond;
-  struct kconfig * cfg;
+    struct condition * cond_list;
+    struct condition * cond_last;
+    int i;
 
-  newcond = tail = NULL;
-  for(i=0; i<depth; i++, cond++)
+    cond_list = cond_last = NULL;
+    for ( i = 0; i < depth; i++ )
     {
-      /*
-       * First insert the left parenthesis
-       */
-      new = (struct condition *) malloc(sizeof(struct condition));
-      memset(new, 0, sizeof(*new));
-      new->op = op_lparen;
-      if( tail == NULL )
-	{
-	  newcond = tail = new;
-	}
-      else
-	{
-	  tail->next = new;
-	  tail = new;
+	struct condition * cond;
+	struct condition * cnew;
+
+	/* add a '(' */
+	cnew = malloc( sizeof(*cnew) );
+	memset( cnew, 0, sizeof(*cnew) );
+	cnew->op = op_lparen;
+	if ( cond_last == NULL )
+	    { cond_list = cond_last = cnew; }
+	else
+	    { cond_last->next = cnew; cond_last = cnew; }
+
+	/* duplicate the chain */
+	for ( cond = conditions [i]; cond != NULL; cond = cond->next )
+	{
+	    cnew            = malloc( sizeof(*cnew) );
+	    cnew->next      = NULL;
+	    cnew->op        = cond->op;
+	    cnew->str       = cond->str ? strdup( cond->str ) : NULL;
+	    cnew->cfg       = cond->cfg;
+	    cond_last->next = cnew;
+	    cond_last       = cnew;
+	}
+
+	/* add a ')' */
+	cnew = malloc( sizeof(*cnew) );
+	memset( cnew, 0, sizeof(*cnew) );
+	cnew->op = op_rparen;
+	cond_last->next = cnew;
+	cond_last = cnew;
+
+	/* if i have another condition, add an '&&' operator */
+	if ( i < depth - 1 )
+	{
+	    cnew = malloc( sizeof(*cnew) );
+	    memset( cnew, 0, sizeof(*cnew) );
+	    cnew->op = op_and;
+	    cond_last->next = cnew;
+	    cond_last = cnew;
 	}
+    }
 
-      /*
-       * Now duplicate the chain.
-       */
-      ocond = *cond;
-      for(;ocond != NULL; ocond = ocond->next)
+    /*
+     * Remove duplicate conditions.
+     */
+    {
+	struct condition *cond1, *cond1b, *cond1c, *cond1d, *cond1e, *cond1f;
+
+	for ( cond1 = cond_list; cond1 != NULL; cond1 = cond1->next )
 	{
-	  new = (struct condition *) malloc(sizeof(struct condition));
-	  memset(new, 0, sizeof(*new));
-	  new->op = ocond->op;
-	  if( ocond->variable.str != NULL )
+	    if ( cond1->op == op_lparen )
 	    {
-	      if( ocond->op == op_variable )
+		cond1b = cond1 ->next; if ( cond1b == NULL ) break;
+		cond1c = cond1b->next; if ( cond1c == NULL ) break;
+		cond1d = cond1c->next; if ( cond1d == NULL ) break;
+		cond1e = cond1d->next; if ( cond1e == NULL ) break;
+		cond1f = cond1e->next; if ( cond1f == NULL ) break;
+
+		if ( cond1b->op == op_kvariable
+		&& ( cond1c->op == op_eq || cond1c->op == op_neq )
+		&&   cond1d->op == op_constant 
+		&&   cond1e->op == op_rparen )
 		{
-		  /*
-		   * Search for structure to insert here.
-		   */
-		  for(cfg = config;cfg != NULL; cfg = cfg->next)
+		    struct condition *cond2, *cond2b, *cond2c, *cond2d, *cond2e, *cond2f;
+
+		    for ( cond2 = cond1f->next; cond2 != NULL; cond2 = cond2->next )
 		    {
-		      if( cfg->tok != tok_bool
-		         && cfg->tok != tok_int
-		         && cfg->tok != tok_hex
-		         && cfg->tok != tok_string
-			 && cfg->tok != tok_tristate 
-			 && cfg->tok != tok_choice
-			 && cfg->tok != tok_dep_tristate)
+			if ( cond2->op == op_lparen )
 			{
-			  continue;
+			    cond2b = cond2 ->next; if ( cond2b == NULL ) break;
+			    cond2c = cond2b->next; if ( cond2c == NULL ) break;
+			    cond2d = cond2c->next; if ( cond2d == NULL ) break;
+			    cond2e = cond2d->next; if ( cond2e == NULL ) break;
+			    cond2f = cond2e->next;
+
+			    /* look for match */
+			    if ( cond2b->op == op_kvariable
+			    &&   cond2b->cfg == cond1b->cfg
+			    &&   cond2c->op == cond1c->op
+			    &&   cond2d->op == op_constant
+			    &&   strcmp( cond2d->str, cond1d->str ) == 0
+			    &&   cond2e->op == op_rparen )
+			    {
+				/* one of these must be followed by && */
+				if ( cond1f->op == op_and
+				|| ( cond2f != NULL && cond2f->op == op_and ) )
+				{
+				    /* nuke the first duplicate */
+				    cond1 ->op = op_nuked;
+				    cond1b->op = op_nuked;
+				    cond1c->op = op_nuked;
+				    cond1d->op = op_nuked;
+				    cond1e->op = op_nuked;
+				    if ( cond1f->op == op_and )
+					cond1f->op = op_nuked;
+				    else
+					cond2f->op = op_nuked;
+				}
+			    }
 			}
-		      if( strcmp(cfg->optionname, ocond->variable.str) == 0)
-			{
-			  new->variable.cfg = cfg;
-			  new->op = op_kvariable;
-			  break;
-			}
-		    }
-		  if( cfg == NULL )
-		    {
-		      new->variable.str = strdup(ocond->variable.str);
 		    }
 		}
-	      else
-		{
-		  new->variable.str = strdup(ocond->variable.str);
-		}
 	    }
-	  tail->next = new;
-	  tail = new;
 	}
-
-      /*
-       * Next insert the left parenthesis
-       */
-      new = (struct condition *) malloc(sizeof(struct condition));
-      memset(new, 0, sizeof(*new));
-      new->op = op_rparen;
-      tail->next = new;
-      tail = new;
-
-      /*
-       * Insert an and operator, if we have another condition.
-       */
-      if( i < depth - 1 )
-	{
-	  new = (struct condition *) malloc(sizeof(struct condition));
-	  memset(new, 0, sizeof(*new));
-	  new->op = op_and;
-	  tail->next = new;
-	  tail = new;
-	}
-
     }
 
-  return newcond;
+    return cond_list;
 }
 
-/*
- * Walk a single chain of conditions and clone it.  These are assumed
- * to be created/processed by  get_token_cond in a previous pass.
- */
-struct condition * get_token_cond_frag(struct condition * cond, 
-				       struct condition ** last)
-{
-  struct condition * newcond;
-  struct condition * tail;
-  struct condition * new;
-  struct condition * ocond;
-
-  newcond = tail = NULL;
-
-  /*
-   * Now duplicate the chain.
-   */
-  for(ocond = cond;ocond != NULL; ocond = ocond->next)
-    {
-      new = (struct condition *) malloc(sizeof(struct condition));
-      memset(new, 0, sizeof(*new));
-      new->op = ocond->op;
-      new->variable.cfg = ocond->variable.cfg;
-      if( tail == NULL )
-	{
-	  newcond = tail = new;
-	}
-      else
-	{
-	  tail->next = new;
-	  tail = new;
-	}
-    }
 
-  new = (struct condition *) malloc(sizeof(struct condition));
-  memset(new, 0, sizeof(*new));
-  new->op = op_and;
-  tail->next = new;
-  tail = new;
-  
-  *last = tail;
-  return newcond;
-}
 
 /*
- * Walk through the if conditionals and maintain a chain.
+ * This is the main transformation function.
  */
-void fix_conditionals(struct kconfig * scfg)
+void fix_conditionals( struct kconfig * scfg )
 {
-  int depth = 0;
-  int i;
-  struct kconfig * cfg;
-  struct kconfig * cfg1;
-  struct condition * conditions[25];
-  struct condition * cnd;
-  struct condition * cnd1;
-  struct condition * cnd2;
-  struct condition * cnd3;
-  struct condition * newcond;
-  struct condition * last;
-
-  /*
-   * Start by walking the chain.  Every time we see an ifdef, push
-   * the condition chain on the stack.  When we see an "else", we invert
-   * the condition at the top of the stack, and when we see an "endif"
-   * we free all of the memory for the condition at the top of the stack
-   * and remove the condition from the top of the stack.
-   *
-   * For any other type of token (i.e. a bool), we clone a new condition chain
-   * by anding together all of the conditions that are currently stored on
-   * the stack.  In this way, we have a correct representation of whatever
-   * conditions govern the usage of each option.
-   */
-  memset(conditions, 0, sizeof(conditions));
-  for(cfg=scfg;cfg != NULL; cfg = cfg->next)
-    {
-      switch(cfg->tok)
-	{
-	case tok_if:
-	  /*
-	   * Push this condition on the stack, and nuke the token
-	   * representing the ifdef, since we no longer need it.
-	   */
-	  conditions[depth] = cfg->cond;
-	  depth++;
-	  cfg->tok = tok_nop;
-	  cfg->cond =  NULL;
-	  break;
-	case tok_else:
-	  /*
-	   * For an else, we just invert the condition at the top of
-	   * the stack.  This is done in place with no reallocation
-	   * of memory taking place.
-	   */
-	  invert_condition(conditions[depth-1]);
-	  cfg->tok = tok_nop;
-	  break;
-	case tok_fi:
-	  depth--;
-	  free_condition(conditions[depth]);
-	  conditions[depth] = NULL;
-	  cfg->tok = tok_nop;
-	  break;
-	case tok_comment:
-	case tok_define:
-	case tok_menuoption:
-	case tok_bool:
-	case tok_tristate:
-	case tok_int:
-	case tok_hex:
-	case tok_string:
-	case tok_choice:
-	  /*
-	   * We need to duplicate the chain of conditions and attach them to
-	   * this token.
-	   */
-	  cfg->cond = get_token_cond(&conditions[0], depth);
-	  break;
-	case tok_dep_tristate:
-	  /*
-	   * Same as tok_tristate et al except we have a temporary
-	   * conditional. (Sort of a hybrid tok_if, tok_tristate, tok_fi
-	   * option)
-	   */
-	  conditions[depth] = cfg->cond;
-	  depth++;
-	  cfg->cond = get_token_cond(&conditions[0], depth);
-	  depth--;
-	  free_condition(conditions[depth]);
-	  conditions[depth] = NULL;
-	default:
-	  break;
-	}
-    }
+    struct kconfig * cfg;
 
-  /*
-   * Fix any conditions involving the "choice" operator.
-   */
-  fix_choice_cond();
-
-  /*
-   * Walk through and see if there are multiple options that control the
-   * same kvariable.  If there are we need to treat them a little bit
-   * special.
-   */
-  for(cfg=scfg;cfg != NULL; cfg = cfg->next)
+    /*
+     * Transform op_variable to op_kvariable.
+     */
+    transform_to_kvariable( scfg );
+
+    /*
+     * Transform conditions that use variables from "choice" statements.
+     * Choice values appear to the user as a collection of booleans, and the
+     * script can test the individual booleans.  But internally, all I have is
+     * the N-way value of an unnamed temporary for the whole statement.  So I
+     * have to tranform '"$CONFIG_M386" != "y"'
+     * into '"$tmpvar_N" != "CONFIG_M386"'.
+     */
+    for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
     {
-      switch(cfg->tok)
+	struct condition * cond;
+
+	for ( cond = cfg->cond; cond != NULL; cond = cond->next )
 	{
-	case tok_bool:
-	case tok_tristate:
-	case tok_dep_tristate:
-	case tok_int:
-	case tok_hex:
-	case tok_string:
-	  for(cfg1=cfg;cfg1 != NULL; cfg1 = cfg1->next)
+	    if ( cond->op == op_kvariable && cond->cfg->token == token_choice_item )
 	    {
-	      switch(cfg1->tok)
+		/*
+		 * Look two more tokens down for the comparison token.
+		 * It has to be "y" for this trick to work.
+		 *
+		 * If you get this error, don't even think about relaxing the
+		 * strcmp test.  You will produce incorrect TK code.  Instead,
+		 * look for the place in your Config.in script where you are
+		 * comparing a 'choice' variable to a value other than 'y',
+		 * and rewrite the comparison to be '= "y"' or '!= "y"'.
+		 */
+		struct condition * cond2 = cond->next->next;
+		const char * label;
+
+		if ( strcmp( cond2->str, "y" ) != 0 )
 		{
-		case tok_define:
-		case tok_bool:
-		case tok_tristate:
-		case tok_dep_tristate:
-		case tok_int:
-		case tok_hex:
-		case tok_string:
-		  if( strcmp(cfg->optionname, cfg1->optionname) == 0)
-		    {
-		      cfg->flags |= CFG_DUP;
-		      cfg1->flags |= CFG_DUP;
-		    }
-		  break;
-		default:
-		  break;
+		    fprintf( stderr, "tkparse choked in fix_choice_cond\n" );
+		    exit( 1 );
 		}
+
+		label = cond->cfg->label;
+		cond->cfg  = cond->cfg->cfg_parent;
+		cond2->str = strdup( label );
 	    }
-	  break;
-	default:
-	  break;
 	}
     }
 
-  /*
-   * Now go through the list, and every time we see a kvariable, check
-   * to see whether it also has some dependencies.  If so, then
-   * append it to our list.  The reason we do this is that we might have
-   * option CONFIG_FOO which is only used if CONFIG_BAR is set.  It may
-   * turn out that in config.in that the default value for CONFIG_BAR is
-   * set to "y", but that CONFIG_BAR is not enabled because CONFIG_XYZZY
-   * is not set.  The current condition chain does not reflect this, but
-   * we can fix this by searching for the tokens that this option depends
-   * upon and cloning the conditions and merging them with the list.
-   */
-  for(cfg=scfg;cfg != NULL; cfg = cfg->next)
+    /*
+     * Walk the statement list, maintaining a stack of current conditions.
+     *   token_if      push its condition onto the stack.
+     *   token_else    invert the condition on the top of the stack.
+     *   token_endif   pop the stack.
+     *
+     * For a simple statement, create a condition chain by joining together
+     * all of the conditions on the stack.
+     */
     {
-      /*
-       * Search for a token that has a condition list.
-       */
-      if(cfg->cond == NULL) continue;
-      for(cnd = cfg->cond; cnd; cnd=cnd->next)
-	{
-	  /*
-	   * Now search the condition list for a known configuration variable
-	   * that has conditions of its own.
-	   */
-	  if(cnd->op != op_kvariable) continue;
-	  if(cnd->variable.cfg->cond == NULL) continue;
-
-	  if(cnd->variable.cfg->flags & CFG_DUP) continue; 
-	  /*
-	   * OK, we have some conditions to append to cfg.  Make  a clone
-	   * of the conditions,
-	   */
-	  newcond = get_token_cond_frag(cnd->variable.cfg->cond, &last);
-
-	  /*
-	   * Finally, we splice it into our list.
-	   */
-	  last->next = cfg->cond;
-	  cfg->cond = newcond;
+	struct condition * cond_stack [32];
+	int depth = 0;
 
-	}
-    }
-
-  /*
-   * There is a strong possibility that we have duplicate conditions
-   * in here.  It would make the script more efficient and readable to
-   * remove these.  Here is where we assume here that there are no
-   * parenthesis in the input script.
-   */
-  for(cfg=scfg;cfg != NULL; cfg = cfg->next)
-    {
-      /*
-       * Search for configuration options that have conditions.
-       */
-      if(cfg->cond == NULL) continue;
-      for(cnd = cfg->cond; cnd; cnd=cnd->next)
+	for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
 	{
-	  /*
-	   * Search for a left parenthesis.
-	   */
-	  if(cnd->op != op_lparen) continue;
-	  for(cnd1 = cnd->next; cnd1; cnd1=cnd1->next)
+	    switch ( cfg->token )
 	    {
-	      /*
-	       * Search after the previous left parenthesis, and try
-	       * and find a second left parenthesis.
-	       */
-	      if(cnd1->op != op_lparen) continue;
-
-	      /*
-	       * Now compare the next 5 tokens to see if they are
-	       * identical.  We are looking for two chains that
-	       * are like: '(' $VARIABLE operator constant ')'.
-	       */
-	      cnd2 = cnd;
-	      cnd3 = cnd1;
-	      for(i=0; i<5; i++, cnd2=cnd2->next, cnd3=cnd3->next)
-		{
-		  if(!cnd2 || !cnd3) break;
-		  if(cnd2->op != cnd3->op) break;
-		  if(i == 1 && (cnd2->op != op_kvariable 
-		     || cnd2->variable.cfg != cnd3->variable.cfg) ) break;
-		  if(i==2 && cnd2->op != op_eq && cnd2->op != op_neq) break;
-		  if(i == 3 && cnd2->op != op_constant &&
-		     strcmp(cnd2->variable.str, cnd3->variable.str) != 0)
-		    break;
-		  if(i==4 && cnd2->op != op_rparen) break;
-		}
-	      /*
-	       * If these match, and there is an and gluing these together,
-	       * then we can nuke the second one.
-	       */
-	      if(i==5 && ((cnd3 && cnd3->op == op_and)
-			  ||(cnd2 && cnd2->op == op_and)))
+	    default:
+		break;
+
+	    case token_if:
+		cond_stack [depth++] = cfg->cond;
+		cfg->cond = NULL;
+		break;
+
+	    case token_else:
 		{
-		  /*
-		   * We have a duplicate.  Nuke 5 ops.
-		   */
-		  cnd3 = cnd1;
-		  for(i=0; i<5; i++, cnd3=cnd3->next)
+		    /*
+		     * Invert the condition chain.
+		     *
+		     * Be careful to transfrom op_or to op_and1, not op_and.
+		     * I will need this later in the code that removes
+		     * duplicate conditions.
+		     */
+		    struct condition * cond;
+
+		    for ( cond  = cond_stack [depth-1];
+			  cond != NULL;
+			  cond  = cond->next )
 		    {
-		      cnd3->op = op_nuked;
+			switch( cond->op )
+			{
+			default:     break;
+			case op_and: cond->op = op_or;   break;
+			case op_or:  cond->op = op_and1; break;
+			case op_neq: cond->op = op_eq;   break;
+			case op_eq:  cond->op = op_neq;  break;
+			}
 		    }
-		  /*
-		   * Nuke the and that glues the conditions together.
-		   */
-		  if(cnd3 && cnd3->op == op_and) cnd3->op = op_nuked;
-		  else if(cnd2 && cnd2->op == op_and) cnd2->op = op_nuked;
 		}
+		break;
+
+	    case token_fi:
+		--depth;
+		break;
+
+	    case token_bool:
+	    case token_choice_item:
+	    case token_comment:
+	    case token_define_bool:
+	    case token_hex:
+	    case token_int:
+	    case token_mainmenu_option:
+	    case token_string:
+	    case token_tristate:
+		cfg->cond = join_condition_stack( cond_stack, depth );
+		break;
+
+	    case token_dep_tristate:
+		/*
+		 * Same as the other simple statements, plus an additional
+		 * condition for the dependency.
+		 */
+		cond_stack [depth] = cfg->cond;
+		cfg->cond = join_condition_stack( cond_stack, depth+1 );
+		break;
 	    }
 	}
     }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov