summaryrefslogtreecommitdiffstats
path: root/scripts/tkcond.c
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>1997-01-07 02:33:00 +0000
committer <ralf@linux-mips.org>1997-01-07 02:33:00 +0000
commitbeb116954b9b7f3bb56412b2494b562f02b864b1 (patch)
tree120e997879884e1b9d93b265221b939d2ef1ade1 /scripts/tkcond.c
parent908d4681a1dc3792ecafbe64265783a86c4cccb6 (diff)
Import of Linux/MIPS 2.1.14
Diffstat (limited to 'scripts/tkcond.c')
-rw-r--r--scripts/tkcond.c542
1 files changed, 542 insertions, 0 deletions
diff --git a/scripts/tkcond.c b/scripts/tkcond.c
new file mode 100644
index 000000000..9cc10fa4f
--- /dev/null
+++ b/scripts/tkcond.c
@@ -0,0 +1,542 @@
+/* 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 following 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 <stdlib.h>
+#include <stdio.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;
+
+ 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.
+ */
+void fix_choice_cond()
+{
+ struct condition * cond;
+ struct condition * cond2;
+ struct kconfig * cfg;
+ char tmpbuf[10];
+
+ for(cfg = config;cfg != NULL; cfg = cfg->next)
+ {
+ if( cfg->cond == NULL )
+ {
+ continue;
+ }
+
+ 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 )
+ {
+ cond->variable.cfg = cond->variable.cfg->choice_label;
+ cond2->variable.str = strdup(tmpbuf);
+ }
+ else
+ {
+ fprintf(stderr,"Ooops\n");
+ exit(0);
+ }
+ }
+
+ }
+}
+
+/*
+ * 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_hex
+ && cfg->tok != tok_tristate
+ && cfg->tok != tok_choice
+ && cfg->tok != tok_dep_tristate)
+ {
+ continue;
+ }
+ 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;
+}
+
+/*
+ * 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.
+ */
+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_choice:
+ case tok_make:
+ /*
+ * 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;
+ }
+ }
+
+ /*
+ * 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)
+ {
+ switch(cfg->tok)
+ {
+ case tok_bool:
+ case tok_tristate:
+ case tok_dep_tristate:
+ case tok_int:
+ case tok_hex:
+ for(cfg1=cfg;cfg1 != NULL; cfg1 = cfg1->next)
+ {
+ switch(cfg1->tok)
+ {
+ case tok_define:
+ case tok_bool:
+ case tok_tristate:
+ case tok_dep_tristate:
+ case tok_int:
+ case tok_hex:
+ if( strcmp(cfg->optionname, cfg1->optionname) == 0)
+ {
+ cfg->flags |= CFG_DUP;
+ cfg1->flags |= CFG_DUP;
+ }
+ break;
+ default:
+ break;
+ }
+ }
+ 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 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;
+
+ }
+ }
+
+ /*
+ * 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;
+ }
+ }
+ }
+ }
+}