linux-old/scripts/tkgen.c
<<
>>
Prefs
   1/* Generate tk script based upon config.in
   2 *
   3 * Version 1.0
   4 * Eric Youngdale
   5 * 10/95
   6 *
   7 * 1996 01 04
   8 * Avery Pennarun - Aesthetic improvements.
   9 *
  10 * 1996 01 24
  11 * Avery Pennarun - Bugfixes and more aesthetics.
  12 *
  13 * 1996 03 08
  14 * Avery Pennarun - The int and hex config.in commands work right.
  15 *                - Choice buttons are more user-friendly.
  16 *                - Disabling a text entry line greys it out properly.
  17 *                - dep_tristate now works like in Configure. (not pretty)
  18 *                - No warnings in gcc -Wall. (Fixed some "interesting" bugs.)
  19 *                - Faster/prettier "Help" lookups.
  20 *
  21 * 1996 03 15
  22 * Avery Pennarun - Added new sed script from Axel Boldt to make help even
  23 *                  faster. (Actually awk is downright slow on some machines.)
  24 *                - Fixed a bug I introduced into Choice dependencies.  Thanks
  25 *                  to Robert Krawitz for pointing this out.
  26 *
  27 * 1996 03 16
  28 * Avery Pennarun - basic "do_make" support added to let sound config work.
  29 *
  30 * 1996 03 25
  31 *     Axel Boldt - Help now works on "choice" buttons.
  32 *
  33 * 1996 04 06
  34 * Avery Pennarun - Improved sound config stuff. (I think it actually works
  35 *                  now!)
  36 *                - Window-resize-limits don't use ugly /usr/lib/tk4.0 hack.
  37 *                - int/hex work with tk3 again. (The "cget" error.)
  38 *                - Next/Prev buttons switch between menus.  I can't take
  39 *                  much credit for this; the code was already there, but
  40 *                  ifdef'd out for some reason.  It flickers a lot, but
  41 *                  I suspect there's no "easy" fix for that.
  42 *                - Labels no longer highlight as you move the mouse over
  43 *                  them (although you can still press them... oh well.)
  44 *                - Got rid of the last of the literal color settings, to
  45 *                  help out people with mono X-Windows systems. 
  46 *                  (Apparently there still are some out there!)
  47 *                - Tabstops seem sensible now.
  48 *
  49 * 1996 04 14
  50 * Avery Pennarun - Reduced flicker when creating windows, even with "update
  51 *                  idletasks" hack.
  52 *
  53 * 1997 12 08
  54 * Michael Chastain - Remove sound driver special cases.
  55 *
  56 * 1997 11 15
  57 * Michael Chastain - For choice buttons, write values for all options,
  58 *                    not just the single chosen one.  This is compatible
  59 *                    with 'make config' and 'make oldconfig', and is
  60 *                    needed so smart-config dependencies work if the
  61 *                    user switches from one configuration method to
  62 *                    another.
  63 *
  64 * 1998 03 09
  65 * Axel Boldt - Smaller layout of main menu - it's still too big for 800x600.
  66 *            - Display help in text window to allow for cut and paste.
  67 *            - Allow for empty lines in help texts.
  68 *            - update_define should not set all variables unconditionally to
  69 *              0: they may have been set to 1 elsewhere. CONFIG_NETLINK is
  70 *              an example.
  71 *
  72 * 1999 01 04
  73 * Michael Elizabeth Chastain <mec@shout.net>
  74 * - Call clear_globalflags when writing out update_mainmenu.
  75 *   This fixes the missing global/vfix lines for ARCH=alpha on 2.2.0-pre4.
  76 *
  77 * 8 January 1999, Michael Elizabeth Chastain <mec@shout.net>
  78 * - Emit menus_per_column
  79 *
  80 * 14 January 1999, Michael Elizabeth Chastain <mec@shout.net>
  81 * - Steam-clean this file.  I tested this by generating kconfig.tk for every
  82 *   architecture and comparing it character-for-character against the output
  83 *   of the old tkparse.
  84 * - Fix flattening of nested menus.  The old code simply assigned items to
  85 *   the most recent token_mainmenu_option, without paying attention to scope.
  86 *   For example: "menu-1 bool-a menu-2 bool-b endmenu bool-c bool-d endmenu".
  87 *   The old code would put bool-a in menu-1, bool-b in menu-2, and bool-c
  88 *   and bool-d in *menu-2*.  This hosed the nested submenus in
  89 *   drives/net/Config.in and other places.
  90 * - Fix menu line wraparound at 128 menus (some fool used a 'char' for
  91 *   a counter).
  92 *
  93 * 23 January 1999, Michael Elizabeth Chastain <mec@shout.net>
  94 * - Remove bug-compatible code.
  95 *
  96 * 07 July 1999, Andrzej M. Krzysztofowicz <ankry@mif.pg.gda.pl>
  97 * Some bugfixes, including
  98 * - disabling "m" options when CONFIG_MODULES is set to "n" as well as "y"
  99 *   option in dep_tristate when dependency is set to "m",
 100 * - deactivating choices which should not be available,
 101 * - basic validation for int and hex introduced if the entered one is not 
 102 *   valid,
 103 * - updates of all opened menus instead of the active only. I was afraid
 104 *   that it would slow down updates, but I don't even see any speed difference
 105 *   on my machine. If it slows you can still work with only a single menu
 106 *   opened,
 107 * - fixed error when focussing non-existent window (especially Help windows),
 108 * Higher level submenus implemented.
 109 */
 110
 111#include <stdio.h>
 112#include <stdlib.h>
 113#include <unistd.h>
 114#include <string.h>
 115#include "tkparse.h"
 116
 117
 118/*
 119 * Total number of menus.
 120 */
 121static int tot_menu_num = 0;
 122
 123/*
 124 * Pointers to mainmenu_option and endmenu of each menu.
 125 */
 126struct kconfig * menu_first [100];
 127struct kconfig * menu_last  [100];
 128
 129/*
 130 * Generate portion of wish script for the beginning of a submenu.
 131 * The guts get filled in with the various options.
 132 */
 133static void start_proc( char * label, int menu_num, int toplevel )
 134{
 135    if ( toplevel )
 136        printf( "menu_option menu%d %d \"%s\"\n", menu_num, menu_num, label );
 137    printf( "proc menu%d {w title} {\n", menu_num );
 138    printf( "\tset oldFocus [focus]\n" );
 139    if ( menu_first[menu_num]->menu_number != 0 )
 140        printf( "\tcatch {focus .menu%d}\n",
 141                menu_first[menu_num]->menu_number );
 142    printf( "\tcatch {destroy $w; unregister_active %d}\n", menu_num );
 143    printf( "\ttoplevel $w -class Dialog\n" );
 144    printf( "\twm withdraw $w\n" );
 145    printf( "\tglobal active_menus\n" );
 146    printf( "\tset active_menus [lsort -integer [linsert $active_menus end %d]]\n", menu_num );
 147    printf( "\tmessage $w.m -width 400 -aspect 300 -text \\\n" );
 148    printf( "\t\t\"%s\"  -relief raised\n", label );
 149    printf( "\tpack $w.m -pady 10 -side top -padx 10\n" );
 150    printf( "\twm title $w \"%s\" \n\n", label );
 151
 152    /*
 153     * Attach the "Prev", "Next" and "OK" buttons at the end of the window.
 154     */
 155    printf( "\tframe $w.f\n" );
 156    if ( toplevel )
 157        printf( "\tbutton $w.f.back -text \"Main Menu\" \\\n" );
 158    else
 159        printf( "\tbutton $w.f.back -text \"OK\" \\\n" );
 160    printf( "\t\t-width 15 -command \"catch {focus $oldFocus}; destroy $w; unregister_active %d\"\n",
 161        menu_num );
 162    printf( "\tbutton $w.f.next -text \"Next\" \\\n" );
 163    printf( "\t\t-width 15 -command \"catch {focus $oldFocus}; " );
 164    /* 
 165     * We are checking which windows should be destroyed and which are 
 166     * common parrents with the next one. Remember that menu_num field
 167     * in mainmenu_option record reports number of its *parent* menu.
 168     */
 169    if ( menu_num < tot_menu_num
 170    && menu_first[menu_num + 1]->menu_number != menu_num )
 171    {
 172        int to_destr;
 173
 174        printf( "destroy $w; unregister_active %d; ", menu_num );
 175        to_destr = menu_first[menu_num]->menu_number;
 176        while ( to_destr > 0 && menu_first[menu_num + 1]->menu_number != to_destr )
 177        {
 178            printf( "catch {destroy .menu%d}; unregister_active %d; ",
 179                to_destr, to_destr );
 180            to_destr = menu_first[to_destr]->menu_number;
 181        }
 182    }
 183    printf( "menu%d .menu%d \\\"$title\\\"\"\n",
 184        menu_num+1, menu_num+1 );
 185    if ( menu_num == tot_menu_num )
 186        printf( "\t$w.f.next configure -state disabled\n" );
 187    printf( "\tbutton $w.f.prev -text \"Prev\" \\\n" );
 188    printf( "\t\t-width 15 -command \"catch {focus $oldFocus}; destroy $w; unregister_active %d; menu%d .menu%d \\\"$title\\\"\"\n",
 189        menu_num, menu_num-1, menu_num-1 );
 190    if ( menu_num == 1 )
 191        printf( "\t$w.f.prev configure -state disabled\n" );
 192    printf( "\tpack $w.f.back $w.f.next $w.f.prev -side left -expand on\n" );
 193    printf( "\tpack $w.f -pady 10 -side bottom -anchor w -fill x\n" );
 194
 195    /*
 196     * Lines between canvas and other areas of the window.
 197     */
 198    printf( "\tframe $w.topline -relief ridge -borderwidth 2 -height 2\n" );
 199    printf( "\tpack $w.topline -side top -fill x\n\n" );
 200    printf( "\tframe $w.botline -relief ridge -borderwidth 2 -height 2\n" );
 201    printf( "\tpack $w.botline -side bottom -fill x\n\n" );
 202
 203    /*
 204     * The "config" frame contains the canvas and a scrollbar.
 205     */
 206    printf( "\tframe $w.config\n" );
 207    printf( "\tpack $w.config -fill y -expand on\n\n" );
 208    printf( "\tscrollbar $w.config.vscroll -command \"$w.config.canvas yview\"\n" );
 209    printf( "\tpack $w.config.vscroll -side right -fill y\n\n" );
 210
 211    /*
 212     * The scrollable canvas itself, where the real work (and mess) gets done.
 213     */
 214    printf( "\tcanvas $w.config.canvas -height 1\\\n" );
 215    printf( "\t\t-relief flat -borderwidth 0 -yscrollcommand \"$w.config.vscroll set\" \\\n" );
 216    printf( "\t\t-width [expr [winfo screenwidth .] * 1 / 2] \n" );
 217    printf( "\tframe $w.config.f\n" );
 218    printf( "\tpack $w.config.canvas -side right -fill y\n" );
 219    printf("\n\n");
 220}
 221
 222
 223
 224/*
 225 * Each proc we create needs a global declaration for any global variables we
 226 * use.  To minimize the size of the file, we set a flag each time we output
 227 * a global declaration so we know whether we need to insert one for a
 228 * given function or not.
 229 */
 230static void clear_globalflags(void)
 231{
 232    int i;
 233    for ( i = 1; i <= max_varnum; i++ )
 234        vartable[i].global_written = 0;
 235}
 236
 237
 238
 239/*
 240 * Output a "global" line for a given variable.  Also include the
 241 * call to "vfix".  (If vfix is not needed, then it's fine to just printf
 242 * a "global" line).
 243 */
 244void global( const char *var )
 245{
 246    printf( "\tglobal %s\n", var );
 247}
 248
 249
 250
 251/*
 252 * This function walks the chain of conditions that we got from cond.c
 253 * and creates a TCL conditional to enable/disable a given widget.
 254 */
 255void generate_if( struct kconfig * cfg, struct condition * ocond,
 256    int menu_num, int line_num )
 257{
 258    struct condition * cond;
 259    struct dependency * tmp;
 260    struct kconfig * cfg1;
 261
 262    if ( line_num >= -1 )
 263    {
 264        if ( cfg->token == token_define_bool || cfg->token == token_define_hex
 265        ||   cfg->token == token_define_int || cfg->token == token_define_string
 266        ||   cfg->token == token_define_tristate || cfg->token == token_unset )
 267            return;
 268        if ( cfg->token == token_comment && line_num == -1 )
 269            return;
 270    }
 271    else
 272    {
 273        if ( cfg->token == token_string || cfg->token == token_mainmenu_option )
 274            return;
 275    }
 276
 277    /*
 278     * First write any global declarations we need for this conditional.
 279     */
 280    for ( cond = ocond; cond != NULL; cond = cond->next )
 281    {
 282        switch ( cond->op )
 283        {
 284        default:
 285            break;
 286
 287        case op_variable:
 288            if ( ! vartable[cond->nameindex].global_written )
 289            {
 290                vartable[cond->nameindex].global_written = 1;
 291                global( vartable[cond->nameindex].name );
 292            }
 293            break;
 294        }
 295    }
 296
 297    /*
 298     * Now write this option.
 299     */
 300    if ( cfg->nameindex > 0 && ! vartable[cfg->nameindex].global_written )
 301    {
 302        vartable[cfg->nameindex].global_written = 1;
 303        global( vartable[cfg->nameindex].name );
 304    }
 305
 306    /*
 307     * Generate the body of the conditional.
 308     */
 309    printf( "\tif {" );
 310    for ( cond = ocond; cond != NULL; cond = cond->next )
 311    {
 312        switch ( cond->op )
 313        {
 314        default:
 315            break;
 316
 317        case op_bang:   printf( " ! "  ); break;
 318        case op_eq:     printf( " == " ); break;
 319        case op_neq:    printf( " != " ); break;
 320        case op_and:    printf( " && " ); break;
 321        case op_and1:   printf( " && " ); break;
 322        case op_or:     printf( " || " ); break;
 323        case op_lparen: printf( "("    ); break;
 324        case op_rparen: printf( ")"    ); break;
 325
 326        case op_variable:
 327            printf( "$%s", vartable[cond->nameindex].name );
 328            break;
 329
 330        case op_constant:
 331            if      ( strcmp( cond->str, "y" ) == 0 ) printf( "1" );
 332            else if ( strcmp( cond->str, "n" ) == 0 ) printf( "0" );
 333            else if ( strcmp( cond->str, "m" ) == 0 ) printf( "2" );
 334            else if ( strcmp( cond->str, "" ) == 0 )  printf( "4" );
 335            else
 336                printf( "\"%s\"", cond->str );
 337            break;
 338        }
 339    }
 340    printf( "} then {" );
 341
 342    /*
 343     * Generate a procedure call to write the value.
 344     * This code depends on procedures in header.tk.
 345     */
 346    if ( line_num >= -1 )
 347    {
 348        int modtoyes = 0;
 349
 350        switch ( cfg->token )
 351        {
 352        default:
 353            printf( " }\n" );
 354            break;
 355
 356        case token_dep_mbool:
 357            modtoyes = 1;
 358        case token_dep_bool:
 359            printf( "\n" );
 360            for ( tmp = cfg->depend; tmp; tmp = tmp->next )
 361                if ( ! vartable[get_varnum( tmp->name )].global_written )
 362                {
 363                    global( tmp->name );
 364                }
 365            printf( "\tset tmpvar_dep [effective_dep [list" );
 366            for ( tmp = cfg->depend; tmp; tmp = tmp->next )
 367                printf( " $%s", tmp->name );
 368            printf( "]];set %s [sync_bool $%s $tmpvar_dep %d];",
 369                vartable[cfg->nameindex].name, vartable[cfg->nameindex].name,
 370                modtoyes );
 371            printf( "if {$tmpvar_dep != 1" );
 372            if (modtoyes)
 373                printf( " && $tmpvar_dep != 2" );
 374            printf( "} then {configure_entry .menu%d.config.f.x%d disabled {y};",
 375                menu_num, line_num );
 376            printf( "} else {" );
 377            printf( "configure_entry .menu%d.config.f.x%d normal {y};",
 378                menu_num, line_num );
 379            printf( "}; " );
 380        case token_bool:
 381            if ( cfg->token == token_bool )
 382                printf( "\n\t" );
 383            printf( "configure_entry .menu%d.config.f.x%d normal {n l",
 384                menu_num, line_num );
 385            if ( cfg->token == token_bool )
 386                printf( " y" );
 387            printf( "}" );
 388            printf( "} else {");
 389            printf( "configure_entry .menu%d.config.f.x%d disabled {y n l}}\n",
 390                menu_num, line_num );
 391            break;
 392
 393        case token_choice_header:
 394            printf( "configure_entry .menu%d.config.f.x%d normal {x l}",
 395                menu_num, line_num );
 396            printf( "} else {" );
 397            printf( "configure_entry .menu%d.config.f.x%d disabled {x l}",
 398                menu_num, line_num );
 399            printf( "}\n" );
 400            break;
 401
 402        case token_choice_item:
 403            fprintf( stderr, "Internal error on token_choice_item\n" );
 404            exit( 1 );
 405
 406        case token_dep_tristate:
 407            printf( "\n" );
 408            for ( tmp = cfg->depend; tmp; tmp = tmp->next )
 409                if ( ! vartable[get_varnum( tmp->name )].global_written )
 410                {
 411                    global( tmp->name );
 412                }
 413            printf( "\tset tmpvar_dep [effective_dep [list" );
 414            for ( tmp = cfg->depend; tmp; tmp = tmp->next )
 415                printf( " $%s", tmp->name );
 416            printf( "]];set %s [sync_tristate $%s $tmpvar_dep];",
 417                vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
 418            printf( "\tif {$tmpvar_dep != 1} then {" );
 419            printf( "configure_entry .menu%d.config.f.x%d disabled {y}",
 420                menu_num, line_num );
 421            printf( "} else {" );
 422            printf( "configure_entry .menu%d.config.f.x%d normal {y}",
 423                menu_num, line_num );
 424            printf( "}; " );
 425            printf( "if {$tmpvar_dep == 0} then {" );
 426            printf( "configure_entry .menu%d.config.f.x%d disabled {m}",
 427                menu_num, line_num );
 428            printf( "} else {" );
 429            printf( "configure_entry .menu%d.config.f.x%d normal {m}",
 430                menu_num, line_num );
 431            printf( "}; " );
 432        case token_tristate:
 433            if ( cfg->token == token_tristate )
 434            {
 435                printf( "\n\tconfigure_entry .menu%d.config.f.x%d normal {y}; ",
 436                    menu_num, line_num );
 437            }
 438            printf( "if {($CONFIG_MODULES == 1)} then {" );
 439            printf( "configure_entry .menu%d.config.f.x%d normal {m}} else {",
 440                menu_num, line_num );
 441            printf( "configure_entry .menu%d.config.f.x%d disabled {m}}; ",
 442                menu_num, line_num );
 443            printf( "configure_entry .menu%d.config.f.x%d normal {n l}",
 444                menu_num, line_num );
 445
 446        /*
 447         * Or in a bit to the variable - this causes all of the radiobuttons
 448         * to be deselected (i.e. not be red).
 449         */
 450            printf( "} else {" );
 451            printf( "configure_entry .menu%d.config.f.x%d disabled {y n m l}}\n",
 452                menu_num, line_num );
 453            break;
 454
 455        case token_hex:
 456        case token_int:
 457        case token_string:
 458            printf( ".menu%d.config.f.x%d.x configure -state normal -foreground [ cget .ref -foreground ]; ",
 459                menu_num, line_num );
 460            printf( ".menu%d.config.f.x%d.l configure -state normal; ",
 461                menu_num, line_num );
 462            printf( "} else {" );
 463            printf( ".menu%d.config.f.x%d.x configure -state disabled -foreground [ cget .ref -disabledforeground ]; ",
 464                menu_num, line_num );
 465            printf( ".menu%d.config.f.x%d.l configure -state disabled}\n",
 466                menu_num, line_num );
 467            break;
 468
 469        case token_comment:
 470        case token_mainmenu_option:
 471            if ( line_num >= 0 )
 472            {
 473                printf( "configure_entry .menu%d.config.f.x%d normal {m}",
 474                    menu_num, line_num );
 475                printf( "} else {" );
 476                printf( "configure_entry .menu%d.config.f.x%d disabled {m}}\n",
 477                    menu_num, line_num );
 478            }
 479            else
 480                printf( ".f0.x%d configure -state normal } else { .f0.x%d configure -state disabled }\n",
 481                    menu_num, menu_num );
 482            break;
 483        }
 484    }
 485    else
 486    {
 487        int modtoyes = 0;
 488
 489        switch ( cfg->token )
 490        {
 491        default:
 492            printf( " }\n" );
 493            break;
 494
 495        case token_dep_mbool:
 496            modtoyes = 1;
 497        case token_dep_bool:
 498            printf( "\n" );
 499            for ( tmp = cfg->depend; tmp; tmp = tmp->next )
 500                if ( ! vartable[get_varnum( tmp->name )].global_written )
 501                {
 502                    global( tmp->name );
 503                }
 504            printf( "\tset tmpvar_dep [effective_dep [list" );
 505            for ( tmp = cfg->depend; tmp; tmp = tmp->next )
 506                printf( " $%s", tmp->name );
 507            printf( "]];set %s [sync_bool $%s $tmpvar_dep %d];",
 508                vartable[cfg->nameindex].name, vartable[cfg->nameindex].name,
 509                modtoyes );
 510        case token_bool:
 511            if ( cfg->token == token_bool )
 512                printf( "\n\t" );
 513            printf( "set %s [expr $%s&15]",
 514                vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
 515            printf( "} else {");
 516            printf( "set %s [expr $%s|16]}\n",
 517                vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
 518            break;
 519
 520        case token_choice_header:
 521            printf( "} else {" );
 522            for ( cfg1  = cfg->next;
 523                  cfg1 != NULL && cfg1->token == token_choice_item;
 524                  cfg1  = cfg1->next )
 525                printf( "set %s 4;", vartable[cfg1->nameindex].name );
 526            printf( "}\n" );
 527            break;
 528
 529        case token_choice_item:
 530            fprintf( stderr, "Internal error on token_choice_item\n" );
 531            exit( 1 );
 532
 533        case token_define_bool:
 534        case token_define_tristate:
 535            if ( ! vartable[get_varnum( cfg->value )].global_written )
 536            {
 537                global( cfg->value );
 538            }
 539            printf( "set %s $%s }\n",
 540                vartable[cfg->nameindex].name, cfg->value );
 541            break;
 542
 543        case token_define_hex:
 544        case token_define_int:
 545            printf( "set %s %s }\n",
 546                vartable[cfg->nameindex].name, cfg->value );
 547            break;
 548
 549        case token_define_string:
 550            printf( "set %s \"%s\" }\n",
 551                vartable[cfg->nameindex].name, cfg->value );
 552            break;
 553
 554        case token_dep_tristate:
 555            printf( "\n" );
 556            for ( tmp = cfg->depend; tmp; tmp = tmp->next )
 557                if ( ! vartable[get_varnum( tmp->name )].global_written )
 558                {
 559                    global( tmp->name );
 560                }
 561            printf( "\tset tmpvar_dep [effective_dep [list" );
 562            for ( tmp = cfg->depend; tmp; tmp = tmp->next )
 563                printf( " $%s", tmp->name );
 564            printf( "]]; set %s [sync_tristate $%s $tmpvar_dep]; ",
 565                vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
 566        case token_tristate:
 567            if ( cfg->token == token_tristate )
 568                printf( "if {($CONFIG_MODULES == 0) && ($%s == 2)} then {set %s 1}; ",
 569                    vartable[cfg->nameindex].name,
 570                    vartable[cfg->nameindex].name );
 571        /*
 572         * Or in a bit to the variable - this causes all of the radiobuttons
 573         * to be deselected (i.e. not be red).
 574         */
 575            printf( "set %s [expr $%s&15]",
 576                vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
 577            printf( "} else {" );
 578
 579        /*
 580         * Clear the disable bit to enable the correct radiobutton.
 581         */
 582            printf( "set %s [expr $%s|16]}\n",
 583                vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
 584            break;
 585
 586        case token_hex:
 587        case token_int:
 588            if ( cfg->value && *cfg->value == '$' )
 589            {
 590                int i = get_varnum( cfg->value+1 );
 591                printf( "\n" );
 592                if ( ! vartable[i].global_written )
 593                {
 594                    global( vartable[i].name );
 595                }
 596                printf( "\t" );
 597            }
 598            if ( cfg->token == token_hex )
 599                printf( "validate_hex " );
 600            else if ( cfg->token == token_int )
 601                printf( "validate_int " );
 602            printf( "%s \"$%s\" %s}\n",
 603                vartable[cfg->nameindex].name, vartable[cfg->nameindex].name,
 604                cfg->value );
 605            break;
 606
 607        case token_unset:
 608            printf( "set %s 4}\n", vartable[cfg->nameindex].name );
 609            break;
 610        }
 611    }
 612}
 613
 614
 615/*
 616 * Generate a line that writes a variable to the output file.
 617 */
 618void generate_writeconfig( struct kconfig * cfg )
 619{
 620    struct condition * cond;
 621    struct dependency * tmp;
 622    int depmod = 2;
 623    
 624    /*
 625     * Generate global declaration for this symbol.
 626     */
 627    if ( cfg->token != token_comment )
 628    {
 629        if ( cfg->nameindex > 0 && ! vartable[cfg->nameindex].global_written )
 630        {
 631            vartable[cfg->nameindex].global_written = 1;
 632            global( vartable[cfg->nameindex].name );
 633        }
 634        if ( cfg->token == token_define_tristate || cfg->token == token_define_bool )
 635        {
 636            if ( ! vartable[get_varnum( cfg->value )].global_written )
 637            {
 638                vartable[get_varnum( cfg->value )].global_written = 1;
 639                global( cfg->value );
 640            }
 641        }
 642        else if ( cfg->nameindex <= 0 && cfg->token == token_choice_header )
 643        {
 644            printf( "\tglobal tmpvar_%d\n", -(cfg->nameindex) );
 645        }
 646    }
 647
 648    /*
 649     * Generate global declarations for the condition chain.
 650     */
 651    for ( cond = cfg->cond; cond != NULL; cond = cond->next )
 652    {
 653        switch( cond->op )
 654        {
 655        default:
 656            break;
 657
 658        case op_variable:
 659            if ( ! vartable[cond->nameindex].global_written )
 660            {
 661                vartable[cond->nameindex].global_written = 1;
 662                global( vartable[cond->nameindex].name );
 663            }
 664            break;
 665        }
 666    }
 667
 668    /*
 669     * Generate indentation.
 670     */
 671        printf( "\t" );
 672
 673    /*
 674     * Generate the conditional.
 675     */
 676    if ( cfg->cond != NULL )
 677    {
 678        printf( "if {" );
 679        for ( cond = cfg->cond; cond != NULL; cond = cond->next )
 680        {
 681            switch ( cond->op )
 682            {
 683            default:           break;
 684            case op_bang:      printf( " ! "  ); break;
 685            case op_eq:        printf( " == " ); break;
 686            case op_neq:       printf( " != " ); break;
 687            case op_and:       printf( " && " ); break;
 688            case op_and1:      printf( " && " ); break;
 689            case op_or:        printf( " || " ); break;
 690            case op_lparen:    printf( "("    ); break;
 691            case op_rparen:    printf( ")"    ); break;
 692
 693            case op_variable:
 694                printf( "$%s", vartable[cond->nameindex].name );
 695                break;
 696
 697            case op_constant:
 698                if      ( strcmp( cond->str, "n" ) == 0 ) printf( "0" );
 699                else if ( strcmp( cond->str, "y" ) == 0 ) printf( "1" );
 700                else if ( strcmp( cond->str, "m" ) == 0 ) printf( "2" );
 701                else if ( strcmp( cond->str, "" ) == 0 )  printf( "4" );
 702                else
 703                    printf( "\"%s\"", cond->str );
 704                break;
 705            }
 706        }
 707        printf( "} then {" );
 708    }
 709
 710    /*
 711     * Generate a procedure call to write the value.
 712     * This code depends on the write_* procedures in header.tk.
 713     */
 714    switch ( cfg->token )
 715    {
 716    default:
 717        if ( cfg->cond != NULL )
 718            printf( " }" );
 719        printf( "\n" );
 720        break;
 721
 722    case token_bool:
 723    case token_tristate:
 724        printf( "write_tristate $cfg $autocfg %s $%s [list $notmod] 2", 
 725            vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
 726        if ( cfg->cond != NULL )
 727            printf( " }" );
 728        printf( "\n" );
 729        break;
 730
 731    case token_choice_header:
 732        /*
 733         * This is funky code -- it fails if there were any conditionals.
 734         * Fortunately all the conditionals got stripped off somewhere
 735         * else.
 736         */
 737        {
 738            struct kconfig * cfg1;
 739            for ( cfg1  = cfg->next;
 740                  cfg1 != NULL && cfg1->token == token_choice_item;
 741                  cfg1  = cfg1->next )
 742            {
 743                printf("\n\tif { $tmpvar_%d == \"%s\" } then { write_tristate $cfg $autocfg %s 1 [list $notmod] 2 } else { write_tristate $cfg $autocfg %s 0 [list $notmod] 2 }",
 744                    -(cfg->nameindex), cfg1->label,
 745                    vartable[cfg1->nameindex].name,
 746                    vartable[cfg1->nameindex].name );
 747            }
 748        }
 749        if ( cfg->cond != NULL )
 750            printf( "}" );
 751        printf( "\n" );
 752        break;
 753
 754    case token_choice_item:
 755        fprintf( stderr, "Internal error on token_choice_item\n" );
 756        exit( 1 );
 757
 758    case token_comment:
 759        printf( "write_comment $cfg $autocfg \"%s\"",
 760            cfg->label );
 761        if ( cfg->cond != NULL )
 762            printf( "}" );
 763        printf( "\n" );
 764        break;
 765
 766    case token_define_bool:
 767    case token_define_tristate:
 768        if ( cfg->cond == NULL )
 769        {
 770            printf( "write_tristate $cfg $autocfg %s $%s [list $notmod] 2\n",
 771                vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
 772        }
 773        else
 774        {
 775            printf( "write_tristate $cfg $autocfg %s $%s [list $notmod] 2 }\n",
 776                vartable[cfg->nameindex].name, cfg->value );
 777        }
 778        break;
 779
 780    case token_dep_mbool:
 781        depmod = 1;
 782    case token_dep_bool:
 783    case token_dep_tristate:
 784        printf( "write_tristate $cfg $autocfg %s $%s [list",
 785            vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
 786        for ( tmp = cfg->depend; tmp; tmp = tmp->next )
 787            printf( " $%s", tmp->name );
 788        printf( "] %d", depmod );
 789        if ( cfg->cond != NULL )
 790            printf( " }" );
 791        printf( "\n" );
 792        break;
 793
 794    case token_define_hex:
 795        printf( "write_hex $cfg $autocfg %s %s $notmod",
 796            vartable[cfg->nameindex].name, cfg->value );
 797        if ( cfg->cond != NULL )
 798            printf( " }" );
 799        printf( "\n" );
 800        break;
 801
 802    case token_define_int:
 803        printf( "write_int $cfg $autocfg %s %s $notmod",
 804            vartable[cfg->nameindex].name, cfg->value );
 805        if ( cfg->cond != NULL )
 806            printf( " }" );
 807        printf( "\n" );
 808        break;
 809
 810    case token_define_string:
 811        printf( "write_string $cfg $autocfg %s \"%s\" $notmod",
 812            vartable[cfg->nameindex].name, cfg->value );
 813        if ( cfg->cond != NULL )
 814            printf( " }" );
 815        printf( "\n" );
 816        break;
 817
 818    case token_hex:
 819        printf( "write_hex $cfg $autocfg %s $%s $notmod",
 820            vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
 821        if ( cfg->cond != NULL )
 822            printf( " }" );
 823        printf( "\n" );
 824        break;
 825
 826    case token_int:
 827        printf( "write_int $cfg $autocfg %s $%s $notmod",
 828            vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
 829        if ( cfg->cond != NULL )
 830            printf( " }" );
 831        printf( "\n" );
 832        break;
 833
 834    case token_string:
 835        printf( "write_string $cfg $autocfg %s \"$%s\" $notmod",
 836            vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
 837        if ( cfg->cond != NULL )
 838            printf( " }" );
 839        printf( "\n" );
 840        break;
 841    }
 842}
 843
 844static void generate_update_var( struct kconfig * scfg, int menu_num )
 845{
 846    struct kconfig * cfg;
 847
 848    if ( menu_num>0 )
 849    {
 850        printf( "proc update_define_menu%d {} {\n", menu_num );
 851        printf( "\tupdate_define_mainmenu\n" );
 852    }
 853    else
 854        printf( "proc update_define_mainmenu {} {\n" );
 855    clear_globalflags();
 856    global( "CONFIG_MODULES" );
 857    vartable[ get_varnum( "CONFIG_MODULES" ) ].global_written = 1;
 858    for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
 859    {
 860        if ( cfg->menu_number == menu_num && (cfg->token == token_define_bool || cfg->token == token_define_tristate
 861        ||   cfg->token == token_define_hex || cfg->token == token_define_int
 862        ||   cfg->token == token_define_string || cfg->token == token_unset 
 863        ||   cfg->token == token_tristate) )
 864        {
 865            if ( ! vartable[cfg->nameindex].global_written )
 866            {
 867                vartable[cfg->nameindex].global_written = 1;
 868                global( vartable[cfg->nameindex].name );
 869            }
 870        }
 871    }
 872
 873    for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
 874    {
 875        char tmp[20];
 876        struct kconfig * cfg1;
 877
 878        if ( cfg->menu_number == menu_num )
 879        {
 880            switch ( cfg->token )
 881            {
 882            default:
 883            case token_choice_item:
 884                break;
 885            case token_choice_header:
 886                sprintf( tmp, "tmpvar_%d", -(cfg->nameindex) );
 887                global( tmp );
 888                for ( cfg1  = cfg->next;
 889                      cfg1 != NULL && cfg1->token == token_choice_item;
 890                      cfg1  = cfg1->next )
 891                {
 892                    vartable[cfg1->nameindex].global_written = 1;
 893                    global( vartable[cfg1->nameindex].name );
 894                    printf( "\tif {$tmpvar_%d == \"%s\"} then {set %s 1} else {set %s 0}\n",
 895                        -(cfg->nameindex), cfg1->label,
 896                        vartable[cfg1->nameindex].name,
 897                        vartable[cfg1->nameindex].name );
 898                }
 899                break;
 900            case token_bool:
 901            case token_define_bool:
 902            case token_define_tristate:
 903            case token_define_hex:
 904            case token_define_int:
 905            case token_define_string:
 906            case token_dep_bool:
 907            case token_dep_tristate:
 908            case token_dep_mbool:
 909            case token_int:
 910            case token_hex:
 911            case token_mainmenu_option:
 912            case token_tristate:
 913            case token_unset:
 914                if ( cfg->cond != NULL )
 915                    generate_if( cfg, cfg->cond, menu_num, -2 );
 916                else switch ( cfg->token )
 917                {
 918                case token_tristate:
 919                    printf( "\n\tif {($CONFIG_MODULES == 0)} then {if {($%s == 2)} then {set %s 1}}\n",
 920                        vartable[cfg->nameindex].name, vartable[cfg->nameindex].name );
 921                    break;
 922                case token_define_bool:
 923                case token_define_tristate:
 924                    if ( ! vartable[get_varnum( cfg->value )].global_written )
 925                    {
 926                        vartable[get_varnum( cfg->value )].global_written = 1;
 927                        global( cfg->value );
 928                    }
 929                    printf( "\tset %s $%s\n", vartable[cfg->nameindex].name,
 930                        cfg->value );
 931                    break;
 932                case token_define_hex:
 933                case token_define_int:
 934                    printf( "\tset %s %s\n", vartable[cfg->nameindex].name,
 935                        cfg->value );
 936                    break;
 937                case token_define_string:
 938                    printf( "\tset %s \"%s\"\n", vartable[cfg->nameindex].name,
 939                        cfg->value );
 940                    break;
 941                case token_unset:
 942                    printf( "\tset %s 4\n", vartable[cfg->nameindex].name );
 943                default:
 944                    break;
 945                }
 946            }
 947        }
 948    }
 949    printf( "}\n\n\n" );
 950}
 951
 952
 953/*
 954 * Generates the end of a menu procedure.
 955 */
 956static void end_proc( struct kconfig * scfg, int menu_num )
 957{
 958    struct kconfig * cfg;
 959
 960    printf( "\n\n\n" );
 961    printf( "\tfocus $w\n" );
 962    printf( "\tupdate_active\n" );
 963    printf( "\tglobal winx; global winy\n" );
 964    if ( menu_first[menu_num]->menu_number != 0 )
 965    {
 966        printf( "\tif {[winfo exists .menu%d] == 0} then ",
 967                menu_first[menu_num]->menu_number );
 968        printf( "{menu%d .menu%d \"%s\"}\n",
 969                menu_first[menu_num]->menu_number, menu_first[menu_num]->menu_number,
 970                menu_first[menu_first[menu_num]->menu_number]->label );
 971        printf( "\tset winx [expr [winfo x .menu%d]+30]; set winy [expr [winfo y .menu%d]+30]\n",
 972                menu_first[menu_num]->menu_number, menu_first[menu_num]->menu_number );
 973    }
 974    else
 975        printf( "\tset winx [expr [winfo x .]+30]; set winy [expr [winfo y .]+30]\n" );
 976    printf( "\twm geometry $w +$winx+$winy\n" );
 977
 978    /*
 979     * Now that the whole window is in place, we need to wait for an "update"
 980     * so we can tell the canvas what its virtual size should be.
 981     *
 982     * Unfortunately, this causes some ugly screen-flashing because the whole
 983     * window is drawn, and then it is immediately resized.  It seems
 984     * unavoidable, though, since "frame" objects won't tell us their size
 985     * until after an update, and "canvas" objects can't automatically pack
 986     * around frames.  Sigh.
 987     */
 988    printf( "\tupdate idletasks\n" );
 989    printf( "\t$w.config.canvas create window 0 0 -anchor nw -window $w.config.f\n\n" );
 990    printf( "\t$w.config.canvas configure \\\n" );
 991    printf( "\t\t-width [expr [winfo reqwidth $w.config.f] + 1]\\\n" );
 992    printf( "\t\t-scrollregion \"-1 -1 [expr [winfo reqwidth $w.config.f] + 1] \\\n" );
 993    printf( "\t\t\t [expr [winfo reqheight $w.config.f] + 1]\"\n\n" );
 994         
 995    /*
 996     * If the whole canvas will fit in 3/4 of the screen height, do it;
 997     * otherwise, resize to around 1/2 the screen and let us scroll.
 998     */
 999    printf( "\tset winy [expr [winfo reqh $w] - [winfo reqh $w.config.canvas]]\n" );
1000    printf( "\tset scry [expr [winfo screenh $w] / 2]\n" );
1001    printf( "\tset maxy [expr [winfo screenh $w] * 3 / 4]\n" );
1002    printf( "\tset canvtotal [expr [winfo reqh $w.config.f] + 2]\n" );
1003    printf( "\tif [expr $winy + $canvtotal < $maxy] {\n" );
1004    printf( "\t\t$w.config.canvas configure -height $canvtotal\n" );
1005    printf( "\t} else {\n" );
1006    printf( "\t\t$w.config.canvas configure -height [expr $scry - $winy]\n" );
1007    printf( "\t}\n" );
1008
1009    /*
1010     * Limit the min/max window size.  Height can vary, but not width,
1011     * because of the limitations of canvas and our laziness.
1012     */
1013    printf( "\tupdate idletasks\n" );
1014    printf( "\twm maxsize $w [winfo width $w] [winfo screenheight $w]\n" );
1015    printf( "\twm minsize $w [winfo width $w] 100\n\n" );
1016    printf( "\twm deiconify $w\n" );
1017    printf( "}\n\n\n" );
1018
1019    /*
1020     * Now we generate the companion procedure for the menu we just
1021     * generated.  This procedure contains all of the code to
1022     * disable/enable widgets based upon the settings of the other
1023     * widgets, and will be called first when the window is mapped,
1024     * and each time one of the buttons in the window are clicked.
1025     */
1026    printf( "proc update_menu%d {} {\n", menu_num );
1027
1028    /*
1029     * Clear all of the booleans that are defined in this menu.
1030     */
1031    clear_globalflags();
1032    for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
1033    {
1034        if ( cfg->menu_number == menu_num
1035        &&   cfg->token != token_mainmenu_option
1036        &&   cfg->token != token_choice_item )
1037        {
1038            if ( cfg->cond != NULL )
1039            {
1040                int i;
1041                if ( (cfg->token == token_tristate || cfg->token == token_dep_tristate)
1042                && ! vartable[i = get_varnum( "CONFIG_MODULES" )].global_written )
1043                {
1044                    global( "CONFIG_MODULES" );
1045                    vartable[i].global_written = 1;
1046                }
1047                generate_if( cfg, cfg->cond, cfg->menu_number, cfg->menu_line );
1048            }
1049            else
1050            {
1051                if ( cfg->token == token_tristate )
1052                {
1053                    int i;
1054                    if ( ! vartable[cfg->nameindex].global_written )
1055                    {
1056                        vartable[cfg->nameindex].global_written = 1;
1057                        printf( "\tglobal %s\n", vartable[cfg->nameindex].name );
1058                    }
1059                    if ( ! vartable[i = get_varnum( "CONFIG_MODULES" )].global_written )
1060                    {
1061                        global( "CONFIG_MODULES" );
1062                        vartable[i].global_written = 1;
1063                    }
1064                    printf( "\n\tif {($CONFIG_MODULES == 1)} then {configure_entry .menu%d.config.f.x%d normal {m}} else {configure_entry .menu%d.config.f.x%d disabled {m}}\n",
1065                        menu_num, cfg->menu_line,
1066                        menu_num, cfg->menu_line );
1067                }
1068            }
1069        }
1070        else if ( cfg->token == token_mainmenu_option
1071             &&   cfg->menu_number == menu_num
1072             &&   cfg->cond != NULL )
1073        {
1074            generate_if( cfg, cfg->cond, menu_num, cfg->menu_line );
1075        }
1076    }
1077    printf("}\n\n\n");
1078
1079    generate_update_var( scfg, menu_num );
1080}
1081
1082/*
1083 * This is the top level function for generating the tk script.
1084 */
1085void dump_tk_script( struct kconfig * scfg )
1086{
1087    int menu_depth;
1088    int menu_num [64];
1089    int imenu, i;
1090    int top_level_num = 0;
1091    struct kconfig * cfg;
1092    struct kconfig * cfg1 = NULL;
1093    const char * name = "No Name";
1094
1095    /*
1096     * Mark begin and end of each menu so I can omit submenus when walking
1097     * over a parent menu.
1098     */
1099    tot_menu_num = 0;
1100    menu_depth   = 0;
1101    menu_num [0] = 0;
1102
1103    for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
1104    {
1105        switch ( cfg->token )
1106        {
1107        default:
1108            break;
1109
1110        case token_mainmenu_name:
1111            name = cfg->label;
1112            break;
1113
1114        case token_mainmenu_option:
1115            if ( ++menu_depth >= 64 )
1116                { fprintf( stderr, "menus too deep\n" ); exit( 1 ); }
1117            if ( ++tot_menu_num >= 100 )
1118                { fprintf( stderr, "too many menus\n" ); exit( 1 ); }
1119            menu_num   [menu_depth]   = tot_menu_num;
1120            menu_first [tot_menu_num] = cfg;
1121            menu_last  [tot_menu_num] = cfg;
1122            /*
1123             * Note, that menu_number is set to the number of parent 
1124             * (upper level) menu.
1125             */
1126            cfg->menu_number = menu_num[menu_depth - 1];
1127            if ( menu_depth == 1 )
1128                ++top_level_num;
1129            break;
1130
1131        case token_endmenu:
1132            menu_last [menu_num [menu_depth]] = cfg;
1133            /* flatten menus with proper scoping */
1134            if ( --menu_depth < 0 )
1135                { fprintf( stderr, "unmatched endmenu\n" ); exit( 1 ); }
1136            break;
1137
1138        case token_bool:
1139        case token_choice_header:
1140        case token_choice_item:
1141        case token_comment:
1142        case token_dep_bool:
1143        case token_dep_tristate:
1144        case token_dep_mbool:
1145        case token_hex:
1146        case token_int:
1147        case token_string:
1148        case token_tristate:
1149            cfg->menu_number = menu_num[menu_depth];
1150            if ( menu_depth == 0 )
1151                { fprintf( stderr, "statement not in menu\n" ); exit( 1 ); }
1152            break;
1153
1154        case token_define_bool:
1155        case token_define_hex:
1156        case token_define_int:
1157        case token_define_string:
1158        case token_define_tristate:
1159        case token_unset:
1160            cfg->menu_number = menu_num[menu_depth];
1161            break;
1162        }
1163    }
1164
1165    /*
1166     * Generate menus per column setting.
1167     * There are:
1168     *   four extra buttons for save/quit/load/store;
1169     *   one blank button
1170     *   add two to round up for division
1171     */
1172    printf( "set menus_per_column %d\n", (top_level_num + 4 + 1 + 2) / 3 );
1173    printf( "set total_menus %d\n\n", tot_menu_num );
1174
1175    printf( "proc toplevel_menu {num} {\n" );
1176    for ( imenu = 1; imenu <= tot_menu_num; ++imenu )
1177    {
1178        int parent = 1;
1179
1180        if ( menu_first[imenu]->menu_number == 0 )
1181            parent = menu_first[imenu]->menu_number;
1182        else
1183            printf( "\tif {$num == %d} then {return %d}\n",
1184                imenu, menu_first[imenu]->menu_number );
1185    }
1186    printf( "\treturn $num\n}\n\n" );
1187
1188    /*
1189     * Generate the menus.
1190     */
1191    printf( "mainmenu_name \"%s\"\n", name );
1192    for ( imenu = 1; imenu <= tot_menu_num; ++imenu )
1193    {
1194        int menu_line = 0;
1195        int nr_submenu = imenu;
1196        int menu_name_omitted = 0;
1197        int opt_count = 0;
1198
1199        clear_globalflags();
1200        start_proc( menu_first[imenu]->label, imenu, 
1201                !menu_first[imenu]->menu_number );
1202
1203        for ( cfg = menu_first[imenu]->next; cfg != NULL && cfg != menu_last[imenu]; cfg = cfg->next )
1204        {
1205            switch ( cfg->token )
1206            {
1207            default:
1208                break;
1209
1210            case token_mainmenu_option:
1211                while ( menu_first[++nr_submenu]->menu_number > imenu )
1212                    ;
1213                cfg->menu_line = menu_line++;
1214                printf( "\tsubmenu $w.config.f %d %d \"%s\" %d\n",
1215                    cfg->menu_number, cfg->menu_line, cfg->label, nr_submenu );
1216                cfg = menu_last[nr_submenu];
1217                break;
1218
1219            case token_comment:
1220                if ( !cfg->menu_line && !menu_name_omitted )
1221                {
1222                    cfg->menu_line = -1;
1223                    menu_name_omitted = 1;
1224                }
1225                else
1226                {
1227                    menu_name_omitted = 1;
1228                    cfg->menu_line = menu_line++;
1229                    printf( "\tcomment $w.config.f %d %d \"%s\"\n",
1230                        cfg->menu_number, cfg->menu_line, cfg->label );
1231                }
1232                break;
1233
1234            case token_bool:
1235                cfg->menu_line = menu_line++;
1236                printf( "\tbool $w.config.f %d %d \"%s\" %s\n",
1237                    cfg->menu_number, cfg->menu_line, cfg->label,
1238                    vartable[cfg->nameindex].name );
1239                break;
1240
1241            case token_choice_header:
1242                /*
1243                 * I need the first token_choice_item to pick out the right
1244                 * help text from Documentation/Configure.help.
1245                 */
1246                cfg->menu_line = menu_line++;
1247                printf( "\tglobal tmpvar_%d\n", -(cfg->nameindex) );
1248                printf( "\tminimenu $w.config.f %d %d \"%s\" tmpvar_%d %s\n",
1249                    cfg->menu_number, cfg->menu_line, cfg->label,
1250                    -(cfg->nameindex), vartable[cfg->next->nameindex].name );
1251                printf( "\tmenu $w.config.f.x%d.x.menu -tearoffcommand \"menutitle \\\"%s\\\"\"\n",
1252                    cfg->menu_line, cfg->label );
1253                cfg1 = cfg;
1254                opt_count = 0;
1255                break;
1256
1257            case token_choice_item:
1258                /* note: no menu line; uses choice header menu line */
1259                printf( "\t$w.config.f.x%d.x.menu add radiobutton -label \"%s\" -variable tmpvar_%d -value \"%s\" -command \"update_active\"\n",
1260                    cfg1->menu_line, cfg->label, -(cfg1->nameindex),
1261                    cfg->label );
1262                opt_count++;
1263                if ( cfg->next && cfg->next->token != token_choice_item ) {
1264                    /* last option in the menu */
1265                    printf( "\tmenusplit $w $w.config.f.x%d.x.menu %d\n",
1266                        cfg1->menu_line, opt_count );
1267                }
1268                break;
1269
1270            case token_dep_bool:
1271            case token_dep_mbool:
1272                cfg->menu_line = menu_line++;
1273                printf( "\tdep_bool $w.config.f %d %d \"%s\" %s\n",
1274                    cfg->menu_number, cfg->menu_line, cfg->label,
1275                    vartable[cfg->nameindex].name );
1276                break;
1277
1278            case token_dep_tristate:
1279                cfg->menu_line = menu_line++;
1280                printf( "\tdep_tristate $w.config.f %d %d \"%s\" %s\n",
1281                    cfg->menu_number, cfg->menu_line, cfg->label,
1282                    vartable[cfg->nameindex].name );
1283                break;
1284
1285            case token_hex:
1286                cfg->menu_line = menu_line++;
1287                printf( "\thex $w.config.f %d %d \"%s\" %s\n",
1288                    cfg->menu_number, cfg->menu_line, cfg->label,
1289                    vartable[cfg->nameindex].name );
1290                break;
1291
1292            case token_int:
1293                cfg->menu_line = menu_line++;
1294                printf( "\tint $w.config.f %d %d \"%s\" %s\n",
1295                    cfg->menu_number, cfg->menu_line, cfg->label,
1296                    vartable[cfg->nameindex].name );
1297                break;
1298
1299            case token_string:
1300                cfg->menu_line = menu_line++;
1301                printf( "\tistring $w.config.f %d %d \"%s\" %s\n",
1302                    cfg->menu_number, cfg->menu_line, cfg->label,
1303                    vartable[cfg->nameindex].name );
1304                break;
1305
1306            case token_tristate:
1307                cfg->menu_line = menu_line++;
1308                printf( "\ttristate $w.config.f %d %d \"%s\" %s\n",
1309                    cfg->menu_number, cfg->menu_line, cfg->label,
1310                    vartable[cfg->nameindex].name );
1311                break;
1312            }
1313        }
1314
1315        end_proc( scfg, imenu );
1316    }
1317
1318    /*
1319     * The top level menu also needs an update function.  When we update a
1320     * submenu, we may need to disable one or more of the submenus on
1321     * the top level menu, and this procedure will ensure that things are
1322     * correct.
1323     */
1324    clear_globalflags();
1325    printf( "proc update_mainmenu {}  {\n" );
1326    for ( imenu = 1; imenu <= tot_menu_num; imenu++ )
1327    {
1328        if ( menu_first[imenu]->cond != NULL && menu_first[imenu]->menu_number == 0 )
1329            generate_if( menu_first[imenu], menu_first[imenu]->cond, imenu, -1 );
1330    }
1331    printf( "}\n\n\n" );
1332
1333    clear_globalflags();
1334    /*
1335     * Generate code to load the default settings into the variables.
1336     * The script in tail.tk will attempt to load .config,
1337     * which may override these settings, but that's OK.
1338     */
1339    for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
1340    {
1341        switch ( cfg->token )
1342        {
1343        default:
1344            break;
1345
1346        case token_bool:
1347        case token_choice_item:
1348        case token_dep_bool:
1349        case token_dep_tristate:
1350        case token_dep_mbool:
1351        case token_tristate:
1352            if ( ! vartable[cfg->nameindex].global_written )
1353            {
1354                printf( "set %s 0\n", vartable[cfg->nameindex].name );
1355                vartable[cfg->nameindex].global_written = 1;
1356            }
1357            break;
1358
1359        case token_choice_header:
1360            printf( "set tmpvar_%d \"(not set)\"\n", -(cfg->nameindex) );
1361            break;
1362
1363        case token_hex:
1364        case token_int:
1365            if ( ! vartable[cfg->nameindex].global_written )
1366            {
1367                printf( "set %s %s\n", vartable[cfg->nameindex].name, cfg->value ? cfg->value : "0" );
1368                vartable[cfg->nameindex].global_written = 1;
1369            }
1370            break;
1371
1372        case token_string:
1373            if ( ! vartable[cfg->nameindex].global_written )
1374            {
1375                printf( "set %s \"%s\"\n", vartable[cfg->nameindex].name, cfg->value );
1376                vartable[cfg->nameindex].global_written = 1;
1377            }
1378            break;
1379        }
1380    }
1381
1382    /*
1383     * Define to an empty value all other variables (which are never defined)
1384     */
1385    for ( i = 1; i <= max_varnum; i++ )
1386    {
1387        if ( ! vartable[i].global_written
1388        &&   strncmp( vartable[i].name, "CONSTANT_", 9 ) )
1389            printf( "set %s 4\n", vartable[i].name );
1390    }
1391
1392    /*
1393     * Generate a function to write all of the variables to a file.
1394     */
1395    printf( "proc writeconfig {file1 file2} {\n" );
1396    printf( "\tset cfg [open $file1 w]\n" );
1397    printf( "\tset autocfg [open $file2 w]\n" );
1398    printf( "\tset notmod 1\n" );
1399    printf( "\tset notset 0\n" );
1400    printf( "\tputs $cfg \"#\"\n");
1401    printf( "\tputs $cfg \"# Automatically generated make config: don't edit\"\n");
1402    printf( "\tputs $cfg \"#\"\n" );
1403
1404    printf( "\tputs $autocfg \"/*\"\n" );
1405    printf( "\tputs $autocfg \" * Automatically generated C config: don't edit\"\n" );
1406    printf( "\tputs $autocfg \" */\"\n" );
1407    printf( "\tputs $autocfg \"#define AUTOCONF_INCLUDED\"\n" );
1408
1409    clear_globalflags();
1410    for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
1411    {
1412        switch ( cfg->token )
1413        {
1414        default:
1415            break;
1416
1417        case token_bool:
1418        case token_choice_header:
1419        case token_comment:
1420        case token_define_bool:
1421        case token_define_hex:
1422        case token_define_int:
1423        case token_define_string:
1424        case token_define_tristate:
1425        case token_dep_bool:
1426        case token_dep_tristate:
1427        case token_dep_mbool:
1428        case token_hex:
1429        case token_int:
1430        case token_string:
1431        case token_tristate:
1432            generate_writeconfig( cfg );
1433            break;
1434        }
1435    }
1436    printf( "\tclose $cfg\n" );
1437    printf( "\tclose $autocfg\n" );
1438    printf( "}\n\n\n" );
1439
1440    /*
1441     * Generate a simple function that updates the master choice
1442     * variable depending upon what values were loaded from a .config
1443     * file.  
1444     */
1445    printf( "proc clear_choices { } {\n" );
1446    for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
1447    {
1448        if ( cfg->token == token_choice_header )
1449        {
1450            for ( cfg1  = cfg->next; 
1451                  cfg1 != NULL && cfg1->token == token_choice_item;
1452                  cfg1  = cfg1->next )
1453            {
1454                printf( "\tglobal %s; set %s 0\n",
1455                    vartable[cfg1->nameindex].name,
1456                    vartable[cfg1->nameindex].name );
1457            }
1458        }
1459    }
1460    printf( "}\n\n\n" );
1461
1462    printf( "proc update_choices { } {\n" );
1463    for ( cfg = scfg; cfg != NULL; cfg = cfg->next )
1464    {
1465        if ( cfg->token == token_choice_header )
1466        {
1467            printf( "\tglobal tmpvar_%d\n", -(cfg->nameindex) );
1468            printf("\tset tmpvar_%d \"%s\"\n", -(cfg->nameindex), cfg->value);
1469            for ( cfg1  = cfg->next; 
1470                  cfg1 != NULL && cfg1->token == token_choice_item;
1471                  cfg1  = cfg1->next )
1472            {
1473                printf( "\tglobal %s\n", vartable[cfg1->nameindex].name );
1474                printf( "\tif { $%s == 1 } then { set tmpvar_%d \"%s\" }\n",
1475                    vartable[cfg1->nameindex].name,
1476                    -(cfg->nameindex), cfg1->label );
1477            }
1478        }
1479    }
1480    printf( "}\n\n\n" );
1481
1482    generate_update_var( scfg, 0 );
1483
1484    /*
1485     * That's it.  We are done.  The output of this file will have header.tk
1486     * prepended and tail.tk appended to create an executable wish script.
1487     */
1488}
1489
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.