tkgen.c 33 KB

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