patch-2.2.0-pre9 linux/scripts/tkgen.c

Next file: linux/scripts/tkparse.c
Previous file: linux/scripts/tkcond.c
Back to the patch index
Back to the overall index

diff -u --recursive --new-file v2.2.0-pre8/linux/scripts/tkgen.c linux/scripts/tkgen.c
@@ -77,1095 +77,970 @@
  * 8 January 1999, Michael Elizabeth Chastain <mec@shout.net>
  * - Emit menus_per_column
  *
- * 1999 01 04
- * Michael Elizabeth Chastain <mec@shout.net>
- * - Call clear_globalflags when writing out update_mainmenu.
- *   This fixes the missing global/vfix lines for ARCH=alpha on 2.2.0-pre4.
- *
- * TO DO:
- *   - clean up - there are useless ifdef's everywhere.
- *   - better comments throughout - C code generating tcl is really cryptic.
- *   - eliminate silly "update idletasks" hack to improve display speed and
- *     reduce flicker.  But how?
- *   - make canvas contents resize with the window (good luck).
- *   - some way to make submenus inside of submenus (ie. Main->Networking->IP)
- *           (perhaps a button where the description would be)
- *   - make the main menu use the same tcl code as the submenus.
- *   - make choice and int/hex input types line up vertically with
- *           bool/tristate.
- *   - general speedups - how?  The canvas seems to slow it down a lot.
- *   - clean up +/- 16 confusion for enabling/disabling variables; causes
- *           (theoretical, at the moment) problems with dependencies.
- *   
+ * 14 January 1999, Michael Elizabeth Chastain <mec@shout.net>
+ * - Steam-clean this file.  I tested this by generating kconfig.tk for every
+ *   architecture and comparing it character-for-character against the output
+ *   of the old tkparse.
+ * - Fix flattening of nested menus.  The old code simply assigned items to
+ *   the most recent token_mainmenu_option, without paying attention to scope.
+ *   For example: "menu-1 bool-a menu-2 bool-b endmenu bool-c bool-d endmenu".
+ *   The old code would put bool-a in menu-1, bool-b in menu-2, and bool-c
+ *   and bool-d in *menu-2*.  This hosed the nested submenus in
+ *   drives/net/Config.in and other places.
+ * - Fix menu line wraparound at 128 menus (some fool used a 'char' for
+ *   a counter).
  */
+
 #include <stdio.h>
 #include <unistd.h>
 #include "tkparse.h"
 
-#ifndef TRUE
-#define TRUE (1)
-#endif
 
-#ifndef FALSE
-#define FALSE (0)
-#endif
 
 /*
- * This is the total number of submenus that we have.
+ * Total number of menus.
  */
-static int tot_menu_num =0;
+static int tot_menu_num = 0;
+
+
 
 /*
  * Generate portion of wish script for the beginning of a submenu.
  * The guts get filled in with the various options.
  */
-static void start_proc(char * label, int menu_num, int flag)
+static void start_proc( char * label, int menu_num, int flag )
 {
-  if( flag )
-    printf("menu_option menu%d %d \"%s\"\n", menu_num, menu_num, label);
-  printf("proc menu%d {w title} {\n", menu_num);
-  printf("\tcatch {destroy $w}\n");
-  printf("\ttoplevel $w -class Dialog\n");
-  printf("\twm withdraw $w\n");
-  printf("\tmessage $w.m -width 400 -aspect 300 -text \\\n");
-  printf("\t\t\"%s\"  -relief raised\n",label);
-  printf("\tpack $w.m -pady 10 -side top -padx 10\n");
-  printf("\twm title $w \"%s\" \n\n", label);
-  
-  /*
-   * Attach the "Prev", "Next" and "OK" buttons at the end of the window.
-   */
-  printf("\tset oldFocus [focus]\n");
-  printf("\tframe $w.f\n");
-  printf("\tbutton $w.f.back -text \"Main Menu\" \\\n"
-         "\t\t-width 15 -command \"destroy $w; focus $oldFocus; update_mainmenu $w\"\n");
-  printf("\tbutton $w.f.next -text \"Next\" \\\n"
-         "\t\t-width 15 -command \" destroy $w; focus $oldFocus;  menu%d .menu%d \\\"$title\\\"\"\n",
-         	menu_num+1, menu_num+1);
-  if (menu_num == tot_menu_num)
-  	printf("\t$w.f.next configure -state disabled\n");
-  printf("\tbutton $w.f.prev -text \"Prev\" \\\n"
-         "\t\t-width 15 -command \" destroy $w; focus $oldFocus; menu%d .menu%d \\\"$title\\\"\"\n",
-       		menu_num-1, menu_num-1);
-  if (1 == menu_num)
-  	printf("\t$w.f.prev configure -state disabled\n");
-  printf("\tpack $w.f.back $w.f.next $w.f.prev -side left -expand on\n");
-  printf("\tpack $w.f -pady 10 -side bottom -anchor w -fill x\n");
-
-  /*
-   * Lines between canvas and other areas of the window.
-   */
-  printf("\tframe $w.topline -relief ridge -borderwidth 2 -height 2\n");
-  printf("\tpack $w.topline -side top -fill x\n\n");
-  printf("\tframe $w.botline -relief ridge -borderwidth 2 -height 2\n");
-  printf("\tpack $w.botline -side bottom -fill x\n\n");
-  
-  /*
-   * The "config" frame contains the canvas and a scrollbar.
-   */
-  printf("\tframe $w.config\n");
-  printf("\tpack $w.config -fill y -expand on\n\n");
-  printf("\tscrollbar $w.config.vscroll -command \"$w.config.canvas yview\"\n");
-  printf("\tpack $w.config.vscroll -side right -fill y\n\n");
-  
-  /*
-   * The scrollable canvas itself, where the real work (and mess) gets done.
-   */
-  printf("\tcanvas $w.config.canvas -height 1\\\n"
-  	 "\t\t-relief flat -borderwidth 0 -yscrollcommand \"$w.config.vscroll set\" \\\n"
-  	 "\t\t-width [expr [winfo screenwidth .] * 1 / 2] \n");
-  printf("\tframe $w.config.f\n");
-  printf("\tpack $w.config.canvas -side right -fill y\n");
-  
-  printf("\n\n");
+    if ( flag )
+	printf( "menu_option menu%d %d \"%s\"\n", menu_num, menu_num, label );
+    printf( "proc menu%d {w title} {\n", menu_num );
+    printf( "\tcatch {destroy $w}\n" );
+    printf( "\ttoplevel $w -class Dialog\n" );
+    printf( "\twm withdraw $w\n" );
+    printf( "\tmessage $w.m -width 400 -aspect 300 -text \\\n" );
+    printf( "\t\t\"%s\"  -relief raised\n", label );
+    printf( "\tpack $w.m -pady 10 -side top -padx 10\n" );
+    printf( "\twm title $w \"%s\" \n\n", label );
+
+    /*
+     * Attach the "Prev", "Next" and "OK" buttons at the end of the window.
+     */
+    printf( "\tset oldFocus [focus]\n" );
+    printf( "\tframe $w.f\n" );
+    printf( "\tbutton $w.f.back -text \"Main Menu\" \\\n" );
+    printf( "\t\t-width 15 -command \"destroy $w; focus $oldFocus; update_mainmenu $w\"\n" );
+    printf( "\tbutton $w.f.next -text \"Next\" \\\n" );
+    printf( "\t\t-width 15 -command \" destroy $w; focus $oldFocus;  menu%d .menu%d \\\"$title\\\"\"\n", menu_num+1, menu_num+1 );
+    if ( menu_num == tot_menu_num )
+	printf( "\t$w.f.next configure -state disabled\n" );
+    printf( "\tbutton $w.f.prev -text \"Prev\" \\\n" );
+    printf( "\t\t-width 15 -command \" destroy $w; focus $oldFocus; menu%d .menu%d \\\"$title\\\"\"\n", menu_num-1, menu_num-1 );
+    if ( menu_num == 1 )
+	printf( "\t$w.f.prev configure -state disabled\n" );
+    printf( "\tpack $w.f.back $w.f.next $w.f.prev -side left -expand on\n" );
+    printf( "\tpack $w.f -pady 10 -side bottom -anchor w -fill x\n" );
+
+    /*
+     * Lines between canvas and other areas of the window.
+     */
+    printf( "\tframe $w.topline -relief ridge -borderwidth 2 -height 2\n" );
+    printf( "\tpack $w.topline -side top -fill x\n\n" );
+    printf( "\tframe $w.botline -relief ridge -borderwidth 2 -height 2\n" );
+    printf( "\tpack $w.botline -side bottom -fill x\n\n" );
+
+    /*
+     * The "config" frame contains the canvas and a scrollbar.
+     */
+    printf( "\tframe $w.config\n" );
+    printf( "\tpack $w.config -fill y -expand on\n\n" );
+    printf( "\tscrollbar $w.config.vscroll -command \"$w.config.canvas yview\"\n" );
+    printf( "\tpack $w.config.vscroll -side right -fill y\n\n" );
+
+    /*
+     * The scrollable canvas itself, where the real work (and mess) gets done.
+     */
+    printf( "\tcanvas $w.config.canvas -height 1\\\n" );
+    printf( "\t\t-relief flat -borderwidth 0 -yscrollcommand \"$w.config.vscroll set\" \\\n" );
+    printf( "\t\t-width [expr [winfo screenwidth .] * 1 / 2] \n" );
+    printf( "\tframe $w.config.f\n" );
+    printf( "\tpack $w.config.canvas -side right -fill y\n" );
+    printf("\n\n");
 }
 
