patch-2.2.0-pre9 linux/scripts/tkparse.c
Next file: linux/scripts/tkparse.h
Previous file: linux/scripts/tkgen.c
Back to the patch index
Back to the overall index
- Lines: 1293
- Date:
Wed Jan 20 10:05:49 1999
- Orig file:
v2.2.0-pre8/linux/scripts/tkparse.c
- Orig date:
Tue Jan 19 11:32:53 1999
diff -u --recursive --new-file v2.2.0-pre8/linux/scripts/tkparse.c linux/scripts/tkparse.c
@@ -1,777 +1,622 @@
-/* parser config.in
- *
- * Version 1.0
- * Eric Youngdale
- * 10/95
+/*
+ * tkparse.c
*
- * 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.
+ * Eric Youngdale was the original author of xconfig.
+ * Michael Elizabeth Chastain (mec@shout.net) is the current maintainer.
*
- * 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.
+ * Parse a config.in file and translate it to a wish script.
+ * This task has three parts:
*
- * This file contains the code to do the first parse of config.in.
+ * tkparse.c tokenize the input
+ * tkcond.c transform 'if ...' statements
+ * tkgen.c generate output
*
* Change History
*
- * 7 January 1999, Michael Elizabeth Chastain, <mailto:mec@shout.net>
- * Teach dep_tristate about a few literals, such as:
- * dep_tristate 'foo' CONFIG_FOO m
- * Also have it print an error message and exit on some parse failures.
+ * 7 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
+ * - Teach dep_tristate about a few literals, such as:
+ * dep_tristate 'foo' CONFIG_FOO m
+ * Also have it print an error message and exit on some parse failures.
+ *
+ * 14 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
+ * - Don't fclose stdin. Thanks to Tony Hoyle for nailing this one.
+ *
+ * 14 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
+ * - Steam-clean this file. I tested this by generating kconfig.tk for
+ * every architecture and comparing it character-for-character against
+ * the output of the old tkparse.
*
- * 14 January 1999, Michael Elizabeth Chastain, <mailto:mec@shout.net>
- * Don't fclose stdin. Thanks to Tony Hoyle for nailing this one.
+ * TO DO:
+ * - xconfig is at the end of its life cycle. Contact <mec@shout.net> if
+ * you are interested in working on the replacement.
*/
-#include <stdlib.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
+
#include "tkparse.h"
-struct kconfig * config = NULL;
-struct kconfig * clast = NULL;
-struct kconfig * koption = NULL;
+static struct kconfig * config_list = NULL;
+static struct kconfig * config_last = NULL;
+static const char * current_file = "<unknown file>";
static int lineno = 0;
-static int menus_seen = 0;
-static char * current_file = NULL;
-static int do_source(char * filename);
-static char * get_string(char *pnt, char ** labl);
-static int choose_number = 0;
+
+static void do_source( const char * );
+
+#undef strcmp
+int my_strcmp( const char * s1, const char * s2 ) { return strcmp( s1, s2 ); }
+#define strcmp my_strcmp
+
/*
- * Simple function just to skip over spaces and tabs in config.in.
+ * Report a syntax error.
*/
-static char * skip_whitespace(char * pnt)
+static void syntax_error( const char * msg )
{
- while( *pnt && (*pnt == ' ' || *pnt == '\t')) pnt++;
- return pnt;
+ fprintf( stderr, "%s: %d: %s\n", current_file, lineno, msg );
+ exit( 1 );
}
+
+
/*
- * This function parses a conditional from a config.in (i.e. from an ifdef)
- * and generates a linked list of tokens that describes the conditional.
+ * Get a string.
*/
-static struct condition * parse_if(char * pnt)
+static const char * get_string( const char * pnt, char ** label )
{
- char * opnt;
- struct condition *list;
- struct condition *last;
- struct condition *cpnt;
- char varname[64];
- char * pnt1;
-
- opnt = pnt;
-
- /*
- * We need to find the various tokens, and build the linked list.
- */
- pnt = skip_whitespace(pnt);
- if( *pnt != '[' ) return NULL;
- pnt++;
- pnt = skip_whitespace(pnt);
-
- list = last = NULL;
- while(*pnt && *pnt != ']') {
+ const char * word;
- pnt = skip_whitespace(pnt);
- if(*pnt== '\0' || *pnt == ']') break;
-
- /*
- * Allocate memory for the token we are about to parse, and insert
- * it in the linked list.
- */
- cpnt = (struct condition *) malloc(sizeof(struct condition));
- memset(cpnt, 0, sizeof(struct condition));
- if( last == NULL )
- {
- list = last = cpnt;
- }
- else
- {
- last->next = cpnt;
- last = cpnt;
- }
+ word = pnt;
+ for ( ; ; )
+ {
+ if ( *pnt == '\0' || *pnt == ' ' || *pnt == '\t' )
+ break;
+ pnt++;
+ }
- /*
- * Determine what type of operation this token represents.
- */
- if( *pnt == '-' && pnt[1] == 'a' )
- {
- cpnt->op = op_and;
- pnt += 2;
- continue;
- }
-
- if( *pnt == '-' && pnt[1] == 'o' )
- {
- cpnt->op = op_or;
- pnt += 2;
- continue;
- }
-
- if( *pnt == '!' && pnt[1] == '=' )
- {
- cpnt->op = op_neq;
- pnt += 2;
- continue;
- }
-
- if( *pnt == '=')
- {
- cpnt->op = op_eq;
- pnt += 1;
- continue;
- }
-
- if( *pnt == '!')
- {
- cpnt->op = op_bang;
- pnt += 1;
- continue;
- }
+ *label = malloc( pnt - word + 1 );
+ memcpy( *label, word, pnt - word );
+ (*label)[pnt - word] = '\0';
- if( *pnt != '"' ) goto error; /* This cannot be right. */
- pnt++;
- if( *pnt == '`' )
- {
- cpnt->op = op_shellcmd;
- pnt1 = varname;
- pnt++;
- while(*pnt && *pnt != '`') *pnt1++ = *pnt++;
- *pnt1++ = '\0';
- cpnt->variable.str = strdup(varname);
- if( *pnt == '`' ) pnt++;
- if( *pnt == '"' ) pnt++;
- continue;
- }
- if( *pnt == '$' )
- {
- cpnt->op = op_variable;
- pnt1 = varname;
+ if ( *pnt != '\0' )
pnt++;
- while(*pnt && *pnt != '"') *pnt1++ = *pnt++;
- *pnt1++ = '\0';
- cpnt->variable.str = strdup(varname);
- if( *pnt == '"' ) pnt++;
- continue;
- }
-
- cpnt->op = op_constant;
- pnt1 = varname;
- while(*pnt && *pnt != '"') *pnt1++ = *pnt++;
- *pnt1++ = '\0';
- cpnt->variable.str = strdup(varname);
- if( *pnt == '"' ) pnt++;
- continue;
- }
-
- return list;
-
- error:
- if(current_file != NULL)
- fprintf(stderr,
- "Bad if clause at line %d(%s):%s\n", lineno, current_file, opnt);
- else
- fprintf(stderr,
- "Bad if clause at line %d:%s\n", lineno, opnt);
- return NULL;
+ return pnt;
}
+
+
/*
- * This function looks for a quoted string, from the input buffer, and
- * returns a pointer to a copy of this string. Any characters in
- * the string that need to be "quoted" have a '\' character inserted
- * in front - this way we can directly write these strings into
- * wish scripts.
+ * Get a quoted string.
+ * Insert a '\' before any characters that need quoting.
*/
-static char * get_qstring(char *pnt, char ** labl)
+static const char * get_qstring( const char * pnt, char ** label )
{
- char quotechar;
- char newlabel[1024];
- char * pnt1;
- char * pnt2;
-
- while( *pnt && *pnt != '"' && *pnt != '\'') pnt++;
- if (*pnt == '\0') return pnt;
-
- quotechar = *pnt++;
- pnt1 = newlabel;
- while(*pnt && *pnt != quotechar && pnt[-1] != '\\')
- {
- /*
- * Quote the character if we need to.
- */
- if( *pnt == '"' || *pnt == '\'' || *pnt == '[' || *pnt == ']')
- *pnt1++ = '\\';
-
- *pnt1++ = *pnt++;
- }
- *pnt1++ = '\0';
-
- pnt2 = (char *) malloc(strlen(newlabel) + 1);
- strcpy(pnt2, newlabel);
- *labl = pnt2;
-
- /*
- * Skip over last quote, and whitespace.
- */
- pnt++;
- pnt = skip_whitespace(pnt);
- return pnt;
-}
+ char quote_char;
+ char newlabel [1024];
+ char * pnt1;
-static char * parse_choices(struct kconfig * choice_kcfg, char * pnt)
-{
- struct kconfig * kcfg;
- int index = 1;
+ /* advance to the open quote */
+ for ( ; ; )
+ {
+ if ( *pnt == '\0' )
+ return pnt;
+ quote_char = *pnt++;
+ if ( quote_char == '"' || quote_char == '\'' )
+ break;
+ }
- /*
- * Choices appear in pairs of strings. The parse is fairly trivial.
- */
- while(1)
- {
- pnt = skip_whitespace(pnt);
- if(*pnt == '\0') break;
-
- kcfg = (struct kconfig *) malloc(sizeof(struct kconfig));
- memset(kcfg, 0, sizeof(struct kconfig));
- kcfg->tok = tok_choice;
- if( clast != NULL )
- {
- clast->next = kcfg;
- clast = kcfg;
- }
- else
- {
- clast = config = kcfg;
- }
+ /* copy into an intermediate buffer */
+ pnt1 = newlabel;
+ for ( ; ; )
+ {
+ if ( *pnt == '\0' )
+ syntax_error( "unterminated quoted string" );
+ if ( *pnt == quote_char && pnt[-1] != '\\' )
+ break;
- pnt = get_string(pnt, &kcfg->label);
- pnt = skip_whitespace(pnt);
- pnt = get_string(pnt, &kcfg->optionname);
- kcfg->choice_label = choice_kcfg;
- kcfg->choice_value = index++;
- if( strcmp(kcfg->label, choice_kcfg->value) == 0 )
- choice_kcfg->choice_value = kcfg->choice_value;
+ /* copy the character, quoting if needed */
+ if ( *pnt == '"' || *pnt == '\'' || *pnt == '[' || *pnt == ']' )
+ *pnt1++ = '\\';
+ *pnt1++ = *pnt++;
}
-
+
+ /* copy the label into a permanent location */
+ *pnt1++ = '\0';
+ *label = (char *) malloc( pnt1 - newlabel );
+ memcpy( *label, newlabel, pnt1 - newlabel );
+
+ /* skip over last quote and next whitespace */
+ pnt++;
+ while ( *pnt == ' ' || *pnt == '\t' )
+ pnt++;
return pnt;
}
/*
- * This function grabs one text token from the input buffer
- * and returns a pointer to a copy of just the identifier.
- * This can be either a variable name (i.e. CONFIG_NET),
- * or it could be the default value for the option.
+ * Tokenize an 'if' statement condition.
*/
-static char * get_string(char *pnt, char ** labl)
+static struct condition * tokenize_if( const char * pnt )
{
- char newlabel[1024];
- char * pnt1;
- char * pnt2;
+ struct condition * list;
+ struct condition * last;
- if (*pnt == '\0') return pnt;
+ /* eat the open bracket */
+ while ( *pnt == ' ' || *pnt == '\t' )
+ pnt++;
+ if ( *pnt != '[' )
+ syntax_error( "bad 'if' condition" );
+ pnt++;
- pnt1 = newlabel;
- while(*pnt && *pnt != ' ' && *pnt != '\t')
+ list = last = NULL;
+ for ( ; ; )
{
- *pnt1++ = *pnt++;
+ struct condition * cond;
+
+ /* advance to the next token */
+ while ( *pnt == ' ' || *pnt == '\t' )
+ pnt++;
+ if ( *pnt == '\0' )
+ syntax_error( "unterminated 'if' condition" );
+ if ( *pnt == ']' )
+ return list;
+
+ /* allocate a new token */
+ cond = malloc( sizeof(*cond) );
+ memset( cond, 0, sizeof(*cond) );
+ if ( last == NULL )
+ { list = last = cond; }
+ else
+ { last->next = cond; last = cond; }
+
+ /* determine the token value */
+ if ( *pnt == '-' && pnt[1] == 'a' )
+ { cond->op = op_and; pnt += 2; continue; }
+
+ if ( *pnt == '-' && pnt[1] == 'o' )
+ { cond->op = op_or; pnt += 2; continue; }
+
+ if ( *pnt == '!' && pnt[1] == '=' )
+ { cond->op = op_neq; pnt += 2; continue; }
+
+ if ( *pnt == '=' )
+ { cond->op = op_eq; pnt += 1; continue; }
+
+ if ( *pnt == '!' )
+ { cond->op = op_bang; pnt += 1; continue; }
+
+ if ( *pnt == '"' )
+ {
+ const char * word;
+
+ /* advance to the word */
+ pnt++;
+ if ( *pnt == '$' )
+ { cond->op = op_variable; pnt++; }
+ else
+ { cond->op = op_constant; }
+
+ /* find the end of the word */
+ word = pnt;
+ for ( ; ; )
+ {
+ if ( *pnt == '\0' )
+ syntax_error( "unterminated double quote" );
+ if ( *pnt == '"' )
+ break;
+ pnt++;
+ }
+
+ /* store a copy of this word */
+ {
+ char * str = malloc( pnt - word + 1 );
+ memcpy( str, word, pnt - word );
+ str [pnt - word] = '\0';
+ cond->str = str;
+ }
+
+ pnt++;
+ continue;
+ }
+
+ /* unknown token */
+ syntax_error( "bad if condition" );
}
- *pnt1++ = '\0';
+}
+
- pnt2 = (char *) malloc(strlen(newlabel) + 1);
- strcpy(pnt2, newlabel);
- *labl = pnt2;
- if( *pnt ) pnt++;
- return pnt;
+/*
+ * Tokenize a choice list. Choices appear as pairs of strings;
+ * note that I am parsing *inside* the double quotes. Ugh.
+ */
+static const char * tokenize_choices( struct kconfig * cfg_choose,
+ const char * pnt )
+{
+ for ( ; ; )
+ {
+ struct kconfig * cfg;
+
+ /* skip whitespace */
+ while ( *pnt == ' ' || *pnt == '\t' )
+ pnt++;
+ if ( *pnt == '\0' )
+ return pnt;
+
+ /* allocate a new kconfig line */
+ cfg = malloc( sizeof(*cfg) );
+ memset( cfg, 0, sizeof(*cfg) );
+ if ( config_last == NULL )
+ { config_last = config_list = cfg; }
+ else
+ { config_last->next = cfg; config_last = cfg; }
+
+ /* fill out the line */
+ cfg->token = token_choice_item;
+ cfg->cfg_parent = cfg_choose;
+ pnt = get_string( pnt, &cfg->label );
+ while ( *pnt == ' ' || *pnt == '\t' )
+ pnt++;
+ pnt = get_string( pnt, &cfg->optionname );
+ }
+
+ return pnt;
}
+
+
+
/*
- * Top level parse function. Input pointer is one complete line from config.in
- * and the result is that we create a token that describes this line
- * and insert it into our linked list.
+ * Tokenize one line.
*/
-void parse(char * pnt) {
- enum token tok;
- struct kconfig * kcfg;
- char tmpbuf[24],fake_if[1024];
+static void tokenize_line( const char * pnt )
+{
+ static struct kconfig * last_menuoption = NULL;
+ enum e_token token;
+ struct kconfig * cfg;
- /*
- * Ignore comments and leading whitespace.
- */
+ /* skip white space */
+ while ( *pnt == ' ' || *pnt == '\t' )
+ pnt++;
- pnt = skip_whitespace(pnt);
- while( *pnt && (*pnt == ' ' || *pnt == '\t')) pnt++;
- if(! *pnt ) return;
- if( *pnt == '#' ) return;
+ /*
+ * categorize the next token
+ */
- /*
- * Now categorize the next token.
- */
- tok = tok_unknown;
- if (strncmp(pnt, "mainmenu_name", 13) == 0)
- {
- tok = tok_menuname;
- pnt += 13;
- }
- else if (strncmp(pnt, "source", 6) == 0)
- {
- pnt += 7;
- pnt = skip_whitespace(pnt);
- do_source(pnt);
- return;
- }
- else if (strncmp(pnt, "mainmenu_option", 15) == 0)
- {
- menus_seen++;
- tok = tok_menuoption;
- pnt += 15;
- }
- else if (strncmp(pnt, "comment", 7) == 0)
- {
- tok = tok_comment;
- pnt += 7;
- }
- else if (strncmp(pnt, "choice", 6) == 0)
- {
- tok = tok_choose;
- pnt += 6;
- }
- else if (strncmp(pnt, "define_bool", 11) == 0)
- {
- tok = tok_define;
- pnt += 11;
- }
- else if (strncmp(pnt, "bool", 4) == 0)
- {
- tok = tok_bool;
- pnt += 4;
- }
- else if (strncmp(pnt, "tristate", 8) == 0)
- {
- tok = tok_tristate;
- pnt += 8;
- }
- else if (strncmp(pnt, "dep_tristate", 12) == 0)
- {
- tok = tok_dep_tristate;
- pnt += 12;
- }
- else if (strncmp(pnt, "int", 3) == 0)
- {
- tok = tok_int;
- pnt += 3;
- }
- else if (strncmp(pnt, "hex", 3) == 0)
- {
- tok = tok_hex;
- pnt += 3;
- }
- else if (strncmp(pnt, "string", 6) == 0)
- {
- tok = tok_string;
- pnt += 6;
- }
- else if (strncmp(pnt, "if", 2) == 0)
- {
- tok = tok_if;
- pnt += 2;
- }
- else if (strncmp(pnt, "else", 4) == 0)
- {
- tok = tok_else;
- pnt += 4;
- }
- else if (strncmp(pnt, "fi", 2) == 0)
- {
- tok = tok_fi;
- pnt += 2;
- }
- else if (strncmp(pnt, "endmenu", 7) == 0)
+#define match_token(t, s) \
+ if (strncmp(pnt, s, strlen(s)) == 0) { token = t; pnt += strlen(s); break; }
+
+ token = token_UNKNOWN;
+ switch ( *pnt )
{
- tok = tok_endmenu;
- pnt += 7;
+ default:
+ break;
+
+ case '#':
+ case '\0':
+ return;
+
+ case 'b':
+ match_token( token_bool, "bool" );
+ break;
+
+ case 'c':
+ match_token( token_choice_header, "choice" );
+ match_token( token_comment, "comment" );
+ break;
+
+ case 'd':
+ match_token( token_define_bool, "define_bool" );
+ match_token( token_dep_tristate, "dep_tristate" );
+ break;
+
+ case 'e':
+ match_token( token_else, "else" );
+ match_token( token_endmenu, "endmenu" );
+ break;
+
+ case 'f':
+ match_token( token_fi, "fi" );
+ break;
+
+ case 'h':
+ match_token( token_hex, "hex" );
+ break;
+
+ case 'i':
+ match_token( token_if, "if" );
+ match_token( token_int, "int" );
+ break;
+
+ case 'm':
+ match_token( token_mainmenu_name, "mainmenu_name" );
+ match_token( token_mainmenu_option, "mainmenu_option" );
+ break;
+
+ case 's':
+ match_token( token_source, "source" );
+ match_token( token_string, "string" );
+ break;
+
+ case 't':
+ match_token( token_then, "then" );
+ match_token( token_tristate, "tristate" );
+ break;
+
+ case 'u':
+ match_token( token_unset, "unset" );
+ break;
}
- if( tok == tok_unknown)
+#undef match_token
+
+ if ( token == token_source )
{
- if( clast != NULL && clast->tok == tok_if
- && strcmp(pnt,"then") == 0) return;
- if( current_file != NULL )
- fprintf(stderr, "unknown command=%s(%s %d)\n", pnt,
- current_file, lineno);
- else
- fprintf(stderr, "unknown command=%s(%d)\n", pnt,lineno);
- return;
+ while ( *pnt == ' ' || *pnt == '\t' )
+ pnt++;
+ do_source( pnt );
+ return;
}
- /*
- * Allocate memory for this item, and attach it to the end of the linked
- * list.
- */
- kcfg = (struct kconfig *) malloc(sizeof(struct kconfig));
- memset(kcfg, 0, sizeof(struct kconfig));
- kcfg->tok = tok;
- if( clast != NULL )
+ if ( token == token_then )
{
- clast->next = kcfg;
- clast = kcfg;
+ if ( config_last != NULL && config_last->token == token_if )
+ return;
+ syntax_error( "bogus 'then'" );
}
- else
+
+ if ( token == token_unset )
{
- clast = config = kcfg;
+ fprintf( stderr, "Ignoring 'unset' command\n" );
+ return;
}
- pnt = skip_whitespace(pnt);
+ if ( token == token_UNKNOWN )
+ syntax_error( "unknown command" );
- /*
- * Now parse the remaining parts of the option, and attach the results
- * to the structure.
- */
- switch (tok)
- {
- case tok_choose:
- pnt = get_qstring(pnt, &kcfg->label);
- pnt = get_qstring(pnt, &kcfg->optionname);
- pnt = get_string(pnt, &kcfg->value);
- /*
- * Now we need to break apart the individual options into their
- * own configuration structures.
- */
- parse_choices(kcfg, kcfg->optionname);
- free(kcfg->optionname);
- sprintf(tmpbuf, "tmpvar_%d", choose_number++);
- kcfg->optionname = strdup(tmpbuf);
- break;
- case tok_define:
- pnt = get_string(pnt, &kcfg->optionname);
- if(*pnt == 'y' || *pnt == 'Y' ) kcfg->value = "1";
- if(*pnt == 'n' || *pnt == 'N' ) kcfg->value = "0";
- if(*pnt == 'm' || *pnt == 'M' ) kcfg->value = "2";
- break;
- case tok_menuname:
- pnt = get_qstring(pnt, &kcfg->label);
- break;
- case tok_bool:
- case tok_tristate:
- pnt = get_qstring(pnt, &kcfg->label);
- pnt = get_string(pnt, &kcfg->optionname);
- break;
- case tok_int:
- case tok_hex:
- case tok_string:
- pnt = get_qstring(pnt, &kcfg->label);
- pnt = get_string(pnt, &kcfg->optionname);
- pnt = get_string(pnt, &kcfg->value);
- break;
- case tok_dep_tristate:
- pnt = get_qstring(pnt, &kcfg->label);
- pnt = get_string(pnt, &kcfg->optionname);
- pnt = skip_whitespace(pnt);
+ /*
+ * Allocate an item.
+ */
+ cfg = malloc( sizeof(*cfg) );
+ memset( cfg, 0, sizeof(*cfg) );
+ if ( config_last == NULL )
+ { config_last = config_list = cfg; }
+ else
+ { config_last->next = cfg; config_last = cfg; }
- if ( ( pnt[0] == 'y' || pnt[0] == 'm' || pnt[0] == 'n' )
- && ( pnt[1] == '\0' || pnt[1] == ' ' || pnt[1] == '\t' ) ) {
- if ( pnt[0] == 'y' ) kcfg->depend.str = strdup( "CONSTANT_Y" );
- else if ( pnt[0] == 'm' ) kcfg->depend.str = strdup( "CONSTANT_M" );
- else kcfg->depend.str = strdup( "CONSTANT_N" );
- pnt++;
- } else if ( *pnt == '$' ) {
+ /*
+ * Tokenize the arguments.
+ */
+ while ( *pnt == ' ' || *pnt == '\t' )
pnt++;
- pnt = get_string(pnt, &kcfg->depend.str);
- } else {
- fprintf( stderr, "Can't handle dep_tristate condition\n" );
- exit( 1 );
- }
-
- /*
- * Create a conditional for this object's dependency.
- *
- * We can't use "!= n" because this is internally converted to "!= 0"
- * and if UMSDOS depends on MSDOS which depends on FAT, then when FAT
- * is disabled MSDOS has 16 added to its value, making UMSDOS fully
- * available. Whew.
- *
- * This is more of a hack than a fix. Nested "if" conditionals are
- * probably affected too - that +/- 16 affects things in too many
- * places. But this should do for now.
- */
- sprintf(fake_if,"[ \"$%s\" = \"y\" -o \"$%s\" = \"m\" ]; then",
- kcfg->depend.str,kcfg->depend.str);
- kcfg->cond = parse_if(fake_if);
- if(kcfg->cond == NULL )
+
+ cfg->token = token;
+ switch ( token )
+ {
+ default:
+ syntax_error( "unknown token" );
+
+ case token_bool:
+ case token_tristate:
+ pnt = get_qstring ( pnt, &cfg->label );
+ pnt = get_string ( pnt, &cfg->optionname );
+ break;
+
+ case token_choice_header:
{
- exit(1);
+ static int choose_number = 0;
+ char * choice_list;
+
+ pnt = get_qstring ( pnt, &cfg->label );
+ pnt = get_qstring ( pnt, &choice_list );
+ pnt = get_string ( pnt, &cfg->value );
+
+ cfg->optionname = malloc( 32 );
+ sprintf( cfg->optionname, "tmpvar_%d", choose_number++ );
+
+ tokenize_choices( cfg, choice_list );
+ free( choice_list );
}
- break;
- case tok_comment:
- pnt = get_qstring(pnt, &kcfg->label);
- if( koption != NULL )
- {
- pnt = get_qstring(pnt, &kcfg->label);
- koption->label = kcfg->label;
- koption = NULL;
+ break;
+
+ case token_comment:
+ pnt = get_qstring(pnt, &cfg->label);
+ if ( last_menuoption != NULL )
+ {
+ pnt = get_qstring(pnt, &cfg->label);
+ last_menuoption->label = cfg->label;
+ last_menuoption = NULL;
+ }
+ break;
+
+ case token_define_bool:
+ pnt = get_string( pnt, &cfg->optionname );
+#if ! defined(BUG_COMPATIBLE)
+ while ( *pnt == ' ' || *pnt == '\t' )
+ pnt++;
+#endif
+ if ( *pnt == 'n' || *pnt == 'N' ) cfg->value = "0";
+ else if ( *pnt == 'y' || *pnt == 'Y' ) cfg->value = "1";
+ else if ( *pnt == 'm' || *pnt == 'M' ) cfg->value = "2";
+ else
+ {
+#if ! defined(BUG_COMPATIBLE)
+ syntax_error( "unknown define_bool value" );
+#else
+ /*
+ * This ought to give the same output as printf'ing
+ * through the null pointer ... I don't want to be
+ * SIGSEGV compatible!
+ */
+ cfg->value = "(null)";
+#endif
}
- break;
- case tok_menuoption:
- if( strncmp(pnt, "next_comment", 12) == 0)
+ break;
+
+ case token_dep_tristate:
+ pnt = get_qstring ( pnt, &cfg->label );
+ pnt = get_string ( pnt, &cfg->optionname );
+
+ while ( *pnt == ' ' || *pnt == '\t' )
+ pnt++;
+
+ if ( ( pnt[0] == 'Y' || pnt[0] == 'M' || pnt[0] == 'N'
+ || pnt[0] == 'y' || pnt[0] == 'm' || pnt[0] == 'n' )
+ && ( pnt[1] == '\0' || pnt[1] == ' ' || pnt[1] == '\t' ) )
{
- koption = kcfg;
+ /* dep_tristate 'foo' CONFIG_FOO m */
+ if ( pnt[0] == 'Y' || pnt[0] == 'y' )
+ cfg->depend = strdup( "CONSTANT_Y" );
+ else if ( pnt[0] == 'M' || pnt[0] == 'm' )
+ cfg->depend = strdup( "CONSTANT_M" );
+ else
+ cfg->depend = strdup( "CONSTANT_N" );
+ pnt++;
}
- else
+ else if ( *pnt == '$' )
{
- pnt = get_qstring(pnt, &kcfg->label);
+ pnt++;
+ pnt = get_string( pnt, &cfg->depend );
}
- break;
- case tok_else:
- case tok_fi:
- case tok_endmenu:
- break;
- case tok_if:
- /*
- * Conditionals are different. For the first level parse, only
- * tok_if and tok_dep_tristate items have a ->cond chain attached.
- */
- kcfg->cond = parse_if(pnt);
- if(kcfg->cond == NULL )
+ else
{
- exit(1);
+ syntax_error( "can't handle dep_tristate condition" );
}
- break;
- default:
- exit(0);
- }
-
- return;
-}
-/*
- * Simple function to dump to the screen what the condition chain looks like.
- */
-void dump_if(struct condition * cond)
-{
- printf(" ");
- while(cond != NULL )
- {
- switch(cond->op){
- case op_eq:
- printf(" = ");
- break;
- case op_bang:
- printf(" ! ");
- break;
- case op_neq:
- printf(" != ");
+ /*
+ * Create a conditional for this object's dependency.
+ */
+ {
+ char fake_if [1024];
+ sprintf( fake_if, "[ \"$%s\" = \"y\" -o \"$%s\" = \"m\" ]; then",
+ cfg->depend, cfg->depend );
+ cfg->cond = tokenize_if( fake_if );
+ }
break;
- case op_and:
- printf(" -a ");
+
+ case token_else:
+ case token_endmenu:
+ case token_fi:
break;
- case op_lparen:
- printf("(");
+
+ case token_hex:
+ case token_int:
+ case token_string:
+ pnt = get_qstring ( pnt, &cfg->label );
+ pnt = get_string ( pnt, &cfg->optionname );
+ pnt = get_string ( pnt, &cfg->value );
break;
- case op_rparen:
- printf(")");
+
+ case token_if:
+ cfg->cond = tokenize_if( pnt );
break;
- case op_variable:
- printf("$%s", cond->variable.str);
+
+ case token_mainmenu_name:
+ pnt = get_qstring( pnt, &cfg->label );
break;
- case op_constant:
- printf("'%s'", cond->variable.str);
+
+ case token_mainmenu_option:
+ if ( strncmp( pnt, "next_comment", 12 ) == 0 )
+ last_menuoption = cfg;
+ else
+ pnt = get_qstring( pnt, &cfg->label );
break;
- default:
- break;
- }
- cond = cond->next;
}
- printf("\n");
+ return;
}
-static int do_source(char * filename)
+
+
+/*
+ * Implement the "source" command.
+ */
+static void do_source( const char * filename )
{
- char buffer[1024];
- int offset;
- int old_lineno;
- char * old_file = 0; /* superfluous, just for gcc */
- char * pnt;
- FILE * infile;
-
- if( strcmp(filename, "-") == 0 )
- infile = stdin;
- else
- infile = fopen(filename,"r");
-
- /*
- * If our cwd was in the scripts directory, we might have to go up one
- * to find the sourced file.
- */
- if(!infile) {
- strcpy (buffer, "../");
- strcat (buffer, filename);
- infile = fopen(buffer,"r");
- }
-
- if(!infile) {
- fprintf(stderr,"Unable to open file %s\n", filename);
- return 1;
- }
- old_lineno = lineno;
- lineno = 0;
- if( infile != stdin ) {
- old_file = current_file;
- current_file = filename;
- }
- offset = 0;
- while(1)
- {
- fgets(&buffer[offset], sizeof(buffer) - offset, infile);
- if(feof(infile)) break;
-
- /*
- * Strip the trailing return character.
- */
- pnt = buffer + strlen(buffer) - 1;
- if( *pnt == '\n') *pnt-- = 0;
- lineno++;
- if( *pnt == '\\' )
- {
- offset = pnt - buffer;
- }
- else
- {
- parse(buffer);
- offset = 0;
- }
+ char buffer [1024];
+ FILE * infile;
+ const char * old_file;
+ int old_lineno;
+ int offset;
+
+ /* open the file */
+ if ( strcmp( filename, "-" ) == 0 )
+ infile = stdin;
+ else
+ infile = fopen( filename, "r" );
+
+ /* if that failed, try ../filename */
+ if ( infile == NULL )
+ {
+ sprintf( buffer, "../%s", filename );
+ infile = fopen( buffer, "r" );
}
- if( infile != stdin ) {
- fclose(infile);
- current_file = old_file;
- }
- lineno = old_lineno;
- return 0;
-}
-int main(int argc, char * argv[])
-{
-#if 0
- char buffer[1024];
- char * pnt;
- struct kconfig * cfg;
- int i;
+ if ( infile == NULL )
+ {
+ sprintf( buffer, "unable to open %s", filename );
+#if defined(BUG_COMPATIBLE)
+ fprintf( stderr, "%s\n", buffer );
+ return;
+#else
+ syntax_error( buffer );
#endif
+ }
+
+ /* push the new file name and line number */
+ old_file = current_file;
+ old_lineno = lineno;
+ current_file = filename;
+ lineno = 0;
- /*
- * Read stdin to get the top level script.
- */
- do_source("-");
-
- if( menus_seen == 0 )
- {
- fprintf(stderr,"The config.in file for this platform does not support\n");
- fprintf(stderr,"menus.\n");
- exit(1);
- }
- /*
- * Input file is now parsed. Next we need to go through and attach
- * the correct conditions to each of the actual menu items and kill
- * the if/else/endif tokens from the list. We also flag the menu items
- * that have other things that depend upon its setting.
- */
- fix_conditionals(config);
-
- /*
- * Finally, we generate the wish script.
- */
- dump_tk_script(config);
-
-#if 0
- /*
- * Now dump what we have so far. This is only for debugging so that
- * we can display what we think we have in the list.
- */
- for(cfg = config; cfg; cfg = cfg->next)
+ /* read and process lines */
+ for ( offset = 0; ; )
{
+ char * pnt;
- if(cfg->cond != NULL && cfg->tok != tok_if)
- dump_if(cfg->cond);
+ /* read a line */
+ fgets( buffer + offset, sizeof(buffer) - offset, infile );
+ if ( feof( infile ) )
+ break;
+ lineno++;
- switch(cfg->tok)
- {
- case tok_menuname:
- printf("main_menuname ");
- break;
- case tok_bool:
- printf("bool ");
- break;
- case tok_tristate:
- printf("tristate ");
- break;
- case tok_dep_tristate:
- printf("dep_tristate ");
- break;
- case tok_int:
- printf("int ");
- break;
- case tok_hex:
- printf("hex ");
- break;
- case tok_string:
- printf("istring ");
- break;
- case tok_comment:
- printf("comment ");
- break;
- case tok_menuoption:
- printf("menuoption ");
- break;
- case tok_else:
- printf("else");
- break;
- case tok_fi:
- printf("fi");
- break;
- case tok_if:
- printf("if");
- break;
- default:
- }
+ /* strip the trailing return character */
+ pnt = buffer + strlen(buffer) - 1;
+ if ( *pnt == '\n' )
+ *pnt-- = '\0';
- switch(cfg->tok)
+ /* eat \ NL pairs */
+ if ( *pnt == '\\' )
{
- case tok_menuoption:
- case tok_comment:
- case tok_menuname:
- printf("%s\n", cfg->label);
- break;
- case tok_bool:
- case tok_tristate:
- case tok_dep_tristate:
- case tok_int:
- case tok_hex:
- case tok_string:
- printf("%s %s\n", cfg->label, cfg->optionname);
- break;
- case tok_if:
- dump_if(cfg->cond);
- break;
- case tok_nop:
- case tok_endmenu:
- break;
- default:
- printf("\n");
+ offset = pnt - buffer;
+ continue;
}
+
+ /* tokenize this line */
+ tokenize_line( buffer );
+ offset = 0;
}
-#endif
- return 0;
+ /* that's all, folks */
+ if ( infile != stdin )
+ fclose( infile );
+ current_file = old_file;
+ lineno = old_lineno;
+ return;
+}
+
+
+/*
+ * Main program.
+ */
+int main( int argc, const char * argv [] )
+{
+ do_source ( "-" );
+ fix_conditionals ( config_list );
+ dump_tk_script ( config_list );
+ return 0;
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov