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 */
121 static int tot_menu_num = 0;
122
123 /*
124 * Pointers to mainmenu_option and endmenu of each menu.
125 */
126 struct kconfig * menu_first [100];
127 struct 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 */
start_proc(char * label,int menu_num,int toplevel)133 static 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 */
clear_globalflags(void)263 static 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 */
global(const char * var)277 void 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 */
generate_if(struct kconfig * cfg,struct condition * ocond,int menu_num,int line_num)288 void 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 */
generate_writeconfig(struct kconfig * cfg)651 void 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
generate_update_var(struct kconfig * scfg,int menu_num)877 static 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 */
end_proc(struct kconfig * scfg,int menu_num)989 static 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 */
dump_tk_script(struct kconfig * scfg)1118 void 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