OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [scripts/] [tkparse.c] - Blame information for rev 1777

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1629 jcastillo
/* parser config.in
2
 *
3
 * Version 1.0
4
 * Eric Youngdale
5
 * 10/95
6
 *
7
 * The general idea here is that we want to parse a config.in file and
8
 * from this, we generate a wish script which gives us effectively the
9
 * same functionality that the original config.in script provided.
10
 *
11
 * This task is split roughly into 3 parts.  The first parse is the parse
12
 * of the input file itself.  The second part is where we analyze the
13
 * #ifdef clauses, and attach a linked list of tokens to each of the
14
 * menu items.  In this way, each menu item has a complete list of
15
 * dependencies that are used to enable/disable the options.
16
 * The third part is to take the configuration database we have build,
17
 * and build the actual wish script.
18
 *
19
 * This file contains the code to do the first parse of config.in.
20
 */
21
#include <stdlib.h>
22
#include <stdio.h>
23
#include <string.h>
24
#include "tkparse.h"
25
 
26
struct kconfig * config = NULL;
27
struct kconfig * clast = NULL;
28
struct kconfig * koption = NULL;
29
static int lineno = 0;
30
static int menus_seen = 0;
31
static char * current_file = NULL;
32
static int do_source(char * filename);
33
static char * get_string(char *pnt, char ** labl);
34
static int choose_number = 0;
35
 
36
 
37
/*
38
 * Simple function just to skip over spaces and tabs in config.in.
39
 */
40
static char * skip_whitespace(char * pnt)
41
{
42
  while( *pnt && (*pnt == ' ' || *pnt == '\t')) pnt++;
43
  return pnt;
44
}
45
 
46
/*
47
 * This function parses a conditional from a config.in (i.e. from an ifdef)
48
 * and generates a linked list of tokens that describes the conditional.
49
 */
50
static struct condition * parse_if(char * pnt)
51
{
52
  char * opnt;
53
  struct condition *list;
54
  struct condition *last;
55
  struct condition *cpnt;
56
  char varname[64];
57
  char * pnt1;
58
 
59
  opnt = pnt;
60
 
61
  /*
62
   * We need to find the various tokens, and build the linked list.
63
   */
64
  pnt = skip_whitespace(pnt);
65
  if( *pnt != '[' ) return NULL;
66
  pnt++;
67
  pnt = skip_whitespace(pnt);
68
 
69
  list = last = NULL;
70
  while(*pnt && *pnt != ']') {
71
 
72
    pnt = skip_whitespace(pnt);
73
    if(*pnt== '\0' || *pnt == ']') break;
74
 
75
    /*
76
     * Allocate memory for the token we are about to parse, and insert
77
     * it in the linked list.
78
     */
79
    cpnt = (struct condition *) malloc(sizeof(struct condition));
80
    memset(cpnt, 0, sizeof(struct condition));
81
    if( last == NULL )
82
      {
83
        list = last = cpnt;
84
      }
85
    else
86
      {
87
        last->next = cpnt;
88
        last = cpnt;
89
      }
90
 
91
    /*
92
     * Determine what type of operation this token represents.
93
     */
94
    if( *pnt == '-' && pnt[1] == 'a' )
95
      {
96
        cpnt->op = op_and;
97
        pnt += 2;
98
        continue;
99
      }
100
 
101
    if( *pnt == '-' && pnt[1] == 'o' )
102
      {
103
        cpnt->op = op_or;
104
        pnt += 2;
105
        continue;
106
      }
107
 
108
    if( *pnt == '!' && pnt[1] == '=' )
109
      {
110
        cpnt->op = op_neq;
111
        pnt += 2;
112
        continue;
113
      }
114
 
115
    if( *pnt == '=')
116
      {
117
        cpnt->op = op_eq;
118
        pnt += 1;
119
        continue;
120
      }
121
 
122
    if( *pnt == '!')
123
      {
124
        cpnt->op = op_bang;
125
        pnt += 1;
126
        continue;
127
      }
128
 
129
    if( *pnt != '"' ) goto error;  /* This cannot be right. */
130
    pnt++;
131
    if( *pnt == '`' )
132
      {
133
        cpnt->op = op_shellcmd;
134
        pnt1 = varname;
135
        pnt++;
136
        while(*pnt && *pnt != '`') *pnt1++ = *pnt++;
137
        *pnt1++ = '\0';
138
        cpnt->variable.str = strdup(varname);
139
        if( *pnt == '`' ) pnt++;
140
        if( *pnt == '"' ) pnt++;
141
        continue;
142
      }
143
    if( *pnt == '$' )
144
      {
145
        cpnt->op = op_variable;
146
        pnt1 = varname;
147
        pnt++;
148
        while(*pnt && *pnt != '"') *pnt1++ = *pnt++;
149
        *pnt1++ = '\0';
150
        cpnt->variable.str = strdup(varname);
151
        if( *pnt == '"' ) pnt++;
152
        continue;
153
      }
154
 
155
    cpnt->op = op_constant;
156
    pnt1 = varname;
157
    while(*pnt && *pnt != '"') *pnt1++ = *pnt++;
158
    *pnt1++ = '\0';
159
    cpnt->variable.str = strdup(varname);
160
    if( *pnt == '"' ) pnt++;
161
    continue;
162
  }
163
 
164
  return list;
165
 
166
 error:
167
  if(current_file != NULL)
168
    fprintf(stderr,
169
            "Bad if clause at line %d(%s):%s\n", lineno, current_file, opnt);
170
  else
171
    fprintf(stderr,
172
            "Bad if clause at line %d:%s\n", lineno, opnt);
173
  return NULL;
174
}
175
 
