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

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