123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755 |
- /* parser config.in
- * $Id: tkparse.c 2281 2010-10-15 14:21:13Z smasson $
- *
- * This software is governed by the CeCILL license
- * See IOIPSL/IOIPSL_License_CeCILL.txt
- *
- * 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 do the first parse of config.in.
- */
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include "tkparse.h"
- struct kconfig * config = NULL;
- struct kconfig * clast = NULL;
- struct kconfig * koption = NULL;
- 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;
- /*
- * Simple function just to skip over spaces and tabs in config.in.
- */
- static char * skip_whitespace(char * pnt)
- {
- while( *pnt && (*pnt == ' ' || *pnt == '\t')) pnt++;
- return pnt;
- }
- /*
- * 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.
- */
- static struct condition * parse_if(char * pnt)
- {
- 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 != ']') {
- 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;
- }
- /*
- * 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;
- }
- 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;
- 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;
- }
- /*
- * 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.
- */
- static char * get_qstring(char *pnt, char ** labl)
- {
- 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;
- }
- static char * parse_choices(struct kconfig * choice_kcfg, char * pnt)
- {
- struct kconfig * kcfg;
- int index = 1;
- /*
- * 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;
- }
- 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;
- }
-
- 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.
- */
- static char * get_string(char *pnt, char ** labl)
- {
- char newlabel[1024];
- char * pnt1;
- char * pnt2;
- if (*pnt == '\0') return pnt;
- pnt1 = newlabel;
- while(*pnt && *pnt != ' ' && *pnt != '\t')
- {
- *pnt1++ = *pnt++;
- }
- *pnt1++ = '\0';
- pnt2 = (char *) malloc(strlen(newlabel) + 1);
- strcpy(pnt2, newlabel);
- *labl = pnt2;
- if( *pnt ) pnt++;
- 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.
- */
- void parse(char * pnt) {
- enum token tok;
- struct kconfig * kcfg;
- char tmpbuf[24],fake_if[1024];
- /*
- * Ignore comments and leading whitespace.
- */
- pnt = skip_whitespace(pnt);
- while( *pnt && (*pnt == ' ' || *pnt == '\t')) pnt++;
- if(! *pnt ) return;
- if( *pnt == '#' ) return;
- /*
- * 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, "$MAKE ", 6) == 0)
- {
- tok = tok_make;
- }
- 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, "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)
- {
- tok = tok_endmenu;
- pnt += 7;
- }
- if( tok == tok_unknown)
- {
- 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;
- }
- /*
- * 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 )
- {
- clast->next = kcfg;
- clast = kcfg;
- }
- else
- {
- clast = config = kcfg;
- }
- pnt = skip_whitespace(pnt);
- /*
- * 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:
- 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);
- if( *pnt == '$') pnt++;
- pnt = get_string(pnt, &kcfg->depend.str);
- /*
- * 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 )
- {
- exit(1);
- }
- 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 tok_menuoption:
- if( strncmp(pnt, "next_comment", 12) == 0)
- {
- koption = kcfg;
- }
- else
- {
- pnt = get_qstring(pnt, &kcfg->label);
- }
- break;
- case tok_make:
- kcfg->value=strdup(pnt);
- 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 )
- {
- exit(1);
- }
- 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(" != ");
- break;
- case op_and:
- printf(" -a ");
- break;
- case op_lparen:
- printf("(");
- break;
- case op_rparen:
- printf(")");
- break;
- case op_variable:
- printf("$%s", cond->variable.str);
- break;
- case op_constant:
- printf("'%s'", cond->variable.str);
- break;
- default:
- break;
- }
- cond = cond->next;
- }
- printf("\n");
- }
- static int do_source(char * filename)
- {
- char buffer[1024];
- int offset;
- int old_lineno;
- char * old_file;
- 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;
- }
- }
- fclose(infile);
- if( infile != stdin ) {
- 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;
- #endif
- /*
- * 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)
- {
- if(cfg->cond != NULL && cfg->tok != tok_if)
- dump_if(cfg->cond);
- 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_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:
- }
- switch(cfg->tok)
- {
- 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:
- 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");
- }
- }
- #endif
- return 0;
- }
|