root/scripts/tkgen.c

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

DEFINITIONS

This source file includes following definitions.
  1. start_proc
  2. clear_globalflags
  3. generate_if
  4. generate_if_for_outfile
  5. end_proc
  6. find_menu_size
  7. dump_tk_script

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

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