/* parser config.in
|
/* parser config.in
|
*
|
*
|
* Version 1.0
|
* Version 1.0
|
* Eric Youngdale
|
* Eric Youngdale
|
* 10/95
|
* 10/95
|
*
|
*
|
* The general idea here is that we want to parse a config.in file and
|
* 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
|
* from this, we generate a wish script which gives us effectively the
|
* same functionality that the original config.in script provided.
|
* same functionality that the original config.in script provided.
|
*
|
*
|
* This task is split roughly into 3 parts. The first parse is the parse
|
* 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
|
* 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
|
* #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
|
* menu items. In this way, each menu item has a complete list of
|
* dependencies that are used to enable/disable the options.
|
* dependencies that are used to enable/disable the options.
|
* The third part is to take the configuration database we have build,
|
* The third part is to take the configuration database we have build,
|
* and build the actual wish script.
|
* and build the actual wish script.
|
*
|
*
|
* This file contains the code to further process the conditions from
|
* This file contains the code to further process the conditions from
|
* the "ifdef" clauses.
|
* the "ifdef" clauses.
|
*
|
*
|
* The conditions are assumed to be one of the following formats
|
* 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:= "$VARIABLE != y/n/m
|
* simple_condition:= "$VARIABLE != y/n/m
|
*
|
*
|
* simple_condition -a simple_condition
|
* simple_condition -a simple_condition
|
*
|
*
|
* If the input condition contains '(' or ')' it would screw us up, but for now
|
* If the input condition contains '(' or ')' it would screw us up, but for now
|
* this is not a problem.
|
* this is not a problem.
|
*/
|
*/
|
#include <stdlib.h>
|
#include <stdlib.h>
|
#include <stdio.h>
|
#include <stdio.h>
|
#include <string.h>
|
#include <string.h>
|
#include "tkparse.h"
|
#include "tkparse.h"
|
|
|
|
|
/*
|
/*
|
* Walk a condition chain and invert it so that the logical result is
|
* Walk a condition chain and invert it so that the logical result is
|
* inverted.
|
* inverted.
|
*/
|
*/
|
static void invert_condition(struct condition * cnd)
|
static void invert_condition(struct condition * cnd)
|
{
|
{
|
/*
|
/*
|
* This is simple. Just walk through the list, and invert
|
* This is simple. Just walk through the list, and invert
|
* all of the operators.
|
* all of the operators.
|
*/
|
*/
|
for(;cnd; cnd = cnd->next)
|
for(;cnd; cnd = cnd->next)
|
{
|
{
|
switch(cnd->op)
|
switch(cnd->op)
|
{
|
{
|
case op_and:
|
case op_and:
|
cnd->op = op_or;
|
cnd->op = op_or;
|
break;
|
break;
|
case op_or:
|
case op_or:
|
/*
|
/*
|
* This is not turned into op_and - we need to keep track
|
* This is not turned into op_and - we need to keep track
|
* of what operators were used here since we have an optimization
|
* of what operators were used here since we have an optimization
|
* later on to remove duplicate conditions, and having
|
* later on to remove duplicate conditions, and having
|
* inverted ors in there would make it harder if we did not
|
* inverted ors in there would make it harder if we did not
|
* distinguish an inverted or from an and we inserted because
|
* distinguish an inverted or from an and we inserted because
|
* of nested ifs.
|
* of nested ifs.
|
*/
|
*/
|
cnd->op = op_and1;
|
cnd->op = op_and1;
|
break;
|
break;
|
case op_neq:
|
case op_neq:
|
cnd->op = op_eq;
|
cnd->op = op_eq;
|
break;
|
break;
|
case op_eq:
|
case op_eq:
|
cnd->op = op_neq;
|
cnd->op = op_neq;
|
break;
|
break;
|
default:
|
default:
|
break;
|
break;
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|
/*
|
/*
|
* Walk a condition chain, and free the memory associated with it.
|
* Walk a condition chain, and free the memory associated with it.
|
*/
|
*/
|
static void free_condition(struct condition * cnd)
|
static void free_condition(struct condition * cnd)
|
{
|
{
|
struct condition * next;
|
struct condition * next;
|
for(;cnd; cnd = next)
|
for(;cnd; cnd = next)
|
{
|
{
|
next = cnd->next;
|
next = cnd->next;
|
|
|
if( cnd->variable.str != NULL )
|
if( cnd->variable.str != NULL )
|
free(cnd->variable.str);
|
free(cnd->variable.str);
|
|
|
free(cnd);
|
free(cnd);
|
}
|
}
|
}
|
}
|
|
|
/*
|
/*
|
* Walk all of the conditions, and look for choice values. Convert
|
* Walk all of the conditions, and look for choice values. Convert
|
* the tokens into something more digestible.
|
* the tokens into something more digestible.
|
*/
|
*/
|
void fix_choice_cond()
|
void fix_choice_cond()
|
{
|
{
|
struct condition * cond;
|
struct condition * cond;
|
struct condition * cond2;
|
struct condition * cond2;
|
struct kconfig * cfg;
|
struct kconfig * cfg;
|
char tmpbuf[10];
|
char tmpbuf[10];
|
|
|
for(cfg = config;cfg != NULL; cfg = cfg->next)
|
for(cfg = config;cfg != NULL; cfg = cfg->next)
|
{
|
{
|
if( cfg->cond == NULL )
|
if( cfg->cond == NULL )
|
{
|
{
|
continue;
|
continue;
|
}
|
}
|
|
|
for(cond = cfg->cond; cond != NULL; cond = cond->next)
|
for(cond = cfg->cond; cond != NULL; cond = cond->next)
|
{
|
{
|
if( cond->op != op_kvariable )
|
if( cond->op != op_kvariable )
|
continue;
|
continue;
|
|
|
if( cond->variable.cfg->tok != tok_choice )
|
if( cond->variable.cfg->tok != tok_choice )
|
continue;
|
continue;
|
|
|
/*
|
/*
|
* Look ahead for what we are comparing this to. There should
|
* Look ahead for what we are comparing this to. There should
|
* be one operator in between.
|
* be one operator in between.
|
*/
|
*/
|
cond2 = cond->next->next;
|
cond2 = cond->next->next;
|
strcpy(tmpbuf, cond->variable.cfg->label);
|
strcpy(tmpbuf, cond->variable.cfg->label);
|
|
|
if( strcmp(cond2->variable.str, "y") == 0 )
|
if( strcmp(cond2->variable.str, "y") == 0 )
|
{
|
{
|
cond->variable.cfg = cond->variable.cfg->choice_label;
|
cond->variable.cfg = cond->variable.cfg->choice_label;
|
cond2->variable.str = strdup(tmpbuf);
|
cond2->variable.str = strdup(tmpbuf);
|
}
|
}
|
else
|
else
|
{
|
{
|
fprintf(stderr,"Ooops\n");
|
fprintf(stderr,"Ooops\n");
|
exit(0);
|
exit(0);
|
}
|
}
|
}
|
}
|
|
|
}
|
}
|
}
|
}
|
|
|
/*
|
/*
|
* Walk the stack of conditions, and clone all of them with "&&" operators
|
* Walk the stack of conditions, and clone all of them with "&&" operators
|
* gluing them together. The conditions from each level of the stack
|
* gluing them together. The conditions from each level of the stack
|
* are wrapped in parenthesis so as to guarantee that the results
|
* are wrapped in parenthesis so as to guarantee that the results
|
* are logically correct.
|
* are logically correct.
|
*/
|
*/
|
struct condition * get_token_cond(struct condition ** cond, int depth)
|
struct condition * get_token_cond(struct condition ** cond, int depth)
|
{
|
{
|
int i;
|
int i;
|
struct condition * newcond;
|
struct condition * newcond;
|
struct condition * tail;
|
struct condition * tail;
|
struct condition * new;
|
struct condition * new;
|
struct condition * ocond;
|
struct condition * ocond;
|
struct kconfig * cfg;
|
struct kconfig * cfg;
|
|
|
newcond = tail = NULL;
|
newcond = tail = NULL;
|
for(i=0; i<depth; i++, cond++)
|
for(i=0; i<depth; i++, cond++)
|
{
|
{
|
/*
|
/*
|
* First insert the left parenthesis
|
* First insert the left parenthesis
|
*/
|
*/
|
new = (struct condition *) malloc(sizeof(struct condition));
|
new = (struct condition *) malloc(sizeof(struct condition));
|
memset(new, 0, sizeof(*new));
|
memset(new, 0, sizeof(*new));
|
new->op = op_lparen;
|
new->op = op_lparen;
|
if( tail == NULL )
|
if( tail == NULL )
|
{
|
{
|
newcond = tail = new;
|
newcond = tail = new;
|
}
|
}
|
else
|
else
|
{
|
{
|
tail->next = new;
|
tail->next = new;
|
tail = new;
|
tail = new;
|
}
|
}
|
|
|
/*
|
/*
|
* Now duplicate the chain.
|
* Now duplicate the chain.
|
*/
|
*/
|
ocond = *cond;
|
ocond = *cond;
|
for(;ocond != NULL; ocond = ocond->next)
|
for(;ocond != NULL; ocond = ocond->next)
|
{
|
{
|
new = (struct condition *) malloc(sizeof(struct condition));
|
new = (struct condition *) malloc(sizeof(struct condition));
|
memset(new, 0, sizeof(*new));
|
memset(new, 0, sizeof(*new));
|
new->op = ocond->op;
|
new->op = ocond->op;
|
if( ocond->variable.str != NULL )
|
if( ocond->variable.str != NULL )
|
{
|
{
|
if( ocond->op == op_variable )
|
if( ocond->op == op_variable )
|
{
|
{
|
/*
|
/*
|
* Search for structure to insert here.
|
* Search for structure to insert here.
|
*/
|
*/
|
for(cfg = config;cfg != NULL; cfg = cfg->next)
|
for(cfg = config;cfg != NULL; cfg = cfg->next)
|
{
|
{
|
if( cfg->tok != tok_bool
|
if( cfg->tok != tok_bool
|
&& cfg->tok != tok_int
|
&& cfg->tok != tok_int
|
&& cfg->tok != tok_hex
|
&& cfg->tok != tok_hex
|
&& cfg->tok != tok_tristate
|
&& cfg->tok != tok_tristate
|
&& cfg->tok != tok_choice
|
&& cfg->tok != tok_choice
|
&& cfg->tok != tok_dep_tristate)
|
&& cfg->tok != tok_dep_tristate)
|
{
|
{
|
continue;
|
continue;
|
}
|
}
|
if( strcmp(cfg->optionname, ocond->variable.str) == 0)
|
if( strcmp(cfg->optionname, ocond->variable.str) == 0)
|
{
|
{
|
new->variable.cfg = cfg;
|
new->variable.cfg = cfg;
|
new->op = op_kvariable;
|
new->op = op_kvariable;
|
break;
|
break;
|
}
|
}
|
}
|
}
|
if( cfg == NULL )
|
if( cfg == NULL )
|
{
|
{
|
new->variable.str = strdup(ocond->variable.str);
|
new->variable.str = strdup(ocond->variable.str);
|
}
|
}
|
}
|
}
|
else
|
else
|
{
|
{
|
new->variable.str = strdup(ocond->variable.str);
|
new->variable.str = strdup(ocond->variable.str);
|
}
|
}
|
}
|
}
|
tail->next = new;
|
tail->next = new;
|
tail = new;
|
tail = new;
|
}
|
}
|
|
|
/*
|
/*
|
* Next insert the left parenthesis
|
* Next insert the left parenthesis
|
*/
|
*/
|
new = (struct condition *) malloc(sizeof(struct condition));
|
new = (struct condition *) malloc(sizeof(struct condition));
|
memset(new, 0, sizeof(*new));
|
memset(new, 0, sizeof(*new));
|
new->op = op_rparen;
|
new->op = op_rparen;
|
tail->next = new;
|
tail->next = new;
|
tail = new;
|
tail = new;
|
|
|
/*
|
/*
|
* Insert an and operator, if we have another condition.
|
* Insert an and operator, if we have another condition.
|
*/
|
*/
|
if( i < depth - 1 )
|
if( i < depth - 1 )
|
{
|
{
|
new = (struct condition *) malloc(sizeof(struct condition));
|
new = (struct condition *) malloc(sizeof(struct condition));
|
memset(new, 0, sizeof(*new));
|
memset(new, 0, sizeof(*new));
|
new->op = op_and;
|
new->op = op_and;
|
tail->next = new;
|
tail->next = new;
|
tail = new;
|
tail = new;
|
}
|
}
|
|
|
}
|
}
|
|
|
return newcond;
|
return newcond;
|
}
|
}
|
|
|
/*
|
/*
|
* Walk a single chain of conditions and clone it. These are assumed
|
* Walk a single chain of conditions and clone it. These are assumed
|
* to be created/processed by get_token_cond in a previous pass.
|
* to be created/processed by get_token_cond in a previous pass.
|
*/
|
*/
|
struct condition * get_token_cond_frag(struct condition * cond,
|
struct condition * get_token_cond_frag(struct condition * cond,
|
struct condition ** last)
|
struct condition ** last)
|
{
|
{
|
struct condition * newcond;
|
struct condition * newcond;
|
struct condition * tail;
|
struct condition * tail;
|
struct condition * new;
|
struct condition * new;
|
struct condition * ocond;
|
struct condition * ocond;
|
|
|
newcond = tail = NULL;
|
newcond = tail = NULL;
|
|
|
/*
|
/*
|
* Now duplicate the chain.
|
* Now duplicate the chain.
|
*/
|
*/
|
for(ocond = cond;ocond != NULL; ocond = ocond->next)
|
for(ocond = cond;ocond != NULL; ocond = ocond->next)
|
{
|
{
|
new = (struct condition *) malloc(sizeof(struct condition));
|
new = (struct condition *) malloc(sizeof(struct condition));
|
memset(new, 0, sizeof(*new));
|
memset(new, 0, sizeof(*new));
|
new->op = ocond->op;
|
new->op = ocond->op;
|
new->variable.cfg = ocond->variable.cfg;
|
new->variable.cfg = ocond->variable.cfg;
|
if( tail == NULL )
|
if( tail == NULL )
|
{
|
{
|
newcond = tail = new;
|
newcond = tail = new;
|
}
|
}
|
else
|
else
|
{
|
{
|
tail->next = new;
|
tail->next = new;
|
tail = new;
|
tail = new;
|
}
|
}
|
}
|
}
|
|
|
new = (struct condition *) malloc(sizeof(struct condition));
|
new = (struct condition *) malloc(sizeof(struct condition));
|
memset(new, 0, sizeof(*new));
|
memset(new, 0, sizeof(*new));
|
new->op = op_and;
|
new->op = op_and;
|
tail->next = new;
|
tail->next = new;
|
tail = new;
|
tail = new;
|
|
|
*last = tail;
|
*last = tail;
|
return newcond;
|
return newcond;
|
}
|
}
|
|
|
/*
|
/*
|
* Walk through the if conditionals and maintain a chain.
|
* Walk through the if conditionals and maintain a chain.
|
*/
|
*/
|
void fix_conditionals(struct kconfig * scfg)
|
void fix_conditionals(struct kconfig * scfg)
|
{
|
{
|
int depth = 0;
|
int depth = 0;
|
int i;
|
int i;
|
struct kconfig * cfg;
|
struct kconfig * cfg;
|
struct kconfig * cfg1;
|
struct kconfig * cfg1;
|
struct condition * conditions[25];
|
struct condition * conditions[25];
|
struct condition * cnd;
|
struct condition * cnd;
|
struct condition * cnd1;
|
struct condition * cnd1;
|
struct condition * cnd2;
|
struct condition * cnd2;
|
struct condition * cnd3;
|
struct condition * cnd3;
|
struct condition * newcond;
|
struct condition * newcond;
|
struct condition * last;
|
struct condition * last;
|
|
|
/*
|
/*
|
* Start by walking the chain. Every time we see an ifdef, push
|
* 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 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"
|
* 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
|
* 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.
|
* 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
|
* 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
|
* by anding together all of the conditions that are currently stored on
|
* the stack. In this way, we have a correct representation of whatever
|
* the stack. In this way, we have a correct representation of whatever
|
* conditions govern the usage of each option.
|
* conditions govern the usage of each option.
|
*/
|
*/
|
memset(conditions, 0, sizeof(conditions));
|
memset(conditions, 0, sizeof(conditions));
|
for(cfg=scfg;cfg != NULL; cfg = cfg->next)
|
for(cfg=scfg;cfg != NULL; cfg = cfg->next)
|
{
|
{
|
switch(cfg->tok)
|
switch(cfg->tok)
|
{
|
{
|
case tok_if:
|
case tok_if:
|
/*
|
/*
|
* Push this condition on the stack, and nuke the token
|
* Push this condition on the stack, and nuke the token
|
* representing the ifdef, since we no longer need it.
|
* representing the ifdef, since we no longer need it.
|
*/
|
*/
|
conditions[depth] = cfg->cond;
|
conditions[depth] = cfg->cond;
|
depth++;
|
depth++;
|
cfg->tok = tok_nop;
|
cfg->tok = tok_nop;
|
cfg->cond = NULL;
|
cfg->cond = NULL;
|
break;
|
break;
|
case tok_else:
|
case tok_else:
|
/*
|
/*
|
* For an else, we just invert the condition at the top of
|
* For an else, we just invert the condition at the top of
|
* the stack. This is done in place with no reallocation
|
* the stack. This is done in place with no reallocation
|
* of memory taking place.
|
* of memory taking place.
|
*/
|
*/
|
invert_condition(conditions[depth-1]);
|
invert_condition(conditions[depth-1]);
|
cfg->tok = tok_nop;
|
cfg->tok = tok_nop;
|
break;
|
break;
|
case tok_fi:
|
case tok_fi:
|
depth--;
|
depth--;
|
free_condition(conditions[depth]);
|
free_condition(conditions[depth]);
|
conditions[depth] = NULL;
|
conditions[depth] = NULL;
|
cfg->tok = tok_nop;
|
cfg->tok = tok_nop;
|
break;
|
break;
|
case tok_comment:
|
case tok_comment:
|
case tok_define:
|
case tok_define:
|
case tok_menuoption:
|
case tok_menuoption:
|
case tok_bool:
|
case tok_bool:
|
case tok_tristate:
|
case tok_tristate:
|
case tok_int:
|
case tok_int:
|
case tok_hex:
|
case tok_hex:
|
case tok_choice:
|
case tok_choice:
|
case tok_make:
|
case tok_make:
|
/*
|
/*
|
* We need to duplicate the chain of conditions and attach them to
|
* We need to duplicate the chain of conditions and attach them to
|
* this token.
|
* this token.
|
*/
|
*/
|
cfg->cond = get_token_cond(&conditions[0], depth);
|
cfg->cond = get_token_cond(&conditions[0], depth);
|
break;
|
break;
|
case tok_dep_tristate:
|
case tok_dep_tristate:
|
/*
|
/*
|
* Same as tok_tristate et al except we have a temporary
|
* Same as tok_tristate et al except we have a temporary
|
* conditional. (Sort of a hybrid tok_if, tok_tristate, tok_fi
|
* conditional. (Sort of a hybrid tok_if, tok_tristate, tok_fi
|
* option)
|
* option)
|
*/
|
*/
|
conditions[depth] = cfg->cond;
|
conditions[depth] = cfg->cond;
|
depth++;
|
depth++;
|
cfg->cond = get_token_cond(&conditions[0], depth);
|
cfg->cond = get_token_cond(&conditions[0], depth);
|
depth--;
|
depth--;
|
free_condition(conditions[depth]);
|
free_condition(conditions[depth]);
|
conditions[depth] = NULL;
|
conditions[depth] = NULL;
|
default:
|
default:
|
break;
|
break;
|
}
|
}
|
}
|
}
|
|
|
/*
|
/*
|
* Fix any conditions involving the "choice" operator.
|
* Fix any conditions involving the "choice" operator.
|
*/
|
*/
|
fix_choice_cond();
|
fix_choice_cond();
|
|
|
/*
|
/*
|
* Walk through and see if there are multiple options that control the
|
* 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
|
* same kvariable. If there are we need to treat them a little bit
|
* special.
|
* special.
|
*/
|
*/
|
for(cfg=scfg;cfg != NULL; cfg = cfg->next)
|
for(cfg=scfg;cfg != NULL; cfg = cfg->next)
|
{
|
{
|
switch(cfg->tok)
|
switch(cfg->tok)
|
{
|
{
|
case tok_bool:
|
case tok_bool:
|
case tok_tristate:
|
case tok_tristate:
|
case tok_dep_tristate:
|
case tok_dep_tristate:
|
case tok_int:
|
case tok_int:
|
case tok_hex:
|
case tok_hex:
|
for(cfg1=cfg;cfg1 != NULL; cfg1 = cfg1->next)
|
for(cfg1=cfg;cfg1 != NULL; cfg1 = cfg1->next)
|
{
|
{
|
switch(cfg1->tok)
|
switch(cfg1->tok)
|
{
|
{
|
case tok_define:
|
case tok_define:
|
case tok_bool:
|
case tok_bool:
|
case tok_tristate:
|
case tok_tristate:
|
case tok_dep_tristate:
|
case tok_dep_tristate:
|
case tok_int:
|
case tok_int:
|
case tok_hex:
|
case tok_hex:
|
if( strcmp(cfg->optionname, cfg1->optionname) == 0)
|
if( strcmp(cfg->optionname, cfg1->optionname) == 0)
|
{
|
{
|
cfg->flags |= CFG_DUP;
|
cfg->flags |= CFG_DUP;
|
cfg1->flags |= CFG_DUP;
|
cfg1->flags |= CFG_DUP;
|
}
|
}
|
break;
|
break;
|
default:
|
default:
|
break;
|
break;
|
}
|
}
|
}
|
}
|
break;
|
break;
|
default:
|
default:
|
break;
|
break;
|
}
|
}
|
}
|
}
|
|
|
/*
|
/*
|
* Now go through the list, and every time we see a kvariable, check
|
* Now go through the list, and every time we see a kvariable, check
|
* to see whether it also has some dependencies. If so, then
|
* 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
|
* 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
|
* 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
|
* 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
|
* 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
|
* 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
|
* we can fix this by searching for the tokens that this option depends
|
* upon and cloning the conditions and merging them with the list.
|
* upon and cloning the conditions and merging them with the list.
|
*/
|
*/
|
for(cfg=scfg;cfg != NULL; cfg = cfg->next)
|
for(cfg=scfg;cfg != NULL; cfg = cfg->next)
|
{
|
{
|
/*
|
/*
|
* Search for a token that has a condition list.
|
* Search for a token that has a condition list.
|
*/
|
*/
|
if(cfg->cond == NULL) continue;
|
if(cfg->cond == NULL) continue;
|
for(cnd = cfg->cond; cnd; cnd=cnd->next)
|
for(cnd = cfg->cond; cnd; cnd=cnd->next)
|
{
|
{
|
/*
|
/*
|
* Now search the condition list for a known configuration variable
|
* Now search the condition list for a known configuration variable
|
* that has conditions of its own.
|
* that has conditions of its own.
|
*/
|
*/
|
if(cnd->op != op_kvariable) continue;
|
if(cnd->op != op_kvariable) continue;
|
if(cnd->variable.cfg->cond == NULL) continue;
|
if(cnd->variable.cfg->cond == NULL) continue;
|
|
|
if(cnd->variable.cfg->flags & CFG_DUP) continue;
|
if(cnd->variable.cfg->flags & CFG_DUP) continue;
|
/*
|
/*
|
* OK, we have some conditions to append to cfg. Make a clone
|
* OK, we have some conditions to append to cfg. Make a clone
|
* of the conditions,
|
* of the conditions,
|
*/
|
*/
|
newcond = get_token_cond_frag(cnd->variable.cfg->cond, &last);
|
newcond = get_token_cond_frag(cnd->variable.cfg->cond, &last);
|
|
|
/*
|
/*
|
* Finally, we splice it into our list.
|
* Finally, we splice it into our list.
|
*/
|
*/
|
last->next = cfg->cond;
|
last->next = cfg->cond;
|
cfg->cond = newcond;
|
cfg->cond = newcond;
|
|
|
}
|
}
|
}
|
}
|
|
|
/*
|
/*
|
* There is a strong possibility that we have duplicate conditions
|
* There is a strong possibility that we have duplicate conditions
|
* in here. It would make the script more efficient and readable to
|
* in here. It would make the script more efficient and readable to
|
* remove these. Here is where we assume here that there are no
|
* remove these. Here is where we assume here that there are no
|
* parenthesis in the input script.
|
* parenthesis in the input script.
|
*/
|
*/
|
for(cfg=scfg;cfg != NULL; cfg = cfg->next)
|
for(cfg=scfg;cfg != NULL; cfg = cfg->next)
|
{
|
{
|
/*
|
/*
|
* Search for configuration options that have conditions.
|
* Search for configuration options that have conditions.
|
*/
|
*/
|
if(cfg->cond == NULL) continue;
|
if(cfg->cond == NULL) continue;
|
for(cnd = cfg->cond; cnd; cnd=cnd->next)
|
for(cnd = cfg->cond; cnd; cnd=cnd->next)
|
{
|
{
|
/*
|
/*
|
* Search for a left parenthesis.
|
* Search for a left parenthesis.
|
*/
|
*/
|
if(cnd->op != op_lparen) continue;
|
if(cnd->op != op_lparen) continue;
|
for(cnd1 = cnd->next; cnd1; cnd1=cnd1->next)
|
for(cnd1 = cnd->next; cnd1; cnd1=cnd1->next)
|
{
|
{
|
/*
|
/*
|
* Search after the previous left parenthesis, and try
|
* Search after the previous left parenthesis, and try
|
* and find a second left parenthesis.
|
* and find a second left parenthesis.
|
*/
|
*/
|
if(cnd1->op != op_lparen) continue;
|
if(cnd1->op != op_lparen) continue;
|
|
|
/*
|
/*
|
* Now compare the next 5 tokens to see if they are
|
* Now compare the next 5 tokens to see if they are
|
* identical. We are looking for two chains that
|
* identical. We are looking for two chains that
|
* are like: '(' $VARIABLE operator constant ')'.
|
* are like: '(' $VARIABLE operator constant ')'.
|
*/
|
*/
|
cnd2 = cnd;
|
cnd2 = cnd;
|
cnd3 = cnd1;
|
cnd3 = cnd1;
|
for(i=0; i<5; i++, cnd2=cnd2->next, cnd3=cnd3->next)
|
for(i=0; i<5; i++, cnd2=cnd2->next, cnd3=cnd3->next)
|
{
|
{
|
if(!cnd2 || !cnd3) break;
|
if(!cnd2 || !cnd3) break;
|
if(cnd2->op != cnd3->op) break;
|
if(cnd2->op != cnd3->op) break;
|
if(i == 1 && (cnd2->op != op_kvariable
|
if(i == 1 && (cnd2->op != op_kvariable
|
|| cnd2->variable.cfg != cnd3->variable.cfg) ) break;
|
|| cnd2->variable.cfg != cnd3->variable.cfg) ) break;
|
if(i==2 && cnd2->op != op_eq && cnd2->op != op_neq) break;
|
if(i==2 && cnd2->op != op_eq && cnd2->op != op_neq) break;
|
if(i == 3 && cnd2->op != op_constant &&
|
if(i == 3 && cnd2->op != op_constant &&
|
strcmp(cnd2->variable.str, cnd3->variable.str) != 0)
|
strcmp(cnd2->variable.str, cnd3->variable.str) != 0)
|
break;
|
break;
|
if(i==4 && cnd2->op != op_rparen) break;
|
if(i==4 && cnd2->op != op_rparen) break;
|
}
|
}
|
/*
|
/*
|
* If these match, and there is an and gluing these together,
|
* If these match, and there is an and gluing these together,
|
* then we can nuke the second one.
|
* then we can nuke the second one.
|
*/
|
*/
|
if(i==5 && ((cnd3 && cnd3->op == op_and)
|
if(i==5 && ((cnd3 && cnd3->op == op_and)
|
||(cnd2 && cnd2->op == op_and)))
|
||(cnd2 && cnd2->op == op_and)))
|
{
|
{
|
/*
|
/*
|
* We have a duplicate. Nuke 5 ops.
|
* We have a duplicate. Nuke 5 ops.
|
*/
|
*/
|
cnd3 = cnd1;
|
cnd3 = cnd1;
|
for(i=0; i<5; i++, cnd3=cnd3->next)
|
for(i=0; i<5; i++, cnd3=cnd3->next)
|
{
|
{
|
cnd3->op = op_nuked;
|
cnd3->op = op_nuked;
|
}
|
}
|
/*
|
/*
|
* Nuke the and that glues the conditions together.
|
* Nuke the and that glues the conditions together.
|
*/
|
*/
|
if(cnd3 && cnd3->op == op_and) cnd3->op = op_nuked;
|
if(cnd3 && cnd3->op == op_and) cnd3->op = op_nuked;
|
else if(cnd2 && cnd2->op == op_and) cnd2->op = op_nuked;
|
else if(cnd2 && cnd2->op == op_and) cnd2->op = op_nuked;
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
}
|
|
|