+
+
 /*
  * Each proc we create needs a global declaration for any global variables we
  * use.  To minimize the size of the file, we set a flag each time we output
  * a global declaration so we know whether we need to insert one for a
  * given function or not.
  */
-void clear_globalflags(struct kconfig * cfg)
+void clear_globalflags( struct kconfig * scfg )
 {
-  for(; cfg != NULL; cfg = cfg->next)
-  {
-    cfg->flags &= ~GLOBAL_WRITTEN;
-  }
+    struct kconfig * cfg;
+
+    for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
+	cfg->global_written = 0;
 }
 
+
+
 /*
  * Output a "global" line for a given variable.  Also include the
  * call to "vfix".  (If vfix is not needed, then it's fine to just printf
  * a "global" line).
  */
-void inline global(char *var)
+void global( const char *var )
 {
-  printf("\tglobal %s; vfix %s\n", var, var);
+    printf( "\tglobal %s; vfix %s\n", var, var );
 }
 
+
+
 /*
- * This function walks the chain of conditions that we got from cond.c,
- * and creates a wish conditional to enable/disable a given widget.
+ * This function walks the chain of conditions that we got from cond.c
+ * and creates a TCL conditional to enable/disable a given widget.
  */
-void generate_if(struct kconfig * item,
-	    struct condition * cond,
-	    int menu_num,
-	    int line_num)
+void generate_if( struct kconfig * cfg, struct condition * ocond,
+    int menu_num, int line_num )
 {
-  struct condition * ocond;
+    struct condition * cond;
 
-  ocond = cond;
-
-  /*
-   * First write any global declarations we need for this conditional.
-   */
-  while(cond != NULL )
+    /*
+     * First write any global declarations we need for this conditional.
+     */
+    for ( cond = ocond; cond != NULL; cond = cond->next )
     {
-      switch(cond->op){
-      case op_variable:
-      	global(cond->variable.str);
-	break;
-      case op_kvariable:
-	if(cond->variable.cfg->flags & GLOBAL_WRITTEN) break;
-	cond->variable.cfg->flags |= GLOBAL_WRITTEN;
-	global(cond->variable.cfg->optionname);
-	break;
-      default:
-	break;
-      }
-      cond = cond->next;
+	switch ( cond->op )
+	{
+	default:
+	    break;
+
+	case op_variable:
+	    global( cond->str );
+	    break;
+
+	case op_kvariable:
+	    if ( ! cond->cfg->global_written )
+	    {
+		cond->cfg->global_written = 1;
+		global( cond->cfg->optionname );
+	    }
+	    break;
+	}
     }
-  
-  /*
-   * Now write this option.
-   */
-  if(   (item->flags & GLOBAL_WRITTEN) == 0
-     && (item->optionname != NULL) )
+
+    /*
+     * Now write this option.
+     */
+    if ( ! cfg->global_written && cfg->optionname != NULL )
     {
-      global(item->optionname);
-      item->flags |= GLOBAL_WRITTEN;
+	cfg->global_written = 1;
+	global( cfg->optionname );
     }
-  /*
-   * Now generate the body of the conditional.
-   */
-  printf("\tif {");
-  cond = ocond;
-  while(cond != NULL )
+
+    /*
+     * Generate the body of the conditional.
+     */
+    printf( "\tif {" );
+    for ( cond = ocond; cond != NULL; cond = cond->next )
     {
-      switch(cond->op){
-      case op_bang:
-	printf(" ! ");
-	break;
-      case op_eq:
-	printf(" == ");
-	break;
-      case op_neq:
-	printf(" != ");
-	break;
-      case op_and:
-      case op_and1:
-	printf(" && ");
-	break;
-      case op_or:
-	printf(" || ");
-	break;
-      case op_lparen:
-	printf("(");
-	break;
-      case op_rparen:
-	printf(")");
-	break;
-      case op_variable:
-	printf("$%s", cond->variable.str);
-	break;
-      case op_kvariable:
-	printf("$%s", cond->variable.cfg->optionname);
-	break;
-      case op_shellcmd:
-	printf("[exec %s]", cond->variable.str);
-	break;
-      case op_constant:
-	if( strcmp(cond->variable.str, "y") == 0 )
-	  printf("1");
-	else if( strcmp(cond->variable.str, "n") == 0 )
-	  printf("0");
-	else if( strcmp(cond->variable.str, "m") == 0 )
-	  printf("2");
-	else
-	  printf("\"%s\"", cond->variable.str);
-	break;
-      default:
-        break;
-      }
-      cond = cond->next;
-    }
+	switch ( cond->op )
+	{
+	default:
+	    break;
 
-  /*
-   * Now we generate what we do depending upon the value of the conditional.
-   * Depending upon what the token type is, there are different things
-   * we must do to enable/disable the given widget - this code needs to
-   * be closely coordinated with the widget creation procedures in header.tk.
-   */
-  switch(item->tok)
+	case op_bang:   printf( " ! "  ); break;
+	case op_eq:     printf( " == " ); break;
+	case op_neq:    printf( " != " ); break;
+	case op_and:    printf( " && " ); break;
+	case op_and1:   printf( " && " ); break;
+	case op_or:     printf( " || " ); break;
+	case op_lparen: printf( "("    ); break;
+	case op_rparen: printf( ")"    ); break;
+
+	case op_variable:
+	    printf( "$%s", cond->str );
+	    break;
+
+	case op_kvariable:
+	    printf( "$%s", cond->cfg->optionname );
+	    break;
+
+	case op_constant:
+	    if      ( strcmp( cond->str, "y" ) == 0 ) printf( "1" );
+	    else if ( strcmp( cond->str, "n" ) == 0 ) printf( "0" );
+	    else if ( strcmp( cond->str, "m" ) == 0 ) printf( "2" );
+	    else
+		printf( "\"%s\"", cond->str );
+	    break;
+	}
+    }
+    printf( "} then { " );
+
+    /*
+     * Generate a procedure call to write the value.
+     * This code depends on procedures in header.tk.
+     */
+    switch ( cfg->token )
     {
-    case tok_define:
-      printf("} then { set %s %s } \n",  item->optionname, item->value);
-      break;
-    case tok_menuoption:
-      printf("} then { .f0.x%d configure -state normal } else { .f0.x%d configure -state disabled }\n",
-	     menu_num, menu_num);
-      break;
-    case tok_int:
-    case tok_hex:
-    case tok_string:
-      printf("} then { ");
-      printf(".menu%d.config.f.x%d.x configure -state normal -foreground [ cget .ref -foreground ]; ", menu_num, line_num);
-      printf(".menu%d.config.f.x%d.l configure -state normal; ", menu_num, line_num);
-      printf("} else { ");
-      printf(".menu%d.config.f.x%d.x configure -state disabled -foreground [ cget .ref -disabledforeground ];", menu_num, line_num );
-      printf(".menu%d.config.f.x%d.l configure -state disabled;", menu_num, line_num );
-      printf("}\n");
-      break;
-    case tok_bool:
-#ifdef BOOL_IS_BUTTON
-      /*
-       * If a bool is just a button, then use this definition.
-       */
-      printf("} then { .menu%d.config.f.x%d configure -state normal } else { .menu%d.config.f.x%d configure -state disabled }\n",
-	     menu_num, line_num,
-	     menu_num, line_num );
-#else
-      /*
-       * If a bool is a radiobutton, then use this instead.
-       */
-      printf("} then { ");
-      printf(".menu%d.config.f.x%d.y configure -state normal;",menu_num, line_num);
-      printf(".menu%d.config.f.x%d.n configure -state normal;",menu_num, line_num);
-      printf(".menu%d.config.f.x%d.l configure -state normal;",menu_num, line_num);
-      printf("set %s [expr $%s&15];", item->optionname, item->optionname);
-      printf("} else { ");
-      printf(".menu%d.config.f.x%d.y configure -state disabled;",menu_num, line_num);
-      printf(".menu%d.config.f.x%d.n configure -state disabled;",menu_num, line_num);
-      printf(".menu%d.config.f.x%d.l configure -state disabled;",menu_num, line_num);
-      printf("set %s [expr $%s|16];", item->optionname, item->optionname);
-      printf("}\n");
-#endif
-      break;
-    case tok_tristate:
-    case tok_dep_tristate:
-      printf("} then { ");
-      if( item->tok == tok_dep_tristate )
-	{
-	  global(item->depend.str);
-	  printf("if { $%s != 1 && $%s != 0 } then {", 
-	  	item->depend.str,item->depend.str);
-	  printf(".menu%d.config.f.x%d.y configure -state disabled;",menu_num, line_num);
-	  printf("} else {");
-	  printf(".menu%d.config.f.x%d.y configure -state normal;",menu_num, line_num);
-	  printf("}; ");
-	}
-      else
-	{
-	  printf(".menu%d.config.f.x%d.y configure -state normal;",menu_num, line_num);
-	}
-      
-      printf(".menu%d.config.f.x%d.n configure -state normal;",menu_num, line_num);
-      printf("global CONFIG_MODULES; if {($CONFIG_MODULES == 1)} then { .menu%d.config.f.x%d.m configure -state normal };",menu_num, line_num);
-      printf(".menu%d.config.f.x%d.l configure -state normal;",menu_num, line_num);
-      /*
-       * Or in a bit to the variable - this causes all of the radiobuttons
-       * to be deselected (i.e. not be red).
-       */
-      printf("set %s [expr $%s&15];", item->optionname, item->optionname);
-      printf("} else { ");
-      printf(".menu%d.config.f.x%d.y configure -state disabled;",menu_num, line_num);
-      printf(".menu%d.config.f.x%d.n configure -state disabled;",menu_num, line_num);
-      printf(".menu%d.config.f.x%d.m configure -state disabled;",menu_num, line_num);
-      printf(".menu%d.config.f.x%d.l configure -state disabled;",menu_num, line_num);
-      /*
-       * Clear the disable bit - this causes the correct radiobutton
-       * to appear selected (i.e. turn red).
-       */
-      printf("set %s [expr $%s|16];", item->optionname, item->optionname);
-      printf("}\n");
-      break;
-    case tok_choose:
-    case tok_choice:
-      fprintf(stderr,"Fixme\n");
-      exit(0);
     default:
-      break;
+	printf( " }\n" );
+	break;
+
+    case token_bool:
+	printf( ".menu%d.config.f.x%d.y configure -state normal;",
+	    menu_num, line_num );
+	printf( ".menu%d.config.f.x%d.n configure -state normal;",
+	    menu_num, line_num );
+	printf( ".menu%d.config.f.x%d.l configure -state normal;",
+	    menu_num, line_num );
+	printf( "set %s [expr $%s&15];",
+	    cfg->optionname, cfg->optionname );
+	printf( "} else { ");
+	printf( ".menu%d.config.f.x%d.y configure -state disabled;",
+	    menu_num, line_num );
+	printf( ".menu%d.config.f.x%d.n configure -state disabled;",
+	    menu_num, line_num );
+	printf( ".menu%d.config.f.x%d.l configure -state disabled;",
+	    menu_num, line_num );
+	printf( "set %s [expr $%s|16];}\n",
+	    cfg->optionname, cfg->optionname );
+	break;
+
+    case token_choice_header:
+	fprintf( stderr, "Internal error on token_choice_header\n" );
+	exit( 1 );
+
+    case token_choice_item:
+	fprintf( stderr, "Internal error on token_choice_item\n" );
+	exit( 1 );
+
+    case token_define_bool:
+	printf( "set %s %s } \n",
+	    cfg->optionname, cfg->value );
+	break;
+
+    case token_dep_tristate:
+    case token_tristate:
+	if ( cfg->token == token_dep_tristate )
+	{
+	    global( cfg->depend );
+	    printf( "if { $%s != 1 && $%s != 0 } then {",
+		cfg->depend, cfg->depend );
+	    printf( ".menu%d.config.f.x%d.y configure -state disabled;",
+		menu_num, line_num );
+	    printf( "} else {" );
+	    printf( ".menu%d.config.f.x%d.y configure -state normal;",
+		menu_num, line_num);
+	    printf( "}; " );
+	}
+	else
+	{
+	    printf( ".menu%d.config.f.x%d.y configure -state normal;",
+		menu_num, line_num );
+	}
+
+	printf( ".menu%d.config.f.x%d.n configure -state normal;",
+	    menu_num, line_num );
+	printf( "global CONFIG_MODULES; if {($CONFIG_MODULES == 1)} then { .menu%d.config.f.x%d.m configure -state normal };",
+	    menu_num, line_num );
+	printf( ".menu%d.config.f.x%d.l configure -state normal;",
+	    menu_num, line_num );
+
+	/*
+	 * Or in a bit to the variable - this causes all of the radiobuttons
+	 * to be deselected (i.e. not be red).
+	 */
+	printf( "set %s [expr $%s&15];",
+	    cfg->optionname, cfg->optionname );
+	printf( "} else { " );
+	printf( ".menu%d.config.f.x%d.y configure -state disabled;",
+	    menu_num, line_num );
+	printf( ".menu%d.config.f.x%d.n configure -state disabled;",
+	    menu_num, line_num );
+	printf( ".menu%d.config.f.x%d.m configure -state disabled;",
+	    menu_num, line_num );
+	printf( ".menu%d.config.f.x%d.l configure -state disabled;",
+	    menu_num, line_num );
+
+	/*
+	 * Clear the disable bit to enable the correct radiobutton.
+	 */
+	printf( "set %s [expr $%s|16];}\n",
+	    cfg->optionname, cfg->optionname );
+	break;
+
+    case token_hex:
+    case token_int:
+    case token_string:
+	printf( ".menu%d.config.f.x%d.x configure -state normal -foreground [ cget .ref -foreground ]; ",
+	    menu_num, line_num);
+	printf( ".menu%d.config.f.x%d.l configure -state normal; ",
+	    menu_num, line_num);
+	printf( "} else { " );
+	printf( ".menu%d.config.f.x%d.x configure -state disabled -foreground [ cget .ref -disabledforeground ];",
+	    menu_num, line_num );
+	printf( ".menu%d.config.f.x%d.l configure -state disabled;}\n",
+	    menu_num, line_num );
+	break;
+
+    case token_mainmenu_option:
+	printf( ".f0.x%d configure -state normal } else { .f0.x%d configure -state disabled }\n",
+	    menu_num, menu_num );
+	break;
     }
 }
 
