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

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