source: IOIPSL/trunk/tools/tkgen.c @ 15

Last change on this file since 15 was 15, checked in by bellier, 15 years ago

JB: add tools and examples
dd

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