| /* |
| * tkparse.c |
| * |
| * Eric Youngdale was the original author of xconfig. |
| * Michael Elizabeth Chastain (mec@shout.net) is the current maintainer. |
| * |
| * Parse a config.in file and translate it to a wish script. |
| * This task has three parts: |
| * |
| * tkparse.c tokenize the input |
| * tkcond.c transform 'if ...' statements |
| * tkgen.c generate output |
| * |
| * Change History |
| * |
| * 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. |
| * |
| * 23 January 1999, Michael Elizabeth Chastain, <mec@shout.net> |
| * - Remove bug-compatible code. |
| * |
| * 07 July 1999, Andrzej M. Krzysztofowicz, <ankry@mif.pg.gda.pl> |
| * - Submenus implemented, |
| * - plenty of option updating/displaying fixes, |
| * - dep_bool, define_hex, define_int, define_string, define_tristate and |
| * undef implemented, |
| * - dep_tristate fixed to support multiple dependencies, |
| * - handling of variables with an empty value implemented, |
| * - value checking for int and hex fields, |
| * - more checking during condition parsing; choice variables are treated as |
| * all others now, |
| * |
| * 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 <stdio.h> |
| #include <stdlib.h> |
| #include <string.h> |
| |
| #include "tkparse.h" |
| |
| static struct kconfig * config_list = NULL; |
| static struct kconfig * config_last = NULL; |
| static const char * current_file = "<unknown file>"; |
| static int lineno = 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 |
| |
| /* |
| * Report a syntax error. |
| */ |
| static void syntax_error( const char * msg ) |
| { |
| fprintf( stderr, "%s: %d: %s\n", current_file, lineno, msg ); |
| exit( 1 ); |
| } |
| |
| |
| |
| /* |
| * Find index of a specyfic variable in the symbol table. |
| * Create a new entry if it does not exist yet. |
| */ |
| #define VARTABLE_SIZE 4096 |
| struct variable vartable[VARTABLE_SIZE]; |
| int max_varnum = 0; |
| |
| int get_varnum( char * name ) |
| { |
| int i; |
| |
| for ( i = 1; i <= max_varnum; i++ ) |
| if ( strcmp( vartable[i].name, name ) == 0 ) |
| return i; |
| if (max_varnum > VARTABLE_SIZE-1) |
| syntax_error( "Too many variables defined." ); |
| vartable[++max_varnum].name = malloc( strlen( name )+1 ); |
| strcpy( vartable[max_varnum].name, name ); |
| return max_varnum; |
| } |
| |
| |
| |
| /* |
| * Get a string. |
| */ |
| static const char * get_string( const char * pnt, char ** label ) |
| { |
| const char * word; |
| |
| word = pnt; |
| for ( ; ; ) |
| { |
| if ( *pnt == '\0' || *pnt == ' ' || *pnt == '\t' ) |
| break; |
| pnt++; |
| } |
| |
| *label = malloc( pnt - word + 1 ); |
| memcpy( *label, word, pnt - word ); |
| (*label)[pnt - word] = '\0'; |
| |
| if ( *pnt != '\0' ) |
| pnt++; |
| return pnt; |
| } |
| |
| |
| |
| /* |
| * Get a quoted string. |
| * Insert a '\' before any characters that need quoting. |
| */ |
| static const char * get_qstring( const char * pnt, char ** label ) |
| { |
| char quote_char; |
| char newlabel [2048]; |
| char * pnt1; |
| |
| /* advance to the open quote */ |
| for ( ; ; ) |
| { |
| if ( *pnt == '\0' ) |
| return pnt; |
| quote_char = *pnt++; |
| if ( quote_char == '"' || quote_char == '\'' ) |
| break; |
| } |
| |
| /* copy into an intermediate buffer */ |
| pnt1 = newlabel; |
| for ( ; ; ) |
| { |
| if ( *pnt == '\0' ) |
| syntax_error( "unterminated quoted string" ); |
| if ( *pnt == quote_char && pnt[-1] != '\\' ) |
| break; |
| |
| /* 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; |
| } |
| |
| |
| |
| /* |
| * Get a quoted or unquoted string. It is recognized by the first |
| * non-white character. '"' and '"' are not allowed inside the string. |
| */ |
| static const char * get_qnqstring( const char * pnt, char ** label ) |
| { |
| char quote_char; |
| |
| while ( *pnt == ' ' || *pnt == '\t' ) |
| pnt++; |
| |
| if ( *pnt == '\0' ) |
| return pnt; |
| quote_char = *pnt; |
| if ( quote_char == '"' || quote_char == '\'' ) |
| return get_qstring( pnt, label ); |
| else |
| return get_string( pnt, label ); |
| } |
| |
| |
| |
| /* |
| * Tokenize an 'if' statement condition. |
| */ |
| static struct condition * tokenize_if( const char * pnt ) |
| { |
| struct condition * list; |
| struct condition * last; |
| struct condition * prev; |
| |
| /* eat the open bracket */ |
| while ( *pnt == ' ' || *pnt == '\t' ) |
| pnt++; |
| if ( *pnt != '[' ) |
| syntax_error( "bad 'if' condition" ); |
| pnt++; |
| |
| list = last = NULL; |
| for ( ; ; ) |
| { |
| 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; prev = NULL; } |
| else |
| { prev = last; last->next = cond; last = cond; } |
| |
| /* determine the token value */ |
| if ( *pnt == '-' && pnt[1] == 'a' ) |
| { |
| if ( ! prev || ( prev->op != op_variable && prev->op != op_constant ) ) |
| syntax_error( "incorrect argument" ); |
| cond->op = op_and; pnt += 2; continue; |
| } |
| |
| if ( *pnt == '-' && pnt[1] == 'o' ) |
| { |
| if ( ! prev || ( prev->op != op_variable && prev->op != op_constant ) ) |
| syntax_error( "incorrect argument" ); |
| cond->op = op_or; pnt += 2; continue; |
| } |
| |
| if ( *pnt == '!' && pnt[1] == '=' ) |
| { |
| if ( ! prev || ( prev->op != op_variable && prev->op != op_constant ) ) |
| syntax_error( "incorrect argument" ); |
| cond->op = op_neq; pnt += 2; continue; |
| } |
| |
| if ( *pnt == '=' ) |
| { |
| if ( ! prev || ( prev->op != op_variable && prev->op != op_constant ) ) |
| syntax_error( "incorrect argument" ); |
| cond->op = op_eq; pnt += 1; continue; |
| } |
| |
| if ( *pnt == '!' ) |
| { |
| if ( prev && ( prev->op != op_and && prev->op != op_or |
| && prev->op != op_bang ) ) |
| syntax_error( "incorrect argument" ); |
| cond->op = op_bang; pnt += 1; continue; |
| } |
| |
| if ( *pnt == '"' ) |
| { |
| const char * word; |
| |
| if ( prev && ( prev->op == op_variable || prev->op == op_constant ) ) |
| syntax_error( "incorrect argument" ); |
| /* 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'; |
| if ( cond->op == op_variable ) |
| { |
| cond->nameindex = get_varnum( str ); |
| free( str ); |
| } |
| else /* op_constant */ |
| { |
| cond->str = str; |
| } |
| } |
| |
| pnt++; |
| continue; |
| } |
| |
| /* unknown token */ |
| syntax_error( "bad if condition" ); |
| } |
| } |
| |
| |
| |
| /* |
| * 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 ) |
| { |
| int default_checked = 0; |
| for ( ; ; ) |
| { |
| struct kconfig * cfg; |
| char * buffer = malloc( 64 ); |
| |
| /* 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 ); |
| if ( ! default_checked && |
| ! strncmp( cfg->label, cfg_choose->value, strlen( cfg_choose->value ) ) ) |
| { |
| default_checked = 1; |
| free( cfg_choose->value ); |
| cfg_choose->value = cfg->label; |
| } |
| while ( *pnt == ' ' || *pnt == '\t' ) |
| pnt++; |
| pnt = get_string( pnt, &buffer ); |
| cfg->nameindex = get_varnum( buffer ); |
| } |
| if ( ! default_checked ) |
| syntax_error( "bad 'choice' default value" ); |
| return pnt; |
| } |
| |
| |
| |
| /* |
| * Tokenize one line. |
| */ |
| static void tokenize_line( const char * pnt ) |
| { |
| static struct kconfig * last_menuoption = NULL; |
| enum e_token token; |
| struct kconfig * cfg; |
| struct dependency ** dep_ptr; |
| char * buffer = malloc( 64 ); |
| |
| /* skip white space */ |
| while ( *pnt == ' ' || *pnt == '\t' ) |
| pnt++; |
| |
| /* |
| * categorize the next token |
| */ |
| |
| #define match_token(t, s) \ |
| if (strncmp(pnt, s, strlen(s)) == 0) { token = t; pnt += strlen(s); break; } |
| |
| token = token_UNKNOWN; |
| switch ( *pnt ) |
| { |
| 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_define_hex, "define_hex" ); |
| match_token( token_define_int, "define_int" ); |
| match_token( token_define_string, "define_string" ); |
| match_token( token_define_tristate, "define_tristate" ); |
| match_token( token_dep_bool, "dep_bool" ); |
| match_token( token_dep_mbool, "dep_mbool" ); |
| 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; |
| } |
| |
| #undef match_token |
| |
| if ( token == token_source ) |
| { |
| while ( *pnt == ' ' || *pnt == '\t' ) |
| pnt++; |
| do_source( pnt ); |
| return; |
| } |
| |
| if ( token == token_then ) |
| { |
| if ( config_last != NULL && config_last->token == token_if ) |
| return; |
| syntax_error( "bogus 'then'" ); |
| } |
| |
| #if 0 |
| if ( token == token_unset ) |
| { |
| fprintf( stderr, "Ignoring 'unset' command\n" ); |
| return; |
| } |
| #endif |
| |
| if ( token == token_UNKNOWN ) |
| syntax_error( "unknown command" ); |
| |
| /* |
| * 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; } |
| |
| /* |
| * Tokenize the arguments. |
| */ |
| while ( *pnt == ' ' || *pnt == '\t' ) |
| pnt++; |
| |
| 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, &buffer ); |
| cfg->nameindex = get_varnum( buffer ); |
| break; |
| |
| case token_choice_header: |
| { |
| 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->nameindex = -(choose_number++); |
| tokenize_choices( cfg, choice_list ); |
| free( choice_list ); |
| } |
| break; |
| |
| case token_comment: |
| pnt = get_qstring(pnt, &cfg->label); |
| if ( last_menuoption != NULL ) |
| { |
| pnt = get_qstring(pnt, &cfg->label); |
| if (cfg->label == NULL) |
| syntax_error( "missing comment text" ); |
| last_menuoption->label = cfg->label; |
| last_menuoption = NULL; |
| } |
| break; |
| |
| case token_define_bool: |
| case token_define_tristate: |
| pnt = get_string( pnt, &buffer ); |
| cfg->nameindex = get_varnum( buffer ); |
| 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' ) ) |
| { |
| if ( *pnt == 'n' || *pnt == 'N' ) cfg->value = strdup( "CONSTANT_N" ); |
| else if ( *pnt == 'y' || *pnt == 'Y' ) cfg->value = strdup( "CONSTANT_Y" ); |
| else if ( *pnt == 'm' || *pnt == 'M' ) cfg->value = strdup( "CONSTANT_M" ); |
| } |
| else if ( *pnt == '$' ) |
| { |
| pnt++; |
| pnt = get_string( pnt, &cfg->value ); |
| } |
| else |
| { |
| syntax_error( "unknown define_bool value" ); |
| } |
| get_varnum( cfg->value ); |
| break; |
| |
| case token_define_hex: |
| case token_define_int: |
| pnt = get_string( pnt, &buffer ); |
| cfg->nameindex = get_varnum( buffer ); |
| pnt = get_string( pnt, &cfg->value ); |
| break; |
| |
| case token_define_string: |
| pnt = get_string( pnt, &buffer ); |
| cfg->nameindex = get_varnum( buffer ); |
| pnt = get_qnqstring( pnt, &cfg->value ); |
| if (cfg->value == NULL) |
| syntax_error( "missing value" ); |
| break; |
| |
| case token_dep_bool: |
| case token_dep_mbool: |
| case token_dep_tristate: |
| pnt = get_qstring ( pnt, &cfg->label ); |
| pnt = get_string ( pnt, &buffer ); |
| cfg->nameindex = get_varnum( buffer ); |
| |
| while ( *pnt == ' ' || *pnt == '\t' ) |
| pnt++; |
| |
| dep_ptr = &(cfg->depend); |
| |
| do { |
| *dep_ptr = (struct dependency *) malloc( sizeof( struct dependency ) ); |
| (*dep_ptr)->next = NULL; |
| |
| 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' ) ) |
| { |
| /* dep_tristate 'foo' CONFIG_FOO m */ |
| if ( pnt[0] == 'Y' || pnt[0] == 'y' ) |
| (*dep_ptr)->name = strdup( "CONSTANT_Y" ); |
| else if ( pnt[0] == 'N' || pnt[0] == 'n' ) |
| (*dep_ptr)->name = strdup( "CONSTANT_N" ); |
| else |
| (*dep_ptr)->name = strdup( "CONSTANT_M" ); |
| pnt++; |
| get_varnum( (*dep_ptr)->name ); |
| } |
| else if ( *pnt == '$' ) |
| { |
| pnt++; |
| pnt = get_string( pnt, &(*dep_ptr)->name ); |
| get_varnum( (*dep_ptr)->name ); |
| } |
| else |
| { |
| syntax_error( "can't handle dep_bool/dep_mbool/dep_tristate condition" ); |
| } |
| dep_ptr = &(*dep_ptr)->next; |
| while ( *pnt == ' ' || *pnt == '\t' ) |
| pnt++; |
| } while ( *pnt ); |
| |
| /* |
| * Create a conditional for this object's dependencies. |
| */ |
| { |
| char fake_if [1024]; |
| struct dependency * dep; |
| struct condition ** cond_ptr; |
| int first = 1; |
| |
| cond_ptr = &(cfg->cond); |
| for ( dep = cfg->depend; dep; dep = dep->next ) |
| { |
| if ( token == token_dep_tristate |
| && ! strcmp( dep->name, "CONSTANT_M" ) ) |
| { |
| continue; |
| } |
| if ( first ) |
| { |
| first = 0; |
| } |
| else |
| { |
| *cond_ptr = malloc( sizeof(struct condition) ); |
| memset( *cond_ptr, 0, sizeof(struct condition) ); |
| (*cond_ptr)->op = op_and; |
| cond_ptr = &(*cond_ptr)->next; |
| } |
| *cond_ptr = malloc( sizeof(struct condition) ); |
| memset( *cond_ptr, 0, sizeof(struct condition) ); |
| (*cond_ptr)->op = op_lparen; |
| if ( token == token_dep_bool ) |
| sprintf( fake_if, "[ \"$%s\" = \"y\" -o \"$%s\" = \"\" ]; then", |
| dep->name, dep->name ); |
| else |
| sprintf( fake_if, "[ \"$%s\" = \"y\" -o \"$%s\" = \"m\" -o \"$%s\" = \"\" ]; then", |
| dep->name, dep->name, dep->name ); |
| (*cond_ptr)->next = tokenize_if( fake_if ); |
| while ( *cond_ptr ) |
| cond_ptr = &(*cond_ptr)->next; |
| *cond_ptr = malloc( sizeof(struct condition) ); |
| memset( *cond_ptr, 0, sizeof(struct condition) ); |
| (*cond_ptr)->op = op_rparen; |
| cond_ptr = &(*cond_ptr)->next; |
| } |
| } |
| break; |
| |
| case token_else: |
| case token_endmenu: |
| case token_fi: |
| break; |
| |
| case token_hex: |
| case token_int: |
| pnt = get_qstring ( pnt, &cfg->label ); |
| pnt = get_string ( pnt, &buffer ); |
| cfg->nameindex = get_varnum( buffer ); |
| pnt = get_string ( pnt, &cfg->value ); |
| break; |
| |
| case token_string: |
| pnt = get_qstring ( pnt, &cfg->label ); |
| pnt = get_string ( pnt, &buffer ); |
| cfg->nameindex = get_varnum( buffer ); |
| pnt = get_qnqstring ( pnt, &cfg->value ); |
| if (cfg->value == NULL) |
| syntax_error( "missing initial value" ); |
| break; |
| |
| case token_if: |
| cfg->cond = tokenize_if( pnt ); |
| break; |
| |
| case token_mainmenu_name: |
| pnt = get_qstring( pnt, &cfg->label ); |
| break; |
| |
| case token_mainmenu_option: |
| if ( strncmp( pnt, "next_comment", 12 ) == 0 ) |
| last_menuoption = cfg; |
| else |
| pnt = get_qstring( pnt, &cfg->label ); |
| break; |
| |
| case token_unset: |
| pnt = get_string( pnt, &buffer ); |
| cfg->nameindex = get_varnum( buffer ); |
| while ( *pnt == ' ' || *pnt == '\t' ) |
| pnt++; |
| while (*pnt) |
| { |
| cfg->next = (struct kconfig *) malloc( sizeof(struct kconfig) ); |
| memset( cfg->next, 0, sizeof(struct kconfig) ); |
| cfg = cfg->next; |
| cfg->token = token_unset; |
| pnt = get_string( pnt, &buffer ); |
| cfg->nameindex = get_varnum( buffer ); |
| while ( *pnt == ' ' || *pnt == '\t' ) |
| pnt++; |
| } |
| break; |
| } |
| return; |
| } |
| |
| |
| |
| /* |
| * Implement the "source" command. |
| */ |
| static void do_source( const char * filename ) |
| { |
| char buffer [2048]; |
| 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 == NULL ) |
| { |
| sprintf( buffer, "unable to open %s", filename ); |
| syntax_error( buffer ); |
| } |
| |
| /* push the new file name and line number */ |
| old_file = current_file; |
| old_lineno = lineno; |
| current_file = filename; |
| lineno = 0; |
| |
| /* read and process lines */ |
| for ( offset = 0; ; ) |
| { |
| char * pnt; |
| |
| /* read a line */ |
| fgets( buffer + offset, sizeof(buffer) - offset, infile ); |
| if ( feof( infile ) ) |
| break; |
| lineno++; |
| |
| /* strip the trailing return character */ |
| pnt = buffer + strlen(buffer) - 1; |
| if ( *pnt == '\n' ) |
| *pnt-- = '\0'; |
| |
| /* eat \ NL pairs */ |
| if ( *pnt == '\\' ) |
| { |
| offset = pnt - buffer; |
| continue; |
| } |
| |
| /* tokenize this line */ |
| tokenize_line( buffer ); |
| offset = 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; |
| } |