make oldconfig will rebuild these...
[linux-2.4.21-pre4.git] / scripts / tkparse.c
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
48 #include <stdio.h>
49 #include <stdlib.h>
50 #include <string.h>
51
52 #include "tkparse.h"
53
54 static struct kconfig * config_list = NULL;
55 static struct kconfig * config_last = NULL;
56 static const char * current_file = "<unknown file>";
57 static int lineno = 0;
58
59 static void do_source( const char * );
60
61 #undef strcmp
62 int my_strcmp( const char * s1, const char * s2 ) { return strcmp( s1, s2 ); }
63 #define strcmp my_strcmp
64
65 /*
66  * Report a syntax error.
67  */
68 static void syntax_error( const char * msg )
69 {
70     fprintf( stderr, "%s: %d: %s\n", current_file, lineno, msg );
71     exit( 1 );
72 }
73
74
75
76 /*
77  * Find index of a specific variable in the symbol table.
78  * Create a new entry if it does not exist yet.
79  */
80 struct variable *vartable;
81 int max_varnum = 0;
82 static int vartable_size = 0;
83
84 int get_varnum( char * name )
85 {
86     int i;
87     
88     for ( i = 1; i <= max_varnum; i++ )
89         if ( strcmp( vartable[i].name, name ) == 0 )
90             return i;
91     while (max_varnum+1 >= vartable_size) {
92         vartable = realloc(vartable, (vartable_size += 1000)*sizeof(*vartable));
93         if (!vartable) {
94             fprintf(stderr, "tkparse realloc vartable failed\n");
95             exit(1);
96         }
97     }
98     vartable[++max_varnum].name = malloc( strlen( name )+1 );
99     strcpy( vartable[max_varnum].name, name );
100     return max_varnum;
101 }
102
103
104
105 /*
106  * Get a string.
107  */
108 static const char * get_string( const char * pnt, char ** label )
109 {
110     const char * word;
111
112     word = pnt;
113     for ( ; ; )
114     {
115         if ( *pnt == '\0' || *pnt == ' ' || *pnt == '\t' )
116             break;
117         pnt++;
118     }
119
120     *label = malloc( pnt - word + 1 );
121     memcpy( *label, word, pnt - word );
122     (*label)[pnt - word] = '\0';
123
124     if ( *pnt != '\0' )
125         pnt++;
126     return pnt;
127 }
128
129
130
131 /*
132  * Get a quoted string.
133  * Insert a '\' before any characters that need quoting.
134  */
135 static const char * get_qstring( const char * pnt, char ** label )
136 {
137     char quote_char;
138     char newlabel [2048];
139     char * pnt1;
140
141     /* advance to the open quote */
142     for ( ; ; )
143     {
144         if ( *pnt == '\0' )
145             return pnt;
146         quote_char = *pnt++;
147         if ( quote_char == '"' || quote_char == '\'' )
148             break;
149     }
150
151     /* copy into an intermediate buffer */
152     pnt1 = newlabel;
153     for ( ; ; )
154     {
155         if ( *pnt == '\0' )
156             syntax_error( "unterminated quoted string" );
157         if ( *pnt == quote_char && pnt[-1] != '\\' )
158             break;
159
160         /* copy the character, quoting if needed */
161         if ( *pnt == '"' || *pnt == '\'' || *pnt == '[' || *pnt == ']' )
162             *pnt1++ = '\\';
163         *pnt1++ = *pnt++;
164     }
165
166     /* copy the label into a permanent location */
167     *pnt1++ = '\0';
168     *label = (char *) malloc( pnt1 - newlabel );
169     memcpy( *label, newlabel, pnt1 - newlabel );
170
171     /* skip over last quote and next whitespace */
172     pnt++;
173     while ( *pnt == ' ' || *pnt == '\t' )
174         pnt++;
175     return pnt;
176 }
177
178
179
180 /*
181  * Get a quoted or unquoted string. It is recognized by the first 
182  * non-white character. '"' and '"' are not allowed inside the string.
183  */
184 static const char * get_qnqstring( const char * pnt, char ** label )
185 {
186     char quote_char;
187
188     while ( *pnt == ' ' || *pnt == '\t' )
189         pnt++;
190
191     if ( *pnt == '\0' )
192         return pnt;
193     quote_char = *pnt;
194     if ( quote_char == '"' || quote_char == '\'' )
195         return get_qstring( pnt, label );
196     else
197         return get_string( pnt, label );
198 }
199
200
201
202 /*
203  * Tokenize an 'if' statement condition.
204  */
205 static struct condition * tokenize_if( const char * pnt )
206 {
207     struct condition * list;
208     struct condition * last;
209     struct condition * prev;
210
211     /* eat the open bracket */
212     while ( *pnt == ' ' || *pnt == '\t' )
213         pnt++;
214     if ( *pnt != '[' )
215         syntax_error( "bad 'if' condition" );
216     pnt++;
217
218     list = last = NULL;
219     for ( ; ; )
220     {
221         struct condition * cond;
222
223         /* advance to the next token */
224         while ( *pnt == ' ' || *pnt == '\t' )
225             pnt++;
226         if ( *pnt == '\0' )
227             syntax_error( "unterminated 'if' condition" );
228         if ( *pnt == ']' )
229             return list;
230
231         /* allocate a new token */
232         cond = malloc( sizeof(*cond) );
233         memset( cond, 0, sizeof(*cond) );
234         if ( last == NULL )
235             { list = last = cond; prev = NULL; }
236         else
237             { prev = last; last->next = cond; last = cond; }
238
239         /* determine the token value */
240         if ( *pnt == '-' && pnt[1] == 'a' )
241         {
242             if ( ! prev || ( prev->op != op_variable && prev->op != op_constant ) )
243                 syntax_error( "incorrect argument" );
244             cond->op = op_and;  pnt += 2; continue;
245         }
246
247         if ( *pnt == '-' && pnt[1] == 'o' )
248         {
249             if ( ! prev || ( prev->op != op_variable && prev->op != op_constant ) )
250                 syntax_error( "incorrect argument" );
251             cond->op = op_or;   pnt += 2; continue;
252         }
253
254         if ( *pnt == '!' && pnt[1] == '=' )
255         {
256             if ( ! prev || ( prev->op != op_variable && prev->op != op_constant ) )
257                 syntax_error( "incorrect argument" );
258             cond->op = op_neq;  pnt += 2; continue;
259         }
260
261         if ( *pnt == '=' )
262         {
263             if ( ! prev || ( prev->op != op_variable && prev->op != op_constant ) )
264                 syntax_error( "incorrect argument" );
265             cond->op = op_eq;   pnt += 1; continue;
266         }
267
268         if ( *pnt == '!' )
269         {
270             if ( prev && ( prev->op != op_and && prev->op != op_or
271                       && prev->op != op_bang ) )
272                 syntax_error( "incorrect argument" );
273             cond->op = op_bang; pnt += 1; continue;
274         }
275
276         if ( *pnt == '"' )
277         {
278             const char * word;
279
280             if ( prev && ( prev->op == op_variable || prev->op == op_constant ) )
281                 syntax_error( "incorrect argument" );
282             /* advance to the word */
283             pnt++;
284             if ( *pnt == '$' )
285                 { cond->op = op_variable; pnt++; }
286             else
287                 { cond->op = op_constant; }
288
289             /* find the end of the word */
290             word = pnt;
291             for ( ; ; )
292             {
293                 if ( *pnt == '\0' )
294                     syntax_error( "unterminated double quote" );
295                 if ( *pnt == '"' )
296                     break;
297                 pnt++;
298             }
299
300             /* store a copy of this word */
301             {
302                 char * str = malloc( pnt - word + 1 );
303                 memcpy( str, word, pnt - word );
304                 str [pnt - word] = '\0';
305                 if ( cond->op == op_variable )
306                 {
307                     cond->nameindex = get_varnum( str );
308                     free( str );
309                 }
310                 else /* op_constant */
311                 {
312                     cond->str = str;
313                 }
314             }
315
316             pnt++;
317             continue;
318         }
319
320         /* unknown token */
321         syntax_error( "bad if condition" );
322     }
323 }
324
325
326
327 /*
328  * Tokenize a choice list.  Choices appear as pairs of strings;
329  * note that I am parsing *inside* the double quotes.  Ugh.
330  */
331 static const char * tokenize_choices( struct kconfig * cfg_choose,
332     const char * pnt )
333 {
334     int default_checked = 0;
335     for ( ; ; )
336     {
337         struct kconfig * cfg;
338         char * buffer = malloc( 64 );
339
340         /* skip whitespace */
341         while ( *pnt == ' ' || *pnt == '\t' )
342             pnt++;
343         if ( *pnt == '\0' )
344             return pnt;
345
346         /* allocate a new kconfig line */
347         cfg = malloc( sizeof(*cfg) );
348         memset( cfg, 0, sizeof(*cfg) );
349         if ( config_last == NULL )
350             { config_last = config_list = cfg; }
351         else
352             { config_last->next = cfg; config_last = cfg; }
353
354         /* fill out the line */
355         cfg->token      = token_choice_item;
356         cfg->cfg_parent = cfg_choose;
357         pnt = get_string( pnt, &cfg->label );
358         if ( ! default_checked &&
359              ! strncmp( cfg->label, cfg_choose->value, strlen( cfg_choose->value ) ) )
360         {
361             default_checked = 1;
362             free( cfg_choose->value );
363             cfg_choose->value = cfg->label;
364         }
365         while ( *pnt == ' ' || *pnt == '\t' )
366             pnt++;
367         pnt = get_string( pnt, &buffer );
368         cfg->nameindex = get_varnum( buffer );
369     }
370     if ( ! default_checked )
371         syntax_error( "bad 'choice' default value" );
372     return pnt;
373 }
374
375
376
377 /*
378  * Tokenize one line.
379  */
380 static void tokenize_line( const char * pnt )
381 {
382     static struct kconfig * last_menuoption = NULL;
383     enum e_token token;
384     struct kconfig * cfg;
385     struct dependency ** dep_ptr;
386     char * buffer = malloc( 64 );
387
388     /* skip white space */
389     while ( *pnt == ' ' || *pnt == '\t' )
390         pnt++;
391
392     /*
393      * categorize the next token
394      */
395
396 #define match_token(t, s) \
397     if (strncmp(pnt, s, strlen(s)) == 0) { token = t; pnt += strlen(s); break; }
398
399     token = token_UNKNOWN;
400     switch ( *pnt )
401     {
402     default:
403         break;
404
405     case '#':
406     case '\0':
407         return;
408
409     case 'b':
410         match_token( token_bool, "bool" );
411         break;
412
413     case 'c':
414         match_token( token_choice_header, "choice"  );
415         match_token( token_comment, "comment" );
416         break;
417
418     case 'd':
419         match_token( token_define_bool, "define_bool" );
420         match_token( token_define_hex, "define_hex" );
421         match_token( token_define_int, "define_int" );
422         match_token( token_define_string, "define_string" );
423         match_token( token_define_tristate, "define_tristate" );
424         match_token( token_dep_bool, "dep_bool" );
425         match_token( token_dep_mbool, "dep_mbool" );
426         match_token( token_dep_tristate, "dep_tristate" );
427         break;
428
429     case 'e':
430         match_token( token_else, "else" );
431         match_token( token_endmenu, "endmenu" );
432         break;
433
434     case 'f':
435         match_token( token_fi, "fi" );
436         break;
437
438     case 'h':
439         match_token( token_hex, "hex" );
440         break;
441
442     case 'i':
443         match_token( token_if, "if" );
444         match_token( token_int, "int" );
445         break;
446
447     case 'm':
448         match_token( token_mainmenu_name, "mainmenu_name" );
449         match_token( token_mainmenu_option, "mainmenu_option" );
450         break;
451
452     case 's':
453         match_token( token_source, "source" );
454         match_token( token_string, "string" );
455         break;
456
457     case 't':
458         match_token( token_then, "then" );
459         match_token( token_tristate, "tristate" );
460         break;
461
462     case 'u':
463         match_token( token_unset, "unset" );
464         break;
465     }
466
467 #undef match_token
468
469     if ( token == token_source )
470     {
471         while ( *pnt == ' ' || *pnt == '\t' )
472             pnt++;
473         do_source( pnt );
474         return;
475     }
476
477     if ( token == token_then )
478     {
479         if ( config_last != NULL && config_last->token == token_if )
480             return;
481         syntax_error( "bogus 'then'" );
482     }
483
484 #if 0
485     if ( token == token_unset )
486     {
487         fprintf( stderr, "Ignoring 'unset' command\n" );
488         return;
489     }
490 #endif
491
492     if ( token == token_UNKNOWN )
493         syntax_error( "unknown command" );
494
495     /*
496      * Allocate an item.
497      */
498     cfg = malloc( sizeof(*cfg) );
499     memset( cfg, 0, sizeof(*cfg) );
500     if ( config_last == NULL )
501         { config_last = config_list = cfg; }
502     else
503         { config_last->next = cfg; config_last = cfg; }
504
505     /*
506      * Tokenize the arguments.
507      */
508     while ( *pnt == ' ' || *pnt == '\t' )
509         pnt++;
510
511     cfg->token = token;
512     switch ( token )
513     {
514     default:
515         syntax_error( "unknown token" );
516
517     case token_bool:
518     case token_tristate:
519         pnt = get_qstring ( pnt, &cfg->label );
520         pnt = get_string  ( pnt, &buffer );
521         cfg->nameindex = get_varnum( buffer );
522         break;
523
524     case token_choice_header:
525         {
526             static int choose_number = 0;
527             char * choice_list;
528
529             pnt = get_qstring ( pnt, &cfg->label  );
530             pnt = get_qstring ( pnt, &choice_list );
531             pnt = get_string  ( pnt, &cfg->value  );
532             cfg->nameindex = -(choose_number++);
533             tokenize_choices( cfg, choice_list );
534             free( choice_list );
535         }
536         break;
537
538     case token_comment:
539         pnt = get_qstring(pnt, &cfg->label);
540         if ( last_menuoption != NULL )
541         {
542             pnt = get_qstring(pnt, &cfg->label);
543             if (cfg->label == NULL)
544                 syntax_error( "missing comment text" );
545             last_menuoption->label = cfg->label;
546             last_menuoption = NULL;
547         }
548         break;
549
550     case token_define_bool:
551     case token_define_tristate:
552         pnt = get_string( pnt, &buffer );
553         cfg->nameindex = get_varnum( buffer );
554         while ( *pnt == ' ' || *pnt == '\t' )
555             pnt++;
556         if ( ( pnt[0] == 'Y'  || pnt[0] == 'M' || pnt[0] == 'N'
557         ||     pnt[0] == 'y'  || pnt[0] == 'm' || pnt[0] == 'n' )
558         &&   ( pnt[1] == '\0' || pnt[1] == ' ' || pnt[1] == '\t' ) )
559         {
560             if      ( *pnt == 'n' || *pnt == 'N' ) cfg->value = strdup( "CONSTANT_N" );
561             else if ( *pnt == 'y' || *pnt == 'Y' ) cfg->value = strdup( "CONSTANT_Y" );
562             else if ( *pnt == 'm' || *pnt == 'M' ) cfg->value = strdup( "CONSTANT_M" );
563         }
564         else if ( *pnt == '$' )
565         {
566             pnt++;
567             pnt = get_string( pnt, &cfg->value );
568         }
569         else
570         {
571             syntax_error( "unknown define_bool value" );
572         }
573         get_varnum( cfg->value );
574         break;
575
576     case token_define_hex:
577     case token_define_int:
578         pnt = get_string( pnt, &buffer );
579         cfg->nameindex = get_varnum( buffer );
580         pnt = get_string( pnt, &cfg->value );
581         break;
582
583     case token_define_string:
584         pnt = get_string( pnt, &buffer );
585         cfg->nameindex = get_varnum( buffer );
586         pnt = get_qnqstring( pnt, &cfg->value );
587         if (cfg->value == NULL)
588             syntax_error( "missing value" );
589         break;
590
591     case token_dep_bool:
592     case token_dep_mbool:
593     case token_dep_tristate:
594         pnt = get_qstring ( pnt, &cfg->label );
595         pnt = get_string  ( pnt, &buffer );
596         cfg->nameindex = get_varnum( buffer );
597
598         while ( *pnt == ' ' || *pnt == '\t' )
599             pnt++;
600
601         dep_ptr = &(cfg->depend);
602
603         do {
604             *dep_ptr = (struct dependency *) malloc( sizeof( struct dependency ) );
605             (*dep_ptr)->next = NULL;
606
607             if ( ( pnt[0] == 'Y'  || pnt[0] == 'M' || pnt[0] == 'N'
608             ||     pnt[0] == 'y'  || pnt[0] == 'm' || pnt[0] == 'n' )
609             &&   ( pnt[1] == '\0' || pnt[1] == ' ' || pnt[1] == '\t' ) )
610             {
611                 /* dep_tristate 'foo' CONFIG_FOO m */
612                 if      ( pnt[0] == 'Y' || pnt[0] == 'y' )
613                     (*dep_ptr)->name = strdup( "CONSTANT_Y" );
614                 else if ( pnt[0] == 'N' || pnt[0] == 'n' )
615                     (*dep_ptr)->name = strdup( "CONSTANT_N" );
616                 else
617                     (*dep_ptr)->name = strdup( "CONSTANT_M" );
618                 pnt++;
619                 get_varnum( (*dep_ptr)->name );
620             }
621             else if ( *pnt == '$' )
622             {
623                 pnt++;
624                 pnt = get_string( pnt, &(*dep_ptr)->name );
625                 get_varnum( (*dep_ptr)->name );
626             }
627             else
628             {
629                 syntax_error( "can't handle dep_bool/dep_mbool/dep_tristate condition" );
630             }
631             dep_ptr = &(*dep_ptr)->next;
632             while ( *pnt == ' ' || *pnt == '\t' )
633                 pnt++;
634         } while ( *pnt );
635
636         /*
637          * Create a conditional for this object's dependencies.
638          */
639         {
640             char fake_if [1024];
641             struct dependency * dep;
642             struct condition ** cond_ptr;
643             int first = 1;
644
645             cond_ptr = &(cfg->cond);
646             for ( dep = cfg->depend; dep; dep = dep->next )
647             {
648                 if ( token == token_dep_tristate
649                 && ! strcmp( dep->name, "CONSTANT_M" ) )
650                 {
651                     continue;
652                 }
653                 if ( first )
654                 {
655                     first = 0;
656                 }
657                 else
658                 {
659                     *cond_ptr = malloc( sizeof(struct condition) );
660                     memset( *cond_ptr, 0, sizeof(struct condition) );
661                     (*cond_ptr)->op = op_and;
662                     cond_ptr = &(*cond_ptr)->next;
663                 }
664                 *cond_ptr = malloc( sizeof(struct condition) );
665                 memset( *cond_ptr, 0, sizeof(struct condition) );
666                 (*cond_ptr)->op = op_lparen;
667                 if ( token == token_dep_bool )
668                     sprintf( fake_if, "[ \"$%s\" = \"y\" -o \"$%s\" = \"\" ]; then",
669                         dep->name, dep->name );
670                 else
671                     sprintf( fake_if, "[ \"$%s\" = \"y\" -o \"$%s\" = \"m\" -o \"$%s\" = \"\" ]; then",
672                         dep->name, dep->name, dep->name );
673                 (*cond_ptr)->next = tokenize_if( fake_if );
674                 while ( *cond_ptr )
675                     cond_ptr = &(*cond_ptr)->next;
676                 *cond_ptr = malloc( sizeof(struct condition) );
677                 memset( *cond_ptr, 0, sizeof(struct condition) );
678                 (*cond_ptr)->op = op_rparen;
679                 cond_ptr = &(*cond_ptr)->next;
680             }
681         }
682         break;
683
684     case token_else:
685     case token_endmenu:
686     case token_fi:
687         break;
688
689     case token_hex:
690     case token_int:
691         pnt = get_qstring ( pnt, &cfg->label );
692         pnt = get_string  ( pnt, &buffer );
693         cfg->nameindex = get_varnum( buffer );
694         pnt = get_string  ( pnt, &cfg->value );
695         break;
696
697     case token_string:
698         pnt = get_qstring ( pnt, &cfg->label );
699         pnt = get_string  ( pnt, &buffer );
700         cfg->nameindex = get_varnum( buffer );
701         pnt = get_qnqstring  ( pnt, &cfg->value );
702         if (cfg->value == NULL)
703             syntax_error( "missing initial value" );
704         break;
705
706     case token_if:
707         cfg->cond = tokenize_if( pnt );
708         break;
709
710     case token_mainmenu_name:
711         pnt = get_qstring( pnt, &cfg->label );
712         break;
713
714     case token_mainmenu_option:
715         if ( strncmp( pnt, "next_comment", 12 ) == 0 )
716             last_menuoption = cfg;
717         else
718             pnt = get_qstring( pnt, &cfg->label );
719         break;
720
721     case token_unset:
722         pnt = get_string( pnt, &buffer );
723         cfg->nameindex = get_varnum( buffer );
724         while ( *pnt == ' ' || *pnt == '\t' )
725             pnt++;
726         while (*pnt)
727         {
728             cfg->next = (struct kconfig *) malloc( sizeof(struct kconfig) );
729             memset( cfg->next, 0, sizeof(struct kconfig) );
730             cfg = cfg->next;
731             cfg->token = token_unset;
732             pnt = get_string( pnt, &buffer );
733             cfg->nameindex = get_varnum( buffer );
734             while ( *pnt == ' ' || *pnt == '\t' )
735                 pnt++;
736         }
737         break;
738     }
739     return;
740 }
741
742
743
744 /*
745  * Implement the "source" command.
746  */
747 static void do_source( const char * filename )
748 {
749     char buffer [2048];
750     FILE * infile;
751     const char * old_file;
752     int old_lineno;
753     int offset;
754
755     /* open the file */
756     if ( strcmp( filename, "-" ) == 0 )
757         infile = stdin;
758     else
759         infile = fopen( filename, "r" );
760
761     /* if that failed, try ../filename */
762     if ( infile == NULL )
763     {
764         sprintf( buffer, "../%s", filename );
765         infile = fopen( buffer, "r" );
766     }
767
768     if ( infile == NULL )
769     {
770         sprintf( buffer, "unable to open %s", filename );
771         syntax_error( buffer );
772     }
773
774     /* push the new file name and line number */
775     old_file     = current_file;
776     old_lineno   = lineno;
777     current_file = filename;
778     lineno       = 0;
779
780     /* read and process lines */
781     for ( offset = 0; ; )
782     {
783         char * pnt;
784
785         /* read a line */
786         fgets( buffer + offset, sizeof(buffer) - offset, infile );
787         if ( feof( infile ) )
788             break;
789         lineno++;
790
791         /* strip the trailing return character */
792         pnt = buffer + strlen(buffer) - 1;
793         if ( *pnt == '\n' )
794             *pnt-- = '\0';
795
796         /* eat \ NL pairs */
797         if ( *pnt == '\\' )
798         {
799             offset = pnt - buffer;
800             continue;
801         }
802
803         /* tokenize this line */
804         tokenize_line( buffer );
805         offset = 0;
806     }
807
808     /* that's all, folks */
809     if ( infile != stdin )
810         fclose( infile );
811     current_file = old_file;
812     lineno       = old_lineno;
813     return;
814 }
815
816
817
818 /*
819  * Main program.
820  */
821 int main( int argc, const char * argv [] )
822 {
823     do_source        ( "-"         );
824     fix_conditionals ( config_list );
825     dump_tk_script   ( config_list );
826     free(vartable);
827     return 0;
828 }