root/scripts/tkparse.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. skip_whitespace
  2. parse_if
  3. get_qstring
  4. parse_choices
  5. get_string
  6. parse
  7. dump_if
  8. do_source
  9. main

   1 /* 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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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)
     /* [previous][next][first][last][top][bottom][index][help] */
  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 = 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 = 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 = 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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)
     /* [previous][next][first][last][top][bottom][index][help] */
 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 }
 255 
 256 
 257 /*
 258  * This function grabs one text token from the input buffer
 259  * and returns a pointer to a copy of just the identifier.
 260  * This can be either a variable name (i.e. CONFIG_NET),
 261  * or it could be the default value for the option.
 262  */
 263 static char * get_string(char *pnt, char ** labl)
     /* [previous][next][first][last][top][bottom][index][help] */
 264 {
 265   char quotechar;
 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 int parse(char * pnt) {
     /* [previous][next][first][last][top][bottom][index][help] */
 294   enum token tok;
 295   struct kconfig * kcfg;
 296   char tmpbuf[24];
 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 -C drivers/sound", 22) == 0) 
 330     {
 331       pnt += 22;
 332       tok = tok_sound;
 333     }
 334   else if (strncmp(pnt, "comment", 7) == 0) 
 335     {
 336       tok = tok_comment;
 337       pnt += 7;
 338     }
 339   else if (strncmp(pnt, "choice", 6) == 0) 
 340     {
 341       tok = tok_choose;
 342       pnt += 6;
 343     }
 344   else if (strncmp(pnt, "define_bool", 11) == 0) 
 345     {
 346       tok = tok_define;
 347       pnt += 11;
 348     }
 349   else if (strncmp(pnt, "bool", 4) == 0) 
 350     {
 351       tok = tok_bool;
 352       pnt += 4;
 353     }
 354   else if (strncmp(pnt, "tristate", 8) == 0) 
 355     {
 356       tok = tok_tristate;
 357       pnt += 8;
 358     }
 359   else if (strncmp(pnt, "dep_tristate", 12) == 0) 
 360     {
 361       tok = tok_dep_tristate;
 362       pnt += 12;
 363     }
 364   else if (strncmp(pnt, "int", 3) == 0) 
 365     {
 366       tok = tok_int;
 367       pnt += 3;
 368     }
 369   else if (strncmp(pnt, "if", 2) == 0) 
 370     {
 371       tok = tok_if;
 372       pnt += 2;
 373     }
 374   else if (strncmp(pnt, "else", 4) == 0) 
 375     {
 376       tok = tok_else;
 377       pnt += 4;
 378     }
 379   else if (strncmp(pnt, "fi", 2) == 0) 
 380     {
 381       tok = tok_fi;
 382       pnt += 2;
 383     }
 384 
 385   if( tok == tok_unknown)
 386     {
 387       if( clast != NULL && clast->tok == tok_if 
 388           && strcmp(pnt,"then") == 0) return 0;
 389       if( current_file != NULL )
 390         fprintf(stderr, "unknown command=%s(%s %d)\n", pnt,
 391                 current_file, lineno);
 392       else
 393         fprintf(stderr, "unknown command=%s(%d)\n", pnt,lineno);
 394       return 1;
 395     }
 396 
 397   /*
 398    * Allocate memory for this item, and attach it to the end of the linked
 399    * list.
 400    */
 401   kcfg = (struct kconfig *) malloc(sizeof(struct kconfig));
 402   memset(kcfg, 0, sizeof(struct kconfig));
 403   kcfg->tok = tok;
 404   if( clast != NULL )
 405     {
 406       clast->next = kcfg;
 407       clast = kcfg;
 408     }
 409   else
 410     {
 411       clast = config = kcfg;
 412     }
 413 
 414   pnt = skip_whitespace(pnt);
 415 
 416   /*
 417    * Now parse the remaining parts of the option, and attach the results
 418    * to the structure.
 419    */
 420   switch (tok)
 421     {
 422     case tok_choose:
 423       pnt = get_qstring(pnt, &kcfg->label);
 424       pnt = get_qstring(pnt, &kcfg->optionname);
 425       pnt = get_string(pnt, &kcfg->value);
 426       /*
 427        * Now we need to break apart the individual options into their
 428        * own configuration structures.
 429        */
 430       parse_choices(kcfg, kcfg->optionname);
 431       free(kcfg->optionname);
 432       sprintf(tmpbuf, "tmpvar_%d", choose_number++);
 433       kcfg->optionname = strdup(tmpbuf);
 434       break;
 435     case tok_define:
 436       pnt = get_string(pnt, &kcfg->optionname);
 437       if(*pnt == 'y' || *pnt == 'Y' ) kcfg->value = "1";
 438       if(*pnt == 'n' || *pnt == 'N' ) kcfg->value = "0";
 439       if(*pnt == 'm' || *pnt == 'M' ) kcfg->value = "2";
 440       break;
 441     case tok_menuname:
 442       pnt = get_qstring(pnt, &kcfg->label);
 443       break;
 444     case tok_bool:
 445     case tok_tristate:
 446     case tok_int:
 447       pnt = get_qstring(pnt, &kcfg->label);
 448       pnt = get_string(pnt, &kcfg->optionname);
 449       break;
 450     case tok_dep_tristate:
 451       pnt = get_qstring(pnt, &kcfg->label);
 452       pnt = get_string(pnt, &kcfg->optionname);
 453       pnt = skip_whitespace(pnt);
 454       if( *pnt == '$') pnt++;
 455       pnt = get_string(pnt, &kcfg->depend.str);
 456       break;
 457     case tok_comment:
 458       pnt = get_qstring(pnt, &kcfg->label);
 459       if( koption != NULL )
 460         {
 461           pnt = get_qstring(pnt, &kcfg->label);
 462           koption->label = kcfg->label;
 463           koption = NULL;
 464         }
 465       break;
 466     case tok_menuoption:
 467       if( strncmp(pnt, "next_comment", 12) == 0)
 468         {
 469           koption = kcfg;
 470         }
 471       else
 472         {
 473           pnt = get_qstring(pnt, &kcfg->label);
 474         }
 475       break;
 476     case tok_else:
 477     case tok_fi:
 478     case tok_sound:
 479       break;
 480     case tok_if:
 481       /*
 482        * Conditionals are different.  For the first level parse, only
 483        * tok_if items have a ->cond chain attached.
 484        */
 485       kcfg->cond = parse_if(pnt);
 486       if(kcfg->cond == NULL )
 487         {
 488           exit(1);
 489         }
 490       break;
 491     default:
 492       exit(0);
 493 
 494     }
 495 }
 496 
 497 /*
 498  * Simple function to dump to the screen what the condition chain looks like.
 499  */
 500 dump_if(struct condition * cond)
     /* [previous][next][first][last][top][bottom][index][help] */
 501 {
 502   printf(" ");
 503   while(cond != NULL )
 504     {
 505       switch(cond->op){
 506       case op_eq:
 507         printf(" = ");
 508         break;
 509       case op_bang:
 510         printf(" ! ");
 511         break;
 512       case op_neq:
 513         printf(" != ");
 514         break;
 515       case op_and:
 516         printf(" -a ");
 517         break;
 518       case op_lparen:
 519         printf("(");
 520         break;
 521       case op_rparen:
 522         printf(")");
 523         break;
 524       case op_variable:
 525         printf("$%s", cond->variable);
 526         break;
 527       case op_constant:
 528         printf("'%s'", cond->variable);
 529         break;
 530       }
 531       cond = cond->next;
 532     }
 533 
 534   printf("\n");
 535 }
 536 
 537 static int do_source(char * filename)
     /* [previous][next][first][last][top][bottom][index][help] */
 538 {
 539   char buffer[1024];
 540   int  offset;
 541   int old_lineno;
 542   char * old_file;
 543   char * pnt;
 544   FILE * infile;
 545 
 546   if( strcmp(filename, "-") == 0 )
 547     infile = stdin;
 548   else
 549     infile = fopen(filename,"r");
 550 
 551   /*
 552    * If our cwd was in the scripts directory, we might have to go up one
 553    * to find the sourced file.
 554    */
 555   if(!infile) {
 556     strcpy (buffer, "../");
 557     strcat (buffer, filename);
 558     infile = fopen(buffer,"r");
 559   }
 560 
 561   if(!infile) {
 562     fprintf(stderr,"Unable to open file %s\n", filename);
 563     return 1;
 564   }
 565   old_lineno = lineno;
 566   lineno = 0;
 567   if( infile != stdin ) {
 568     old_file = current_file;
 569     current_file = filename;
 570   }
 571   offset = 0;
 572   while(1)
 573     {
 574       fgets(&buffer[offset], sizeof(buffer) - offset, infile);
 575       if(feof(infile)) break;
 576 
 577       /*
 578        * Strip the trailing return character.
 579        */
 580       pnt = buffer + strlen(buffer) - 1;
 581       if( *pnt == '\n') *pnt-- = 0;
 582       lineno++;
 583       if( *pnt == '\\' )
 584         {
 585           offset = pnt - buffer;
 586         }
 587       else
 588         {
 589           parse(buffer);
 590           offset = 0;
 591         }
 592     }
 593   fclose(infile);
 594   if( infile != stdin ) {
 595     current_file = old_file;
 596   }
 597   lineno = old_lineno;
 598   return 0;
 599 }
 600 
 601 main(int argc, char * argv[])
     /* [previous][next][first][last][top][bottom][index][help] */
 602 {
 603   char buffer[1024];
 604   char * pnt;
 605   struct kconfig * cfg;
 606   int    i;
 607 
 608   /*
 609    * Read stdin to get the top level script.
 610    */
 611   do_source("-");
 612 
 613   if( menus_seen == 0 )
 614     {
 615       fprintf(stderr,"The config.in file for this platform does not support\n");
 616       fprintf(stderr,"menus.\n");
 617       exit(1);
 618     }
 619   /*
 620    * Input file is now parsed.  Next we need to go through and attach
 621    * the correct conditions to each of the actual menu items and kill
 622    * the if/else/endif tokens from the list.  We also flag the menu items
 623    * that have other things that depend upon it's setting.
 624    */
 625   fix_conditionals(config);
 626 
 627   /*
 628    * Finally, we generate the wish script.
 629    */
 630   dump_tk_script(config);
 631 
 632 #if 0
 633   /*
 634    * Now dump what we have so far.  This is only for debugging so that
 635    * we can display what we think we have in the list.
 636    */
 637   for(cfg = config; cfg; cfg = cfg->next)
 638     {
 639 
 640       if(cfg->cond != NULL && cfg->tok != tok_if)
 641         dump_if(cfg->cond);
 642 
 643       switch(cfg->tok)
 644         {
 645         case tok_menuname:
 646           printf("main_menuname ");
 647           break;
 648         case tok_bool:
 649           printf("bool ");
 650           break;
 651         case tok_tristate:
 652           printf("tristate ");
 653           break;
 654         case tok_dep_tristate:
 655           printf("dep_tristate ");
 656           break;
 657         case tok_int:
 658           printf("int ");
 659           break;
 660         case tok_comment:
 661           printf("comment ");
 662           break;
 663         case tok_menuoption:
 664           printf("menuoption ");
 665           break;
 666         case tok_else:
 667           printf("else");
 668           break;
 669         case tok_fi:
 670           printf("fi");
 671           break;
 672         case tok_if:
 673           printf("if");
 674           break;
 675         default:
 676         }
 677 
 678       switch(cfg->tok)
 679         {
 680         case tok_menuoption:
 681         case tok_comment:
 682         case tok_menuname:
 683           printf("%s\n", cfg->label);
 684           break;
 685         case tok_bool:
 686         case tok_tristate:
 687         case tok_dep_tristate:
 688         case tok_int:
 689           printf("%s %s\n", cfg->label, cfg->optionname);
 690           break;
 691         case tok_if:
 692           dump_if(cfg->cond);
 693           break;
 694         case tok_nop:
 695           break;
 696         default:
 697           printf("\n");
 698         }
 699     }
 700 #endif
 701 
 702   return 0;
 703 
 704 }

/* [previous][next][first][last][top][bottom][index][help] */