linux-old/scripts/tkgen.c
<<
>>
Prefs
   1/* Generate tk script based upon config.in
   2 *
   3 * Version 1.0
   4 * Eric Youngdale
   5 * 10/95
   6 *
   7 * 1996 01 04
   8 * Avery Pennarun - Aesthetic improvements.
   9 *
  10 * 1996 01 24
  11 * Avery Pennarun - Bugfixes and more aesthetics.
  12 *
  13 * 1996 03 08
  14 * Avery Pennarun - The int and hex config.in commands work right.
  15 *                - Choice buttons are more user-friendly.
  16 *                - Disabling a text entry line greys it out properly.
  17 *                - dep_tristate now works like in Configure. (not pretty)
  18 *                - No warnings in gcc -Wall. (Fixed some "interesting" bugs.)
  19 *                - Faster/prettier "Help" lookups.
  20 *
  21 * 1996 03 15
  22 * Avery Pennarun - Added new sed script from Axel Boldt to make help even
  23 *                  faster. (Actually awk is downright slow on some machines.)
  24 *                - Fixed a bug I introduced into Choice dependencies.  Thanks
  25 *                  to Robert Krawitz for pointing this out.
  26 *
  27 * 1996 03 16
  28 * Avery Pennarun - basic "do_make" support added to let sound config work.
  29 *
  30 * 1996 03 25
  31 *     Axel Boldt - Help now works on "choice" buttons.
  32 *
  33 * 1996 04 06
  34 * Avery Pennarun - Improved sound config stuff. (I think it actually works
  35 *                  now!)
  36 *                - Window-resize-limits don't use ugly /usr/lib/tk4.0 hack.
  37 *                - int/hex work with tk3 again. (The "cget" error.)
  38 *                - Next/Prev buttons switch between menus.  I can't take
  39 *                  much credit for this; the code was already there, but
  40 *                  ifdef'd out for some reason.  It flickers a lot, but
  41 *                  I suspect there's no "easy" fix for that.
  42 *                - Labels no longer highlight as you move the mouse over
  43 *                  them (although you can still press them... oh well.)
  44 *                - Got rid of the last of the literal color settings, to
  45 *                  help out people with mono X-Windows systems. 
  46 *                  (Apparently there still are some out there!)
  47 *                - Tabstops seem sensible now.
  48 *
  49 * 1996 04 14
  50 * Avery Pennarun - Reduced flicker when creating windows, even with "update
  51 *                  idletasks" hack.
  52 *
  53 * TO DO:
  54 *   - clean up - there are useless ifdef's everywhere.
  55 *   - better comments throughout - C code generating tcl is really cryptic.
  56 *   - eliminate silly "update idletasks" hack to improve display speed and
  57 *     reduce flicker.  But how?
  58 *   - make canvas contents resize with the window (good luck).
  59 *   - some way to make submenus inside of submenus (ie. Main->Networking->IP)
  60 *           (perhaps a button where the description would be)
  61 *   - make the main menu use the same tcl code as the submenus.
  62 *   - make choice and int/hex input types line up vertically with
  63 *           bool/tristate.
  64 *   - general speedups - how?  The canvas seems to slow it down a lot.
  65 *   - choice buttons should default to the first menu option, rather than a
  66 *           blank.  Also look up the right variable when the help button
  67 *           is pressed.
  68 *   - clean up +/- 16 confusion for enabling/disabling variables; causes
  69 *           (theoretical, at the moment) problems with dependencies.
  70 *   
  71 */
  72#include <stdio.h>
  73#include <unistd.h>
  74#include "tkparse.h"
  75
  76#ifndef TRUE
  77#define TRUE (1)
  78#endif
  79
  80#ifndef FALSE
  81#define FALSE (0)
  82#endif
  83
  84/*
  85 * This is the total number of submenus that we have.
  86 */
  87static int tot_menu_num =0;
  88
  89/*
  90 * Generate portion of wish script for the beginning of a submenu.
  91 * The guts get filled in with the various options.
  92 */
  93static void start_proc(char * label, int menu_num, int flag)
  94{
  95  if( flag )
  96    printf("menu_option menu%d %d \"%s\"\n", menu_num, menu_num, label);
  97  printf("proc menu%d {w title} {\n", menu_num);
  98  printf("\tcatch {destroy $w}\n");
  99  printf("\ttoplevel $w -class Dialog\n");
 100  printf("\twm withdraw $w\n");
 101  printf("\tmessage $w.m -width 400 -aspect 300 -text \\\n");
 102  printf("\t\t\"%s\"  -relief raised\n",label);
 103  printf("\tpack $w.m -pady 10 -side top -padx 10\n");
 104  printf("\twm title $w \"%s\" \n\n", label);
 105  
 106  /*
 107   * Attach the "Prev", "Next" and "OK" buttons at the end of the window.
 108   */
 109  printf("\tset oldFocus [focus]\n");
 110  printf("\tframe $w.f\n");
 111  printf("\tbutton $w.f.back -text \"Main Menu\" \\\n"
 112         "\t\t-width 15 -command \"destroy $w; focus $oldFocus; update_mainmenu $w\"\n");
 113  printf("\tbutton $w.f.next -text \"Next\" \\\n"
 114         "\t\t-width 15 -command \" destroy $w; focus $oldFocus;  menu%d .menu%d \\\"$title\\\"\"\n",
 115                menu_num+1, menu_num+1);
 116  if (menu_num == tot_menu_num)
 117        printf("\t$w.f.next configure -state disabled\n");
 118  printf("\tbutton $w.f.prev -text \"Prev\" \\\n"
 119         "\t\t-width 15 -command \" destroy $w; focus $oldFocus; menu%d .menu%d \\\"$title\\\"\"\n",
 120                menu_num-1, menu_num-1);
 121  if (1 == menu_num)
 122        printf("\t$w.f.prev configure -state disabled\n");
 123  printf("\tpack $w.f.back $w.f.next $w.f.prev -side left -expand on\n");
 124  printf("\tpack $w.f -pady 10 -side bottom -anchor w -fill x\n");
 125
 126  /*
 127   * Lines between canvas and other areas of the window.
 128   */
 129  printf("\tframe $w.topline -relief ridge -borderwidth 2 -height 2\n");
 130  printf("\tpack $w.topline -side top -fill x\n\n");
 131  printf("\tframe $w.botline -relief ridge -borderwidth 2 -height 2\n");
 132  printf("\tpack $w.botline -side bottom -fill x\n\n");
 133  
 134  /*
 135   * The "config" frame contains the canvas and a scrollbar.
 136   */
 137  printf("\tframe $w.config\n");
 138  printf("\tpack $w.config -fill y -expand on\n\n");
 139  printf("\tscrollbar $w.config.vscroll -command \"$w.config.canvas yview\"\n");
 140  printf("\tpack $w.config.vscroll -side right -fill y\n\n");
 141  
 142  /*
 143   * The scrollable canvas itself, where the real work (and mess) gets done.
 144   */
 145  printf("\tcanvas $w.config.canvas -height 1\\\n"
 146         "\t\t-relief flat -borderwidth 0 -yscrollcommand \"$w.config.vscroll set\" \\\n"
 147         "\t\t-width [expr [winfo screenwidth .] * 1 / 2] \n");
 148  printf("\tframe $w.config.f\n");
 149  printf("\tpack $w.config.canvas -side right -fill y\n");
 150  
 151  printf("\n\n");
 152}
 153
 154/*
 155 * Each proc we create needs a global declaration for any global variables we
 156 * use.  To minimize the size of the file, we set a flag each time we output
 157 * a global declaration so we know whether we need to insert one for a
 158 * given function or not.
 159 */
 160void clear_globalflags(struct kconfig * cfg)
 161{
 162  for(; cfg != NULL; cfg = cfg->next)
 163  {
 164    cfg->flags &= ~GLOBAL_WRITTEN;
 165  }
 166}
 167
 168/*
 169 * Output a "global" line for a given variable.  Also include the
 170 * call to "vfix".  (If vfix is not needed, then it's fine to just printf
 171 * a "global" line).
 172 */
 173void inline global(char *var)
 174{
 175  printf("\tglobal %s; vfix %s\n", var, var);
 176}
 177
 178/*
 179 * This function walks the chain of conditions that we got from cond.c,
 180 * and creates a wish conditional to enable/disable a given widget.
 181 */
 182void generate_if(struct kconfig * item,
 183            struct condition * cond,
 184            int menu_num,
 185            int line_num)
 186{
 187  struct condition * ocond;
 188
 189  ocond = cond;
 190
 191  /*
 192   * First write any global declarations we need for this conditional.
 193   */
 194  while(cond != NULL )
 195    {
 196      switch(cond->op){
 197      case op_variable:
 198        global(cond->variable.str);
 199        break;
 200      case op_kvariable:
 201        if(cond->variable.cfg->flags & GLOBAL_WRITTEN) break;
 202        cond->variable.cfg->flags |= GLOBAL_WRITTEN;
 203        global(cond->variable.cfg->optionname);
 204        break;
 205      default:
 206        break;
 207      }
 208      cond = cond->next;
 209    }
 210  
 211  /*
 212   * Now write this option.
 213   */
 214  if(   (item->flags & GLOBAL_WRITTEN) == 0
 215     && (item->optionname != NULL) )
 216    {
 217      global(item->optionname);
 218      item->flags |= GLOBAL_WRITTEN;
 219    }
 220  /*
 221   * Now generate the body of the conditional.
 222   */
 223  printf("\tif {");
 224  cond = ocond;
 225  while(cond != NULL )
 226    {
 227      switch(cond->op){
 228      case op_bang:
 229        printf(" ! ");
 230        break;
 231      case op_eq:
 232        printf(" == ");
 233        break;
 234      case op_neq:
 235        printf(" != ");
 236        break;
 237      case op_and:
 238      case op_and1:
 239        printf(" && ");
 240        break;
 241      case op_or:
 242        printf(" || ");
 243        break;
 244      case op_lparen:
 245        printf("(");
 246        break;
 247      case op_rparen:
 248        printf(")");
 249        break;
 250      case op_variable:
 251        printf("$%s", cond->variable.str);
 252        break;
 253      case op_kvariable:
 254        printf("$%s", cond->variable.cfg->optionname);
 255        break;
 256      case op_shellcmd:
 257        printf("[exec %s]", cond->variable.str);
 258        break;
 259      case op_constant:
 260        if( strcmp(cond->variable.str, "y") == 0 )
 261          printf("1");
 262        else if( strcmp(cond->variable.str, "n") == 0 )
 263          printf("0");
 264        else if( strcmp(cond->variable.str, "m") == 0 )
 265          printf("2");
 266        else
 267          printf("\"%s\"", cond->variable.str);
 268        break;
 269      default:
 270        break;
 271      }
 272      cond = cond->next;
 273    }
 274
 275  /*
 276   * Now we generate what we do depending upon the value of the conditional.
 277   * Depending upon what the token type is, there are different things
 278   * we must do to enable/disable the given widget - this code needs to
 279   * be closely coordinated with the widget creation procedures in header.tk.
 280   */
 281  switch(item->tok)
 282    {
 283    case tok_define:
 284      printf("} then { set %s %s } \n",  item->optionname, item->value);
 285      break;
 286    case tok_menuoption:
 287      printf("} then { .f0.x%d configure -state normal } else { .f0.x%d configure -state disabled }\n",
 288             menu_num, menu_num);
 289      break;
 290    case tok_int:
 291    case tok_hex:
 292    case tok_string:
 293      printf("} then { ");
 294      printf(".menu%d.config.f.x%d.x configure -state normal -fore [ cget .ref -foreground ]; ", menu_num, line_num);
 295      printf(".menu%d.config.f.x%d.l configure -state normal; ", menu_num, line_num);
 296      printf("} else { ");
 297      printf(".menu%d.config.f.x%d.x configure -state disabled -fore [ cget .ref -disabledforeground ];", menu_num, line_num );
 298      printf(".menu%d.config.f.x%d.l configure -state disabled;", menu_num, line_num );
 299      printf("}\n");
 300      break;
 301    case tok_bool:
 302#ifdef BOOL_IS_BUTTON
 303      /*
 304       * If a bool is just a button, then use this definition.
 305       */
 306      printf("} then { .menu%d.config.f.x%d configure -state normal } else { .menu%d.config.f.x%d configure -state disabled }\n",
 307             menu_num, line_num,
 308             menu_num, line_num );
 309#else
 310      /*
 311       * If a bool is a radiobutton, then use this instead.
 312       */
 313      printf("} then { ");
 314      printf(".menu%d.config.f.x%d.y configure -state normal;",menu_num, line_num);
 315      printf(".menu%d.config.f.x%d.n configure -state normal;",menu_num, line_num);
 316      printf(".menu%d.config.f.x%d.l configure -state normal;",menu_num, line_num);
 317      printf("set %s [expr $%s&15];", item->optionname, item->optionname);
 318      printf("} else { ");
 319      printf(".menu%d.config.f.x%d.y configure -state disabled;",menu_num, line_num);
 320      printf(".menu%d.config.f.x%d.n configure -state disabled;",menu_num, line_num);
 321      printf(".menu%d.config.f.x%d.l configure -state disabled;",menu_num, line_num);
 322      printf("set %s [expr $%s|16];", item->optionname, item->optionname);
 323      printf("}\n");
 324#endif
 325      break;
 326    case tok_tristate:
 327    case tok_dep_tristate:
 328      printf("} then { ");
 329      if( item->tok == tok_dep_tristate )
 330        {
 331          global(item->depend.str);
 332          printf("if { $%s != 1 && $%s != 0 } then {", 
 333                item->depend.str,item->depend.str);
 334          printf(".menu%d.config.f.x%d.y configure -state disabled;",menu_num, line_num);
 335          printf("} else {");
 336          printf(".menu%d.config.f.x%d.y configure -state normal;",menu_num, line_num);
 337          printf("}; ");
 338        }
 339      else
 340        {
 341          printf(".menu%d.config.f.x%d.y configure -state normal;",menu_num, line_num);
 342        }
 343      
 344      printf(".menu%d.config.f.x%d.n configure -state normal;",menu_num, line_num);
 345      printf(".menu%d.config.f.x%d.m configure -state normal;",menu_num, line_num);
 346      printf(".menu%d.config.f.x%d.l configure -state normal;",menu_num, line_num);
 347      /*
 348       * Or in a bit to the variable - this causes all of the radiobuttons
 349       * to be deselected (i.e. not be red).
 350       */
 351      printf("set %s [expr $%s&15];", item->optionname, item->optionname);
 352      printf("} else { ");
 353      printf(".menu%d.config.f.x%d.y configure -state disabled;",menu_num, line_num);
 354      printf(".menu%d.config.f.x%d.n configure -state disabled;",menu_num, line_num);
 355      printf(".menu%d.config.f.x%d.m configure -state disabled;",menu_num, line_num);
 356      printf(".menu%d.config.f.x%d.l configure -state disabled;",menu_num, line_num);
 357      /*
 358       * Clear the disable bit - this causes the correct radiobutton
 359       * to appear selected (i.e. turn red).
 360       */
 361      printf("set %s [expr $%s|16];", item->optionname, item->optionname);
 362      printf("}\n");
 363      break;
 364    case tok_choose:
 365    case tok_choice:
 366      fprintf(stderr,"Fixme\n");
 367      exit(0);
 368    default:
 369      break;
 370    }
 371}
 372
 373/*
 374 * Similar to generate_if, except we come here when generating an
 375 * output file.  Thus instead of enabling/disabling a widget, we
 376 * need to decide whether to write out a given configuration variable
 377 * to the output file.
 378 */
 379void generate_if_for_outfile(struct kconfig * item,
 380            struct condition * cond)
 381{
 382  struct condition * ocond;
 383
 384  /*
 385   * First write any global declarations we need for this conditional.
 386   */
 387  ocond = cond;
 388  for(; cond != NULL; cond = cond->next )
 389    {
 390      switch(cond->op){
 391      case op_variable:
 392        global(cond->variable.str);
 393        break;
 394      case op_kvariable:
 395        if(cond->variable.cfg->flags & GLOBAL_WRITTEN) break;
 396        cond->variable.cfg->flags |= GLOBAL_WRITTEN;
 397        global(cond->variable.cfg->optionname);
 398        break;
 399      default:
 400        break;
 401      }
 402    }
 403
 404  /*
 405   * Now generate the body of the conditional.
 406   */
 407  printf("\tif {");
 408  cond = ocond;
 409  while(cond != NULL )
 410    {
 411      switch(cond->op){
 412      case op_bang:
 413        printf(" ! ");
 414        break;
 415      case op_eq:
 416        printf(" == ");
 417        break;
 418      case op_neq:
 419        printf(" != ");
 420        break;
 421      case op_and:
 422      case op_and1:
 423        printf(" && ");
 424        break;
 425      case op_or:
 426        printf(" || ");
 427        break;
 428      case op_lparen:
 429        printf("(");
 430        break;
 431      case op_rparen:
 432        printf(")");
 433        break;
 434      case op_variable:
 435        printf("$%s", cond->variable.str);
 436        break;
 437      case op_shellcmd:
 438        printf("[exec %s]", cond->variable.str);
 439        break;
 440      case op_kvariable:
 441        printf("$%s", cond->variable.cfg->optionname);
 442        break;
 443      case op_constant:
 444        if( strcmp(cond->variable.str, "y") == 0 )
 445          printf("1");
 446        else if( strcmp(cond->variable.str, "n") == 0 )
 447          printf("0");
 448        else if( strcmp(cond->variable.str, "m") == 0 )
 449          printf("2");
 450        else
 451          printf("\"%s\"", cond->variable.str);
 452        break;
 453      default:
 454        break;
 455      }
 456      cond = cond->next;
 457    }
 458
 459  /*
 460   * Now we generate what we do depending upon the value of the
 461   * conditional.  Depending upon what the token type is, there are
 462   * different things we must do write the value the given widget -
 463   * this code needs to be closely coordinated with the widget
 464   * creation procedures in header.tk.  
 465   */
 466  switch(item->tok)
 467    {
 468    case tok_define:
 469      printf("} then {write_tristate $cfg $autocfg %s %s $notmod }\n", item->optionname, item->value);
 470      break;
 471    case tok_comment:
 472      printf("} then {write_comment $cfg $autocfg \"%s\"}\n", item->label);
 473      break;
 474    case tok_dep_tristate:
 475      printf("} then { write_tristate $cfg $autocfg %s $%s $%s } \n", 
 476             item->optionname, item->optionname, item->depend.str);
 477      break;
 478    case tok_tristate:
 479    case tok_bool:
 480      printf("} then { write_tristate $cfg $autocfg %s $%s $notmod }\n", 
 481             item->optionname, item->optionname);
 482      break;
 483    case tok_int:
 484      printf("} then { write_int $cfg $autocfg %s $%s $notmod }\n",
 485             item->optionname, item->optionname);
 486      break;
 487    case tok_hex:
 488      printf("} then { write_hex $cfg $autocfg %s $%s $notmod }\n",
 489             item->optionname, item->optionname);
 490      break;
 491    case tok_string:
 492      printf("} then { write_string $cfg $autocfg %s $%s $notmod }\n",
 493             item->optionname, item->optionname);
 494      break;
 495    case tok_make:
 496      printf("} then { do_make {%s} }\n",item->value);
 497      break;
 498    case tok_choose:
 499    case tok_choice:
 500      fprintf(stderr,"Fixme\n");
 501      exit(0);
 502    default:
 503      break;
 504    }
 505}
 506
 507/*
 508 * Generates a fragment of wish script that closes out a submenu procedure.
 509 */
 510static void end_proc(int menu_num)
 511{
 512  struct kconfig * cfg;
 513
 514  printf("\n\n\n");
 515  printf("\tfocus $w\n");
 516  printf("\tupdate_menu%d $w.config.f\n", menu_num);
 517  printf("\tglobal winx; global winy\n");
 518  printf("\tset winx [expr [winfo x .]+30]; set winy [expr [winfo y .]+30]\n");
 519  printf("\twm geometry $w +$winx+$winy\n");
 520  
 521  /*
 522   * Now that the whole window is in place, we need to wait for an "update"
 523   * so we can tell the canvas what its virtual size should be.
 524   *
 525   * Unfortunately, this causes some ugly screen-flashing because the whole
 526   * window is drawn, and then it is immediately resized.  It seems
 527   * unavoidable, though, since "frame" objects won't tell us their size
 528   * until after an update, and "canvas" objects can't automatically pack
 529   * around frames.  Sigh.
 530   */
 531  printf("\tupdate idletasks\n");
 532  printf("\t$w.config.canvas create window 0 0 -anchor nw -window $w.config.f\n\n");
 533  printf("\t$w.config.canvas configure \\\n"
 534         "\t\t-width [expr [winfo reqwidth $w.config.f] + 1]\\\n"
 535         "\t\t-scrollregion \"-1 -1 [expr [winfo reqwidth $w.config.f] + 1] \\\n"
 536         "\t\t\t [expr [winfo reqheight $w.config.f] + 1]\"\n\n");
 537         
 538  /*
 539   * If the whole canvas will fit in 3/4 of the screen height, do it;
 540   * otherwise, resize to around 1/2 the screen and let us scroll.
 541   */
 542  printf("\tset winy [expr [winfo reqh $w] - [winfo reqh $w.config.canvas]]\n");
 543  printf("\tset scry [expr [winfo screenh $w] / 2]\n");
 544  printf("\tset maxy [expr [winfo screenh $w] * 3 / 4]\n");
 545  printf("\tset canvtotal [expr [winfo reqh $w.config.f] + 2]\n");
 546  printf("\tif [expr $winy + $canvtotal < $maxy] {\n"
 547         "\t\t$w.config.canvas configure -height $canvtotal\n"
 548         "\t} else {\n"
 549         "\t\t$w.config.canvas configure -height [expr $scry - $winy]\n"
 550         "\t}\n");
 551  
 552  /*
 553   * Limit the min/max window size.  Height can vary, but not width,
 554   * because of the limitations of canvas and our laziness.
 555   */
 556  printf("\tupdate idletasks\n");
 557  printf("\twm maxsize $w [winfo width $w] [winfo screenheight $w]\n");
 558  printf("\twm minsize $w [winfo width $w] 100\n\n");
 559  printf("\twm deiconify $w\n");
 560    
 561  printf("}\n\n\n");
 562
 563  /*
 564   * Now we generate the companion procedure for the menu we just
 565   * generated.  This procedure contains all of the code to
 566   * disable/enable widgets based upon the settings of the other
 567   * widgets, and will be called first when the window is mapped,
 568   * and each time one of the buttons in the window are clicked.
 569   */
 570  printf("proc update_menu%d {w}  {\n", menu_num);
 571
 572  printf("\tupdate_define\n");
 573  clear_globalflags(config);
 574  for(cfg = config;cfg != NULL; cfg = cfg->next)
 575    {
 576      /*
 577       * Skip items not for this menu, or ones having no conditions.
 578       */
 579      if (cfg->menu_number != menu_num ) continue;
 580      if (cfg->tok != tok_define) continue;
 581      /*
 582       * Clear all of the booleans that are defined in this menu.
 583       */
 584      if(   (cfg->flags & GLOBAL_WRITTEN) == 0
 585         && (cfg->optionname != NULL) )
 586        {
 587          printf("\tglobal %s\n", cfg->optionname);
 588          cfg->flags |= GLOBAL_WRITTEN;
 589          printf("\tset %s 0\n", cfg->optionname);
 590        }
 591
 592    }
 593  for(cfg = config;cfg != NULL; cfg = cfg->next)
 594    {
 595      /*
 596       * Skip items not for this menu, or ones having no conditions.
 597       */
 598      if (cfg->menu_number != menu_num ) continue;
 599      if (cfg->tok == tok_menuoption) continue;
 600      if (cfg->cond != NULL ) 
 601        generate_if(cfg, cfg->cond, menu_num, cfg->menu_line);
 602      else
 603        {
 604          /*
 605           * If this token has no conditionals, check to see whether
 606           * it is a tristate - if so, then generate the conditional
 607           * to enable/disable the "y" button based upon the setting
 608           * of the option it depends upon.
 609           */
 610          if(cfg->tok == tok_dep_tristate)
 611            {
 612              global(cfg->depend.str);
 613              printf("\tif {$%s != 1 && $%s != 0 } then { .menu%d.config.f.x%d.y configure -state disabled } else { .menu%d.config.f.x%d.y configure -state normal}\n",
 614                     cfg->depend.str,cfg->depend.str,
 615                     menu_num, cfg->menu_line,
 616                     menu_num, cfg->menu_line);
 617            }
 618        }
 619
 620    }
 621
 622
 623  printf("}\n\n\n");
 624}
 625
 626/*
 627 * This function goes through and counts up the number of items in
 628 * each submenu. If there are too many options, we need to split it
 629 * into submenus.  This function just calculates how many submenus,
 630 * and how many items go in each submenu.
 631 */
 632static void find_menu_size(struct kconfig *cfg,
 633                          int *menu_max, 
 634                          int *menu_maxlines)
 635
 636{
 637  struct kconfig * pnt;
 638  int tot;
 639  
 640  /*
 641   * First count up the number of options in this menu.
 642   */
 643  tot = 0;
 644  for(pnt = cfg->next; pnt; pnt = pnt->next)
 645  {
 646    if( pnt->tok == tok_menuoption) break;
 647    switch (pnt->tok)
 648      {
 649      case tok_bool:
 650      case tok_tristate:
 651      case tok_dep_tristate:
 652      case tok_int:
 653      case tok_hex:
 654      case tok_string:
 655      case tok_choose:
 656        tot++;
 657        break;
 658      case tok_choice:
 659      default:
 660        break;
 661      }
 662  }
 663
 664  *menu_max = cfg->menu_number;
 665  *menu_maxlines = tot;
 666}
 667
 668/*
 669 * This is the top level function for generating the tk script.
 670 */
 671void dump_tk_script(struct kconfig *scfg)
 672{
 673  int menu_num =0;
 674  int menu_max =0;
 675  int menu_min =0;
 676  int menu_line = 0;
 677  int menu_maxlines = 0;
 678  struct kconfig * cfg;
 679  struct kconfig * cfg1 = NULL;
 680  char * menulabel;
 681
 682  /*
 683   * Start by assigning menu numbers, and submenu numbers.
 684   */
 685  for(cfg = scfg;cfg != NULL; cfg = cfg->next)
 686    {
 687      switch (cfg->tok)
 688        {
 689        case tok_menuname:
 690          break;
 691        case tok_menuoption:
 692          /*
 693           * At the start of a new menu, calculate the number of items
 694           * we will put into each submenu so we know when to bump the
 695           * menu number. The submenus are really no different from a
 696           * normal menu, but the top level buttons only access the first
 697           * of the chain of menus, and the prev/next buttons are used
 698           * access the submenus.
 699           */
 700          cfg->menu_number = ++menu_num;
 701          find_menu_size(cfg, &menu_max, &menu_maxlines);
 702          cfg->submenu_start = menu_num;
 703          cfg->submenu_end = menu_max;
 704          menu_line = 0;
 705          break;
 706        case tok_bool:
 707        case tok_tristate:
 708        case tok_dep_tristate:
 709        case tok_int:
 710        case tok_hex:
 711        case tok_string:
 712        case tok_choose:
 713          /*
 714           * If we have overfilled the menu, then go to the next one.
 715           */
 716          if( menu_line == menu_maxlines )
 717            {
 718              menu_line = 0;
 719              menu_num++;
 720            }
 721          cfg->menu_number = menu_num;
 722          cfg->submenu_start = menu_min;
 723          cfg->submenu_end = menu_max;
 724          cfg->menu_line = menu_line++;
 725          break;
 726        case tok_define:
 727          cfg->menu_number = -1;
 728        case tok_choice:
 729        default:
 730          break;
 731        };
 732    }
 733
 734  /*
 735   * Record this so we can set up the prev/next buttons correctly.
 736   */
 737  tot_menu_num = menu_num;
 738
 739  /*
 740   * Now start generating the actual wish script that we will use.
 741   * We need to keep track of the menu numbers of the min/max menu
 742   * for a range of submenus so that we can correctly limit the
 743   * prev and next buttons so that they don't go over into some other
 744   * category.
 745   */
 746  for(cfg = scfg; cfg != NULL; cfg = cfg->next)
 747    {
 748      switch (cfg->tok)
 749        {
 750        case tok_menuname:
 751          printf("mainmenu_name \"%s\"\n", cfg->label);
 752          break;
 753        case tok_menuoption:
 754          /*
 755           * We are at the start of a new menu. If we had one that
 756           * we were working on before, close it out, and then generate
 757           * the script to start the new one.
 758           */
 759          if( cfg->menu_number > 1 )
 760            {
 761              end_proc(menu_num);
 762            }
 763          menulabel = cfg->label;
 764          start_proc(cfg->label, cfg->menu_number, TRUE);
 765          menu_num = cfg->menu_number;
 766          menu_max = cfg->submenu_end;
 767          menu_min = cfg->submenu_start;
 768          break;
 769        case tok_bool:
 770          /*
 771           * If we reached the point where we need to switch over
 772           * to the next submenu, then bump the menu number and generate
 773           * the code to close out the old menu and start the new one.
 774           */
 775          if( cfg->menu_number != menu_num )
 776            {
 777              end_proc(menu_num);
 778              start_proc(menulabel, cfg->menu_number, FALSE);
 779              menu_num = cfg->menu_number;
 780            }
 781          printf("\tbool $w.config.f %d %d \"%s\" %s\n",
 782                 cfg->menu_number,
 783                 cfg->menu_line,
 784                 cfg->label,
 785                 cfg->optionname);
 786          break;
 787
 788        case tok_choice:
 789          printf("\t$w.config.f.x%d.x.menu add radiobutton -label \"%s\" -variable %s -value \"%s\" -command \"update_menu%d .menu%d.config.f\"\n",
 790                 cfg1->menu_line,
 791                 cfg->label,
 792                 cfg1->optionname,
 793                 cfg->label,
 794                 cfg1->menu_number, cfg1->menu_number);
 795          break;
 796        case tok_choose:
 797          if( cfg->menu_number != menu_num )
 798            {
 799              end_proc(menu_num);
 800              start_proc(menulabel, cfg->menu_number, FALSE);
 801              menu_num = cfg->menu_number;
 802            }
 803          printf("\tglobal %s\n",cfg->optionname);
 804          printf("\tminimenu $w.config.f %d %d \"%s\" %s %s\n",
 805                cfg->menu_number,
 806                cfg->menu_line,
 807                cfg->label,
 808                cfg->optionname,
 809                /*
 810                 * We rely on the fact that the first tok_choice corresponding
 811                 * to the current tok_choose is cfg->next (compare parse() in
 812                 * tkparse.c).  We need its name to pick out the right help
 813                 * text from Configure.help.
 814                 */
 815                cfg->next->optionname);
 816          printf("\tmenu $w.config.f.x%d.x.menu\n", cfg->menu_line);
 817          cfg1 = cfg;
 818          break;
 819        case tok_tristate:
 820          if( cfg->menu_number != menu_num )
 821            {
 822              end_proc(menu_num);
 823              start_proc(menulabel, cfg->menu_number, FALSE);
 824              menu_num = cfg->menu_number;
 825            }
 826          printf("\ttristate $w.config.f %d %d \"%s\" %s\n",
 827                 cfg->menu_number,
 828                 cfg->menu_line,
 829                 cfg->label,
 830                 cfg->optionname);
 831          break;
 832        case tok_dep_tristate:
 833          if( cfg->menu_number != menu_num )
 834            {
 835              end_proc(menu_num);
 836              start_proc(menulabel, cfg->menu_number, FALSE);
 837              menu_num = cfg->menu_number;
 838            }
 839          printf("\tdep_tristate $w.config.f %d %d \"%s\" %s %s\n",
 840                 cfg->menu_number,
 841                 cfg->menu_line,
 842                 cfg->label,
 843                 cfg->optionname,
 844                 cfg->depend.str);
 845          break;
 846        case tok_int:
 847          if( cfg->menu_number != menu_num )
 848            {
 849              end_proc(menu_num);
 850              start_proc(menulabel, cfg->menu_number, FALSE);
 851              menu_num = cfg->menu_number;
 852            }
 853          printf("\tint $w.config.f %d %d \"%s\" %s\n",
 854                 cfg->menu_number,
 855                 cfg->menu_line,
 856                 cfg->label,
 857                 cfg->optionname);
 858          break;
 859        case tok_hex:
 860          if( cfg->menu_number != menu_num )
 861            {
 862              end_proc(menu_num);
 863              start_proc(menulabel, cfg->menu_number, FALSE);
 864              menu_num = cfg->menu_number;
 865            }
 866          printf("\thex $w.config.f %d %d \"%s\" %s\n",
 867                 cfg->menu_number,
 868                 cfg->menu_line,
 869                 cfg->label,
 870                 cfg->optionname);
 871          break;
 872        case tok_string:
 873          if( cfg->menu_number != menu_num )
 874            {
 875              end_proc(menu_num);
 876              start_proc(menulabel, cfg->menu_number, FALSE);
 877              menu_num = cfg->menu_number;
 878            }
 879          printf("\tistring $w.config.f %d %d \"%s\" %s\n",
 880                 cfg->menu_number,
 881                 cfg->menu_line,
 882                 cfg->label,
 883                 cfg->optionname);
 884          break;
 885        default:
 886          break;
 887        }
 888
 889    }
 890
 891  /*
 892   * Generate the code to close out the last menu.
 893   */
 894  end_proc(menu_num);
 895
 896#ifdef ERIC_DONT_DEF
 897  /*
 898   * Generate the code for configuring the sound driver.  Right now this
 899   * cannot be done from the X script, but we insert the menu anyways.
 900   */
 901  start_proc("Configure sound driver", ++menu_num, TRUE);
 902#if 0
 903  printf("\tdo_make -C drivers/sound config\n");
 904  printf("\techo check_sound_config %d\n",menu_num);
 905#endif
 906  printf("\tlabel $w.config.f.m0 -bitmap error\n");
 907  printf("\tmessage $w.config.f.m1 -width 400 -aspect 300 -text \"The sound drivers cannot as of yet be configured via the X-based interface\" -relief raised\n");
 908  printf("\tpack $w.config.f.m0 $w.config.f.m1 -side top -pady 10 -expand on\n");
 909  /*
 910   * Close out the last menu.
 911   */
 912  end_proc(menu_num);
 913#endif
 914
 915  /*
 916   * The top level menu also needs an update function.  When we exit a
 917   * submenu, we may need to disable one or more of the submenus on
 918   * the top level menu, and this procedure will ensure that things are
 919   * correct.
 920   */
 921  printf("proc update_mainmenu {w}  {\n");
 922  for(cfg = scfg; cfg != NULL; cfg = cfg->next)
 923    {
 924      switch (cfg->tok)
 925        {
 926        case tok_menuoption:
 927          if (cfg->cond != NULL ) 
 928            generate_if(cfg, cfg->cond, cfg->menu_number, cfg->menu_line);
 929          break;
 930        default:
 931          break;
 932        }
 933    }
 934
 935  printf("}\n\n\n");
 936
 937#if 0
 938  /*
 939   * Generate some code to set the variables that are "defined".
 940   */
 941  for(cfg = config;cfg != NULL; cfg = cfg->next)
 942    {
 943      /*
 944       * Skip items not for this menu, or ones having no conditions.
 945       */
 946      if( cfg->tok != tok_define) continue;
 947      if (cfg->cond != NULL ) 
 948        generate_if(cfg, cfg->cond, menu_num, cfg->menu_line);
 949      else
 950        {
 951          printf("\twrite_define %s %s\n", cfg->optionname, cfg->value);
 952        }
 953
 954    }
 955#endif
 956
 957  /*
 958   * Now generate code to load the default settings into the variables.
 959   * Note that the script in tail.tk will attempt to load .config,
 960   * which may override these settings, but that's OK.
 961   */
 962  for(cfg = scfg; cfg != NULL; cfg = cfg->next)
 963    {
 964      switch (cfg->tok)
 965        {
 966        case tok_bool:
 967        case tok_tristate:
 968        case tok_dep_tristate:
 969        case tok_choice:
 970          printf("set %s 0\n", cfg->optionname);
 971          break;
 972        case tok_int:
 973        case tok_hex:
 974        case tok_string:
 975          printf("set %s %s\n", cfg->optionname, cfg->value);
 976          break;
 977        case tok_choose:
 978          printf("set %s \"(not set)\"\n",cfg->optionname);
 979        default:
 980          break;
 981        }
 982    }
 983
 984  /*
 985   * Next generate a function that can be called from the main menu that will
 986   * write all of the variables out.  This also serves double duty - we can
 987   * save configuration to a file using this.
 988   */
 989  printf("proc writeconfig {file1 file2} {\n");
 990  printf("\tset cfg [open $file1 w]\n");
 991  printf("\tset autocfg [open $file2 w]\n");
 992  printf("\tset notmod 1\n");
 993  printf("\tset notset 0\n");
 994  clear_globalflags(config);
 995  printf("\tputs $cfg \"#\"\n");
 996  printf("\tputs $cfg \"# Automatically generated make config: don't edit\"\n");
 997  printf("\tputs $cfg \"#\"\n");
 998
 999  printf("\tputs $autocfg \"/*\"\n");
1000  printf("\tputs $autocfg \" * Automatically generated C config: don't edit\"\n");
1001  printf("\tputs $autocfg \" */\"\n");
1002  printf("\tputs $autocfg \"#define AUTOCONF_INCLUDED\"\n");
1003  for(cfg = scfg; cfg != NULL; cfg = cfg->next)
1004    {
1005      switch (cfg->tok)
1006        {
1007        case tok_int:
1008        case tok_hex:
1009        case tok_string:
1010        case tok_bool:
1011        case tok_tristate:
1012        case tok_dep_tristate:
1013        case tok_define:
1014        case tok_choose:
1015          if(!(cfg->flags & GLOBAL_WRITTEN))
1016            {
1017              cfg->flags |= GLOBAL_WRITTEN;
1018              printf("\tglobal %s\n", cfg->optionname);
1019            }
1020          /* fall through */
1021        case tok_make:
1022        case tok_comment:
1023          if (cfg->cond != NULL ) 
1024            generate_if_for_outfile(cfg, cfg->cond);
1025          else
1026            {
1027              if(cfg->tok == tok_dep_tristate)
1028                {
1029                  printf("\tif {$%s == 0 } then {\n"
1030                         "\t\twrite_tristate $cfg $autocfg %s $notset $notmod\n"
1031                         "\t} else {\n"
1032                         "\t\twrite_tristate $cfg $autocfg %s $%s $%s\n"
1033                         "\t}\n",
1034                         cfg->depend.str,
1035                         cfg->optionname,
1036                         cfg->optionname,
1037                         cfg->optionname,
1038                         cfg->depend.str);
1039                }
1040              else if(cfg->tok == tok_comment)
1041                {
1042                  printf("\twrite_comment $cfg $autocfg \"%s\"\n", cfg->label);
1043                }
1044#if 0
1045              else if(cfg->tok == tok_define)
1046                {
1047                  printf("\twrite_define %s %s\n", cfg->optionname,
1048                         cfg->value);
1049                }
1050#endif
1051              else if (cfg->tok == tok_choose )
1052                {
1053                  for(cfg1 = cfg->next; 
1054                      cfg1 != NULL && cfg1->tok == tok_choice;
1055                      cfg1 = cfg1->next)
1056                    {
1057                      printf("\tif { $%s == \"%s\" } then { write_tristate $cfg $autocfg %s 1 $notmod }\n",
1058                             cfg->optionname,
1059                             cfg1->label,
1060                             cfg1->optionname);
1061                    }
1062                }
1063              else if (cfg->tok == tok_int )
1064                {
1065                  printf("\twrite_int $cfg $autocfg %s $%s $notmod\n",
1066                         cfg->optionname,
1067                         cfg->optionname);
1068                }
1069              else if (cfg->tok == tok_hex )
1070                {
1071                  printf("\twrite_hex $cfg $autocfg %s $%s $notmod\n",
1072                         cfg->optionname,
1073                         cfg->optionname);
1074                }
1075              else if (cfg->tok == tok_string )
1076                {
1077                  printf("\twrite_string $cfg $autocfg %s $%s $notmod\n",
1078                         cfg->optionname,
1079                         cfg->optionname);
1080                }
1081              else if (cfg->tok == tok_make )
1082                {
1083                  printf("\tdo_make {%s}\n",cfg->value);
1084                }
1085              else
1086                {
1087                  printf("\twrite_tristate $cfg $autocfg %s $%s $notmod\n",
1088                         cfg->optionname,
1089                         cfg->optionname);
1090                }
1091            }
1092          break;
1093        default:
1094          break;
1095        }
1096    }
1097  printf("\tclose $cfg\n");
1098  printf("\tclose $autocfg\n");
1099  printf("}\n\n\n");
1100
1101  /*
1102   * Finally write a simple function that updates the master choice
1103   * variable depending upon what values were loaded from a .config
1104   * file.  
1105   */
1106  printf("proc clear_choices { } {\n");
1107  for(cfg = scfg; cfg != NULL; cfg = cfg->next)
1108    {
1109      if( cfg->tok != tok_choose ) continue;
1110      for(cfg1 = cfg->next; 
1111          cfg1 != NULL && cfg1->tok == tok_choice;
1112          cfg1 = cfg1->next)
1113        {
1114          printf("\tglobal %s; set %s 0\n",cfg1->optionname,cfg1->optionname);
1115        }
1116    }
1117  printf("}\n\n\n");
1118
1119  printf("proc update_choices { } {\n");
1120  for(cfg = scfg; cfg != NULL; cfg = cfg->next)
1121    {
1122      if( cfg->tok != tok_choose ) continue;
1123      printf("\tglobal %s\n", cfg->optionname);
1124      for(cfg1 = cfg->next; 
1125          cfg1 != NULL && cfg1->tok == tok_choice;
1126          cfg1 = cfg1->next)
1127        {
1128          printf("\tglobal %s\n", cfg1->optionname);
1129          printf("\tif { $%s == 1 } then { set %s \"%s\" }\n",
1130                 cfg1->optionname,
1131                 cfg->optionname,
1132                 cfg1->label);
1133        }
1134    }
1135  printf("}\n\n\n");
1136
1137  printf("proc update_define { } {\n");
1138  clear_globalflags(config);
1139  for(cfg = scfg; cfg != NULL; cfg = cfg->next)
1140    {
1141      if( cfg->tok != tok_define ) continue;
1142      printf("\tglobal %s; set %s 0\n",  cfg->optionname,  cfg->optionname);
1143      cfg->flags |= GLOBAL_WRITTEN;
1144    }
1145  for(cfg = scfg; cfg != NULL; cfg = cfg->next)
1146    {
1147      if( cfg->tok != tok_define ) continue;
1148      if (cfg->cond != NULL ) 
1149        generate_if(cfg, cfg->cond, -1, 0);
1150      else
1151        {
1152          printf("\tset %s %s\n",
1153                 cfg->optionname, cfg->value);
1154        }
1155    }
1156  printf("}\n\n\n");
1157  /*
1158   * That's it.  We are done.  The output of this file will have header.tk
1159   * prepended and tail.tk appended to create an executable wish script.
1160   */
1161}
1162
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.