+
+
 /*
- * Similar to generate_if, except we come here when generating an
- * output file.  Thus instead of enabling/disabling a widget, we
- * need to decide whether to write out a given configuration variable
- * to the output file.
+ * Generate a line that writes a variable to the output file.
  */
-void generate_if_for_outfile(struct kconfig * item,
-	    struct condition * cond)
+void generate_writeconfig( struct kconfig * cfg )
 {
-  struct condition * ocond;
+    struct condition * cond;
 
-  /*
-   * First write any global declarations we need for this conditional.
-   */
-  ocond = cond;
-  for(; cond != NULL; cond = cond->next )
+    /*
+     * Generate global declaration for this symbol.
+     */
+    if ( cfg->token != token_comment )
     {
-      switch(cond->op){
-      case op_variable:
-        global(cond->variable.str);
-	break;
-      case op_kvariable:
-	if(cond->variable.cfg->flags & GLOBAL_WRITTEN) break;
-	cond->variable.cfg->flags |= GLOBAL_WRITTEN;
-	global(cond->variable.cfg->optionname);
-	break;
-      default:
-	break;
-      }
+	if ( ! cfg->global_written )
+	{
+	    cfg->global_written = 1;
+	    printf( "\tglobal %s\n", cfg->optionname );
+	}
     }
 
-  /*
-   * Now generate the body of the conditional.
-   */
-  printf("\tif {");
-  cond = ocond;
-  while(cond != NULL )
+    /*
+     * Generate global declarations for the condition chain.
+     */
+    for ( cond = cfg->cond; cond != NULL; cond = cond->next )
     {
-      switch(cond->op){
-      case op_bang:
-	printf(" ! ");
-	break;
-      case op_eq:
-	printf(" == ");
-	break;
-      case op_neq:
-	printf(" != ");
-	break;
-      case op_and:
-      case op_and1:
-	printf(" && ");
-	break;
-      case op_or:
-	printf(" || ");
-	break;
-      case op_lparen:
-	printf("(");
-	break;
-      case op_rparen:
-	printf(")");
-	break;
-      case op_variable:
-	printf("$%s", cond->variable.str);
-	break;
-      case op_shellcmd:
-	printf("[exec %s]", cond->variable.str);
-	break;
-      case op_kvariable:
-	printf("$%s", cond->variable.cfg->optionname);
-	break;
-      case op_constant:
-	if( strcmp(cond->variable.str, "y") == 0 )
-	  printf("1");
-	else if( strcmp(cond->variable.str, "n") == 0 )
-	  printf("0");
-	else if( strcmp(cond->variable.str, "m") == 0 )
-	  printf("2");
-	else
-	  printf("\"%s\"", cond->variable.str);
-	break;
-      default:
-        break;
-      }
-      cond = cond->next;
-    }
+	switch( cond->op )
+	{
+	default:
+	    break;
 
-  /*
-   * Now we generate what we do depending upon the value of the
-   * conditional.  Depending upon what the token type is, there are
-   * different things we must do write the value the given widget -
-   * this code needs to be closely coordinated with the widget
-   * creation procedures in header.tk.  
-   */
-  switch(item->tok)
-    {
-    case tok_define:
-      printf("} then {write_tristate $cfg $autocfg %s %s $notmod }\n", item->optionname, item->value);
-      break;
-    case tok_comment:
-      printf("} then {write_comment $cfg $autocfg \"%s\"}\n", item->label);
-      break;
-    case tok_dep_tristate:
-      printf("} then { write_tristate $cfg $autocfg %s $%s $%s } \n", 
-	     item->optionname, item->optionname, item->depend.str);
-      break;
-    case tok_tristate:
-    case tok_bool:
-      printf("} then { write_tristate $cfg $autocfg %s $%s $notmod }\n", 
-	     item->optionname, item->optionname);
-      break;
-    case tok_int:
-      printf("} then { write_int $cfg $autocfg %s $%s $notmod }\n",
-             item->optionname, item->optionname);
-      break;
-    case tok_hex:
-      printf("} then { write_hex $cfg $autocfg %s $%s $notmod }\n",
-             item->optionname, item->optionname);
-      break;
-    case tok_string:
-      printf("} then { write_string $cfg $autocfg %s $%s $notmod }\n",
-             item->optionname, item->optionname);
-      break;
-    case tok_choose:
-    case tok_choice:
-      fprintf(stderr,"Fixme\n");
-      exit(0);
-    default:
-      break;
+	case op_variable:
+	    global( cond->str );
+	    break;
+
+	case op_kvariable:
+	    if ( ! cond->cfg->global_written )
+	    {
+		cond->cfg->global_written = 1;
+		global( cond->cfg->optionname );
+	    }
+	    break;
+	}
     }
-}
 
