diff options
author | Ralf Baechle <ralf@linux-mips.org> | 1997-01-07 02:33:00 +0000 |
---|---|---|
committer | <ralf@linux-mips.org> | 1997-01-07 02:33:00 +0000 |
commit | beb116954b9b7f3bb56412b2494b562f02b864b1 (patch) | |
tree | 120e997879884e1b9d93b265221b939d2ef1ade1 /scripts/tkcond.c | |
parent | 908d4681a1dc3792ecafbe64265783a86c4cccb6 (diff) |
Import of Linux/MIPS 2.1.14
Diffstat (limited to 'scripts/tkcond.c')
-rw-r--r-- | scripts/tkcond.c | 542 |
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; + } + } + } + } +} |