tkparse.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:19k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

  1. /*
  2.  * tkparse.c
  3.  *
  4.  * Eric Youngdale was the original author of xconfig.
  5.  * Michael Elizabeth Chastain (mec@shout.net) is the current maintainer.
  6.  *
  7.  * Parse a config.in file and translate it to a wish script.
  8.  * This task has three parts:
  9.  *
  10.  *   tkparse.c tokenize the input
  11.  *   tkcond.c   transform 'if ...' statements
  12.  *   tkgen.c    generate output
  13.  *
  14.  * Change History
  15.  *
  16.  * 7 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
  17.  * - Teach dep_tristate about a few literals, such as:
  18.  *     dep_tristate 'foo' CONFIG_FOO m
  19.  *   Also have it print an error message and exit on some parse failures.
  20.  *
  21.  * 14 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
  22.  * - Don't fclose stdin.  Thanks to Tony Hoyle for nailing this one.
  23.  *
  24.  * 14 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
  25.  * - Steam-clean this file.  I tested this by generating kconfig.tk for
  26.  *   every architecture and comparing it character-for-character against
  27.  *   the output of the old tkparse.
  28.  *
  29.  * 23 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
  30.  * - Remove bug-compatible code.
  31.  *
  32.  * 07 July 1999, Andrzej M. Krzysztofowicz, <ankry@mif.pg.gda.pl>
  33.  * - Submenus implemented,
  34.  * - plenty of option updating/displaying fixes,
  35.  * - dep_bool, define_hex, define_int, define_string, define_tristate and
  36.  *   undef implemented,
  37.  * - dep_tristate fixed to support multiple dependencies,
  38.  * - handling of variables with an empty value implemented,
  39.  * - value checking for int and hex fields,
  40.  * - more checking during condition parsing; choice variables are treated as
  41.  *   all others now,
  42.  *
  43.  * TO DO:
  44.  * - xconfig is at the end of its life cycle.  Contact <mec@shout.net> if
  45.  *   you are interested in working on the replacement.
  46.  */
  47. #include <stdio.h>
  48. #include <stdlib.h>
  49. #include <string.h>
  50. #include "tkparse.h"
  51. static struct kconfig * config_list = NULL;
  52. static struct kconfig * config_last = NULL;
  53. static const char * current_file = "<unknown file>";
  54. static int lineno = 0;
  55. static void do_source( const char * );
  56. #undef strcmp
  57. int my_strcmp( const char * s1, const char * s2 ) { return strcmp( s1, s2 ); }
  58. #define strcmp my_strcmp
  59. /*
  60.  * Report a syntax error.
  61.  */
  62. static void syntax_error( const char * msg )
  63. {
  64.     fprintf( stderr, "%s: %d: %sn", current_file, lineno, msg );
  65.     exit( 1 );
  66. }
  67. /*
  68.  * Find index of a specyfic variable in the symbol table.
  69.  * Create a new entry if it does not exist yet.
  70.  */
  71. #define VARTABLE_SIZE 2048
  72. struct variable vartable[VARTABLE_SIZE];
  73. int max_varnum = 0;
  74. int get_varnum( char * name )
  75. {
  76.     int i;
  77.     
  78.     for ( i = 1; i <= max_varnum; i++ )
  79. if ( strcmp( vartable[i].name, name ) == 0 )
  80.     return i;
  81.     if (max_varnum > VARTABLE_SIZE-1)
  82. syntax_error( "Too many variables defined." );
  83.     vartable[++max_varnum].name = malloc( strlen( name )+1 );
  84.     strcpy( vartable[max_varnum].name, name );
  85.     return max_varnum;
  86. }
  87. /*
  88.  * Get a string.
  89.  */
  90. static const char * get_string( const char * pnt, char ** label )
  91. {
  92.     const char * word;
  93.     word = pnt;
  94.     for ( ; ; )
  95.     {
  96. if ( *pnt == '' || *pnt == ' ' || *pnt == 't' )
  97.     break;
  98. pnt++;
  99.     }
  100.     *label = malloc( pnt - word + 1 );
  101.     memcpy( *label, word, pnt - word );
  102.     (*label)[pnt - word] = '';
  103.     if ( *pnt != '' )
  104. pnt++;
  105.     return pnt;
  106. }
  107. /*
  108.  * Get a quoted string.
  109.  * Insert a '' before any characters that need quoting.
  110.  */
  111. static const char * get_qstring( const char * pnt, char ** label )
  112. {
  113.     char quote_char;
  114.     char newlabel [2048];
  115.     char * pnt1;
  116.     /* advance to the open quote */
  117.     for ( ; ; )
  118.     {
  119. if ( *pnt == '' )
  120.     return pnt;
  121. quote_char = *pnt++;
  122. if ( quote_char == '"' || quote_char == ''' )
  123.     break;
  124.     }
  125.     /* copy into an intermediate buffer */
  126.     pnt1 = newlabel;
  127.     for ( ; ; )
  128.     {
  129. if ( *pnt == '' )
  130.     syntax_error( "unterminated quoted string" );
  131. if ( *pnt == quote_char && pnt[-1] != '\' )
  132.     break;
  133. /* copy the character, quoting if needed */
  134. if ( *pnt == '"' || *pnt == ''' || *pnt == '[' || *pnt == ']' )
  135.     *pnt1++ = '\';
  136. *pnt1++ = *pnt++;
  137.     }
  138.     /* copy the label into a permanent location */
  139.     *pnt1++ = '';
  140.     *label = (char *) malloc( pnt1 - newlabel );
  141.     memcpy( *label, newlabel, pnt1 - newlabel );
  142.     /* skip over last quote and next whitespace */
  143.     pnt++;
  144.     while ( *pnt == ' ' || *pnt == 't' )
  145. pnt++;
  146.     return pnt;
  147. }
  148. /*
  149.  * Get a quoted or unquoted string. It is recognized by the first 
  150.  * non-white character. '"' and '"' are not allowed inside the string.
  151.  */
  152. static const char * get_qnqstring( const char * pnt, char ** label )
  153. {
  154.     char quote_char;
  155.     while ( *pnt == ' ' || *pnt == 't' )
  156. pnt++;
  157.     if ( *pnt == '' )
  158. return pnt;
  159.     quote_char = *pnt;
  160.     if ( quote_char == '"' || quote_char == ''' )
  161. return get_qstring( pnt, label );
  162.     else
  163. return get_string( pnt, label );
  164. }
  165. /*
  166.  * Tokenize an 'if' statement condition.
  167.  */
  168. static struct condition * tokenize_if( const char * pnt )
  169. {
  170.     struct condition * list;
  171.     struct condition * last;
  172.     struct condition * prev;
  173.     /* eat the open bracket */
  174.     while ( *pnt == ' ' || *pnt == 't' )
  175. pnt++;
  176.     if ( *pnt != '[' )
  177. syntax_error( "bad 'if' condition" );
  178.     pnt++;
  179.     list = last = NULL;
  180.     for ( ; ; )
  181.     {
  182. struct condition * cond;
  183. /* advance to the next token */
  184. while ( *pnt == ' ' || *pnt == 't' )
  185.     pnt++;
  186. if ( *pnt == '' )
  187.     syntax_error( "unterminated 'if' condition" );
  188. if ( *pnt == ']' )
  189.     return list;
  190. /* allocate a new token */
  191. cond = malloc( sizeof(*cond) );
  192. memset( cond, 0, sizeof(*cond) );
  193. if ( last == NULL )
  194.     { list = last = cond; prev = NULL; }
  195. else
  196.     { prev = last; last->next = cond; last = cond; }
  197. /* determine the token value */
  198. if ( *pnt == '-' && pnt[1] == 'a' )
  199. {
  200.     if ( ! prev || ( prev->op != op_variable && prev->op != op_constant ) )
  201. syntax_error( "incorrect argument" );
  202.     cond->op = op_and;  pnt += 2; continue;
  203. }
  204. if ( *pnt == '-' && pnt[1] == 'o' )
  205. {
  206.     if ( ! prev || ( prev->op != op_variable && prev->op != op_constant ) )
  207. syntax_error( "incorrect argument" );
  208.     cond->op = op_or;   pnt += 2; continue;
  209. }
  210. if ( *pnt == '!' && pnt[1] == '=' )
  211. {
  212.     if ( ! prev || ( prev->op != op_variable && prev->op != op_constant ) )
  213. syntax_error( "incorrect argument" );
  214.     cond->op = op_neq;  pnt += 2; continue;
  215. }
  216. if ( *pnt == '=' )
  217. {
  218.     if ( ! prev || ( prev->op != op_variable && prev->op != op_constant ) )
  219. syntax_error( "incorrect argument" );
  220.     cond->op = op_eq;   pnt += 1; continue;
  221. }
  222. if ( *pnt == '!' )
  223. {
  224.     if ( prev && ( prev->op != op_and && prev->op != op_or
  225.       && prev->op != op_bang ) )
  226. syntax_error( "incorrect argument" );
  227.     cond->op = op_bang; pnt += 1; continue;
  228. }
  229. if ( *pnt == '"' )
  230. {
  231.     const char * word;
  232.     if ( prev && ( prev->op == op_variable || prev->op == op_constant ) )
  233. syntax_error( "incorrect argument" );
  234.     /* advance to the word */
  235.     pnt++;
  236.     if ( *pnt == '$' )
  237. { cond->op = op_variable; pnt++; }
  238.     else
  239. { cond->op = op_constant; }
  240.     /* find the end of the word */
  241.     word = pnt;
  242.     for ( ; ; )
  243.     {
  244. if ( *pnt == '' )
  245.     syntax_error( "unterminated double quote" );
  246. if ( *pnt == '"' )
  247.     break;
  248. pnt++;
  249.     }
  250.     /* store a copy of this word */
  251.     {
  252. char * str = malloc( pnt - word + 1 );
  253. memcpy( str, word, pnt - word );
  254. str [pnt - word] = '';
  255. if ( cond->op == op_variable )
  256. {
  257.     cond->nameindex = get_varnum( str );
  258.     free( str );
  259. }
  260. else /* op_constant */
  261. {
  262.     cond->str = str;
  263. }
  264.     }
  265.     pnt++;
  266.     continue;
  267. }
  268. /* unknown token */
  269. syntax_error( "bad if condition" );
  270.     }
  271. }
  272. /*
  273.  * Tokenize a choice list.  Choices appear as pairs of strings;
  274.  * note that I am parsing *inside* the double quotes.  Ugh.
  275.  */
  276. static const char * tokenize_choices( struct kconfig * cfg_choose,
  277.     const char * pnt )
  278. {
  279.     int default_checked = 0;
  280.     for ( ; ; )
  281.     {
  282. struct kconfig * cfg;
  283. char * buffer = malloc( 64 );
  284. /* skip whitespace */
  285. while ( *pnt == ' ' || *pnt == 't' )
  286.     pnt++;
  287. if ( *pnt == '' )
  288.     return pnt;
  289. /* allocate a new kconfig line */
  290. cfg = malloc( sizeof(*cfg) );
  291. memset( cfg, 0, sizeof(*cfg) );
  292. if ( config_last == NULL )
  293.     { config_last = config_list = cfg; }
  294. else
  295.     { config_last->next = cfg; config_last = cfg; }
  296. /* fill out the line */
  297. cfg->token      = token_choice_item;
  298. cfg->cfg_parent = cfg_choose;
  299. pnt = get_string( pnt, &cfg->label );
  300. if ( ! default_checked &&
  301.      ! strncmp( cfg->label, cfg_choose->value, strlen( cfg_choose->value ) ) )
  302. {
  303.     default_checked = 1;
  304.     free( cfg_choose->value );
  305.     cfg_choose->value = cfg->label;
  306. }
  307. while ( *pnt == ' ' || *pnt == 't' )
  308.     pnt++;
  309. pnt = get_string( pnt, &buffer );
  310. cfg->nameindex = get_varnum( buffer );
  311.     }
  312.     if ( ! default_checked )
  313. syntax_error( "bad 'choice' default value" );
  314.     return pnt;
  315. }
  316. /*
  317.  * Tokenize one line.
  318.  */
  319. static void tokenize_line( const char * pnt )
  320. {
  321.     static struct kconfig * last_menuoption = NULL;
  322.     enum e_token token;
  323.     struct kconfig * cfg;
  324.     struct dependency ** dep_ptr;
  325.     char * buffer = malloc( 64 );
  326.     /* skip white space */
  327.     while ( *pnt == ' ' || *pnt == 't' )
  328. pnt++;
  329.     /*
  330.      * categorize the next token
  331.      */
  332. #define match_token(t, s) 
  333.     if (strncmp(pnt, s, strlen(s)) == 0) { token = t; pnt += strlen(s); break; }
  334.     token = token_UNKNOWN;
  335.     switch ( *pnt )
  336.     {
  337.     default:
  338. break;
  339.     case '#':
  340.     case '':
  341. return;
  342.     case 'b':
  343. match_token( token_bool, "bool" );
  344. break;
  345.     case 'c':
  346. match_token( token_choice_header, "choice"  );
  347. match_token( token_comment, "comment" );
  348. break;
  349.     case 'd':
  350. match_token( token_define_bool, "define_bool" );
  351. match_token( token_define_hex, "define_hex" );
  352. match_token( token_define_int, "define_int" );
  353. match_token( token_define_string, "define_string" );
  354. match_token( token_define_tristate, "define_tristate" );
  355. match_token( token_dep_bool, "dep_bool" );
  356. match_token( token_dep_mbool, "dep_mbool" );
  357. match_token( token_dep_tristate, "dep_tristate" );
  358. break;
  359.     case 'e':
  360. match_token( token_else, "else" );
  361. match_token( token_endmenu, "endmenu" );
  362. break;
  363.     case 'f':
  364. match_token( token_fi, "fi" );
  365. break;
  366.     case 'h':
  367. match_token( token_hex, "hex" );
  368. break;
  369.     case 'i':
  370. match_token( token_if, "if" );
  371. match_token( token_int, "int" );
  372. break;
  373.     case 'm':
  374. match_token( token_mainmenu_name, "mainmenu_name" );
  375. match_token( token_mainmenu_option, "mainmenu_option" );
  376. break;
  377.     case 's':
  378. match_token( token_source, "source" );
  379. match_token( token_string, "string" );
  380. break;
  381.     case 't':
  382. match_token( token_then, "then" );
  383. match_token( token_tristate, "tristate" );
  384. break;
  385.     case 'u':
  386. match_token( token_unset, "unset" );
  387. break;
  388.     }
  389. #undef match_token
  390.     if ( token == token_source )
  391.     {
  392. while ( *pnt == ' ' || *pnt == 't' )
  393.     pnt++;
  394. do_source( pnt );
  395. return;
  396.     }
  397.     if ( token == token_then )
  398.     {
  399. if ( config_last != NULL && config_last->token == token_if )
  400.     return;
  401. syntax_error( "bogus 'then'" );
  402.     }
  403. #if 0
  404.     if ( token == token_unset )
  405.     {
  406. fprintf( stderr, "Ignoring 'unset' commandn" );
  407. return;
  408.     }
  409. #endif
  410.     if ( token == token_UNKNOWN )
  411. syntax_error( "unknown command" );
  412.     /*
  413.      * Allocate an item.
  414.      */
  415.     cfg = malloc( sizeof(*cfg) );
  416.     memset( cfg, 0, sizeof(*cfg) );
  417.     if ( config_last == NULL )
  418. { config_last = config_list = cfg; }
  419.     else
  420. { config_last->next = cfg; config_last = cfg; }
  421.     /*
  422.      * Tokenize the arguments.
  423.      */
  424.     while ( *pnt == ' ' || *pnt == 't' )
  425. pnt++;
  426.     cfg->token = token;
  427.     switch ( token )
  428.     {
  429.     default:
  430. syntax_error( "unknown token" );
  431.     case token_bool:
  432.     case token_tristate:
  433. pnt = get_qstring ( pnt, &cfg->label );
  434. pnt = get_string  ( pnt, &buffer );
  435. cfg->nameindex = get_varnum( buffer );
  436. break;
  437.     case token_choice_header:
  438. {
  439.     static int choose_number = 0;
  440.     char * choice_list;
  441.     pnt = get_qstring ( pnt, &cfg->label  );
  442.     pnt = get_qstring ( pnt, &choice_list );
  443.     pnt = get_string  ( pnt, &cfg->value  );
  444.     cfg->nameindex = -(choose_number++);
  445.     tokenize_choices( cfg, choice_list );
  446.     free( choice_list );
  447. }
  448. break;
  449.     case token_comment:
  450. pnt = get_qstring(pnt, &cfg->label);
  451. if ( last_menuoption != NULL )
  452. {
  453.     pnt = get_qstring(pnt, &cfg->label);
  454.     if (cfg->label == NULL)
  455. syntax_error( "missing comment text" );
  456.     last_menuoption->label = cfg->label;
  457.     last_menuoption = NULL;
  458. }
  459. break;
  460.     case token_define_bool:
  461.     case token_define_tristate:
  462. pnt = get_string( pnt, &buffer );
  463. cfg->nameindex = get_varnum( buffer );
  464. while ( *pnt == ' ' || *pnt == 't' )
  465.     pnt++;
  466. if ( ( pnt[0] == 'Y'  || pnt[0] == 'M' || pnt[0] == 'N'
  467. ||     pnt[0] == 'y'  || pnt[0] == 'm' || pnt[0] == 'n' )
  468. &&   ( pnt[1] == '' || pnt[1] == ' ' || pnt[1] == 't' ) )
  469. {
  470.     if      ( *pnt == 'n' || *pnt == 'N' ) cfg->value = strdup( "CONSTANT_N" );
  471.     else if ( *pnt == 'y' || *pnt == 'Y' ) cfg->value = strdup( "CONSTANT_Y" );
  472.     else if ( *pnt == 'm' || *pnt == 'M' ) cfg->value = strdup( "CONSTANT_M" );
  473. }
  474. else if ( *pnt == '$' )
  475. {
  476.     pnt++;
  477.     pnt = get_string( pnt, &cfg->value );
  478. }
  479. else
  480. {
  481.     syntax_error( "unknown define_bool value" );
  482. }
  483. get_varnum( cfg->value );
  484. break;
  485.     case token_define_hex:
  486.     case token_define_int:
  487. pnt = get_string( pnt, &buffer );
  488. cfg->nameindex = get_varnum( buffer );
  489. pnt = get_string( pnt, &cfg->value );
  490. break;
  491.     case token_define_string:
  492. pnt = get_string( pnt, &buffer );
  493. cfg->nameindex = get_varnum( buffer );
  494. pnt = get_qnqstring( pnt, &cfg->value );
  495. if (cfg->value == NULL)
  496.     syntax_error( "missing value" );
  497. break;
  498.     case token_dep_bool:
  499.     case token_dep_mbool:
  500.     case token_dep_tristate:
  501. pnt = get_qstring ( pnt, &cfg->label );
  502. pnt = get_string  ( pnt, &buffer );
  503. cfg->nameindex = get_varnum( buffer );
  504. while ( *pnt == ' ' || *pnt == 't' )
  505.     pnt++;
  506. dep_ptr = &(cfg->depend);
  507. do {
  508.     *dep_ptr = (struct dependency *) malloc( sizeof( struct dependency ) );
  509.     (*dep_ptr)->next = NULL;
  510.     if ( ( pnt[0] == 'Y'  || pnt[0] == 'M' || pnt[0] == 'N'
  511.     ||     pnt[0] == 'y'  || pnt[0] == 'm' || pnt[0] == 'n' )
  512.     &&   ( pnt[1] == '' || pnt[1] == ' ' || pnt[1] == 't' ) )
  513.     {
  514. /* dep_tristate 'foo' CONFIG_FOO m */
  515. if      ( pnt[0] == 'Y' || pnt[0] == 'y' )
  516.     (*dep_ptr)->name = strdup( "CONSTANT_Y" );
  517. else if ( pnt[0] == 'N' || pnt[0] == 'n' )
  518.     (*dep_ptr)->name = strdup( "CONSTANT_N" );
  519. else
  520.     (*dep_ptr)->name = strdup( "CONSTANT_M" );
  521. pnt++;
  522. get_varnum( (*dep_ptr)->name );
  523.     }
  524.     else if ( *pnt == '$' )
  525.     {
  526. pnt++;
  527. pnt = get_string( pnt, &(*dep_ptr)->name );
  528. get_varnum( (*dep_ptr)->name );
  529.     }
  530.     else
  531.     {
  532. syntax_error( "can't handle dep_bool/dep_mbool/dep_tristate condition" );
  533.     }
  534.     dep_ptr = &(*dep_ptr)->next;
  535.     while ( *pnt == ' ' || *pnt == 't' )
  536. pnt++;
  537. } while ( *pnt );
  538. /*
  539.  * Create a conditional for this object's dependencies.
  540.  */
  541. {
  542.     char fake_if [1024];
  543.     struct dependency * dep;
  544.     struct condition ** cond_ptr;
  545.     int first = 1;
  546.     cond_ptr = &(cfg->cond);
  547.     for ( dep = cfg->depend; dep; dep = dep->next )
  548.     {
  549. if ( token == token_dep_tristate
  550. && ! strcmp( dep->name, "CONSTANT_M" ) )
  551. {
  552.     continue;
  553. }
  554. if ( first )
  555. {
  556.     first = 0;
  557. }
  558. else
  559. {
  560.     *cond_ptr = malloc( sizeof(struct condition) );
  561.     memset( *cond_ptr, 0, sizeof(struct condition) );
  562.     (*cond_ptr)->op = op_and;
  563.     cond_ptr = &(*cond_ptr)->next;
  564. }
  565. *cond_ptr = malloc( sizeof(struct condition) );
  566. memset( *cond_ptr, 0, sizeof(struct condition) );
  567. (*cond_ptr)->op = op_lparen;
  568. if ( token == token_dep_bool )
  569.     sprintf( fake_if, "[ "$%s" = "y" -o "$%s" = "" ]; then",
  570. dep->name, dep->name );
  571. else
  572.     sprintf( fake_if, "[ "$%s" = "y" -o "$%s" = "m" -o "$%s" = "" ]; then",
  573. dep->name, dep->name, dep->name );
  574. (*cond_ptr)->next = tokenize_if( fake_if );
  575. while ( *cond_ptr )
  576.     cond_ptr = &(*cond_ptr)->next;
  577. *cond_ptr = malloc( sizeof(struct condition) );
  578. memset( *cond_ptr, 0, sizeof(struct condition) );
  579. (*cond_ptr)->op = op_rparen;
  580. cond_ptr = &(*cond_ptr)->next;
  581.     }
  582. }
  583. break;
  584.     case token_else:
  585.     case token_endmenu:
  586.     case token_fi:
  587. break;
  588.     case token_hex:
  589.     case token_int:
  590. pnt = get_qstring ( pnt, &cfg->label );
  591. pnt = get_string  ( pnt, &buffer );
  592. cfg->nameindex = get_varnum( buffer );
  593. pnt = get_string  ( pnt, &cfg->value );
  594. break;
  595.     case token_string:
  596. pnt = get_qstring ( pnt, &cfg->label );
  597. pnt = get_string  ( pnt, &buffer );
  598. cfg->nameindex = get_varnum( buffer );
  599. pnt = get_qnqstring  ( pnt, &cfg->value );
  600. if (cfg->value == NULL)
  601.     syntax_error( "missing initial value" );
  602. break;
  603.     case token_if:
  604. cfg->cond = tokenize_if( pnt );
  605. break;
  606.     case token_mainmenu_name:
  607. pnt = get_qstring( pnt, &cfg->label );
  608. break;
  609.     case token_mainmenu_option:
  610. if ( strncmp( pnt, "next_comment", 12 ) == 0 )
  611.     last_menuoption = cfg;
  612. else
  613.     pnt = get_qstring( pnt, &cfg->label );
  614. break;
  615.     case token_unset:
  616. pnt = get_string( pnt, &buffer );
  617. cfg->nameindex = get_varnum( buffer );
  618. while ( *pnt == ' ' || *pnt == 't' )
  619.     pnt++;
  620. while (*pnt)
  621. {
  622.     cfg->next = (struct kconfig *) malloc( sizeof(struct kconfig) );
  623.     memset( cfg->next, 0, sizeof(struct kconfig) );
  624.     cfg = cfg->next;
  625.     cfg->token = token_unset;
  626.     pnt = get_string( pnt, &buffer );
  627.     cfg->nameindex = get_varnum( buffer );
  628.     while ( *pnt == ' ' || *pnt == 't' )
  629. pnt++;
  630. }
  631. break;
  632.     }
  633.     return;
  634. }
  635. /*
  636.  * Implement the "source" command.
  637.  */
  638. static void do_source( const char * filename )
  639. {
  640.     char buffer [2048];
  641.     FILE * infile;
  642.     const char * old_file;
  643.     int old_lineno;
  644.     int offset;
  645.     /* open the file */
  646.     if ( strcmp( filename, "-" ) == 0 )
  647. infile = stdin;
  648.     else
  649. infile = fopen( filename, "r" );
  650.     /* if that failed, try ../filename */
  651.     if ( infile == NULL )
  652.     {
  653. sprintf( buffer, "../%s", filename );
  654. infile = fopen( buffer, "r" );
  655.     }
  656.     if ( infile == NULL )
  657.     {
  658. sprintf( buffer, "unable to open %s", filename );
  659. syntax_error( buffer );
  660.     }
  661.     /* push the new file name and line number */
  662.     old_file     = current_file;
  663.     old_lineno   = lineno;
  664.     current_file = filename;
  665.     lineno       = 0;
  666.     /* read and process lines */
  667.     for ( offset = 0; ; )
  668.     {
  669. char * pnt;
  670. /* read a line */
  671. fgets( buffer + offset, sizeof(buffer) - offset, infile );
  672. if ( feof( infile ) )
  673.     break;
  674. lineno++;
  675. /* strip the trailing return character */
  676. pnt = buffer + strlen(buffer) - 1;
  677. if ( *pnt == 'n' )
  678.     *pnt-- = '';
  679. /* eat  NL pairs */
  680. if ( *pnt == '\' )
  681. {
  682.     offset = pnt - buffer;
  683.     continue;
  684. }
  685. /* tokenize this line */
  686. tokenize_line( buffer );
  687. offset = 0;
  688.     }
  689.     /* that's all, folks */
  690.     if ( infile != stdin )
  691. fclose( infile );
  692.     current_file = old_file;
  693.     lineno       = old_lineno;
  694.     return;
  695. }
  696. /*
  697.  * Main program.
  698.  */
  699. int main( int argc, const char * argv [] )
  700. {
  701.     do_source        ( "-"         );
  702.     fix_conditionals ( config_list );
  703.     dump_tk_script   ( config_list );
  704.     return 0;
  705. }