-/*
- * Generates a fragment of wish script that closes out a submenu procedure.
- */
-static void end_proc(int menu_num)
-{
-  struct kconfig * cfg;
+    /*
+     * Generate indentation.
+     */
+    if ( cfg->token != token_choice_header )
+	printf( "\t" );
 
-  printf("\n\n\n");
-  printf("\tfocus $w\n");
-  printf("\tupdate_menu%d $w.config.f\n", menu_num);
-  printf("\tglobal winx; global winy\n");
-  printf("\tset winx [expr [winfo x .]+30]; set winy [expr [winfo y .]+30]\n");
-  printf("\twm geometry $w +$winx+$winy\n");
-  
-  /*
-   * Now that the whole window is in place, we need to wait for an "update"
-   * so we can tell the canvas what its virtual size should be.
-   *
-   * Unfortunately, this causes some ugly screen-flashing because the whole
-   * window is drawn, and then it is immediately resized.  It seems
-   * unavoidable, though, since "frame" objects won't tell us their size
-   * until after an update, and "canvas" objects can't automatically pack
-   * around frames.  Sigh.
-   */
-  printf("\tupdate idletasks\n");
-  printf("\t$w.config.canvas create window 0 0 -anchor nw -window $w.config.f\n\n");
-  printf("\t$w.config.canvas configure \\\n"
-  	 "\t\t-width [expr [winfo reqwidth $w.config.f] + 1]\\\n"
-  	 "\t\t-scrollregion \"-1 -1 [expr [winfo reqwidth $w.config.f] + 1] \\\n"
-  	 "\t\t\t [expr [winfo reqheight $w.config.f] + 1]\"\n\n");
-  	 
-  /*
-   * If the whole canvas will fit in 3/4 of the screen height, do it;
-   * otherwise, resize to around 1/2 the screen and let us scroll.
-   */
-  printf("\tset winy [expr [winfo reqh $w] - [winfo reqh $w.config.canvas]]\n");
-  printf("\tset scry [expr [winfo screenh $w] / 2]\n");
-  printf("\tset maxy [expr [winfo screenh $w] * 3 / 4]\n");
-  printf("\tset canvtotal [expr [winfo reqh $w.config.f] + 2]\n");
-  printf("\tif [expr $winy + $canvtotal < $maxy] {\n"
-  	 "\t\t$w.config.canvas configure -height $canvtotal\n"
-  	 "\t} else {\n"
-  	 "\t\t$w.config.canvas configure -height [expr $scry - $winy]\n"
-  	 "\t}\n");
-  
-  /*
-   * Limit the min/max window size.  Height can vary, but not width,
-   * because of the limitations of canvas and our laziness.
-   */
-  printf("\tupdate idletasks\n");
-  printf("\twm maxsize $w [winfo width $w] [winfo screenheight $w]\n");
-  printf("\twm minsize $w [winfo width $w] 100\n\n");
-  printf("\twm deiconify $w\n");
-    
-  printf("}\n\n\n");
-
-  /*
-   * Now we generate the companion procedure for the menu we just
-   * generated.  This procedure contains all of the code to
-   * disable/enable widgets based upon the settings of the other
-   * widgets, and will be called first when the window is mapped,
-   * and each time one of the buttons in the window are clicked.
-   */
-  printf("proc update_menu%d {w}  {\n", menu_num);
-
-  printf("\tupdate_define\n");
-  clear_globalflags(config);
-  for(cfg = config;cfg != NULL; cfg = cfg->next)
+    /*
+     * Generate the conditional.
+     */
+    if ( cfg->cond != NULL )
     {
-      /*
-       * Skip items not for this menu, or ones having no conditions.
-       */
-      if (cfg->menu_number != menu_num ) continue;
-      if (cfg->tok != tok_define) continue;
-      /*
-       * Clear all of the booleans that are defined in this menu.
-       */
-      if(   (cfg->flags & GLOBAL_WRITTEN) == 0
-	 && (cfg->optionname != NULL) )
-	{
-	  printf("\tglobal %s\n", cfg->optionname);
-	  cfg->flags |= GLOBAL_WRITTEN;
-	  printf("\tset %s 0\n", cfg->optionname);
-	}
+	printf( "if {" );
+	for ( cond = cfg->cond; cond != NULL; cond = cond->next )
+	{
+	    switch ( cond->op )
+	    {
+	    default:           break;
+	    case op_bang:      printf( " ! "  ); break;
+	    case op_eq:        printf( " == " ); break;
+	    case op_neq:       printf( " != " ); break;
+	    case op_and:       printf( " && " ); break;
+	    case op_and1:      printf( " && " ); break;
+	    case op_or:        printf( " || " ); break;
+	    case op_lparen:    printf( "("    ); break;
+	    case op_rparen:    printf( ")"    ); break;
 
+	    case op_variable:
+		printf( "$%s", cond->str );
+		break;
+
+	    case op_kvariable:
+		printf( "$%s", cond->cfg->optionname );
+		break;
+
+	    case op_constant:
+		if      ( strcmp( cond->str, "n" ) == 0 ) printf( "0" );
+		else if ( strcmp( cond->str, "y" ) == 0 ) printf( "1" );
+		else if ( strcmp( cond->str, "m" ) == 0 ) printf( "2" );
+		else
+		    printf( "\"%s\"", cond->str );
+		break;
+	    }
+	}
+	printf( "} then {" );
     }
-  for(cfg = config;cfg != NULL; cfg = cfg->next)
+
+    /*
+     * Generate a procedure call to write the value.
+     * This code depends on the write_* procedures in header.tk.
+     */
+    switch ( cfg->token )
     {
-      /*
-       * Skip items not for this menu, or ones having no conditions.
-       */
-      if (cfg->menu_number != menu_num ) continue;
-      if (cfg->tok == tok_menuoption) continue;
-      if (cfg->cond != NULL ) 
-	generate_if(cfg, cfg->cond, menu_num, cfg->menu_line);
-      else
-	{
-	  /*
-	   * If this token has no conditionals, check to see whether
-	   * it is a tristate - if so, then generate the conditional
-	   * to enable/disable the "y" button based upon the setting
-	   * of the option it depends upon.
-	   */
-	  if(cfg->tok == tok_dep_tristate)
+    default:
+	if ( cfg->cond != NULL )
+	    printf( " }" );
+	printf( "\n" );
+	break;
+
+    case token_bool:
+    case token_tristate:
+	if ( cfg->cond )
+	    printf( " " );
+	printf( "write_tristate $cfg $autocfg %s $%s $notmod", 
+	    cfg->optionname, cfg->optionname );
+	if ( cfg->cond != NULL )
+	    printf( " }" );
+	printf( "\n" );
+	break;
+
+    case token_choice_header:
+	/*
+	 * This is funky code -- it fails if there were any conditionals.
+	 * Fortunately all the conditionals got stripped off somewhere
+	 * else.
+	 */
+	{
+	    struct kconfig * cfg1;
+	    for ( cfg1  = cfg->next;
+		  cfg1 != NULL && cfg1->token == token_choice_item;
+		  cfg1  = cfg1->next )
 	    {
-	      global(cfg->depend.str);
-	      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",
-		     cfg->depend.str,cfg->depend.str,
-		     menu_num, cfg->menu_line,
-		     menu_num, cfg->menu_line);
+		printf("\tif { $%s == \"%s\" } then { write_tristate $cfg $autocfg %s 1 $notmod } else { write_tristate $cfg $autocfg %s 0 $notmod }\n",
+		    cfg->optionname, cfg1->label,
+		    cfg1->optionname,
+		    cfg1->optionname );
 	    }
 	}
+	break;
 
-    }
+    case token_choice_item:
+	fprintf( stderr, "Internal error on token_choice_item\n" );
+	exit( 1 );
 
+    case token_comment:
+	printf( "write_comment $cfg $autocfg \"%s\"",
+	    cfg->label );
+	if ( cfg->cond != NULL )
+	    printf( "}" );
+	printf( "\n" );
+	break;
+
+    case token_define_bool:
+	if ( cfg->cond == NULL )
+	{
+	    printf( "write_tristate $cfg $autocfg %s $%s $notmod\n",
+		cfg->optionname, cfg->optionname );
+	}
+	else
+	{
+	    printf( "write_tristate $cfg $autocfg %s %s $notmod }\n",
+		cfg->optionname, cfg->value );
+	}
+	break;
 
-  printf("}\n\n\n");
+    case token_dep_tristate:
+	if ( cfg->cond )
+	    printf( " " );
+	printf( "write_tristate $cfg $autocfg %s $%s $%s",
+	    cfg->optionname, cfg->optionname, cfg->depend );
+	if ( cfg->cond != NULL )
+	    printf( " }" );
+	printf( " \n" );
+	break;
+
+    case token_hex:
+	if ( cfg->cond != NULL )
+	    printf( " " );
+	printf( "write_hex $cfg $autocfg %s $%s $notmod",
+	    cfg->optionname, cfg->optionname );
+	if ( cfg->cond != NULL )
+	    printf( " }" );
+	printf( "\n" );
+	break;
+
+    case token_int:
+	if ( cfg->cond != NULL )
+	    printf( " " );
+	printf( "write_int $cfg $autocfg %s $%s $notmod",
+	    cfg->optionname, cfg->optionname );
+	if ( cfg->cond != NULL )
+	    printf( " }" );
+	printf( "\n" );
+	break;
+
+    case token_string:
+	if ( cfg->cond != NULL )
+	    printf( " " );
+	printf( "write_string $cfg $autocfg %s $%s $notmod",
+	    cfg->optionname, cfg->optionname );
+	if ( cfg->cond != NULL )
+	    printf( " }" );
+	printf( "\n" );
+	break;
+    }
 }
 