176
/*
177
 * This function looks for a quoted string, from the input buffer, and
178
 * returns a pointer to a copy of this string.  Any characters in
179
 * the string that need to be "quoted" have a '\' character inserted
180
 * in front - this way we can directly write these strings into
181
 * wish scripts.
182
 */
183
static char * get_qstring(char *pnt, char ** labl)
184
{
185
  char quotechar;
186
  char newlabel[1024];
187
  char * pnt1;
188
  char * pnt2;
189
 
190
  while( *pnt && *pnt != '"' && *pnt != '\'') pnt++;
191
  if (*pnt == '\0') return pnt;
192
 
193
  quotechar = *pnt++;
194
  pnt1 = newlabel;
195
  while(*pnt && *pnt != quotechar && pnt[-1] != '\\')
196
    {
197
      /*
198
       * Quote the character if we need to.
199
       */
200
      if( *pnt == '"' || *pnt == '\'' || *pnt == '[' || *pnt == ']')
201
        *pnt1++ = '\\';
202
 
203
      *pnt1++ = *pnt++;
204
    }
205
  *pnt1++ = '\0';
206
 
207
  pnt2 = (char *) malloc(strlen(newlabel) + 1);
208
  strcpy(pnt2, newlabel);
209
  *labl = pnt2;
210
 
211
  /*
212
   * Skip over last quote, and whitespace.
213
   */
214
  pnt++;
215
  pnt = skip_whitespace(pnt);
216
  return pnt;
217
}
218
 
219
static char * parse_choices(struct kconfig * choice_kcfg, char * pnt)
220
{
221
  struct kconfig * kcfg;
222
  int index = 1;
223
 
224
  /*
225
   * Choices appear in pairs of strings.  The parse is fairly trivial.
226
   */
227
  while(1)
228
    {
229
      pnt = skip_whitespace(pnt);
230
      if(*pnt == '\0') break;
231
 
232
      kcfg = (struct kconfig *) malloc(sizeof(struct kconfig));
233
      memset(kcfg, 0, sizeof(struct kconfig));
234
      kcfg->tok = tok_choice;
235
      if( clast != NULL )
236
        {
237
          clast->next = kcfg;
238
          clast = kcfg;
239
        }
240
      else
241
        {
242
          clast = config = kcfg;
243
        }
244
 
245
      pnt = get_string(pnt, &kcfg->label);
246
      pnt = skip_whitespace(pnt);
247
      pnt = get_string(pnt, &kcfg->optionname);
248
      kcfg->choice_label = choice_kcfg;
249
      kcfg->choice_value = index++;
250
      if( strcmp(kcfg->label, choice_kcfg->value) == 0 )
251
        choice_kcfg->choice_value = kcfg->choice_value;
252
    }
253
 
254
    return pnt;
255
}
256
 
