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

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