+
+
 /*
- * This function goes through and counts up the number of items in
- * each submenu. If there are too many options, we need to split it
- * into submenus.  This function just calculates how many submenus,
- * and how many items go in each submenu.
+ * Generates the end of a menu procedure.
  */
-static void find_menu_size(struct kconfig *cfg,
-			  int *menu_max, 
-			  int *menu_maxlines)
-
+static void end_proc( struct kconfig * scfg, int menu_num )
 {
-  struct kconfig * pnt;
-  int tot;
-  
-  /*
-   * First count up the number of options in this menu.
-   */
-  tot = 0;
-  for(pnt = cfg->next; pnt; pnt = pnt->next)
-  {
-    if( pnt->tok == tok_menuoption) break;
-    switch (pnt->tok)
-      {
-      case tok_bool:
-      case tok_tristate:
-      case tok_dep_tristate:
-      case tok_int:
-      case tok_hex:
-      case tok_string:
-      case tok_choose:
-	tot++;
-	break;
-      case tok_choice:
-      default:
-	break;
-      }
-  }
+    struct kconfig * cfg;
 
-  *menu_max = cfg->menu_number;
-  *menu_maxlines = tot;
+    printf( "\n\n\n" );
+    printf( "\tfocus $w\n" );
+    printf( "\tupdate_menu%d $w.config.f\n",
+	menu_num );
+    printf( "\tglobal winx; global winy\n" );
+    printf( "\tset winx [expr [winfo x .]+30]; set winy [expr [winfo y .]+30]\n" );
+    printf( "\twm geometry $w +$winx+$winy\n" );
+
+    /*
+     * Now that the whole window is in place, we need to wait for an "update"
+     * so we can tell the canvas what its virtual size should be.
+     *
+     * Unfortunately, this causes some ugly screen-flashing because the whole
+     * window is drawn, and then it is immediately resized.  It seems
+     * unavoidable, though, since "frame" objects won't tell us their size
+     * until after an update, and "canvas" objects can't automatically pack
+     * around frames.  Sigh.
+     */
+    printf( "\tupdate idletasks\n" );
+    printf( "\t$w.config.canvas create window 0 0 -anchor nw -window $w.config.f\n\n" );
+    printf( "\t$w.config.canvas configure \\\n" );
+    printf( "\t\t-width [expr [winfo reqwidth $w.config.f] + 1]\\\n" );
+    printf( "\t\t-scrollregion \"-1 -1 [expr [winfo reqwidth $w.config.f] + 1] \\\n" );
+    printf( "\t\t\t [expr [winfo reqheight $w.config.f] + 1]\"\n\n" );
+	 
+    /*
+     * If the whole canvas will fit in 3/4 of the screen height, do it;
+     * otherwise, resize to around 1/2 the screen and let us scroll.
+     */
+    printf( "\tset winy [expr [winfo reqh $w] - [winfo reqh $w.config.canvas]]\n" );
+    printf( "\tset scry [expr [winfo screenh $w] / 2]\n" );
+    printf( "\tset maxy [expr [winfo screenh $w] * 3 / 4]\n" );
+    printf( "\tset canvtotal [expr [winfo reqh $w.config.f] + 2]\n" );
+    printf( "\tif [expr $winy + $canvtotal < $maxy] {\n" );
+    printf( "\t\t$w.config.canvas configure -height $canvtotal\n" );
+    printf( "\t} else {\n" );
+    printf( "\t\t$w.config.canvas configure -height [expr $scry - $winy]\n" );
+    printf( "\t}\n" );
+
+    /*
+     * Limit the min/max window size.  Height can vary, but not width,
+     * because of the limitations of canvas and our laziness.
+     */
+    printf( "\tupdate idletasks\n" );
+    printf( "\twm maxsize $w [winfo width $w] [winfo screenheight $w]\n" );
+    printf( "\twm minsize $w [winfo width $w] 100\n\n" );
+    printf( "\twm deiconify $w\n" );
+    printf( "}\n\n\n" );
+
+    /*
+     * Now we generate the companion procedure for the menu we just
+     * generated.  This procedure contains all of the code to
+     * disable/enable widgets based upon the settings of the other
+     * widgets, and will be called first when the window is mapped,
+     * and each time one of the buttons in the window are clicked.
+     */
+    printf( "proc update_menu%d {w}  {\n", menu_num );
+    printf( "\tupdate_define\n" );
+
+    /*
+     * Clear all of the booleans that are defined in this menu.
+     */
+    clear_globalflags( scfg );
+    for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
+    {
+	if ( cfg->menu_number == menu_num && cfg->token == token_define_bool
+	&&   cfg->optionname  != NULL )
+	{
+	    if ( ! cfg->global_written )
+	    {
+		cfg->global_written = 1;
+		printf( "\tglobal %s\n", cfg->optionname );
+		printf( "\tset %s 0\n",  cfg->optionname );
+	    }
+	}
+    }
+
+    for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
+    {
+	if ( cfg->menu_number == menu_num
+	&&   cfg->token != token_mainmenu_option
+	&&   cfg->token != token_choice_item )
+	{
+	    if ( cfg->cond != NULL )
+		generate_if( cfg, cfg->cond, cfg->menu_number, cfg->menu_line );
+	    else
+	    {
+		/*
+		 * Treat tristate like conditional here.
+		 */
+		if ( cfg->token == token_dep_tristate )
+		{
+		    global( cfg->depend );
+		    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",
+			cfg->depend, cfg->depend,
+			menu_num, cfg->menu_line,
+			menu_num, cfg->menu_line );
+		}
+	    }
+	}
+    }
+
+    printf("}\n\n\n");
 }
 
+
+
 /*
  * This is the top level function for generating the tk script.
  */