257
 
258
/*
259
 * This function grabs one text token from the input buffer
260
 * and returns a pointer to a copy of just the identifier.
261
 * This can be either a variable name (i.e. CONFIG_NET),
262
 * or it could be the default value for the option.
263
 */
264
static char * get_string(char *pnt, char ** labl)
265
{
266
  char newlabel[1024];
267
  char * pnt1;
268
  char * pnt2;
269
 
270
  if (*pnt == '\0') return pnt;
271
 
272
  pnt1 = newlabel;
273
  while(*pnt && *pnt != ' ' && *pnt != '\t')
274
    {
275
      *pnt1++ = *pnt++;
276
    }
277
  *pnt1++ = '\0';
278
 
279
  pnt2 = (char *) malloc(strlen(newlabel) + 1);
280
  strcpy(pnt2, newlabel);
281
  *labl = pnt2;
282
 
283
  if( *pnt ) pnt++;
284
  return pnt;
285
}
286
 
287
 
288
/*
289
 * Top level parse function.  Input pointer is one complete line from config.in
290
 * and the result is that we create a token that describes this line
291
 * and insert it into our linked list.
292
 */
293
void parse(char * pnt) {
294
  enum token tok;
295
  struct kconfig * kcfg;
296
  char tmpbuf[24],fake_if[1024];
297
 
298
  /*
299
   * Ignore comments and leading whitespace.
300
   */
301
 
302
  pnt = skip_whitespace(pnt);
303
  while( *pnt && (*pnt == ' ' || *pnt == '\t')) pnt++;
304
  if(! *pnt ) return;
305
  if( *pnt == '#' ) return;
306
 
307
  /*
308
   * Now categorize the next token.
309
   */
310
  tok = tok_unknown;
311
  if      (strncmp(pnt, "mainmenu_name", 13) == 0)
312
    {
313
      tok = tok_menuname;
314
      pnt += 13;
315
    }
316
  else if      (strncmp(pnt, "source", 6) == 0)
317
    {
318
      pnt += 7;
319
      pnt = skip_whitespace(pnt);
320
      do_source(pnt);
321
      return;
322
    }
323
  else if (strncmp(pnt, "mainmenu_option", 15) == 0)
324
    {
325
      menus_seen++;
326
      tok = tok_menuoption;
327
      pnt += 15;
328
    }
329
  else if (strncmp(pnt, "$MAKE ", 6) == 0)
330
    {
331
      tok = tok_make;
332
    }
333
  else if (strncmp(pnt, "comment", 7) == 0)
334
    {
335
      tok = tok_comment;
336
      pnt += 7;
337
    }
338
  else if (strncmp(pnt, "choice", 6) == 0)
339
    {
340
      tok = tok_choose;
341
      pnt += 6;
342
    }
343
  else if (strncmp(pnt, "define_bool", 11) == 0)
344
    {
345
      tok = tok_define;
346
      pnt += 11;
347
    }
348
  else if (strncmp(pnt, "define_int", 10) == 0)
349
    {
350
      tok = tok_define_int;
351
      pnt += 10;
352
    }
353
  else if (strncmp(pnt, "bool", 4) == 0)
354
    {
355
      tok = tok_bool;
356
      pnt += 4;
357
    }
358
  else if (strncmp(pnt, "tristate", 8) == 0)
359
    {
360
      tok = tok_tristate;
361
      pnt += 8;
362
    }
363
  else if (strncmp(pnt, "dep_tristate", 12) == 0)
364
    {
365
      tok = tok_dep_tristate;
366
      pnt += 12;
367
    }
368
  else if (strncmp(pnt, "int", 3) == 0)
369
    {
370
      tok = tok_int;
371
      pnt += 3;
372
    }
373
  else if (strncmp(pnt, "hex", 3) == 0)
374
    {
375
      tok = tok_hex;
376
      pnt += 3;
377
    }
378
  else if (strncmp(pnt, "if", 2) == 0)
379
    {
380
      tok = tok_if;
381
      pnt += 2;
382
    }
383
  else if (strncmp(pnt, "else", 4) == 0)
384
    {
385
      tok = tok_else;
386
      pnt += 4;
387
    }
388
  else if (strncmp(pnt, "fi", 2) == 0)
389
    {
390
      tok = tok_fi;
391
      pnt += 2;
392
    }
393
  else if (strncmp(pnt, "endmenu", 7) == 0)
394
    {
395
      tok = tok_endmenu;
396
      pnt += 7;
397
    }
398
 
399
  if( tok == tok_unknown)
400
    {
401
      if( clast != NULL && clast->tok == tok_if
402
          && strcmp(pnt,"then") == 0) return;
403
      if( current_file != NULL )
404
        fprintf(stderr, "unknown command=%s(%s %d)\n", pnt,
405
                current_file, lineno);
406
      else
407
        fprintf(stderr, "unknown command=%s(%d)\n", pnt,lineno);
408
      return;
409
    }
410
 
411
  /*
412
   * Allocate memory for this item, and attach it to the end of the linked
413
   * list.
414
   */
415
  kcfg = (struct kconfig *) malloc(sizeof(struct kconfig));
416
  memset(kcfg, 0, sizeof(struct kconfig));
417
  kcfg->tok = tok;
418
  if( clast != NULL )
419
    {
420
      clast->next = kcfg;
421
      clast = kcfg;
422
    }
423
  else
424
    {
425
      clast = config = kcfg;
426
    }
427
 
428
  pnt = skip_whitespace(pnt);
429
 
430
  /*
431
   * Now parse the remaining parts of the option, and attach the results
432
   * to the structure.
433
   */
434
  switch (tok)
435
    {
436
    case tok_choose:
437
      pnt = get_qstring(pnt, &kcfg->label);
438
      pnt = get_qstring(pnt, &kcfg->optionname);
439
      pnt = get_string(pnt, &kcfg->value);
440
      /*
441
       * Now we need to break apart the individual options into their
442
       * own configuration structures.
443
       */
444
      parse_choices(kcfg, kcfg->optionname);
445
      free(kcfg->optionname);
446
      sprintf(tmpbuf, "tmpvar_%d", choose_number++);
447
      kcfg->optionname = strdup(tmpbuf);
448
      break;
449
    case tok_define:
450
      pnt = get_string(pnt, &kcfg->optionname);
451
      if(*pnt == 'y' || *pnt == 'Y' ) kcfg->value = "1";
452
      if(*pnt == 'n' || *pnt == 'N' ) kcfg->value = "0";
453
      if(*pnt == 'm' || *pnt == 'M' ) kcfg->value = "2";
454
      break;
455
    case tok_define_int:
456
      pnt = get_string(pnt, &kcfg->optionname);
457
      pnt = get_string(pnt, &kcfg->value);
458
      break;
459
    case tok_menuname:
460
      pnt = get_qstring(pnt, &kcfg->label);
461
      break;
462
    case tok_bool:
463
    case tok_tristate:
464
      pnt = get_qstring(pnt, &kcfg->label);
465
      pnt = get_string(pnt, &kcfg->optionname);
466
      break;
467
    case tok_int:
468
    case tok_hex:
469
      pnt = get_qstring(pnt, &kcfg->label);
470
      pnt = get_string(pnt, &kcfg->optionname);
471
      pnt = get_string(pnt, &kcfg->value);
472
      break;
473
    case tok_dep_tristate:
474
      pnt = get_qstring(pnt, &kcfg->label);
475
      pnt = get_string(pnt, &kcfg->optionname);
476
      pnt = skip_whitespace(pnt);
477
      if( *pnt == '$') pnt++;
478
      pnt = get_string(pnt, &kcfg->depend.str);
479
 
480
      /*
481
       * Create a conditional for this object's dependency.
482
       *
483
       * We can't use "!= n" because this is internally converted to "!= 0"
484
       * and if UMSDOS depends on MSDOS which depends on FAT, then when FAT
485
       * is disabled MSDOS has 16 added to its value, making UMSDOS fully
486
       * available.  Whew.
487
       *
488
       * This is more of a hack than a fix.  Nested "if" conditionals are
489
       * probably affected too - that +/- 16 affects things in too many
490
       * places.  But this should do for now.
491
       */
492
      sprintf(fake_if,"[ \"$%s\" = \"y\" -o \"$%s\" = \"m\" ]; then",
493
                kcfg->depend.str,kcfg->depend.str);
494
      kcfg->cond = parse_if(fake_if);
495
      if(kcfg->cond == NULL )
496
        {
497
          exit(1);
498
        }
499
      break;
500
    case tok_comment:
501
      pnt = get_qstring(pnt, &kcfg->label);
502
      if( koption != NULL )
503
        {
504
          pnt = get_qstring(pnt, &kcfg->label);
505
          koption->label = kcfg->label;
506
          koption = NULL;
507
        }
508
      break;
509
    case tok_menuoption:
510
      if( strncmp(pnt, "next_comment", 12) == 0)
511
        {
512
          koption = kcfg;
513
        }
514
      else
515
        {
516
          pnt = get_qstring(pnt, &kcfg->label);
517
        }
518
      break;
519
    case tok_make:
520
      kcfg->value=strdup(pnt);
521
      break;
522
    case tok_else:
523
    case tok_fi:
524
    case tok_endmenu:
525
      break;
526
    case tok_if:
527
      /*
528
       * Conditionals are different.  For the first level parse, only
529
       * tok_if and tok_dep_tristate items have a ->cond chain attached.
530
       */
531
      kcfg->cond = parse_if(pnt);
532
      if(kcfg->cond == NULL )
533
        {
534
          exit(1);
535
        }
536
      break;
537
    default:
538
      exit(0);
539
    }
540
 
541
    return;
542
}
543
 
