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 printf( "\tbind $w <Escape> \"catch {focus $oldFocus}; destroy $w; unregister_active %d; break\"\n", menu_num); 153 154 printf("\tset nextscript "); 155 printf("\"catch {focus $oldFocus}; " ); 156 /* 157 * We are checking which windows should be destroyed and which are 158 * common parents with the next one. Remember that menu_num field 159 * in mainmenu_option record reports number of its *parent* menu. 160 */ 161 if ( menu_num < tot_menu_num 162 && menu_first[menu_num + 1]->menu_number != menu_num ) 163 { 164 int to_destr; 165 166 printf( "destroy $w; unregister_active %d; ", menu_num ); 167 to_destr = menu_first[menu_num]->menu_number; 168 while ( to_destr > 0 && menu_first[menu_num + 1]->menu_number != to_destr ) 169 { 170 printf( "catch {destroy .menu%d}; unregister_active %d; ", 171 to_destr, to_destr ); 172 to_destr = menu_first[to_destr]->menu_number; 173 } 174 } 175 printf( "menu%d .menu%d \\\"$title\\\"\"\n", 176 menu_num+1, menu_num+1 ); 177 178 /* 179 * Attach the "Prev", "Next" and "OK" buttons at the end of the window. 180 */ 181 printf( "\tframe $w.f\n" ); 182 if ( toplevel ) 183 printf( "\tbutton $w.f.back -text \"Main Menu\" \\\n" ); 184 else 185 printf( "\tbutton $w.f.back -text \"OK\" \\\n" ); 186 printf( "\t\t-width 15 -command \"catch {focus $oldFocus}; destroy $w; unregister_active %d\"\n", 187 menu_num ); 188 printf( "\tbutton $w.f.next -text \"Next\" -underline 0\\\n" ); 189 printf( "\t\t-width 15 -command $nextscript\n"); 190 191 if ( menu_num == tot_menu_num ) { 192 printf( "\t$w.f.next configure -state disabled\n" ); 193 /* 194 * this is a bit hackish but Alt-n must be rebound 195 * otherwise if the user press Alt-n on the last menu 196 * it will give him/her the next menu of one of the 197 * previous options 198 */ 199 printf( "\tbind all <Alt-n> \"puts \\\"no more menus\\\" \"\n"); 200 } 201 else 202 { 203 /* 204 * I should be binding to $w not all - but if I do nehat I get the error "unknown path" 205 */ 206 printf( "\tbind all <Alt-n> $nextscript\n"); 207 } 208 printf( "\tbutton $w.f.prev -text \"Prev\" -underline 0\\\n" ); 209 printf( "\t\t-width 15 -command \"catch {focus $oldFocus}; destroy $w; unregister_active %d; menu%d .menu%d \\\"$title\\\"\"\n", 210 menu_num, menu_num-1, menu_num-1 ); 211 if ( menu_num == 1 ) { 212 printf( "\t$w.f.prev configure -state disabled\n" ); 213 } 214 else 215 { 216 printf( "\tbind $w <Alt-p> \"catch {focus $oldFocus}; destroy $w; unregister_active %d; menu%d .menu%d \\\"$title\\\";break\"\n", 217 menu_num, menu_num-1, menu_num-1 ); 218 } 219 printf( "\tpack $w.f.back $w.f.next $w.f.prev -side left -expand on\n" ); 220 printf( "\tpack $w.f -pady 10 -side bottom -anchor w -fill x\n" ); 221 222 /* 223 * Lines between canvas and other areas of the window. 224 */ 225 printf( "\tframe $w.topline -relief ridge -borderwidth 2 -height 2\n" ); 226 printf( "\tpack $w.topline -side top -fill x\n\n" ); 227 printf( "\tframe $w.botline -relief ridge -borderwidth 2 -height 2\n" ); 228 printf( "\tpack $w.botline -side bottom -fill x\n\n" ); 229 230 /* 231 * The "config" frame contains the canvas and a scrollbar. 232 */ 233 printf( "\tframe $w.config\n" ); 234 printf( "\tpack $w.config -fill y -expand on\n\n" ); 235 printf( "\tscrollbar $w.config.vscroll -command \"$w.config.canvas yview\"\n" ); 236 printf( "\tpack $w.config.vscroll -side right -fill y\n\n" ); 237 238 /* 239 * The scrollable canvas itself, where the real work (and mess) gets done. 240 */ 241 printf( "\tcanvas $w.config.canvas -height 1\\\n" ); 242 printf( "\t\t-relief flat -borderwidth 0 -yscrollcommand \"$w.config.vscroll set\" \\\n" ); 243 printf( "\t\t-width [expr [winfo screenwidth .] * 1 / 2] \n" ); 244 printf( "\tframe $w.config.f\n" ); 245 printf( "\tbind $w <Key-Down> \"$w.config.canvas yview scroll 1 unit;break;\"\n"); 246 printf( "\tbind $w <Key-Up> \"$w.config.canvas yview scroll -1 unit;break;\"\n"); 247 printf( "\tbind $w <Key-Next> \"$w.config.canvas yview scroll 1 page;break;\"\n"); 248 printf( "\tbind $w <Key-Prior> \"$w.config.canvas yview scroll -1 page;break;\"\n"); 249 printf( "\tbind $w <Key-Home> \"$w.config.canvas yview moveto 0;break;\"\n"); 250 printf( "\tbind $w <Key-End> \"$w.config.canvas yview moveto 1 ;break;\"\n"); 251 printf( "\tpack $w.config.canvas -side right -fill y\n" ); 252 printf("\n\n"); 253} 254 255 256 257/* 258 * Each proc we create needs a global declaration for any global variables we 259 * use. To minimize the size of the file, we set a flag each time we output 260 * a global declaration so we know whether we need to insert one for a 261 * given function or not. 262 */ 263static void clear_globalflags(void) 264{ 265 int i; 266 for ( i = 1; i <= max_varnum; i++ ) 267 vartable[i].global_written = 0; 268} 269 270 271 272/* 273 * Output a "global" line for a given variable. Also include the 274 * call to "vfix". (If vfix is not needed, then it's fine to just printf 275 * a "global" line). 276 */ 277void global( const char *var ) 278{ 279 printf( "\tglobal %s\n", var ); 280} 281 282 283 284/* 285 * This function walks the chain of conditions that we got from cond.c 286 * and creates a TCL conditional to enable/disable a given widget. 287 */ 288void generate_if( struct kconfig * cfg, struct condition * ocond, 289 int menu_num, int line_num ) 290{ 291 struct condition * cond; 292 struct dependency * tmp; 293 struct kconfig * cfg1; 294 295 if ( line_num >= -1 ) 296 { 297 if ( cfg->token == token_define_bool || cfg->token == token_define_hex 298 || cfg->token == token_define_int || cfg->token == token_define_string 299 || cfg->token == token_define_tristate || cfg->token == token_unset ) 300 return; 301 if ( cfg->token == token_comment && line_num == -1 ) 302 return; 303 } 304 else 305 { 306 if ( cfg->token == token_string || cfg->token == token_mainmenu_option ) 307 return; 308 } 309 310 /* 311 * First write any global declarations we need for this conditional. 312 */ 313 for ( cond = ocond; cond != NULL; cond = cond->next ) 314 { 315 switch ( cond->op ) 316 { 317 default: 318 break; 319 320 case op_variable: 321 if ( ! vartable[cond->nameindex].global_written ) 322 { 323 vartable[cond->nameindex].global_written = 1; 324 global( vartable[cond->nameindex].name ); 325 } 326 break; 327 } 328 } 329 330 /* 331 * Now write this option. 332 */ 333 if ( cfg->nameindex > 0 && ! vartable[cfg->nameindex].global_written ) 334 { 335 vartable[cfg->nameindex].global_written = 1; 336 global( vartable[cfg->nameindex].name ); 337 } 338 339 /* 340 * Generate the body of the conditional. 341 */ 342 printf( "\tif {" ); 343 for ( cond = ocond; cond != NULL; cond = cond->next ) 344 { 345 switch ( cond->op ) 346 { 347 default: 348 break; 349 350 case op_bang: printf( " ! " ); break; 351 case op_eq: printf( " == " ); break; 352 case op_neq: printf( " != " ); break; 353 case op_and: printf( " && " ); break; 354 case op_and1: printf( " && " ); break; 355 case op_or: printf( " || " ); break; 356 case op_lparen: printf( "(" ); break; 357 case op_rparen: printf( ")" ); break; 358 359 case op_variable: 360 printf( "$%s", vartable[cond->nameindex].name ); 361 break; 362 363 case op_constant: 364 if ( strcmp( cond->str, "y" ) == 0 ) printf( "1" ); 365 else if ( strcmp( cond->str, "n" ) == 0 ) printf( "0" ); 366 else if ( strcmp( cond->str, "m" ) == 0 ) printf( "2" ); 367 else if ( strcmp( cond->str, "" ) == 0 ) printf( "4" ); 368 else 369 printf( "\"%s\"", cond->str ); 370 break; 371 } 372 } 373 printf( "} then {" ); 374 375 /* 376 * Generate a procedure call to write the value. 377 * This code depends on procedures in header.tk. 378 */ 379 if ( line_num >= -1 ) 380 { 381 int modtoyes = 0; 382 383 switch ( cfg->token ) 384 { 385 default: 386 printf( " }\n" ); 387 break; 388 389 case token_dep_mbool: 390 modtoyes = 1; 391 case token_dep_bool: 392 printf( "\n" ); 393 for ( tmp = cfg->depend; tmp; tmp = tmp->next ) 394 if ( ! vartable[get_varnum( tmp->name )].global_written ) 395 { 396 global( tmp->name ); 397 } 398 printf( "\tset tmpvar_dep [effective_dep [list" ); 399 for ( tmp = cfg->depend; tmp; tmp = tmp->next ) 400 printf( " $%s", tmp->name ); 401 printf( "]];set %s [sync_bool $%s $tmpvar_dep %d];", 402 vartable[cfg->nameindex].name, vartable[cfg->nameindex].name, 403 modtoyes ); 404 printf( "if {$tmpvar_dep != 1" ); 405 if (modtoyes) 406 printf( " && $tmpvar_dep != 2" ); 407 printf( "} then {configure_entry .menu%d.config.f.x%d disabled {y};", 408 menu_num, line_num ); 409 printf( "} else {" ); 410 printf( "configure_entry .menu%d.config.f.x%d normal {y};", 411 menu_num, line_num ); 412 printf( "}; " ); 413 case token_bool: 414 if ( cfg->token == token_bool ) 415 printf( "\n\t" ); 416 printf( "configure_entry .menu%d.config.f.x%d normal {n l", 417 menu_num, line_num ); 418 if ( cfg->token == token_bool ) 419 printf( " y" ); 420 printf( "}" ); 421 printf( "} else {"); 422 printf( "configure_entry .menu%d.config.f.x%d disabled {y n l}}\n", 423 menu_num, line_num ); 424 break; 425 426 case token_choice_header: 427 printf( "configure_entry .menu%d.config.f.x%d normal {x l}", 428 menu_num, line_num ); 429 printf( "} else {" ); 430 printf( "configure_entry .menu%d.config.f.x%d disabled {x l}", 431 menu_num, line_num ); 432 printf( "}\n" ); 433 break; 434 435 case token_choice_item: 436 fprintf( stderr, "Internal error on token_choice_item\n" ); 437 exit( 1 ); 438 439 case token_dep_tristate: 440 printf( "\n" ); 441 for ( tmp = cfg->depend; tmp; tmp = tmp->next ) 442 if ( ! vartable[get_varnum( tmp->name )].global_written ) 443 { 444 global( tmp->name ); 445 } 446 printf( "\tset tmpvar_dep [effective_dep [list" ); 447 for ( tmp = cfg->depend; tmp; tmp = tmp->next ) 448 printf( " $%s", tmp->name ); 449 printf( "]];set %s [sync_tristate $%s $tmpvar_dep];", 450 vartable[cfg->nameindex].name, vartable[cfg->nameindex].name ); 451 printf( "\tif {$tmpvar_dep != 1} then {" ); 452 printf( "configure_entry .menu%d.config.f.x%d disabled {y}", 453 menu_num, line_num ); 454 printf( "} else {" ); 455 printf( "configure_entry .menu%d.config.f.x%d normal {y}", 456 menu_num, line_num ); 457 printf( "}; " ); 458 printf( "if {$tmpvar_dep == 0} then {" ); 459 printf( "configure_entry .menu%d.config.f.x%d disabled {m}", 460 menu_num, line_num ); 461 printf( "} else {" ); 462 printf( "configure_entry .menu%d.config.f.x%d normal {m}", 463 menu_num, line_num ); 464 printf( "}; " ); 465 case token_tristate: 466 if ( cfg->token == token_tristate ) 467 { 468 printf( "\n\tconfigure_entry .menu%d.config.f.x%d normal {y}; ", 469 menu_num, line_num ); 470 } 471 printf( "if {($CONFIG_MODULES == 1)} then {" ); 472 printf( "configure_entry .menu%d.config.f.x%d normal {m}} else {", 473 menu_num, line_num ); 474 printf( "configure_entry .menu%d.config.f.x%d disabled {m}}; ", 475 menu_num, line_num ); 476 printf( "configure_entry .menu%d.config.f.x%d normal {n l}", 477 menu_num, line_num ); 478 479 /* 480 * Or in a bit to the variable - this causes all of the radiobuttons 481 * to be deselected (i.e. not be red). 482 */ 483 printf( "} else {" ); 484 printf( "configure_entry .menu%d.config.f.x%d disabled {y n m l}}\n", 485 menu_num, line_num ); 486 break; 487 488 case token_hex: 489 case token_int: 490 case token_string: 491 printf( ".menu%d.config.f.x%d.x configure -state normal -foreground [ cget .ref -foreground ]; ", 492 menu_num, line_num ); 493 printf( ".menu%d.config.f.x%d.l configure -state normal; ", 494 menu_num, line_num ); 495 printf( "} else {" ); 496 printf( ".menu%d.config.f.x%d.x configure -state disabled -foreground [ cget .ref -disabledforeground ]; ", 497 menu_num, line_num ); 498 printf( ".menu%d.config.f.x%d.l configure -state disabled}\n", 499 menu_num, line_num ); 500 break; 501 502 case token_comment: 503 case token_mainmenu_option: 504 if ( line_num >= 0 ) 505 { 506 printf( "configure_entry .menu%d.config.f.x%d normal {m}", 507 menu_num, line_num ); 508 printf( "} else {" ); 509 printf( "configure_entry .menu%d.config.f.x%d disabled {m}}\n", 510 menu_num, line_num ); 511 } 512 else 513 printf( ".f0.x%d configure -state normal } else { .f0.x%d configure -state disabled }\n", 514 menu_num, menu_num ); 515 break; 516 } 517 } 518 else 519 { 520 int modtoyes = 0; 521 522 switch ( cfg->token ) 523 { 524 default: 525 printf( " }\n" ); 526 break; 527 528 case token_dep_mbool: 529 modtoyes = 1; 530 case token_dep_bool: 531 printf( "\n" ); 532 for ( tmp = cfg->depend; tmp; tmp = tmp->next ) 533 if ( ! vartable[get_varnum( tmp->name )].global_written ) 534 { 535 global( tmp->name ); 536 } 537 printf( "\tset tmpvar_dep [effective_dep [list" ); 538 for ( tmp = cfg->depend; tmp; tmp = tmp->next ) 539 printf( " $%s", tmp->name ); 540 printf( "]];set %s [sync_bool $%s $tmpvar_dep %d];", 541 vartable[cfg->nameindex].name, vartable[cfg->nameindex].name, 542 modtoyes ); 543 case token_bool: 544 if ( cfg->token == token_bool ) 545 printf( "\n\t" ); 546 printf( "set %s [expr $%s&15]", 547 vartable[cfg->nameindex].name, vartable[cfg->nameindex].name ); 548 printf( "} else {"); 549 printf( "set %s [expr $%s|16]}\n", 550 vartable[cfg->nameindex].name, vartable[cfg->nameindex].name ); 551 break; 552 553 case token_choice_header: 554 printf( "} else {" ); 555 for ( cfg1 = cfg->next; 556 cfg1 != NULL && cfg1->token == token_choice_item; 557 cfg1 = cfg1->next ) 558 printf( "set %s 4;", vartable[cfg1->nameindex].name ); 559 printf( "}\n" ); 560 break; 561 562 case token_choice_item: 563 fprintf( stderr, "Internal error on token_choice_item\n" ); 564 exit( 1 ); 565 566 case token_define_bool: 567 case token_define_tristate: 568 if ( ! vartable[get_varnum( cfg->value )].global_written ) 569 { 570 global( cfg->value ); 571 } 572 printf( "set %s $%s }\n", 573 vartable[cfg->nameindex].name, cfg->value ); 574 break; 575 576 case token_define_hex: 577 case token_define_int: 578 printf( "set %s %s }\n", 579 vartable[cfg->nameindex].name, cfg->value ); 580 break; 581 582 case token_define_string: 583 printf( "set %s \"%s\" }\n", 584 vartable[cfg->nameindex].name, cfg->value ); 585 break; 586 587 case token_dep_tristate: 588 printf( "\n" ); 589 for ( tmp = cfg->depend; tmp; tmp = tmp->next ) 590 if ( ! vartable[get_varnum( tmp->name )].global_written ) 591 { 592 global( tmp->name ); 593 } 594 printf( "\tset tmpvar_dep [effective_dep [list" ); 595 for ( tmp = cfg->depend; tmp; tmp = tmp->next ) 596 printf( " $%s", tmp->name ); 597 printf( "]]; set %s [sync_tristate $%s $tmpvar_dep]; ", 598 vartable[cfg->nameindex].name, vartable[cfg->nameindex].name ); 599 case token_tristate: 600 if ( cfg->token == token_tristate ) 601 printf( "if {($CONFIG_MODULES == 0) && ($%s == 2)} then {set %s 1}; ", 602 vartable[cfg->nameindex].name, 603 vartable[cfg->nameindex].name ); 604 /* 605 * Or in a bit to the variable - this causes all of the radiobuttons 606 * to be deselected (i.e. not be red). 607 */ 608 printf( "set %s [expr $%s&15]", 609 vartable[cfg->nameindex].name, vartable[cfg->nameindex].name ); 610 printf( "} else {" ); 611 612 /* 613 * Clear the disable bit to enable the correct radiobutton. 614 */ 615 printf( "set %s [expr $%s|16]}\n", 616 vartable[cfg->nameindex].name, vartable[cfg->nameindex].name ); 617 break; 618 619 case token_hex: 620 case token_int: 621 if ( cfg->value && *cfg->value == '$' ) 622 { 623 int i = get_varnum( cfg->value+1 ); 624 printf( "\n" ); 625 if ( ! vartable[i].global_written ) 626 { 627 global( vartable[i].name ); 628 } 629 printf( "\t" ); 630 } 631 if ( cfg->token == token_hex ) 632 printf( "validate_hex " ); 633 else if ( cfg->token == token_int ) 634 printf( "validate_int " ); 635 printf( "%s \"$%s\" %s}\n", 636 vartable[cfg->nameindex].name, vartable[cfg->nameindex].name, 637 cfg->value ); 638 break; 639 640 case token_unset: 641 printf( "set %s 4}\n", vartable[cfg->nameindex].name ); 642 break; 643 } 644 } 645} 646 647 648/* 649 * Generate a line that writes a variable to the output file. 650 */ 651void generate_writeconfig( struct kconfig * cfg ) 652{ 653 struct condition * cond; 654 struct dependency * tmp; 655 int depmod = 2; 656 657 /* 658 * Generate global declaration for this symbol. 659 */ 660 if ( cfg->token != token_comment ) 661 { 662 if ( cfg->nameindex > 0 && ! vartable[cfg->nameindex].global_written ) 663 { 664 vartable[cfg->nameindex].global_written = 1; 665 global( vartable[cfg->nameindex].name ); 666 } 667 if ( cfg->token == token_define_tristate || cfg->token == token_define_bool ) 668 { 669 if ( ! vartable[get_varnum( cfg->value )].global_written ) 670 { 671 vartable[get_varnum( cfg->value )].global_written = 1; 672 global( cfg->value ); 673 } 674 } 675 else if ( cfg->nameindex <= 0 && cfg->token == token_choice_header ) 676 { 677 printf( "\tglobal tmpvar_%d\n", -(cfg->nameindex) ); 678 } 679 } 680 681 /* 682 * Generate global declarations for the condition chain. 683 */ 684 for ( cond = cfg->cond; cond != NULL; cond = cond->next ) 685 { 686 switch( cond->op ) 687 { 688 default: 689 break; 690 691 case op_variable: 692 if ( ! vartable[cond->nameindex].global_written ) 693 { 694 vartable[cond->nameindex].global_written = 1; 695 global( vartable[cond->nameindex].name ); 696 } 697 break; 698 } 699 } 700 701 /* 702 * Generate indentation. 703 */ 704 printf( "\t" ); 705 706 /* 707 * Generate the conditional. 708 */ 709 if ( cfg->cond != NULL ) 710 { 711 printf( "if {" ); 712 for ( cond = cfg->cond; cond != NULL; cond = cond->next ) 713 { 714 switch ( cond->op ) 715 { 716 default: break; 717 case op_bang: printf( " ! " ); break; 718 case op_eq: printf( " == " ); break; 719 case op_neq: printf( " != " ); break; 720 case op_and: printf( " && " ); break; 721 case op_and1: printf( " && " ); break; 722 case op_or: printf( " || " ); break; 723 case op_lparen: printf( "(" ); break; 724 case op_rparen: printf( ")" ); break; 725 726 case op_variable: 727 printf( "$%s", vartable[cond->nameindex].name ); 728 break; 729 730 case op_constant: 731 if ( strcmp( cond->str, "n" ) == 0 ) printf( "0" ); 732 else if ( strcmp( cond->str, "y" ) == 0 ) printf( "1" ); 733 else if ( strcmp( cond->str, "m" ) == 0 ) printf( "2" ); 734 else if ( strcmp( cond->str, "" ) == 0 ) printf( "4" ); 735 else 736 printf( "\"%s\"", cond->str ); 737 break; 738 } 739 } 740 printf( "} then {" ); 741 } 742 743 /* 744 * Generate a procedure call to write the value. 745 * This code depends on the write_* procedures in header.tk. 746 */ 747 switch ( cfg->token ) 748 { 749 default: 750 if ( cfg->cond != NULL ) 751 printf( " }" ); 752 printf( "\n" ); 753 break; 754 755 case token_bool: 756 case token_tristate: 757 printf( "write_tristate $cfg $autocfg %s $%s [list $notmod] 2", 758 vartable[cfg->nameindex].name, vartable[cfg->nameindex].name ); 759 if ( cfg->cond != NULL ) 760 printf( " }" ); 761 printf( "\n" ); 762 break; 763 764 case token_choice_header: 765 /* 766 * This is funky code -- it fails if there were any conditionals. 767 * Fortunately all the conditionals got stripped off somewhere 768 * else. 769 */ 770 { 771 struct kconfig * cfg1; 772 for ( cfg1 = cfg->next; 773 cfg1 != NULL && cfg1->token == token_choice_item; 774 cfg1 = cfg1->next ) 775 { 776 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 }", 777 -(cfg->nameindex), cfg1->label, 778 vartable[cfg1->nameindex].name, 779 vartable[cfg1->nameindex].name ); 780 } 781 } 782 if ( cfg->cond != NULL ) 783 printf( "}" ); 784 printf( "\n" ); 785 break; 786 787 case token_choice_item: 788 fprintf( stderr, "Internal error on token_choice_item\n" ); 789 exit( 1 ); 790 791 case token_comment: 792 printf( "write_comment $cfg $autocfg \"%s\"", 793 cfg->label ); 794 if ( cfg->cond != NULL ) 795 printf( "}" ); 796 printf( "\n" ); 797 break; 798 799 case token_define_bool: 800 case token_define_tristate: 801 if ( cfg->cond == NULL ) 802 { 803 printf( "write_tristate $cfg $autocfg %s $%s [list $notmod] 2\n", 804 vartable[cfg->nameindex].name, vartable[cfg->nameindex].name ); 805 } 806 else 807 { 808 printf( "write_tristate $cfg $autocfg %s $%s [list $notmod] 2 }\n", 809 vartable[cfg->nameindex].name, cfg->value ); 810 } 811 break; 812 813 case token_dep_mbool: 814 depmod = 1; 815 case token_dep_bool: 816 case token_dep_tristate: 817 printf( "write_tristate $cfg $autocfg %s $%s [list", 818 vartable[cfg->nameindex].name, vartable[cfg->nameindex].name ); 819 for ( tmp = cfg->depend; tmp; tmp = tmp->next ) 820 printf( " $%s", tmp->name ); 821 printf( "] %d", depmod ); 822 if ( cfg->cond != NULL ) 823 printf( " }" ); 824 printf( "\n" ); 825 break; 826 827 case token_define_hex: 828 printf( "write_hex $cfg $autocfg %s %s $notmod", 829 vartable[cfg->nameindex].name, cfg->value ); 830 if ( cfg->cond != NULL ) 831 printf( " }" ); 832 printf( "\n" ); 833 break; 834 835 case token_define_int: 836 printf( "write_int $cfg $autocfg %s %s $notmod", 837 vartable[cfg->nameindex].name, cfg->value ); 838 if ( cfg->cond != NULL ) 839 printf( " }" ); 840 printf( "\n" ); 841 break; 842 843 case token_define_string: 844 printf( "write_string $cfg $autocfg %s \"%s\" $notmod", 845 vartable[cfg->nameindex].name, cfg->value ); 846 if ( cfg->cond != NULL ) 847 printf( " }" ); 848 printf( "\n" ); 849 break; 850 851 case token_hex: 852 printf( "write_hex $cfg $autocfg %s $%s $notmod", 853 vartable[cfg->nameindex].name, vartable[cfg->nameindex].name ); 854 if ( cfg->cond != NULL ) 855 printf( " }" ); 856 printf( "\n" ); 857 break; 858 859 case token_int: 860 printf( "write_int $cfg $autocfg %s $%s $notmod", 861 vartable[cfg->nameindex].name, vartable[cfg->nameindex].name ); 862 if ( cfg->cond != NULL ) 863 printf( " }" ); 864 printf( "\n" ); 865 break; 866 867 case token_string: 868 printf( "write_string $cfg $autocfg %s \"$%s\" $notmod", 869 vartable[cfg->nameindex].name, vartable[cfg->nameindex].name ); 870 if ( cfg->cond != NULL ) 871 printf( " }" ); 872 printf( "\n" ); 873 break; 874 } 875} 876 877static void generate_update_var( struct kconfig * scfg, int menu_num ) 878{ 879 struct kconfig * cfg; 880 881 if ( menu_num>0 ) 882 { 883 printf( "proc update_define_menu%d {} {\n", menu_num ); 884 printf( "\tupdate_define_mainmenu\n" ); 885 } 886 else 887 printf( "proc update_define_mainmenu {} {\n" ); 888 clear_globalflags(); 889 global( "CONFIG_MODULES" ); 890 vartable[ get_varnum( "CONFIG_MODULES" ) ].global_written = 1; 891 for ( cfg = scfg; cfg != NULL; cfg = cfg->next ) 892 { 893 if ( cfg->menu_number == menu_num && (cfg->token == token_define_bool || cfg->token == token_define_tristate 894 || cfg->token == token_define_hex || cfg->token == token_define_int 895 || cfg->token == token_define_string || cfg->token == token_unset 896 || cfg->token == token_tristate) ) 897 { 898 if ( ! vartable[cfg->nameindex].global_written ) 899 { 900 vartable[cfg->nameindex].global_written = 1; 901 global( vartable[cfg->nameindex].name ); 902 } 903 } 904 } 905 906 for ( cfg = scfg; cfg != NULL; cfg = cfg->next ) 907 { 908 char tmp[20]; 909 struct kconfig * cfg1; 910 911 if ( cfg->menu_number == menu_num ) 912 { 913 switch ( cfg->token ) 914 { 915 default: 916 case token_choice_item: 917 break; 918 case token_choice_header: 919 sprintf( tmp, "tmpvar_%d", -(cfg->nameindex) ); 920 global( tmp ); 921 for ( cfg1 = cfg->next; 922 cfg1 != NULL && cfg1->token == token_choice_item; 923 cfg1 = cfg1->next ) 924 { 925 vartable[cfg1->nameindex].global_written = 1; 926 global( vartable[cfg1->nameindex].name ); 927 printf( "\tif {$tmpvar_%d == \"%s\"} then {set %s 1} else {set %s 0}\n", 928 -(cfg->nameindex), cfg1->label, 929 vartable[cfg1->nameindex].name, 930 vartable[cfg1->nameindex].name ); 931 } 932 break; 933 case token_bool: 934 case token_define_bool: 935 case token_define_tristate: 936 case token_define_hex: 937 case token_define_int: 938 case token_define_string: 939 case token_dep_bool: 940 case token_dep_tristate: 941 case token_dep_mbool: 942 case token_int: 943 case token_hex: 944 case token_mainmenu_option: 945 case token_tristate: 946 case token_unset: 947 if ( cfg->cond != NULL ) 948 generate_if( cfg, cfg->cond, menu_num, -2 ); 949 else switch ( cfg->token ) 950 { 951 case token_tristate: 952 printf( "\n\tif {($CONFIG_MODULES == 0)} then {if {($%s == 2)} then {set %s 1}}\n", 953 vartable[cfg->nameindex].name, vartable[cfg->nameindex].name ); 954 break; 955 case token_define_bool: 956 case token_define_tristate: 957 if ( ! vartable[get_varnum( cfg->value )].global_written ) 958 { 959 vartable[get_varnum( cfg->value )].global_written = 1; 960 global( cfg->value ); 961 } 962 printf( "\tset %s $%s\n", vartable[cfg->nameindex].name, 963 cfg->value ); 964 break; 965 case token_define_hex: 966 case token_define_int: 967 printf( "\tset %s %s\n", vartable[cfg->nameindex].name, 968 cfg->value ); 969 break; 970 case token_define_string: 971 printf( "\tset %s \"%s\"\n", vartable[cfg->nameindex].name, 972 cfg->value ); 973 break; 974 case token_unset: 975 printf( "\tset %s 4\n", vartable[cfg->nameindex].name ); 976 default: 977 break; 978 } 979 } 980 } 981 } 982 printf( "}\n\n\n" ); 983} 984 985 986/* 987 * Generates the end of a menu procedure. 988 */ 989static void end_proc( struct kconfig * scfg, int menu_num ) 990{ 991 struct kconfig * cfg; 992 993 printf( "\n\n\n" ); 994 printf( "\tfocus $w\n" ); 995 printf( "\tupdate_active\n" ); 996 printf( "\tglobal winx; global winy\n" ); 997 if ( menu_first[menu_num]->menu_number != 0 ) 998 { 999 printf( "\tif {[winfo exists .menu%d] == 0} then ", 1000 menu_first[menu_num]->menu_number ); 1001 printf( "{menu%d .menu%d \"%s\"}\n", 1002 menu_first[menu_num]->menu_number, menu_first[menu_num]->menu_number, 1003 menu_first[menu_first[menu_num]->menu_number]->label ); 1004 printf( "\tset winx [expr [winfo x .menu%d]+30]; set winy [expr [winfo y .menu%d]+30]\n", 1005 menu_first[menu_num]->menu_number, menu_first[menu_num]->menu_number ); 1006 } 1007 else 1008 printf( "\tset winx [expr [winfo x .]+30]; set winy [expr [winfo y .]+30]\n" ); 1009 printf( "\tif {[winfo exists $w]} then {wm geometry $w +$winx+$winy}\n" ); 1010 1011 /* 1012 * Now that the whole window is in place, we need to wait for an "update" 1013 * so we can tell the canvas what its virtual size should be. 1014 * 1015 * Unfortunately, this causes some ugly screen-flashing because the whole 1016 * window is drawn, and then it is immediately resized. It seems 1017 * unavoidable, though, since "frame" objects won't tell us their size 1018 * until after an update, and "canvas" objects can't automatically pack 1019 * around frames. Sigh. 1020 */ 1021 printf( "\tupdate idletasks\n" ); 1022 printf( "\tif {[winfo exists $w]} then {$w.config.canvas create window 0 0 -anchor nw -window $w.config.f\n\n" ); 1023 printf( "\t$w.config.canvas configure \\\n" ); 1024 printf( "\t\t-width [expr [winfo reqwidth $w.config.f] + 1]\\\n" ); 1025 printf( "\t\t-scrollregion \"-1 -1 [expr [winfo reqwidth $w.config.f] + 1] \\\n" ); 1026 printf( "\t\t\t [expr [winfo reqheight $w.config.f] + 1]\"\n\n" ); 1027 1028 /* 1029 * If the whole canvas will fit in 3/4 of the screen height, do it; 1030 * otherwise, resize to around 1/2 the screen and let us scroll. 1031 */ 1032 printf( "\tset winy [expr [winfo reqh $w] - [winfo reqh $w.config.canvas]]\n" ); 1033 printf( "\tset scry [expr [winfo screenh $w] / 2]\n" ); 1034 printf( "\tset maxy [expr [winfo screenh $w] * 3 / 4]\n" ); 1035 printf( "\tset canvtotal [expr [winfo reqh $w.config.f] + 2]\n" ); 1036 printf( "\tif [expr $winy + $canvtotal < $maxy] {\n" ); 1037 printf( "\t\t$w.config.canvas configure -height $canvtotal\n" ); 1038 printf( "\t} else {\n" ); 1039 printf( "\t\t$w.config.canvas configure -height [expr $scry - $winy]\n" ); 1040 printf( "\t\t}\n\t}\n" ); 1041 1042 /* 1043 * Limit the min/max window size. Height can vary, but not width, 1044 * because of the limitations of canvas and our laziness. 1045 */ 1046 printf( "\tupdate idletasks\n" ); 1047 printf( "\tif {[winfo exists $w]} then {\n\twm maxsize $w [winfo width $w] [winfo screenheight $w]\n" ); 1048 printf( "\twm minsize $w [winfo width $w] 100\n\n" ); 1049 printf( "\twm deiconify $w\n" ); 1050 printf( "}\n}\n\n" ); 1051 1052 /* 1053 * Now we generate the companion procedure for the menu we just 1054 * generated. This procedure contains all of the code to 1055 * disable/enable widgets based upon the settings of the other 1056 * widgets, and will be called first when the window is mapped, 1057 * and each time one of the buttons in the window are clicked. 1058 */ 1059 printf( "proc update_menu%d {} {\n", menu_num ); 1060 1061 /* 1062 * Clear all of the booleans that are defined in this menu. 1063 */ 1064 clear_globalflags(); 1065 for ( cfg = scfg; cfg != NULL; cfg = cfg->next ) 1066 { 1067 if ( cfg->menu_number == menu_num 1068 && cfg->token != token_mainmenu_option 1069 && cfg->token != token_choice_item ) 1070 { 1071 if ( cfg->cond != NULL ) 1072 { 1073 int i; 1074 if ( (cfg->token == token_tristate || cfg->token == token_dep_tristate) 1075 && ! vartable[i = get_varnum( "CONFIG_MODULES" )].global_written ) 1076 { 1077 global( "CONFIG_MODULES" ); 1078 vartable[i].global_written = 1; 1079 } 1080 generate_if( cfg, cfg->cond, cfg->menu_number, cfg->menu_line ); 1081 } 1082 else 1083 { 1084 if ( cfg->token == token_tristate ) 1085 { 1086 int i; 1087 if ( ! vartable[cfg->nameindex].global_written ) 1088 { 1089 vartable[cfg->nameindex].global_written = 1; 1090 printf( "\tglobal %s\n", vartable[cfg->nameindex].name ); 1091 } 1092 if ( ! vartable[i = get_varnum( "CONFIG_MODULES" )].global_written ) 1093 { 1094 global( "CONFIG_MODULES" ); 1095 vartable[i].global_written = 1; 1096 } 1097 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", 1098 menu_num, cfg->menu_line, 1099 menu_num, cfg->menu_line ); 1100 } 1101 } 1102 } 1103 else if ( cfg->token == token_mainmenu_option 1104 && cfg->menu_number == menu_num 1105 && cfg->cond != NULL ) 1106 { 1107 generate_if( cfg, cfg->cond, menu_num, cfg->menu_line ); 1108 } 1109 } 1110 printf("}\n\n\n"); 1111 1112 generate_update_var( scfg, menu_num ); 1113} 1114 1115/* 1116 * This is the top level function for generating the tk script. 1117 */ 1118void dump_tk_script( struct kconfig * scfg ) 1119{ 1120 int menu_depth; 1121 int menu_num [64]; 1122 int imenu, i; 1123 int top_level_num = 0; 1124 struct kconfig * cfg; 1125 struct kconfig * cfg1 = NULL; 1126 const char * name = "No Name"; 1127 1128 /* 1129 * Mark begin and end of each menu so I can omit submenus when walking 1130 * over a parent menu. 1131 */ 1132 tot_menu_num = 0; 1133 menu_depth = 0; 1134 menu_num [0] = 0; 1135 1136 for ( cfg = scfg; cfg != NULL; cfg = cfg->next ) 1137 { 1138 switch ( cfg->token ) 1139 { 1140 default: 1141 break; 1142 1143 case token_mainmenu_name: 1144 name = cfg->label; 1145 break; 1146 1147 case token_mainmenu_option: 1148 if ( ++menu_depth >= 64 ) 1149 { fprintf( stderr, "menus too deep\n" ); exit( 1 ); } 1150 if ( ++tot_menu_num >= 100 ) 1151 { fprintf( stderr, "too many menus\n" ); exit( 1 ); } 1152 menu_num [menu_depth] = tot_menu_num; 1153 menu_first [tot_menu_num] = cfg; 1154 menu_last [tot_menu_num] = cfg; 1155 /* 1156 * Note, that menu_number is set to the number of parent 1157 * (upper level) menu. 1158 */ 1159 cfg->menu_number = menu_num[menu_depth - 1]; 1160 if ( menu_depth == 1 ) 1161 ++top_level_num; 1162 break; 1163 1164 case token_endmenu: 1165 menu_last [menu_num [menu_depth]] = cfg; 1166 /* flatten menus with proper scoping */ 1167 if ( --menu_depth < 0 ) 1168 { fprintf( stderr, "unmatched endmenu\n" ); exit( 1 ); } 1169 break; 1170 1171 case token_bool: 1172 case token_choice_header: 1173 case token_choice_item: 1174 case token_comment: 1175 case token_dep_bool: 1176 case token_dep_tristate: 1177 case token_dep_mbool: 1178 case token_hex: 1179 case token_int: 1180 case token_string: 1181 case token_tristate: 1182 cfg->menu_number = menu_num[menu_depth]; 1183 if ( menu_depth == 0 ) 1184 { fprintf( stderr, "statement not in menu\n" ); exit( 1 ); } 1185 break; 1186 1187 case token_define_bool: 1188 case token_define_hex: 1189 case token_define_int: 1190 case token_define_string: 1191 case token_define_tristate: 1192 case token_unset: 1193 cfg->menu_number = menu_num[menu_depth]; 1194 break; 1195 } 1196 } 1197 1198 /* 1199 * Generate menus per column setting. 1200 * There are: 1201 * four extra buttons for save/quit/load/store; 1202 * one blank button 1203 * add two to round up for division 1204 */ 1205 printf( "set menus_per_column %d\n", (top_level_num + 4 + 1 + 2) / 3 ); 1206 printf( "set total_menus %d\n\n", tot_menu_num ); 1207 1208 printf( "proc toplevel_menu {num} {\n" ); 1209 for ( imenu = 1; imenu <= tot_menu_num; ++imenu ) 1210 { 1211 int parent = 1; 1212 1213 if ( menu_first[imenu]->menu_number == 0 ) 1214 parent = menu_first[imenu]->menu_number; 1215 else 1216 printf( "\tif {$num == %d} then {return %d}\n", 1217 imenu, menu_first[imenu]->menu_number ); 1218 } 1219 printf( "\treturn $num\n}\n\n" ); 1220 1221 /* 1222 * Generate the menus. 1223 */ 1224 printf( "mainmenu_name \"%s\"\n", name ); 1225 for ( imenu = 1; imenu <= tot_menu_num; ++imenu ) 1226 { 1227 int menu_line = 0; 1228 int nr_submenu = imenu; 1229 int menu_name_omitted = 0; 1230 int opt_count = 0; 1231 1232 clear_globalflags(); 1233 start_proc( menu_first[imenu]->label, imenu, 1234 !menu_first[imenu]->menu_number ); 1235 1236 for ( cfg = menu_first[imenu]->next; cfg != NULL && cfg != menu_last[imenu]; cfg = cfg->next ) 1237 { 1238 switch ( cfg->token ) 1239 { 1240 default: 1241 break; 1242 1243 case token_mainmenu_option: 1244 while ( menu_first[++nr_submenu]->menu_number > imenu ) 1245 ; 1246 cfg->menu_line = menu_line++; 1247 printf( "\tsubmenu $w.config.f %d %d \"%s\" %d\n", 1248 cfg->menu_number, cfg->menu_line, cfg->label, nr_submenu ); 1249 cfg = menu_last[nr_submenu]; 1250 break; 1251 1252 case token_comment: 1253 if ( !cfg->menu_line && !menu_name_omitted ) 1254 { 1255 cfg->menu_line = -1; 1256 menu_name_omitted = 1; 1257 } 1258 else 1259 { 1260 menu_name_omitted = 1; 1261 cfg->menu_line = menu_line++; 1262 printf( "\tcomment $w.config.f %d %d \"%s\"\n", 1263 cfg->menu_number, cfg->menu_line, cfg->label ); 1264 } 1265 break; 1266 1267 case token_bool: 1268 cfg->menu_line = menu_line++; 1269 printf( "\tbool $w.config.f %d %d \"%s\" %s\n", 1270 cfg->menu_number, cfg->menu_line, cfg->label, 1271 vartable[cfg->nameindex].name ); 1272 break; 1273 1274 case token_choice_header: 1275 /* 1276 * I need the first token_choice_item to pick out the right 1277 * help text from Documentation/Configure.help. 1278 */ 1279 cfg->menu_line = menu_line++; 1280 printf( "\tglobal tmpvar_%d\n", -(cfg->nameindex) ); 1281 printf( "\tminimenu $w.config.f %d %d \"%s\" tmpvar_%d %s\n", 1282 cfg->menu_number, cfg->menu_line, cfg->label, 1283 -(cfg->nameindex), vartable[cfg->next->nameindex].name ); 1284 printf( "\tmenu $w.config.f.x%d.x.menu -tearoffcommand \"menutitle \\\"%s\\\"\"\n", 1285 cfg->menu_line, cfg->label ); 1286 cfg1 = cfg; 1287 opt_count = 0; 1288 break; 1289 1290 case token_choice_item: 1291 /* note: no menu line; uses choice header menu line */ 1292 printf( "\t$w.config.f.x%d.x.menu add radiobutton -label \"%s\" -variable tmpvar_%d -value \"%s\" -command \"update_active\"\n", 1293 cfg1->menu_line, cfg->label, -(cfg1->nameindex), 1294 cfg->label ); 1295 opt_count++; 1296 if ( cfg->next && cfg->next->token != token_choice_item ) { 1297 /* last option in the menu */ 1298 printf( "\tmenusplit $w $w.config.f.x%d.x.menu %d\n", 1299 cfg1->menu_line, opt_count ); 1300 } 1301 break; 1302 1303 case token_dep_bool: 1304 case token_dep_mbool: 1305 cfg->menu_line = menu_line++; 1306 printf( "\tdep_bool $w.config.f %d %d \"%s\" %s\n", 1307 cfg->menu_number, cfg->menu_line, cfg->label, 1308 vartable[cfg->nameindex].name ); 1309 break; 1310 1311 case token_dep_tristate: 1312 cfg->menu_line = menu_line++; 1313 printf( "\tdep_tristate $w.config.f %d %d \"%s\" %s\n", 1314 cfg->menu_number, cfg->menu_line, cfg->label, 1315 vartable[cfg->nameindex].name ); 1316 break; 1317 1318 case token_hex: 1319 cfg->menu_line = menu_line++; 1320 printf( "\thex $w.config.f %d %d \"%s\" %s\n", 1321 cfg->menu_number, cfg->menu_line, cfg->label, 1322 vartable[cfg->nameindex].name ); 1323 break; 1324 1325 case token_int: 1326 cfg->menu_line = menu_line++; 1327 printf( "\tint $w.config.f %d %d \"%s\" %s\n", 1328 cfg->menu_number, cfg->menu_line, cfg->label, 1329 vartable[cfg->nameindex].name ); 1330 break; 1331 1332 case token_string: 1333 cfg->menu_line = menu_line++; 1334 printf( "\tistring $w.config.f %d %d \"%s\" %s\n", 1335 cfg->menu_number, cfg->menu_line, cfg->label, 1336 vartable[cfg->nameindex].name ); 1337 break; 1338 1339 case token_tristate: 1340 cfg->menu_line = menu_line++; 1341 printf( "\ttristate $w.config.f %d %d \"%s\" %s\n", 1342 cfg->menu_number, cfg->menu_line, cfg->label, 1343 vartable[cfg->nameindex].name ); 1344 break; 1345 } 1346 } 1347 1348 end_proc( scfg, imenu ); 1349 } 1350 1351 /* 1352 * The top level menu also needs an update function. When we update a 1353 * submenu, we may need to disable one or more of the submenus on 1354 * the top level menu, and this procedure will ensure that things are 1355 * correct. 1356 */ 1357 clear_globalflags(); 1358 printf( "proc update_mainmenu {} {\n" ); 1359 for ( imenu = 1; imenu <= tot_menu_num; imenu++ ) 1360 { 1361 if ( menu_first[imenu]->cond != NULL && menu_first[imenu]->menu_number == 0 ) 1362 generate_if( menu_first[imenu], menu_first[imenu]->cond, imenu, -1 ); 1363 } 1364 printf( "}\n\n\n" ); 1365 1366 clear_globalflags(); 1367 /* 1368 * Generate code to load the default settings into the variables. 1369 * The script in tail.tk will attempt to load .config, 1370 * which may override these settings, but that's OK. 1371 */ 1372 for ( cfg = scfg; cfg != NULL; cfg = cfg->next ) 1373 { 1374 switch ( cfg->token ) 1375 { 1376 default: 1377 break; 1378 1379 case token_bool: 1380 case token_choice_item: 1381 case token_dep_bool: 1382 case token_dep_tristate: 1383 case token_dep_mbool: 1384 case token_tristate: 1385 if ( ! vartable[cfg->nameindex].global_written ) 1386 { 1387 printf( "set %s 0\n", vartable[cfg->nameindex].name ); 1388 vartable[cfg->nameindex].global_written = 1; 1389 } 1390 break; 1391 1392 case token_choice_header: 1393 printf( "set tmpvar_%d \"(not set)\"\n", -(cfg->nameindex) ); 1394 break; 1395 1396 case token_hex: 1397 case token_int: 1398 if ( ! vartable[cfg->nameindex].global_written ) 1399 { 1400 printf( "set %s %s\n", vartable[cfg->nameindex].name, cfg->value ? cfg->value : "0" ); 1401 vartable[cfg->nameindex].global_written = 1; 1402 } 1403 break; 1404 1405 case token_string: 1406 if ( ! vartable[cfg->nameindex].global_written ) 1407 { 1408 printf( "set %s \"%s\"\n", vartable[cfg->nameindex].name, cfg->value ); 1409 vartable[cfg->nameindex].global_written = 1; 1410 } 1411 break; 1412 } 1413 } 1414 1415 /* 1416 * Define to an empty value all other variables (which are never defined) 1417 */ 1418 for ( i = 1; i <= max_varnum; i++ ) 1419 { 1420 if ( ! vartable[i].global_written 1421 && strncmp( vartable[i].name, "CONSTANT_", 9 ) ) 1422 printf( "set %s 4\n", vartable[i].name ); 1423 } 1424 1425 /* 1426 * Generate a function to write all of the variables to a file. 1427 */ 1428 printf( "proc writeconfig {file1 file2} {\n" ); 1429 printf( "\tset cfg [open $file1 w]\n" ); 1430 printf( "\tset autocfg [open $file2 w]\n" ); 1431 printf( "\tset notmod 1\n" ); 1432 printf( "\tset notset 0\n" ); 1433 printf( "\tputs $cfg \"#\"\n"); 1434 printf( "\tputs $cfg \"# Automatically generated make config: don't edit\"\n"); 1435 printf( "\tputs $cfg \"#\"\n" ); 1436 1437 printf( "\tputs $autocfg \"/*\"\n" ); 1438 printf( "\tputs $autocfg \" * Automatically generated C config: don't edit\"\n" ); 1439 printf( "\tputs $autocfg \" */\"\n" ); 1440 printf( "\tputs $autocfg \"#define AUTOCONF_INCLUDED\"\n" ); 1441 1442 clear_globalflags(); 1443 for ( cfg = scfg; cfg != NULL; cfg = cfg->next ) 1444 { 1445 switch ( cfg->token ) 1446 { 1447 default: 1448 break; 1449 1450 case token_bool: 1451 case token_choice_header: 1452 case token_comment: 1453 case token_define_bool: 1454 case token_define_hex: 1455 case token_define_int: 1456 case token_define_string: 1457 case token_define_tristate: 1458 case token_dep_bool: 1459 case token_dep_tristate: 1460 case token_dep_mbool: 1461 case token_hex: 1462 case token_int: 1463 case token_string: 1464 case token_tristate: 1465 generate_writeconfig( cfg ); 1466 break; 1467 } 1468 } 1469 printf( "\tclose $cfg\n" ); 1470 printf( "\tclose $autocfg\n" ); 1471 printf( "}\n\n\n" ); 1472 1473 /* 1474 * Generate a simple function that updates the master choice 1475 * variable depending upon what values were loaded from a .config 1476 * file. 1477 */ 1478 printf( "proc clear_choices { } {\n" ); 1479 for ( cfg = scfg; cfg != NULL; cfg = cfg->next ) 1480 { 1481 if ( cfg->token == token_choice_header ) 1482 { 1483 for ( cfg1 = cfg->next; 1484 cfg1 != NULL && cfg1->token == token_choice_item; 1485 cfg1 = cfg1->next ) 1486 { 1487 printf( "\tglobal %s; set %s 0\n", 1488 vartable[cfg1->nameindex].name, 1489 vartable[cfg1->nameindex].name ); 1490 } 1491 } 1492 } 1493 printf( "}\n\n\n" ); 1494 1495 printf( "proc update_choices { } {\n" ); 1496 for ( cfg = scfg; cfg != NULL; cfg = cfg->next ) 1497 { 1498 if ( cfg->token == token_choice_header ) 1499 { 1500 printf( "\tglobal tmpvar_%d\n", -(cfg->nameindex) ); 1501 printf("\tset tmpvar_%d \"%s\"\n", -(cfg->nameindex), cfg->value); 1502 for ( cfg1 = cfg->next; 1503 cfg1 != NULL && cfg1->token == token_choice_item; 1504 cfg1 = cfg1->next ) 1505 { 1506 printf( "\tglobal %s\n", vartable[cfg1->nameindex].name ); 1507 printf( "\tif { $%s == 1 } then { set tmpvar_%d \"%s\" }\n", 1508 vartable[cfg1->nameindex].name, 1509 -(cfg->nameindex), cfg1->label ); 1510 } 1511 } 1512 } 1513 printf( "}\n\n\n" ); 1514 1515 generate_update_var( scfg, 0 ); 1516 1517 /* 1518 * That's it. We are done. The output of this file will have header.tk 1519 * prepended and tail.tk appended to create an executable wish script. 1520 */ 1521} 1522