-void dump_tk_script(struct kconfig *scfg)
+void dump_tk_script( struct kconfig * scfg )
 {
-  int menu_num =0;
-  int menu_max =0;
-  int menu_min =0;
-  int menu_line = 0;
-  int menu_maxlines = 0;
-  struct kconfig * cfg;
-  struct kconfig * cfg1 = NULL;
-  char * menulabel = "tkgen error";
-
-  /*
-   * Start by assigning menu numbers, and submenu numbers.
-   */
-  for(cfg = scfg;cfg != NULL; cfg = cfg->next)
+    int menu_depth;
+    int menu_num [64];
+    struct kconfig * menu_first [256];
+    struct kconfig * menu_last  [256];
+    int imenu;
+    struct kconfig * cfg;
+    struct kconfig * cfg1 = NULL;
+    const char * name = "No Name";
+
+    /*
+    * Thread the menu pointers so I can walk each menu separately.
+    */
+    tot_menu_num = 0;
+    menu_depth   = 0;
+    for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
     {
-      switch (cfg->tok)
+	switch ( cfg->token )
 	{
-	case tok_menuname:
-	  break;
-	case tok_menuoption:
-	  /*
-	   * At the start of a new menu, calculate the number of items
-	   * we will put into each submenu so we know when to bump the
-	   * menu number. The submenus are really no different from a
-	   * normal menu, but the top level buttons only access the first
-	   * of the chain of menus, and the prev/next buttons are used
-	   * access the submenus.
-	   */
-	  cfg->menu_number = ++menu_num;
-	  find_menu_size(cfg, &menu_max, &menu_maxlines);
-	  cfg->submenu_start = menu_num;
-	  cfg->submenu_end = menu_max;
-	  menu_line = 0;
-	  break;
-	case tok_bool:
-	case tok_tristate:
-	case tok_dep_tristate:
-	case tok_int:
-	case tok_hex:
-	case tok_string:
-	case tok_choose:
-	  /*
-	   * If we have overfilled the menu, then go to the next one.
-	   */
-	  if( menu_line == menu_maxlines )
-	    {
-	      menu_line = 0;
-	      menu_num++;
-	    }
-	  cfg->menu_number = menu_num;
-	  cfg->submenu_start = menu_min;
-	  cfg->submenu_end = menu_max;
-	  cfg->menu_line = menu_line++;
-	  break;
-	case tok_define:
-	  cfg->menu_number = -1;
-	case tok_choice:
 	default:
-	  break;
-	};
-    }
+	    break;
 
-  /*
-   * Record this so we can set up the prev/next buttons correctly.
-   * Menus per column computation has extra button space as follows:
-   *   4 for the save/quit/load/store buttons,
-   *   1 for the blank space above save/quit/load/store
-   *   2 to make the rounding work
-   */
-  tot_menu_num = menu_num;
-  printf( "set menus_per_column %d\n\n", (tot_menu_num + 4 + 1 + 2) / 3 );
-
-  /*
-   * Now start generating the actual wish script that we will use.
-   * We need to keep track of the menu numbers of the min/max menu
-   * for a range of submenus so that we can correctly limit the
-   * prev and next buttons so that they don't go over into some other
-   * category.
-   */
-  for(cfg = scfg; cfg != NULL; cfg = cfg->next)
-    {
-      switch (cfg->tok)
-	{
-	case tok_menuname:
-	  printf("mainmenu_name \"%s\"\n", cfg->label);
-	  break;
-	case tok_menuoption:
-	  /*
-	   * We are at the start of a new menu. If we had one that
-	   * we were working on before, close it out, and then generate
-	   * the script to start the new one.
-	   */
-	  if( cfg->menu_number > 1 )
-	    {
-	      end_proc(menu_num);
-	    }
-	  menulabel = cfg->label;
-	  start_proc(cfg->label, cfg->menu_number, TRUE);
-	  menu_num = cfg->menu_number;
-	  menu_max = cfg->submenu_end;
-	  menu_min = cfg->submenu_start;
-	  break;
-	case tok_bool:
-	  /*
-	   * If we reached the point where we need to switch over
-	   * to the next submenu, then bump the menu number and generate
-	   * the code to close out the old menu and start the new one.
-	   */
-	  if( cfg->menu_number != menu_num )
-	    {
-	      end_proc(menu_num);
-	      start_proc(menulabel, cfg->menu_number, FALSE);
-	      menu_num = cfg->menu_number;
-	    }
-	  printf("\tbool $w.config.f %d %d \"%s\" %s\n",
-		 cfg->menu_number,
-		 cfg->menu_line,
-		 cfg->label,
-		 cfg->optionname);
-	  break;
-
-	case tok_choice:
-	  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",
-		 cfg1->menu_line,
-		 cfg->label,
-		 cfg1->optionname,
-		 cfg->label,
-		 cfg1->menu_number, cfg1->menu_number);
-	  break;
-	case tok_choose:
-	  if( cfg->menu_number != menu_num )
-	    {
-	      end_proc(menu_num);
-	      start_proc(menulabel, cfg->menu_number, FALSE);
-	      menu_num = cfg->menu_number;
-	    }
-	  printf("\tglobal %s\n",cfg->optionname);
-	  printf("\tminimenu $w.config.f %d %d \"%s\" %s %s\n",
-	  	cfg->menu_number,
-	  	cfg->menu_line,
-	  	cfg->label,
-	  	cfg->optionname,
-	  	/*
-	  	 * We rely on the fact that the first tok_choice corresponding
-	  	 * to the current tok_choose is cfg->next (compare parse() in
-	  	 * tkparse.c).  We need its name to pick out the right help
-	  	 * text from Configure.help.
-	  	 */
-	  	cfg->next->optionname);
-	  printf("\tmenu $w.config.f.x%d.x.menu\n", cfg->menu_line);
-	  cfg1 = cfg;
-	  break;
-	case tok_tristate:
-	  if( cfg->menu_number != menu_num )
-	    {
-	      end_proc(menu_num);
-	      start_proc(menulabel, cfg->menu_number, FALSE);
-	      menu_num = cfg->menu_number;
-	    }
-	  printf("\ttristate $w.config.f %d %d \"%s\" %s\n",
-		 cfg->menu_number,
-		 cfg->menu_line,
-		 cfg->label,
-		 cfg->optionname);
-	  break;
-	case tok_dep_tristate:
-	  if( cfg->menu_number != menu_num )
-	    {
-	      end_proc(menu_num);
-	      start_proc(menulabel, cfg->menu_number, FALSE);
-	      menu_num = cfg->menu_number;
-	    }
-	  printf("\tdep_tristate $w.config.f %d %d \"%s\" %s %s\n",
-		 cfg->menu_number,
-		 cfg->menu_line,
-		 cfg->label,
-		 cfg->optionname,
-		 cfg->depend.str);
-	  break;
-	case tok_int:
-	  if( cfg->menu_number != menu_num )
-	    {
-	      end_proc(menu_num);
-	      start_proc(menulabel, cfg->menu_number, FALSE);
-	      menu_num = cfg->menu_number;
-	    }
-	  printf("\tint $w.config.f %d %d \"%s\" %s\n",
-		 cfg->menu_number,
-		 cfg->menu_line,
-		 cfg->label,
-		 cfg->optionname);
-	  break;
-	case tok_hex:
-	  if( cfg->menu_number != menu_num )
-	    {
-	      end_proc(menu_num);
-	      start_proc(menulabel, cfg->menu_number, FALSE);
-	      menu_num = cfg->menu_number;
-	    }
-	  printf("\thex $w.config.f %d %d \"%s\" %s\n",
-		 cfg->menu_number,
-		 cfg->menu_line,
-		 cfg->label,
-		 cfg->optionname);
-	  break;
-	case tok_string:
-	  if( cfg->menu_number != menu_num )
-	    {
-	      end_proc(menu_num);
-	      start_proc(menulabel, cfg->menu_number, FALSE);
-	      menu_num = cfg->menu_number;
-	    }
-	  printf("\tistring $w.config.f %d %d \"%s\" %s\n",
-		 cfg->menu_number,
-		 cfg->menu_line,
-		 cfg->label,
-		 cfg->optionname);
-	  break;
-	default:
-	  break;
-	}
+	case token_mainmenu_name:
+	    name = cfg->label;
+	    break;
+
+	case token_mainmenu_option:
+	    if ( ++menu_depth >= 64 )
+		{ fprintf( stderr, "menus too deep\n" ); exit( 1 ); }
+	    if ( ++tot_menu_num >= 256 )
+		{ fprintf( stderr, "too many menus\n" ); exit( 1 ); }
+	    menu_num   [menu_depth]   = tot_menu_num;
+	    menu_first [tot_menu_num] = cfg;
+	    menu_last  [tot_menu_num] = cfg;
+	    break;
+
+	case token_endmenu:
+#if ! defined(BUG_COMPATIBLE)
+	    /* flatten menus with proper scoping */
+	    if ( --menu_depth < 0 )
+		{ fprintf( stderr, "unmatched endmenu\n" ); exit( 1 ); }
+#endif
+	    break;
 
+	case token_bool:
+	case token_choice_header:
+	case token_choice_item:
+	case token_dep_tristate:
+	case token_hex:
+	case token_int:
+	case token_string:
+	case token_tristate:
+	    if ( menu_depth == 0 )
+		{ fprintf( stderr, "statement not in menu\n" ); exit( 1 ); }
+	    menu_last [menu_num [menu_depth]]->menu_next = cfg;
+	    menu_last [menu_num [menu_depth]]            = cfg;
+	    cfg->menu_next                               = NULL;
+	    break;
+
+	case token_define_bool:
+	    break;
+	}
+    }
+
+    /*
+     * Generate menus per column setting.
+     * There are:
+     *   four extra buttons for save/quit/load/store;
+     *   one blank button
+     *   add two to round up for division
+     */
+    printf( "set menus_per_column %d\n\n", (tot_menu_num + 4 + 1 + 2) / 3 );
+
+    /*
+     * Generate the menus.
+     */
+    printf( "mainmenu_name \"%s\"\n", name );
+    for ( imenu = 1; imenu <= tot_menu_num; ++imenu )
+    {
+	int menu_line = 0;
+
+	clear_globalflags( scfg );
+	start_proc( menu_first[imenu]->label, imenu, 1 );
+
+	for ( cfg = menu_first[imenu]; cfg != NULL; cfg = cfg->menu_next )
+	{
+	    cfg->menu_number = imenu;
+
+	    switch ( cfg->token )
+	    {
+	    default:
+		break;
+
+	    case token_bool:
+		cfg->menu_line = menu_line++;
+		printf( "\tbool $w.config.f %d %d \"%s\" %s\n",
+		    cfg->menu_number, cfg->menu_line, cfg->label,
+		    cfg->optionname );
+		break;
+
+	    case token_choice_header:
+		/*
+		 * I need the first token_choice_item to pick out the right
+		 * help text from Documentation/Configure.help.
+		 */
+		cfg->menu_line = menu_line++;
+		printf( "\tglobal %s\n", cfg->optionname );
+		printf( "\tminimenu $w.config.f %d %d \"%s\" %s %s\n",
+		    cfg->menu_number, cfg->menu_line, cfg->label,
+		    cfg->optionname, cfg->next->optionname );
+		printf( "\tmenu $w.config.f.x%d.x.menu\n", cfg->menu_line );
+		cfg1 = cfg;
+		break;
+
+	    case token_choice_item:
+		/* note: no menu line; uses choice header menu line */
+		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",
+		    cfg1->menu_line, cfg->label, cfg1->optionname,
+		    cfg->label, cfg1->menu_number, cfg1->menu_number );
+		break;
+
+	    case token_dep_tristate:
+		cfg->menu_line = menu_line++;
+		printf( "\tdep_tristate $w.config.f %d %d \"%s\" %s %s\n",
+		    cfg->menu_number, cfg->menu_line, cfg->label,
+		    cfg->optionname, cfg->depend );
+		break;
+
+	    case token_hex:
+		cfg->menu_line = menu_line++;
+		printf( "\thex $w.config.f %d %d \"%s\" %s\n",
+		    cfg->menu_number, cfg->menu_line, cfg->label,
+		    cfg->optionname );
+		break;
+
+	    case token_int:
+		cfg->menu_line = menu_line++;
+		printf( "\tint $w.config.f %d %d \"%s\" %s\n",
+		    cfg->menu_number, cfg->menu_line, cfg->label,
+		    cfg->optionname );
+		break;
+
+	    case token_string:
+		cfg->menu_line = menu_line++;
+		printf( "\tistring $w.config.f %d %d \"%s\" %s\n",
+		    cfg->menu_number, cfg->menu_line, cfg->label,
+		    cfg->optionname );
+		break;
+
+	    case token_tristate:
+		cfg->menu_line = menu_line++;
+		printf( "\ttristate $w.config.f %d %d \"%s\" %s\n",
+		    cfg->menu_number, cfg->menu_line, cfg->label,
+		    cfg->optionname );
+		break;
+	    }
+	}
+
+	end_proc( scfg, imenu );
+    }
+
+    /*
+     * The top level menu also needs an update function.  When we exit a
+     * submenu, we may need to disable one or more of the submenus on
+     * the top level menu, and this procedure will ensure that things are
+     * correct.
+     */
+    clear_globalflags( scfg );
+    printf( "proc update_mainmenu {w}  {\n" );
+    for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
+    {
+	if ( cfg->token == token_mainmenu_option && cfg->cond != NULL )
+	    generate_if( cfg, cfg->cond, cfg->menu_number, cfg->menu_line );
     }
