1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48#include <stdio.h>
49#include <stdlib.h>
50#include <string.h>
51
52#include "tkparse.h"
53
54static struct kconfig * config_list = NULL;
55static struct kconfig * config_last = NULL;
56static const char * current_file = "<unknown file>";
57static int lineno = 0;
58
59static void do_source( const char * );
60
61#undef strcmp
62int my_strcmp( const char * s1, const char * s2 ) { return strcmp( s1, s2 ); }
63#define strcmp my_strcmp
64
65
66
67
68static 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
78
79
80struct variable *vartable;
81int max_varnum = 0;
82static int vartable_size = 0;
83
84int 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
107
108static 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
133
134
135static const char * get_qstring( const char * pnt, char ** label )
136{
137 char quote_char;
138 char newlabel [2048];
139 char * pnt1;
140
141
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
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
161 if ( *pnt == '"' || *pnt == '\'' || *pnt == '[' || *pnt == ']' )
162 *pnt1++ = '\\';
163 *pnt1++ = *pnt++;
164 }
165
166
167 *pnt1++ = '\0';
168 *label = (char *) malloc( pnt1 - newlabel );
169 memcpy( *label, newlabel, pnt1 - newlabel );
170
171
172 pnt++;
173 while ( *pnt == ' ' || *pnt == '\t' )
174 pnt++;
175 return pnt;
176}
177
178
179
180
181
182
183
184static 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
204
205static struct condition * tokenize_if( const char * pnt )
206{
207 struct condition * list;
208 struct condition * last;
209 struct condition * prev;
210
211
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
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
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
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
283 pnt++;
284 if ( *pnt == '$' )
285 { cond->op = op_variable; pnt++; }
286 else
287 { cond->op = op_constant; }
288
289
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
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
311 {
312 cond->str = str;
313 }
314 }
315
316 pnt++;
317 continue;
318 }
319
320
321 syntax_error( "bad if condition" );
322 }
323}
324
325
326
327
328
329
330
331static 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
341 while ( *pnt == ' ' || *pnt == '\t' )
342 pnt++;
343 if ( *pnt == '\0' )
344 return pnt;
345
346
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
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
379
380static 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
389 while ( *pnt == ' ' || *pnt == '\t' )
390 pnt++;
391
392
393
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
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
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
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
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
746
747static 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
756 if ( strcmp( filename, "-" ) == 0 )
757 infile = stdin;
758 else
759 infile = fopen( filename, "r" );
760
761
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
775 old_file = current_file;
776 old_lineno = lineno;
777 current_file = filename;
778 lineno = 0;
779
780
781 for ( offset = 0; ; )
782 {
783 char * pnt;
784
785
786 fgets( buffer + offset, sizeof(buffer) - offset, infile );
787 if ( feof( infile ) )
788 break;
789 lineno++;
790
791
792 pnt = buffer + strlen(buffer) - 1;
793 if ( *pnt == '\n' )
794 *pnt-- = '\0';
795
796
797 if ( *pnt == '\\' )
798 {
799 offset = pnt - buffer;
800 continue;
801 }
802
803
804 tokenize_line( buffer );
805 offset = 0;
806 }
807
808
809 if ( infile != stdin )
810 fclose( infile );
811 current_file = old_file;
812 lineno = old_lineno;
813 return;
814}
815
816
817
818
819
820
821int 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}
829