New URL for NEMO forge!   http://forge.nemo-ocean.eu

Since March 2022 along with NEMO 4.2 release, the code development moved to a self-hosted GitLab.
This present forge is now archived and remained online for history.
tkgen.c in branches/2014/dev_r4650_UKMO7_STARTHOUR/NEMOGCM/EXTERNAL/IOIPSL/tools – NEMO

source: branches/2014/dev_r4650_UKMO7_STARTHOUR/NEMOGCM/EXTERNAL/IOIPSL/tools/tkgen.c @ 5984

Last change on this file since 5984 was 5984, checked in by timgraham, 8 years ago

Clear svn keywords to allow use with fcm make

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