+    printf( "}\n\n\n" );
 
-  /*
-   * Generate the code to close out the last menu.
-   */
-  end_proc(menu_num);
-  clear_globalflags(config);
-
-  /*
-   * The top level menu also needs an update function.  When we exit a
-   * submenu, we may need to disable one or more of the submenus on
-   * the top level menu, and this procedure will ensure that things are
-   * correct.
-   */
-  clear_globalflags(scfg);
-  printf("proc update_mainmenu {w}  {\n");
-  for(cfg = scfg; cfg != NULL; cfg = cfg->next)
+#if 0
+    /*
+     * Generate code to set the variables that are "defined".
+     */
+    for ( cfg = config; cfg != NULL; cfg = cfg->next )
     {
-      switch (cfg->tok)
+	if ( cfg->token == token_define_bool )
 	{
-	case tok_menuoption:
-	  if (cfg->cond != NULL ) 
-	    generate_if(cfg, cfg->cond, cfg->menu_number, cfg->menu_line);
-	  break;
-	default:
-	  break;
+	    if ( cfg->cond != NULL ) 
+		generate_if( cfg, cfg->cond, menu_num, cfg->menu_line );
+	    else
+		printf( "\twrite_define %s %s\n", cfg->optionname, cfg->value );
 	}
     }
+    #endif
 
-  printf("}\n\n\n");
-
-#if 0
-  /*
-   * Generate some code to set the variables that are "defined".
-   */
-  for(cfg = config;cfg != NULL; cfg = cfg->next)
+    /*
+     * Generate code to load the default settings into the variables.
+     * The script in tail.tk will attempt to load .config,
+     * which may override these settings, but that's OK.
+     */
+    for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
     {
-      /*
-       * Skip items not for this menu, or ones having no conditions.
-       */
-      if( cfg->tok != tok_define) continue;
-      if (cfg->cond != NULL ) 
-	generate_if(cfg, cfg->cond, menu_num, cfg->menu_line);
-      else
+	switch ( cfg->token )
 	{
-	  printf("\twrite_define %s %s\n", cfg->optionname, cfg->value);
-	}
+	default:
+	    break;
 
+	case token_bool:
+	case token_choice_item:
+	case token_dep_tristate:
+	case token_tristate:
+	    printf( "set %s 0\n", cfg->optionname );
+	    break;
+
+	case token_choice_header:
+	    printf( "set %s \"(not set)\"\n", cfg->optionname );
+	    break;
+
+	case token_hex:
+	case token_int:
+	case token_string:
+	    printf( "set %s %s\n", cfg->optionname, cfg->value );
+	    break;
+	}
     }
-#endif
 
-  /*
-   * Now generate code to load the default settings into the variables.
-   * Note that the script in tail.tk will attempt to load .config,
-   * which may override these settings, but that's OK.
-   */
-  for(cfg = scfg; cfg != NULL; cfg = cfg->next)
+    /*
+     * Generate a function to write all of the variables to a file.
+     */
+    printf( "proc writeconfig {file1 file2} {\n" );
+    printf( "\tset cfg [open $file1 w]\n" );
+    printf( "\tset autocfg [open $file2 w]\n" );
+    printf( "\tset notmod 1\n" );
+    printf( "\tset notset 0\n" );
+    printf( "\tputs $cfg \"#\"\n");
+    printf( "\tputs $cfg \"# Automatically generated make config: don't edit\"\n");
+    printf( "\tputs $cfg \"#\"\n" );
+
+    printf( "\tputs $autocfg \"/*\"\n" );
+    printf( "\tputs $autocfg \" * Automatically generated C config: don't edit\"\n" );
+    printf( "\tputs $autocfg \" */\"\n" );
+    printf( "\tputs $autocfg \"#define AUTOCONF_INCLUDED\"\n" );
+
+    clear_globalflags( scfg );
+    for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
     {
-      switch (cfg->tok)
+	switch ( cfg->token )
 	{
-	case tok_bool:
-	case tok_tristate:
-	case tok_dep_tristate:
-	case tok_choice:
-	  printf("set %s 0\n", cfg->optionname);
-	  break;
-	case tok_int:
-	case tok_hex:
-	case tok_string:
-	  printf("set %s %s\n", cfg->optionname, cfg->value);
-	  break;
-	case tok_choose:
-	  printf("set %s \"(not set)\"\n",cfg->optionname);
 	default:
-	  break;
+	    break;
+
+	case token_bool:
+	case token_choice_header:
+	case token_comment:
+	case token_define_bool:
+	case token_dep_tristate:
+	case token_hex:
+	case token_int:
+	case token_string:
+	case token_tristate:
+	    generate_writeconfig( cfg );
+	    break;
 	}
     }
