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. get_string
  5. parse
  6. dump_if
  7. do_source
  8. 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 <stdio.h>
  22 #include <string.h>
  23 #include "tkparse.h"
  24 
  25 struct kconfig * config = NULL;
  26 struct kconfig * clast = NULL;
  27 struct kconfig * koption = NULL;
  28 static int lineno = 0;
  29 static int menus_seen = 0;
  30 static char * current_file = NULL;
  31 static int do_source(char * filename);
  32 /*
  33  * Simple function just to skip over spaces and tabs in config.in.
  34  */
  35 static char * skip_whitespace(char * pnt)
     /* [previous][next][first][last][top][bottom][index][help] */
  36 {
  37   while( *pnt && (*pnt == ' ' || *pnt == '\t')) pnt++;
  38   return pnt;
  39 }
  40 
  41 /*
  42  * This function parses a conditional from a config.in (i.e. from an ifdef)
  43  * and generates a linked list of tokens that describes the conditional.
  44  */
  45 static struct condition * parse_if(char * pnt)
     /* [previous][next][first][last][top][bottom][index][help] */
  46 {
  47   char * opnt;
  48   struct condition *list;
  49   struct condition *last;
  50   struct condition *cpnt;
  51   char varname[64];
  52   char * pnt1;
  53 
  54   opnt = pnt;
  55 
  56   /*
  57    * We need to find the various tokens, and build the linked list.
  58    */
  59   pnt = skip_whitespace(pnt);
  60   if( *pnt != '[' ) return NULL;
  61   pnt++;
  62   pnt = skip_whitespace(pnt);
  63 
  64   list = last = NULL;
  65   while(*pnt && *pnt != ']') {
  66 
  67     pnt = skip_whitespace(pnt);
  68     if(*pnt== '\0' || *pnt == ']') break;
  69 
  70     /*
  71      * Allocate memory for the token we are about to parse, and insert
  72      * it in the linked list.
  73      */
  74     cpnt = (struct condition *) malloc(sizeof(struct condition));
  75     memset(cpnt, 0, sizeof(struct condition));
  76     if( last == NULL )
  77       {
  78         list = last = cpnt;
  79       }
  80     else
  81       {
  82         last->next = cpnt;
  83         last = cpnt;
  84       }
  85 
  86     /*
  87      * Determine what type of operation this token represents.
  88      */
  89     if( *pnt == '-' && pnt[1] == 'a' )
  90       {
  91         cpnt->op = op_and;
  92         pnt += 2;
  93         continue;
  94       }
  95 
  96     if( *pnt == '!' && pnt[1] == '=' )
  97       {
  98         cpnt->op = op_neq;
  99         pnt += 2;
 100         continue;
 101       }
 102 
 103     if( *pnt == '=')
 104       {
 105         cpnt->op = op_eq;
 106         pnt += 1;
 107         continue;
 108       }
 109 
 110     if( *pnt == '!')
 111       {
 112         cpnt->op = op_bang;
 113         pnt += 1;
 114         continue;
 115       }
 116 
 117     if( *pnt != '"' ) goto error;  /* This cannot be right. */
 118     pnt++;
 119     if( *pnt == '$' )
 120       {
 121         cpnt->op = op_variable;
 122         pnt1 = varname;
 123         pnt++;
 124         while(*pnt && *pnt != '"') *pnt1++ = *pnt++;
 125         *pnt1++ = '\0';
 126         cpnt->variable = strdup(varname);
 127         if( *pnt == '"' ) pnt++;
 128         continue;
 129       }
 130 
 131     cpnt->op = op_constant;
 132     pnt1 = varname;
 133     while(*pnt && *pnt != '"') *pnt1++ = *pnt++;
 134     *pnt1++ = '\0';
 135     cpnt->variable = strdup(varname);
 136     if( *pnt == '"' ) pnt++;
 137     continue;
 138   }
 139 
 140   return list;
 141 
 142  error:
 143   if(current_file != NULL) 
 144     printf("Bad if clause at line %d(%s):%s\n", lineno, current_file, opnt);
 145   else
 146     printf("Bad if clause at line %d:%s\n", lineno, opnt);
 147   return NULL;
 148 }
 149 
 150 /*
 151  * This function looks for a quoted string, from the input buffer, and
 152  * returns a pointer to a copy of this string.  Any characters in
 153  * the string that need to be "quoted" have a '\' character inserted
 154  * in front - this way we can directly write these strings into
 155  * wish scripts.
 156  */
 157 static char * get_qstring(char *pnt, char ** labl)
     /* [previous][next][first][last][top][bottom][index][help] */
 158 {
 159   char quotechar;
 160   char newlabel[1024];
 161   char * pnt1;
 162   char * pnt2;
 163 
 164   while( *pnt && *pnt != '"' && *pnt != '\'') pnt++;
 165   if (*pnt == '\0') return pnt;
 166 
 167   quotechar = *pnt++;
 168   pnt1 = newlabel;
 169   while(*pnt && *pnt != quotechar && pnt[-1] != '\\')
 170     {
 171       /*
 172        * Quote the character if we need to.
 173        */
 174       if( *pnt == '"' || *pnt == '\'' || *pnt == '[' || *pnt == ']')
 175         *pnt1++ = '\\';
 176 
 177       *pnt1++ = *pnt++;
 178     }
 179   *pnt1++ = '\0';
 180 
 181   pnt2 = (char *) malloc(strlen(newlabel) + 1);
 182   strcpy(pnt2, newlabel);
 183   *labl = pnt2;
 184 
 185   /*
 186    * Skip over last quote, and whitespace.
 187    */
 188   pnt++;
 189   pnt = skip_whitespace(pnt);
 190   return pnt;
 191 }
 192 
 193 /*
 194  * This function grabs one text token from the input buffer
 195  * and returns a pointer to a copy of just the identifier.
 196  * This can be either a variable name (i.e. CONFIG_NET),
 197  * or it could be the default value for the option.
 198  */
 199 static char * get_string(char *pnt, char ** labl)
     /* [previous][next][first][last][top][bottom][index][help] */
 200 {
 201   char quotechar;
 202   char newlabel[1024];
 203   char * pnt1;
 204   char * pnt2;
 205 
 206   if (*pnt == '\0') return pnt;
 207 
 208   pnt1 = newlabel;
 209   while(*pnt && *pnt != ' ' && *pnt != '\t')
 210     {
 211       *pnt1++ = *pnt++;
 212     }
 213   *pnt1++ = '\0';
 214 
 215   pnt2 = (char *) malloc(strlen(newlabel) + 1);
 216   strcpy(pnt2, newlabel);
 217   *labl = pnt2;
 218 
 219   if( *pnt ) pnt++;
 220   return pnt;
 221 }
 222 
 223 
 224 /*
 225  * Top level parse function.  Input pointer is one complete line from config.in
 226  * and the result is that we create a token that describes this line
 227  * and insert it into our linked list.
 228  */
 229 int parse(char * pnt) {
     /* [previous][next][first][last][top][bottom][index][help] */
 230   enum token tok;
 231   struct kconfig * kcfg;
 232   /*
 233    * Ignore comments and leading whitespace.
 234    */
 235 
 236   pnt = skip_whitespace(pnt);
 237   while( *pnt && (*pnt == ' ' || *pnt == '\t')) pnt++;
 238   if(! *pnt ) return;
 239   if( *pnt == '#' ) return;
 240 
 241   /*
 242    * Now categorize the next token.
 243    */
 244   tok = tok_unknown;
 245   if      (strncmp(pnt, "mainmenu_name", 13) == 0) 
 246     {
 247       tok = tok_menuname;
 248       pnt += 13;
 249     }
 250   else if      (strncmp(pnt, "source", 6) == 0) 
 251     {
 252       pnt += 7;
 253       pnt = skip_whitespace(pnt);
 254       do_source(pnt);
 255       return;
 256     }
 257   else if (strncmp(pnt, "mainmenu_option", 15) == 0) 
 258     {
 259       menus_seen++;
 260       tok = tok_menuoption;
 261       pnt += 15;
 262     }
 263   else if (strncmp(pnt, "comment", 7) == 0) 
 264     {
 265       tok = tok_comment;
 266       pnt += 7;
 267     }
 268   else if (strncmp(pnt, "bool", 4) == 0) 
 269     {
 270       tok = tok_bool;
 271       pnt += 4;
 272     }
 273   else if (strncmp(pnt, "tristate", 8) == 0) 
 274     {
 275       tok = tok_tristate;
 276       pnt += 8;
 277     }
 278   else if (strncmp(pnt, "dep_tristate", 12) == 0) 
 279     {
 280       tok = tok_dep_tristate;
 281       pnt += 12;
 282     }
 283   else if (strncmp(pnt, "int", 3) == 0) 
 284     {
 285       tok = tok_int;
 286       pnt += 3;
 287     }
 288   else if (strncmp(pnt, "if", 2) == 0) 
 289     {
 290       tok = tok_if;
 291       pnt += 2;
 292     }
 293   else if (strncmp(pnt, "else", 4) == 0) 
 294     {
 295       tok = tok_else;
 296       pnt += 4;
 297     }
 298   else if (strncmp(pnt, "fi", 2) == 0) 
 299     {
 300       tok = tok_fi;
 301       pnt += 2;
 302     }
 303 
 304   if( tok == tok_unknown)
 305     {
 306       printf("unknown command=%s\n", pnt);
 307       return 1;
 308     }
 309 
 310   /*
 311    * Allocate memory for this item, and attach it to the end of the linked
 312    * list.
 313    */
 314   kcfg = (struct kconfig *) malloc(sizeof(struct kconfig));
 315   memset(kcfg, 0, sizeof(struct kconfig));
 316   kcfg->tok = tok;
 317   if( clast != NULL )
 318     {
 319       clast->next = kcfg;
 320       clast = kcfg;
 321     }
 322   else
 323     {
 324       clast = config = kcfg;
 325     }
 326 
 327   pnt = skip_whitespace(pnt);
 328 
 329   /*
 330    * Now parse the remaining parts of the option, and attach the results
 331    * to the structure.
 332    */
 333   switch (tok)
 334     {
 335     case tok_menuname:
 336       pnt = get_qstring(pnt, &kcfg->label);
 337       break;
 338     case tok_bool:
 339     case tok_tristate:
 340     case tok_int:
 341       pnt = get_qstring(pnt, &kcfg->label);
 342       pnt = get_string(pnt, &kcfg->optionname);
 343       pnt = get_string(pnt, &kcfg->dflt);
 344       break;
 345     case tok_dep_tristate:
 346       pnt = get_qstring(pnt, &kcfg->label);
 347       pnt = get_string(pnt, &kcfg->optionname);
 348       pnt = get_string(pnt, &kcfg->dflt);
 349       pnt = skip_whitespace(pnt);
 350       if( *pnt == '$') pnt++;
 351       pnt = get_string(pnt, &kcfg->depend.str);
 352       break;
 353     case tok_comment:
 354       pnt = get_qstring(pnt, &kcfg->label);
 355       if( koption != NULL )
 356         {
 357           pnt = get_qstring(pnt, &kcfg->label);
 358           koption->label = kcfg->label;
 359           koption = NULL;
 360         }
 361       break;
 362     case tok_menuoption:
 363       if( strncmp(pnt, "next_comment", 12) == 0)
 364         {
 365           koption = kcfg;
 366         }
 367       else
 368         {
 369           pnt = get_qstring(pnt, &kcfg->label);
 370         }
 371       break;
 372     case tok_else:
 373     case tok_fi:
 374       break;
 375     case tok_if:
 376       /*
 377        * Conditionals are different.  For the first level parse, only
 378        * tok_if items have a ->cond chain attached.
 379        */
 380       kcfg->cond = parse_if(pnt);
 381       if(kcfg->cond == NULL )
 382         {
 383           exit(1);
 384         }
 385       break;
 386     default:
 387       exit(0);
 388 
 389     }
 390 }
 391 
 392 /*
 393  * Simple function to dump to the screen what the condition chain looks like.
 394  */
 395 dump_if(struct condition * cond)
     /* [previous][next][first][last][top][bottom][index][help] */
 396 {
 397   printf(" ");
 398   while(cond != NULL )
 399     {
 400       switch(cond->op){
 401       case op_eq:
 402         printf(" = ");
 403         break;
 404       case op_bang:
 405         printf(" ! ");
 406         break;
 407       case op_neq:
 408         printf(" != ");
 409         break;
 410       case op_and:
 411         printf(" -a ");
 412         break;
 413       case op_lparen:
 414         printf("(");
 415         break;
 416       case op_rparen:
 417         printf(")");
 418         break;
 419       case op_variable:
 420         printf("$%s", cond->variable);
 421         break;
 422       case op_constant:
 423         printf("'%s'", cond->variable);
 424         break;
 425       }
 426       cond = cond->next;
 427     }
 428 
 429   printf("\n");
 430 }
 431 
 432 static int do_source(char * filename)
     /* [previous][next][first][last][top][bottom][index][help] */
 433 {
 434   char buffer[1024];
 435   int old_lineno;
 436   char * pnt;
 437   FILE * infile;
 438 
 439   infile = fopen(filename,"r");
 440   if(!infile) {
 441     fprintf(stderr,"Unable to open file %s\n", filename);
 442     return 1;
 443   }
 444   old_lineno = lineno;
 445   lineno = 0;
 446   current_file = filename;
 447   while (fgets(buffer, sizeof(buffer), infile))
 448     {
 449       /*
 450        * Strip the trailing return character.
 451        */
 452       pnt = buffer + strlen(buffer) - 1;
 453       if( *pnt == '\n') *pnt = 0;
 454       lineno++;
 455       parse(buffer);
 456     }
 457   fclose(infile);
 458   current_file = NULL;
 459   lineno = old_lineno;
 460   return 0;
 461 }
 462 
 463 main(int argc, char * argv[])
     /* [previous][next][first][last][top][bottom][index][help] */
 464 {
 465   char * pnt;
 466   struct kconfig * cfg;
 467   char buffer[1024];
 468   int    i;
 469 
 470   /*
 471    * Loop over every input line, and parse it into the tables.
 472    */
 473   while(fgets(buffer, sizeof(buffer), stdin))
 474     {
 475       /*
 476        * Strip the trailing return character.
 477        */
 478       pnt = buffer + strlen(buffer) - 1;
 479       if( *pnt == '\n') *pnt = 0;
 480       lineno++;
 481       parse(buffer);
 482     }
 483 
 484 
 485   if( menus_seen == 0 )
 486     {
 487       fprintf(stderr,"The config.in file for this platform does not support\n");
 488       fprintf(stderr,"menus.\n");
 489       exit(1);
 490     }
 491   /*
 492    * Input file is now parsed.  Next we need to go through and attach
 493    * the correct conditions to each of the actual menu items and kill
 494    * the if/else/endif tokens from the list.  We also flag the menu items
 495    * that have other things that depend upon it's setting.
 496    */
 497   fix_conditionals(config);
 498 
 499   /*
 500    * Finally, we generate the wish script.
 501    */
 502   dump_tk_script(config);
 503 
 504 #if 0
 505   /*
 506    * Now dump what we have so far.  This is only for debugging so that
 507    * we can display what we think we have in the list.
 508    */
 509   for(cfg = config; cfg; cfg = cfg->next)
 510     {
 511 
 512       if(cfg->cond != NULL && cfg->tok != tok_if)
 513         dump_if(cfg->cond);
 514 
 515       switch(cfg->tok)
 516         {
 517         case tok_menuname:
 518           printf("main_menuname ");
 519           break;
 520         case tok_bool:
 521           printf("bool ");
 522           break;
 523         case tok_tristate:
 524           printf("tristate ");
 525           break;
 526         case tok_dep_tristate:
 527           printf("dep_tristate ");
 528           break;
 529         case tok_int:
 530           printf("int ");
 531           break;
 532         case tok_comment:
 533           printf("comment ");
 534           break;
 535         case tok_menuoption:
 536           printf("menuoption ");
 537           break;
 538         case tok_else:
 539           printf("else");
 540           break;
 541         case tok_fi:
 542           printf("fi");
 543           break;
 544         case tok_if:
 545           printf("if");
 546           break;
 547         default:
 548         }
 549 
 550       switch(cfg->tok)
 551         {
 552         case tok_menuoption:
 553         case tok_comment:
 554         case tok_menuname:
 555           printf("%s\n", cfg->label);
 556           break;
 557         case tok_bool:
 558         case tok_tristate:
 559         case tok_dep_tristate:
 560         case tok_int:
 561           printf("%s %s %s\n", cfg->label, cfg->optionname, cfg->dflt);
 562           break;
 563         case tok_if:
 564           dump_if(cfg->cond);
 565           break;
 566         case tok_nop:
 567           break;
 568         default:
 569           printf("\n");
 570         }
 571     }
 572 #endif
 573 
 574   return 0;
 575 
 576 }

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