patch-1.3.35 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: 416
- Date:
Sun Oct 15 18:57:01 1995
- Orig file:
v1.3.34/linux/scripts/tkcond.c
- Orig date:
Thu Jan 1 02:00:00 1970
diff -u --recursive --new-file v1.3.34/linux/scripts/tkcond.c linux/scripts/tkcond.c
@@ -0,0 +1,415 @@
+/* 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.
+ *
+ * The conditions are assumed to be one of the folowing formats
+ *
+ * simple_condition:= "$VARIABLE" == y/n/m
+ * simple_condition:= "$VARIABLE != y/n/m
+ *
+ * simple_condition -a simple_condition
+ *
+ * If the input condition contains '(' or ')' it would screw us up, but for now
+ * this is not a problem.
+ */
+#include <stdio.h>
+#include <string.h>
+#include "tkparse.h"
+
+
+/*
+ * Walk a condition chain and invert it so that the logical result is
+ * inverted.
+ */
+static int 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:
+ cnd->op = op_and;
+ break;
+ case op_neq:
+ cnd->op = op_eq;
+ break;
+ case op_eq:
+ cnd->op = op_neq;
+ break;
+ }
+ }
+}
+
+/*
+ * Walk a condition chain, and free the memory associated with it.
+ */
+static int free_condition(struct condition * cnd)
+{
+ struct condition * next;
+ for(;cnd; cnd = next)
+ {
+ next = cnd->next;
+
+ if( cnd->variable.str != NULL )
+ free(cnd->variable.str);
+
+ free(cnd);
+ }
+}
+
+/*
+ * 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.
+ */
+struct condition * get_token_cond(struct condition ** cond, int depth)
+{
+ int i;
+ struct condition * newcond;
+ struct condition * tail;
+ struct condition * new;
+ struct condition * ocond;
+ struct kconfig * cfg;
+
+ newcond = tail = NULL;
+ for(i=0; i<depth; i++, cond++)
+ {
+ /*
+ * 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;
+ }
+
+ /*
+ * Now duplicate the chain.
+ */
+ ocond = *cond;
+ for(;ocond != NULL; ocond = ocond->next)
+ {
+ new = (struct condition *) malloc(sizeof(struct condition));
+ memset(new, 0, sizeof(*new));
+ new->op = ocond->op;
+ if( ocond->variable.str != NULL )
+ {
+ if( ocond->op == op_variable )
+ {
+ /*
+ * Search for structure to insert here.
+ */
+ for(cfg = config;cfg != NULL; cfg = cfg->next)
+ {
+ if( cfg->tok != tok_bool && cfg->tok != tok_int
+ && cfg->tok != tok_tristate
+ && cfg->tok != tok_dep_tristate)
+ {
+ continue;
+ }
+ if( strcmp(cfg->optionname, ocond->variable.str) == 0)
+ {
+ new->variable.cfg = cfg;
+ new->op = op_kvariable;
+ break;
+ }
+ }
+ }
+ 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;
+}
+
+/*
+ * 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)
+{
+ int i;
+ struct condition * newcond;
+ struct condition * tail;
+ struct condition * new;
+ struct condition * ocond;
+ struct kconfig * cfg;
+
+ 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.
+ */
+int fix_conditionals(struct kconfig * scfg)
+{
+ int depth = 0;
+ int i;
+ struct kconfig * cfg;
+ 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_menuoption:
+ case tok_bool:
+ case tok_tristate:
+ case tok_dep_tristate:
+ case tok_int:
+ /*
+ * We need to duplicate the chain of conditions and attach them to
+ * this token.
+ */
+ cfg->cond = get_token_cond(&conditions[0], depth);
+ 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)
+ {
+ /*
+ * 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 it's own.
+ */
+ if(cnd->op != op_kvariable) continue;
+ if(cnd->variable.cfg->cond == NULL) 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;
+
+ }
+ }
+
+ /*
+ * 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)
+ {
+ /*
+ * Search for a left parenthesis.
+ */
+ if(cnd->op != op_lparen) continue;
+ for(cnd1 = cnd->next; cnd1; cnd1=cnd1->next)
+ {
+ /*
+ * 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)))
+ {
+ /*
+ * We have a duplicate. Nuke 5 ops.
+ */
+ cnd3 = cnd1;
+ for(i=0; i<5; i++, cnd3=cnd3->next)
+ {
+ cnd3->op = op_nuked;
+ }
+ /*
+ * 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;
+ }
+ }
+ }
+ }
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov
with Sam's (original) version of this