+    printf( "\tclose $cfg\n" );
+    printf( "\tclose $autocfg\n" );
+    printf( "}\n\n\n" );
 
-  /*
-   * Next generate a function that can be called from the main menu that will
-   * write all of the variables out.  This also serves double duty - we can
-   * save configuration to a file using this.
-   */
-  printf("proc writeconfig {file1 file2} {\n");
-  printf("\tset cfg [open $file1 w]\n");
-  printf("\tset autocfg [open $file2 w]\n");
-  printf("\tset notmod 1\n");
-  printf("\tset notset 0\n");
-  clear_globalflags(config);
-  printf("\tputs $cfg \"#\"\n");
-  printf("\tputs $cfg \"# Automatically generated make config: don't edit\"\n");
-  printf("\tputs $cfg \"#\"\n");
-
-  printf("\tputs $autocfg \"/*\"\n");
-  printf("\tputs $autocfg \" * Automatically generated C config: don't edit\"\n");
-  printf("\tputs $autocfg \" */\"\n");
-  printf("\tputs $autocfg \"#define AUTOCONF_INCLUDED\"\n");
-  for(cfg = scfg; cfg != NULL; cfg = cfg->next)
+    /*
+     * Generate a simple function that updates the master choice
+     * variable depending upon what values were loaded from a .config
+     * file.  
+     */
+    printf( "proc clear_choices { } {\n" );
+    for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
     {
-      switch (cfg->tok)
+	if ( cfg->token == token_choice_header )
 	{
-	case tok_int:
-	case tok_hex:
-	case tok_string:
-	case tok_bool:
-	case tok_tristate:
-	case tok_dep_tristate:
-	case tok_define:
-	case tok_choose:
-	  if(!(cfg->flags & GLOBAL_WRITTEN))
+	    for ( cfg1  = cfg->next; 
+		  cfg1 != NULL && cfg1->token == token_choice_item;
+		  cfg1  = cfg1->next )
 	    {
-	      cfg->flags |= GLOBAL_WRITTEN;
-	      printf("\tglobal %s\n", cfg->optionname);
+		printf( "\tglobal %s; set %s 0\n",
+		    cfg1->optionname, cfg1->optionname );
 	    }
-	  /* fall through */
-	case tok_comment:
-	  if (cfg->cond != NULL ) 
-	    generate_if_for_outfile(cfg, cfg->cond);
-	  else
-	    {
-	      if(cfg->tok == tok_dep_tristate)
-		{
-		  printf("\tif {$%s == 0 } then {\n"
-		  	 "\t\twrite_tristate $cfg $autocfg %s $notset $notmod\n"
-		  	 "\t} else {\n"
-		  	 "\t\twrite_tristate $cfg $autocfg %s $%s $%s\n"
-		  	 "\t}\n",
-		  	 cfg->depend.str,
-			 cfg->optionname,
-			 cfg->optionname,
-			 cfg->optionname,
-			 cfg->depend.str);
-		}
-	      else if(cfg->tok == tok_comment)
-		{
-		  printf("\twrite_comment $cfg $autocfg \"%s\"\n", cfg->label);
-		}
-#if 0
-	      else if(cfg->tok == tok_define)
-		{
-		  printf("\twrite_define %s %s\n", cfg->optionname,
-			 cfg->value);
-		}
-#endif
-	      else if (cfg->tok == tok_choose )
-		{
-		  for(cfg1 = cfg->next; 
-		      cfg1 != NULL && cfg1->tok == tok_choice;
-		      cfg1 = cfg1->next)
-		    {
-		      printf("\tif { $%s == \"%s\" } then { write_tristate $cfg $autocfg %s 1 $notmod } else { write_tristate $cfg $autocfg %s 0 $notmod }\n",
-			     cfg->optionname,
-			     cfg1->label,
-			     cfg1->optionname,
-			     cfg1->optionname);
-		    }
-		}
-	      else if (cfg->tok == tok_int )
-	        {
-		  printf("\twrite_int $cfg $autocfg %s $%s $notmod\n",
-			 cfg->optionname,
-			 cfg->optionname);
-	        }
-	      else if (cfg->tok == tok_hex )
-	        {
-		  printf("\twrite_hex $cfg $autocfg %s $%s $notmod\n",
-			 cfg->optionname,
-			 cfg->optionname);
-	        }
-	      else if (cfg->tok == tok_string )
-	        {
-		  printf("\twrite_string $cfg $autocfg %s $%s $notmod\n",
-			 cfg->optionname,
-			 cfg->optionname);
-	        }
-	      else
-		{
-		  printf("\twrite_tristate $cfg $autocfg %s $%s $notmod\n",
-			 cfg->optionname,
-			 cfg->optionname);
-		}
-	    }
-	  break;
-	default:
-	  break;
 	}
     }
-  printf("\tclose $cfg\n");
-  printf("\tclose $autocfg\n");
-  printf("}\n\n\n");
-
-  /*
-   * Finally write a simple function that updates the master choice
-   * variable depending upon what values were loaded from a .config
-   * file.  
-   */
-  printf("proc clear_choices { } {\n");
-  for(cfg = scfg; cfg != NULL; cfg = cfg->next)
+    printf( "}\n\n\n" );
+
+    printf( "proc update_choices { } {\n" );
+    for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
     {
-      if( cfg->tok != tok_choose ) continue;
-      for(cfg1 = cfg->next; 
-	  cfg1 != NULL && cfg1->tok == tok_choice;
-	  cfg1 = cfg1->next)
+	if ( cfg->token == token_choice_header )
 	{
-	  printf("\tglobal %s; set %s 0\n",cfg1->optionname,cfg1->optionname);
+	    printf( "\tglobal %s\n", cfg->optionname );
+	    for ( cfg1  = cfg->next; 
+		  cfg1 != NULL && cfg1->token == token_choice_item;
+		  cfg1  = cfg1->next )
+	    {
+		printf( "\tglobal %s\n", cfg1->optionname );
+		printf( "\tif { $%s == 1 } then { set %s \"%s\" }\n",
+		    cfg1->optionname, cfg->optionname, cfg1->label );
+	    }
 	}
     }
-  printf("}\n\n\n");
+    printf( "}\n\n\n" );
 
-  printf("proc update_choices { } {\n");
-  for(cfg = scfg; cfg != NULL; cfg = cfg->next)
+    printf( "proc update_define { } {\n" );
+    clear_globalflags( scfg );
+    for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
     {
-      if( cfg->tok != tok_choose ) continue;
-      printf("\tglobal %s\n", cfg->optionname);
-      for(cfg1 = cfg->next; 
-	  cfg1 != NULL && cfg1->tok == tok_choice;
-	  cfg1 = cfg1->next)
-	{
-	  printf("\tglobal %s\n", cfg1->optionname);
-	  printf("\tif { $%s == 1 } then { set %s \"%s\" }\n",
-		 cfg1->optionname,
-		 cfg->optionname,
-		 cfg1->label);
+	if ( cfg->token == token_define_bool )
+	{
+	    cfg->global_written = 1;
+	    printf( "\tglobal %s\n", cfg->optionname );
 	}
     }
-  printf("}\n\n\n");
 
-  printf("proc update_define { } {\n");
-  clear_globalflags(config);
-  for(cfg = scfg; cfg != NULL; cfg = cfg->next)
+    for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
     {
-      if( cfg->tok != tok_define ) continue;
-      printf("\tglobal %s\n",  cfg->optionname);
-      cfg->flags |= GLOBAL_WRITTEN;
-    }
-  for(cfg = scfg; cfg != NULL; cfg = cfg->next)
-    {
-      if( cfg->tok != tok_define ) continue;
-      if (cfg->cond != NULL ) 
-	generate_if(cfg, cfg->cond, -1, 0);
-      else
+	if( cfg->token == token_define_bool )
 	{
-	  printf("\tset %s %s\n",
-		 cfg->optionname, cfg->value);
+	    if ( cfg->cond == NULL )
+		printf( "\tset %s %s\n", cfg->optionname, cfg->value );
+	    else
+		generate_if( cfg, cfg->cond, -1, 0 );
 	}
     }
-  printf("}\n\n\n");
-  /*
-   * That's it.  We are done.  The output of this file will have header.tk
-   * prepended and tail.tk appended to create an executable wish script.
-   */
+    printf( "}\n\n\n" );
+
+    /*
+     * That's it.  We are done.  The output of this file will have header.tk
+     * prepended and tail.tk appended to create an executable wish script.
+     */
 }

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen, slshen@lbl.gov