544
/*
545
 * Simple function to dump to the screen what the condition chain looks like.
546
 */
547
void dump_if(struct condition * cond)
548
{
549
  printf(" ");
550
  while(cond != NULL )
551
    {
552
      switch(cond->op){
553
      case op_eq:
554
        printf(" = ");
555
        break;
556
      case op_bang:
557
        printf(" ! ");
558
        break;
559
      case op_neq:
560
        printf(" != ");
561
        break;
562
      case op_and:
563
        printf(" -a ");
564
        break;
565
      case op_lparen:
566
        printf("(");
567
        break;
568
      case op_rparen:
569
        printf(")");
570
        break;
571
      case op_variable:
572
        printf("$%s", cond->variable.str);
573
        break;
574
      case op_constant:
575
        printf("'%s'", cond->variable.str);
576
        break;
577
      default:
578
        break;
579
      }
580
      cond = cond->next;
581
    }
582
 
583
  printf("\n");
584
}
585
 
586
static int do_source(char * filename)
587
{
588
  char buffer[1024];
589
  int  offset;
590
  int old_lineno;
591
  char * old_file;
592
  char * pnt;
593
  FILE * infile;
594
 
595
  if( strcmp(filename, "-") == 0 )
596
    infile = stdin;
597
  else
598
    infile = fopen(filename,"r");
599
 
600
  /*
601
   * If our cwd was in the scripts directory, we might have to go up one
602
   * to find the sourced file.
603
   */
604
  if(!infile) {
605
    strcpy (buffer, "../");
606
    strcat (buffer, filename);
607
    infile = fopen(buffer,"r");
608
  }
609
 
610
  if(!infile) {
611
    fprintf(stderr,"Unable to open file %s\n", filename);
612
    return 1;
613
  }
614
  old_lineno = lineno;
615
  lineno = 0;
616
  if( infile != stdin ) {
617
    old_file = current_file;
618
    current_file = filename;
619
  }
620
  offset = 0;
621
  while(1)
622
    {
623
      fgets(&buffer[offset], sizeof(buffer) - offset, infile);
624
      if(feof(infile)) break;
625
 
626
      /*
627
       * Strip the trailing return character.
628
       */
629
      pnt = buffer + strlen(buffer) - 1;
630
      if( *pnt == '\n') *pnt-- = 0;
631
      lineno++;
632
      if( *pnt == '\\' )
633
        {
634
          offset = pnt - buffer;
635
        }
636
      else
637
        {
638
          parse(buffer);
639
          offset = 0;
640
        }
641
    }
642
  fclose(infile);
643
  if( infile != stdin ) {
644
    current_file = old_file;
645
  }
646
  lineno = old_lineno;
647
  return 0;
648
}
649
 
