root/scripts/tkgen.c

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

DEFINITIONS

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

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

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