patch-2.2.16 linux/scripts/tkcond.c
Next file: linux/scripts/tkgen.c
Previous file: linux/scripts/tail.tk
Back to the patch index
Back to the overall index
- Lines: 631
- Date:
Wed Jun 7 14:26:44 2000
- Orig file:
v2.2.15/linux/scripts/tkcond.c
- Orig date:
Wed Jan 20 10:05:49 1999
diff -urN v2.2.15/linux/scripts/tkcond.c linux/scripts/tkcond.c
@@ -14,6 +14,12 @@
* every architecture and comparing it character-for-character against
* the output of the old tkparse.
*
+ * 07 July 1999, Andrzej M. Krzysztofowicz <ankry@mif.pg.gda.pl>
+ * - kvariables removed; all variables are stored in a single table now
+ * - some elimination of options non-valid for current architecture
+ * implemented.
+ * - negation (!) eliminated from conditions
+ *
* TO DO:
* - xconfig is at the end of its life cycle. Contact <mec@shout.net> if
* you are interested in working on the replacement.
@@ -28,73 +34,89 @@
/*
- * 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.
+ * Mark variables which are defined anywhere.
*/
-void transform_to_kvariable( struct kconfig * scfg )
+static void mark_variables( struct kconfig * scfg )
{
struct kconfig * cfg;
+ int i;
+ for ( i = 1; i <= max_varnum; i++ )
+ vartable[i].defined = 0;
for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
{
- struct condition * cond;
-
- for ( cond = cfg->cond; cond != NULL; cond = cond->next )
+ if ( cfg->token == token_bool
+ || cfg->token == token_choice_item
+ || cfg->token == token_define_bool
+ || cfg->token == token_define_hex
+ || cfg->token == token_define_int
+ || cfg->token == token_define_string
+ || cfg->token == token_define_tristate
+ || cfg->token == token_dep_bool
+ || cfg->token == token_dep_mbool
+ || cfg->token == token_dep_tristate
+ || cfg->token == token_hex
+ || cfg->token == token_int
+ || cfg->token == token_string
+ || cfg->token == token_tristate
+ || cfg->token == token_unset )
{
- if ( cond->op == op_variable )
+ if ( cfg->nameindex > 0 ) /* paranoid */
{
- /* Here's where it gets DISGUSTING. */
- struct kconfig * cfg1;
+ vartable[cfg->nameindex].defined = 1;
+ }
+ }
+ }
+}
+
+
+
+static void free_cond( struct condition *cond )
+{
+ struct condition *tmp, *tmp1;
+ for ( tmp = cond; tmp; tmp = tmp1 )
+ {
+ tmp1 = tmp->next;
+ free( (void*)tmp );
+ }
+}
+
- for ( cfg1 = scfg; cfg1 != NULL; cfg1 = cfg1->next )
+
+/*
+ * Remove the bang operator from a condition to avoid priority problems.
+ * "!" has different priorities as "test" command argument and in
+ * a tk script.
+ */
+static struct condition * remove_bang( struct condition * condition )
+{
+ struct condition * conda, * condb, * prev = NULL;
+
+ for ( conda = condition; conda; conda = conda->next )
+ {
+ if ( conda->op == op_bang && conda->next &&
+ ( condb = conda->next->next ) )
+ {
+ if ( condb->op == op_eq || condb->op == op_neq )
+ {
+ condb->op = (condb->op == op_eq) ? op_neq : op_eq;
+ conda->op = op_nuked;
+ if ( prev )
{
- 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;
- }
- }
+ prev->next = conda->next;
}
- }
-
-#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 )
- {
- if ( strcmp( cond->str, "ARCH" ) != 0
- && strcmp( cond->str, "CONSTANT_Y" ) != 0
- && strcmp( cond->str, "CONSTANT_M" ) != 0
- && strcmp( cond->str, "CONSTANT_N" ) != 0 )
+ else
{
- fprintf( stderr, "warning: $%s used but not defined\n",
- cond->str );
+ condition = conda->next;
}
+ conda->next = NULL;
+ free_cond( conda );
+ conda = condb;
}
-#endif
}
+ prev = conda;
}
+ return condition;
}
@@ -103,27 +125,65 @@
* Make a new condition chain by joining the current condition stack with
* the "&&" operator for glue.
*/
-struct condition * join_condition_stack( struct condition * conditions [],
+static struct condition * join_condition_stack( struct condition * conditions [],
int depth )
{
struct condition * cond_list;
struct condition * cond_last;
- int i;
+ int i, is_first = 1;
cond_list = cond_last = NULL;
+
+ for ( i = 0; i < depth; i++ )
+ {
+ if ( conditions[i]->op == op_false )
+ {
+ struct condition * cnew;
+
+ /* It is always false condition */
+ cnew = malloc( sizeof(*cnew) );
+ memset( cnew, 0, sizeof(*cnew) );
+ cnew->op = op_false;
+ cond_list = cond_last = cnew;
+ goto join_done;
+ }
+ }
for ( i = 0; i < depth; i++ )
{
struct condition * cond;
struct condition * cnew;
+ int add_paren;
+
+ /* omit always true conditions */
+ if ( conditions[i]->op == op_true )
+ continue;
+
+ /* if i have another condition, add an '&&' operator */
+ if ( !is_first )
+ {
+ cnew = malloc( sizeof(*cnew) );
+ memset( cnew, 0, sizeof(*cnew) );
+ cnew->op = op_and;
+ cond_last->next = cnew;
+ cond_last = 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; }
+ if ( conditions[i]->op != op_lparen )
+ {
+ /* add a '(' */
+ add_paren = 1;
+ 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; }
+ }
else
- { cond_last->next = cnew; cond_last = cnew; }
+ {
+ add_paren = 0;
+ }
/* duplicate the chain */
for ( cond = conditions [i]; cond != NULL; cond = cond->next )
@@ -132,27 +192,23 @@
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;
+ cnew->nameindex = cond->nameindex;
+ if ( cond_last == NULL )
+ { cond_list = cond_last = cnew; }
+ else
+ { 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 )
+ if ( add_paren )
{
+ /* add a ')' */
cnew = malloc( sizeof(*cnew) );
memset( cnew, 0, sizeof(*cnew) );
- cnew->op = op_and;
+ cnew->op = op_rparen;
cond_last->next = cnew;
cond_last = cnew;
}
+ is_first = 0;
}
/*
@@ -171,7 +227,7 @@
cond1e = cond1d->next; if ( cond1e == NULL ) break;
cond1f = cond1e->next; if ( cond1f == NULL ) break;
- if ( cond1b->op == op_kvariable
+ if ( cond1b->op == op_variable
&& ( cond1c->op == op_eq || cond1c->op == op_neq )
&& cond1d->op == op_constant
&& cond1e->op == op_rparen )
@@ -189,8 +245,8 @@
cond2f = cond2e->next;
/* look for match */
- if ( cond2b->op == op_kvariable
- && cond2b->cfg == cond1b->cfg
+ if ( cond2b->op == op_variable
+ && cond2b->nameindex == cond1b->nameindex
&& cond2c->op == cond1c->op
&& cond2d->op == op_constant
&& strcmp( cond2d->str, cond1d->str ) == 0
@@ -219,64 +275,159 @@
}
}
+join_done:
return cond_list;
}
+static char * current_arch = NULL;
+
/*
- * This is the main transformation function.
+ * Eliminating conditions with ARCH = <not current>.
*/
-void fix_conditionals( struct kconfig * scfg )
+static struct condition *eliminate_other_arch( struct condition *list )
{
- struct kconfig * cfg;
-
- /*
- * 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 )
+ struct condition *cond1a = list, *cond1b = NULL, *cond1c = NULL, *cond1d = NULL;
+ if ( current_arch == NULL )
+ current_arch = getenv( "ARCH" );
+ if ( current_arch == NULL )
{
- struct condition * cond;
-
- for ( cond = cfg->cond; cond != NULL; cond = cond->next )
+ fprintf( stderr, "error: ARCH undefined\n" );
+ exit( 1 );
+ }
+ if ( cond1a->op == op_variable
+ && ! strcmp( vartable[cond1a->nameindex].name, "ARCH" ) )
+ {
+ cond1b = cond1a->next; if ( cond1b == NULL ) goto done;
+ cond1c = cond1b->next; if ( cond1c == NULL ) goto done;
+ cond1d = cond1c->next;
+ if ( cond1c->op == op_constant && cond1d == NULL )
{
- if ( cond->op == op_kvariable && cond->cfg->token == token_choice_item )
+ if ( (cond1b->op == op_eq && strcmp( cond1c->str, current_arch ))
+ || (cond1b->op == op_neq && ! strcmp( cond1c->str, current_arch )) )
{
- /*
- * 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 )
+ /* This is for another architecture */
+ cond1a->op = op_false;
+ cond1a->next = NULL;
+ free_cond( cond1b );
+ return cond1a;
+ }
+ else if ( (cond1b->op == op_neq && strcmp( cond1c->str, current_arch ))
+ || (cond1b->op == op_eq && ! strcmp( cond1c->str, current_arch )) )
+ {
+ /* This is for current architecture */
+ cond1a->op = op_true;
+ cond1a->next = NULL;
+ free_cond( cond1b );
+ return cond1a;
+ }
+ }
+ else if ( cond1c->op == op_constant && cond1d->op == op_or )
+ {
+ if ( (cond1b->op == op_eq && strcmp( cond1c->str, current_arch ))
+ || (cond1b->op == op_neq && ! strcmp( cond1c->str, current_arch )) )
+ {
+ /* This is for another architecture */
+ cond1b = cond1d->next;
+ cond1d->next = NULL;
+ free_cond( cond1a );
+ return eliminate_other_arch( cond1b );
+ }
+ else if ( (cond1b->op == op_neq && strcmp( cond1c->str, current_arch ))
+ || (cond1b->op == op_eq && ! strcmp( cond1c->str, current_arch )) )
+ {
+ /* This is for current architecture */
+ cond1a->op = op_true;
+ cond1a->next = NULL;
+ free_cond( cond1b );
+ return cond1a;
+ }
+ }
+ else if ( cond1c->op == op_constant && cond1d->op == op_and )
+ {
+ if ( (cond1b->op == op_eq && strcmp( cond1c->str, current_arch ))
+ || (cond1b->op == op_neq && ! strcmp( cond1c->str, current_arch )) )
+ {
+ /* This is for another architecture */
+ int l_par = 0;
+
+ for ( cond1c = cond1d->next; cond1c; cond1c = cond1c->next )
{
- fprintf( stderr, "tkparse choked in fix_choice_cond\n" );
- exit( 1 );
+ if ( cond1c->op == op_lparen )
+ l_par++;
+ else if ( cond1c->op == op_rparen )
+ l_par--;
+ else if ( cond1c->op == op_or && l_par == 0 )
+ /* Expression too complex - don't touch */
+ return cond1a;
+ else if ( l_par < 0 )
+ {
+ fprintf( stderr, "incorrect condition: programming error ?\n" );
+ exit( 1 );
+ }
}
+ cond1a->op = op_false;
+ cond1a->next = NULL;
+ free_cond( cond1b );
+ return cond1a;
+ }
+ else if ( (cond1b->op == op_neq && strcmp( cond1c->str, current_arch ))
+ || (cond1b->op == op_eq && ! strcmp( cond1c->str, current_arch )) )
+ {
+ /* This is for current architecture */
+ cond1b = cond1d->next;
+ cond1d->next = NULL;
+ free_cond( cond1a );
+ return eliminate_other_arch( cond1b );
+ }
+ }
+ }
+ if ( cond1a->op == op_variable && ! vartable[cond1a->nameindex].defined )
+ {
+ cond1b = cond1a->next; if ( cond1b == NULL ) goto done;
+ cond1c = cond1b->next; if ( cond1c == NULL ) goto done;
+ cond1d = cond1c->next;
- label = cond->cfg->label;
- cond->cfg = cond->cfg->cfg_parent;
- cond2->str = strdup( label );
+ if ( cond1c->op == op_constant
+ && ( cond1d == NULL || cond1d->op == op_and ) ) /*???*/
+ {
+ if ( cond1b->op == op_eq && strcmp( cond1c->str, "" ) )
+ {
+ cond1a->op = op_false;
+ cond1a->next = NULL;
+ free_cond( cond1b );
+ return cond1a;
+ }
+ }
+ else if ( cond1c->op == op_constant && cond1d->op == op_or )
+ {
+ if ( cond1b->op == op_eq && strcmp( cond1c->str, "" ) )
+ {
+ cond1b = cond1d->next;
+ cond1d->next = NULL;
+ free_cond( cond1a );
+ return eliminate_other_arch( cond1b );
}
}
}
+done:
+ return list;
+}
+
+
+
+/*
+ * This is the main transformation function.
+ */
+void fix_conditionals( struct kconfig * scfg )
+{
+ struct kconfig * cfg;
+
+ /*
+ * Transform op_variable to op_kvariable.
+ */
+ mark_variables( scfg );
/*
* Walk the statement list, maintaining a stack of current conditions.
@@ -290,16 +441,19 @@
{
struct condition * cond_stack [32];
int depth = 0;
+ struct kconfig * prev = NULL;
for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
{
+ int good = 1;
switch ( cfg->token )
{
default:
break;
case token_if:
- cond_stack [depth++] = cfg->cond;
+ cond_stack [depth++] =
+ remove_bang( eliminate_other_arch( cfg->cond ) );
cfg->cond = NULL;
break;
@@ -325,6 +479,8 @@
case op_or: cond->op = op_and1; break;
case op_neq: cond->op = op_eq; break;
case op_eq: cond->op = op_neq; break;
+ case op_true: cond->op = op_false;break;
+ case op_false:cond->op = op_true; break;
}
}
}
@@ -336,25 +492,111 @@
case token_bool:
case token_choice_item:
+ case token_choice_header:
case token_comment:
case token_define_bool:
+ case token_define_hex:
+ case token_define_int:
+ case token_define_string:
+ case token_define_tristate:
+ case token_endmenu:
case token_hex:
case token_int:
case token_mainmenu_option:
case token_string:
case token_tristate:
+ case token_unset:
cfg->cond = join_condition_stack( cond_stack, depth );
+ if ( cfg->cond && cfg->cond->op == op_false )
+ {
+ good = 0;
+ if ( prev )
+ prev->next = cfg->next;
+ else
+ scfg = cfg->next;
+ }
break;
+ case token_dep_bool:
+ case token_dep_mbool:
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 );
+ if ( cfg->cond )
+ {
+ cond_stack [depth] = eliminate_other_arch( cfg->cond );
+ cfg->cond = join_condition_stack( cond_stack, depth+1 );
+ }
+ else
+ {
+ cfg->cond = join_condition_stack( cond_stack, depth );
+ }
+ if ( cfg->cond && cfg->cond->op == op_false )
+ {
+ good = 0;
+ if ( prev )
+ prev->next = cfg->next;
+ else
+ scfg = cfg->next;
+ }
break;
}
+ if ( good )
+ prev = cfg;
}
}
}
+
+
+
+#if 0
+void dump_condition( struct condition *list )
+{
+ struct condition *tmp;
+ for ( tmp = list; tmp; tmp = tmp->next )
+ {
+ switch (tmp->op)
+ {
+ default:
+ break;
+ case op_variable:
+ printf( " %s", vartable[tmp->nameindex].name );
+ break;
+ case op_constant:
+ printf( " %s", tmp->str );
+ break;
+ case op_eq:
+ printf( " =" );
+ break;
+ case op_bang:
+ printf( " !" );
+ break;
+ case op_neq:
+ printf( " !=" );
+ break;
+ case op_and:
+ case op_and1:
+ printf( " -a" );
+ break;
+ case op_or:
+ printf( " -o" );
+ break;
+ case op_true:
+ printf( " TRUE" );
+ break;
+ case op_false:
+ printf( " FALSE" );
+ break;
+ case op_lparen:
+ printf( " (" );
+ break;
+ case op_rparen:
+ printf( " )" );
+ break;
+ }
+ }
+ printf( "\n" );
+}
+#endif
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)