650
int main(int argc, char * argv[])
651
{
652
#if 0
653
  char buffer[1024];
654
  char * pnt;
655
  struct kconfig * cfg;
656
  int    i;
657
#endif
658
 
659
  /*
660
   * Read stdin to get the top level script.
661
   */
662
  do_source("-");
663
 
664
  if( menus_seen == 0 )
665
    {
666
      fprintf(stderr,"The config.in file for this platform does not support\n");
667
      fprintf(stderr,"menus.\n");
668
      exit(1);
669
    }
670
  /*
671
   * Input file is now parsed.  Next we need to go through and attach
672
   * the correct conditions to each of the actual menu items and kill
673
   * the if/else/endif tokens from the list.  We also flag the menu items
674
   * that have other things that depend upon its setting.
675
   */
676
  fix_conditionals(config);
677
 
678
  /*
679
   * Finally, we generate the wish script.
680
   */
681
  dump_tk_script(config);
682
 
683
#if 0
684
  /*
685
   * Now dump what we have so far.  This is only for debugging so that
686
   * we can display what we think we have in the list.
687
   */
688
  for(cfg = config; cfg; cfg = cfg->next)
689
    {
690
 
691
      if(cfg->cond != NULL && cfg->tok != tok_if)
692
        dump_if(cfg->cond);
693
 
694
      switch(cfg->tok)
695
        {
696
        case tok_menuname:
697
          printf("main_menuname ");
698
          break;
699
        case tok_bool:
700
          printf("bool ");
701
          break;
702
        case tok_tristate:
703
          printf("tristate ");
704
          break;
705
        case tok_dep_tristate:
706
          printf("dep_tristate ");
707
          break;
708
        case tok_int:
709
          printf("int ");
710
          break;
711
        case tok_hex:
712
          printf("hex ");
713
          break;
714
        case tok_comment:
715
          printf("comment ");
716
          break;
717
        case tok_menuoption:
718
          printf("menuoption ");
719
          break;
720
        case tok_else:
721
          printf("else");
722
          break;
723
        case tok_fi:
724
          printf("fi");
725
          break;
726
        case tok_if:
727
          printf("if");
728
          break;
729
        default:
730
        }
731
 
732
      switch(cfg->tok)
733
        {
734
        case tok_menuoption:
735
        case tok_comment:
736
        case tok_menuname:
737
          printf("%s\n", cfg->label);
738
          break;
739
        case tok_bool:
740
        case tok_tristate:
741
        case tok_dep_tristate:
742
        case tok_int:
743
        case tok_hex:
744
          printf("%s %s\n", cfg->label, cfg->optionname);
745
          break;
746
        case tok_if:
747
          dump_if(cfg->cond);
748
          break;
749
        case tok_nop:
750
        case tok_endmenu:
751
          break;
752
        default:
753
          printf("\n");
754
        }
755
    }
756
#endif
757
 
758
  return 0;
759
 
760
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.