Use an int to hold the result of fgetc (bug noted by David Kimdon).
[oweals/busybox.git] / scripts / Menuconfig
1 #! /bin/sh
2 #
3 # This script is used to configure BusyBox.
4 #
5 # It was inspired by a desire to not have to hit <enter> 9 million times
6 # or startup the X server just to change a single kernel parameter.  
7 #
8 # This script attempts to parse the configuration files, which are
9 # scattered throughout the kernel source tree, and creates a temporary
10 # set of mini scripts which are in turn used to create nested menus and
11 # radiolists.
12 #
13 # It uses a very modified/mutilated version of the "dialog" utility
14 # written by Savio Lam (lam836@cs.cuhk.hk). Savio is not responsible
15 # for this script or the version of dialog used by this script.
16 # Please do not contact him with questions. The official version of 
17 # dialog is available at sunsite.unc.edu or a sunsite mirror.
18 #
19 # Portions of this script were borrowed from the original Configure
20 # script.
21 #
22 # William Roadcap was the original author of Menuconfig.
23 # Michael Elizabeth Chastain (mec@shout.net) is the current maintainer.
24 #
25 # 070497 Bernhard Kaindl (bkaindl@netway.at) - get default values for
26 # new bool, tristate and dep_tristate parameters from the defconfig file.
27 # new configuration parameters are marked with '(NEW)' as in make config.
28 #
29 # 180697 Bernhard Kaindl (bkaindl@netway.at) - added the needed support
30 # for string options. They are handled like the int and hex options.
31 #
32 # 081297 Pavel Machek (pavel@atrey.karlin.mff.cuni.cz) - better error 
33 # handling
34 #
35 # 131197 Michael Chastain (mec@shout.net) - output all lines for a
36 # choice list, not just the selected one.  This makes the output
37 # the same as Configure output, which is important for smart config
38 # dependencies.
39 #
40 # 101297 Michael Chastain (mec@shout.net) - remove sound driver cruft.
41 #
42 # 221297 Michael Chastain (mec@shout.net) - make define_bool actually
43 # define its arguments so that later tests on them work right.
44 #
45 # 160198 Michael Chastain (mec@shout.net) - fix bug with 'c' command
46 # (complement existing value) when used on virgin uninitialized variables.
47 #
48 # 090398 Axel Boldt (boldt@math.ucsb.edu) - allow for empty lines in help
49 # texts.
50 #
51 # 12 Dec 1998, Michael Elizabeth Chastain (mec@shout.net)
52 # Remove a /tmp security hole in get_def (also makes it faster).
53 # Give uninitialized variables canonical values rather than null value.
54 # Change a lot of places to call set_x_info uniformly.
55 # Take out message about preparing version (old sound driver cruft).
56 #
57 # 13 Dec 1998, Riley H Williams <rhw@memalpha.cx>
58 # When an error occurs, actually display the error message as well as
59 # our comments thereon.
60 #
61 # 31 Dec 1998, Michael Elizabeth Chastain (mec@shout.net)
62 # Fix mod_bool to honor $CONFIG_MODULES.
63 # Fix dep_tristate to call define_bool when dependency is "n".
64 #
65 # 02 January 1999, Michael Elizabeth Chastain (mec@shout.net)
66 # Blow away lxdialog.scrltmp on entry to activate_menu.  This protects
67 # against people who use commands like ' ' to select menus.
68 #
69 # 24 January 1999, Michael Elizabeth Chastain, <mec@shout.net>
70 # - Improve the exit message (Jeff Ronne).
71 #
72 # 06 July 1999, Andrzej M. Krzysztofowicz, <ankry@mif.pg.gda.pl>
73 # - Support for multiple conditions in dep_tristate().
74 # - Implemented new functions: define_tristate(), define_int(), define_hex(),
75 #   define_string(), dep_bool().
76
77 # 22 October 2001, Erik Andersen <andersee@debian.org>
78 # - Adjusted for busybox (modified hard coded kernel specific paths, 
79 #   and everything to do with modules (tristates, modbools, etc).
80
81
82 #
83 # Change this to TRUE if you prefer all options listed
84 # in a single menu rather than the standard menu hierarchy.
85 #
86 single_menu_mode=
87
88 #
89 # Make sure we're really running bash.
90 #
91 [ -z "$BASH" ] && { echo "Menuconfig requires bash" 1>&2; exit 1; }
92
93 #
94 # Cache function definitions, turn off posix compliance
95 #
96 set -h +o posix
97
98
99
100 # Given a configuration variable, set the global variable $x to its value,
101 # and the global variable $info to the string " (NEW)" if this is a new
102 # variable.
103 #
104 # This function looks for: (1) the current value, or (2) the default value
105 # from the arch-dependent defconfig file, or (3) a default passed by the caller.
106
107 function set_x_info () {
108     eval x=\$$1
109     if [ -z "$x" ]; then
110         eval `sed -n -e 's/# \(.*\) is not set.*/\1=n/' -e "/^$1=/p" sysdeps/$TARGET_OS/defconfig`
111         eval x=\${$1:-"$2"}
112         eval $1=$x
113         eval INFO_$1="' (NEW)'"
114     fi
115     eval info="\$INFO_$1"
116 }
117
118 #
119 # Load the functions used by the config.in files.
120 #
121 # I do this because these functions must be redefined depending
122 # on whether they are being called for interactive use or for
123 # saving a configuration to a file.
124 #
125 # Thank the heavens bash supports nesting function definitions.
126 #
127 load_functions () {
128
129 #
130 # Additional comments
131 #
132 function comment () {
133         comment_ctr=$[ comment_ctr + 1 ]
134         echo -ne "': $comment_ctr' '--- $1' " >>MCmenu
135 }
136
137 #
138 # Define a boolean to a specific value.
139 #
140 function define_bool () {
141         eval $1=$2
142 }
143
144 function define_hex () {
145         eval $1=$2
146 }
147
148 function define_int () {
149         eval $1=$2
150 }
151
152 function define_string () {
153         eval $1="$2"
154 }
155
156 #
157 # Create a boolean (Yes/No) function for our current menu
158 # which calls our local bool function.
159 #
160 function bool () {
161         set_x_info "$2" "n"
162
163         case $x in
164         y|m)    flag="*" ;;
165         n)      flag=" " ;;
166         esac
167
168         echo -ne "'$2' '[$flag] $1$info' " >>MCmenu
169
170         echo -e "function $2 () { l_bool '$2' \"\$1\" ;}\n" >>MCradiolists
171 }
172
173 #
174 #   Same as above, but now only Y and N are allowed as dependency
175 #   (i.e. third and next arguments).
176 #
177 function dep_bool () {
178         ques="$1"
179         var="$2"
180         dep=y
181         shift 2
182         while [ $# -gt 0 ]; do
183                 if [ "$1" = y ]; then
184                         shift
185                 else
186                         dep=n
187                         shift $#
188                 fi
189         done
190         if [ "$dep" = y ]; then
191             bool "$ques" "$var"
192         else 
193             define_bool "$var" n
194         fi
195 }
196
197 function dep_mbool () {
198         ques="$1"
199         var="$2"
200         dep=y
201         shift 2
202         while [ $# -gt 0 ]; do
203                 if [ "$1" = y -o "$1" = m ]; then
204                         shift
205                 else
206                         dep=n
207                         shift $#
208                 fi
209         done
210         if [ "$dep" = y ]; then
211             bool "$ques" "$var"
212         else 
213             define_bool "$var" n
214         fi
215 }
216
217 #
218 # Add a menu item which will call our local int function.
219
220 function int () {
221         set_x_info "$2" "$3"
222
223         echo -ne "'$2' '($x) $1$info' " >>MCmenu
224
225         echo -e "function $2 () { l_int '$1' '$2' '$3' '$x' ;}" >>MCradiolists
226 }
227
228 #
229 # Add a menu item which will call our local hex function.
230
231 function hex () {
232         set_x_info "$2" "$3"
233         x=${x##*[x,X]}
234
235         echo -ne "'$2' '($x) $1$info' " >>MCmenu
236
237         echo -e "function $2 () { l_hex '$1' '$2' '$3' '$x' ;}" >>MCradiolists
238 }
239
240 #
241 # Add a menu item which will call our local string function.
242
243 function string () {
244         set_x_info "$2" "$3"
245
246         echo -ne "'$2' '     $1: \"$x\"$info' " >>MCmenu
247
248         echo -e "function $2 () { l_string '$1' '$2' '$3' '$x' ;}" >>MCradiolists
249 }
250
251 #
252 # Add a menu item which will call our local One-of-Many choice list.
253 #
254 function choice () {
255         #
256         # Need to remember params cause they're gonna get reset.
257         #
258         title=$1
259         choices=$2
260         default=$3
261         current=
262
263         #
264         # Find out if one of the choices is already set.
265         # If it's not then make it the default.
266         #
267         set -- $choices
268         firstchoice=$2
269
270         while [ -n "$2" ]
271         do
272                 if eval [ "_\$$2" = "_y" ]
273                 then
274                         current=$1
275                         break
276                 fi
277                 shift ; shift
278         done
279
280         : ${current:=$default}
281
282         echo -ne "'$firstchoice' '($current) $title' " >>MCmenu
283
284         echo -e "
285         function $firstchoice () \
286                 { l_choice '$title' \"$choices\" \"$current\" ;}" >>MCradiolists
287 }
288
289 } # END load_functions()
290
291
292
293
294
295 #
296 # Extract available help for an option from Configure.help
297 # and send it to standard output.
298 #
299 # Most of this function was borrowed from the original kernel
300 # Configure script.
301 #
302 function extract_help () {
303   if [ -f docs/Configure.help ]
304   then
305      #first escape regexp special characters in the argument:
306      var=$(echo "$1"|sed 's/[][\/.^$*]/\\&/g')
307      #now pick out the right help text:
308      text=$(sed -n "/^$var[     ]*\$/,\${
309                         /^$var[         ]*\$/c\\
310 ${var}:\\
311
312                         /^#/b
313                         /^[^    ]/q
314                         s/^  //
315                         /<file:\\([^>]*\\)>/s//\\1/g
316                         p
317                     }" docs/Configure.help)
318
319      if [ -z "$text" ]
320      then
321           echo "There is no help available for this option."
322           return 1
323      else
324           echo "$text"
325      fi
326   else
327          echo "There is no help available for this option."
328          return 1
329   fi
330 }
331
332 #
333 # Activate a help dialog.
334 #
335 function help () {
336         if extract_help $1 >help.out
337         then
338                 $DIALOG --backtitle "$backtitle" --title "$2"\
339                         --textbox help.out $ROWS $COLS
340         else
341                 $DIALOG --backtitle "$backtitle" \
342                         --textbox help.out $ROWS $COLS
343         fi
344         rm -f help.out
345 }
346
347 #
348 # Show the README file.
349 #
350 function show_readme () {
351         $DIALOG --backtitle "$backtitle" \
352                 --textbox scripts/README.Menuconfig $ROWS $COLS
353 }
354
355 #
356 # Begin building the dialog menu command and Initialize the 
357 # Radiolist function file.
358 #
359 function menu_name () {
360         echo -ne "$DIALOG --title '$1'\
361                         --backtitle '$backtitle' \
362                         --menu '$menu_instructions' \
363                         $ROWS $COLS $((ROWS-10)) \
364                         '$default' " >MCmenu
365         >MCradiolists
366 }
367
368 #
369 # Add a submenu option to the menu currently under construction.
370 #
371 function submenu () {
372         echo -ne "'activate_menu $2' '$1  --->' " >>MCmenu
373 }
374
375 #
376 # Handle a boolean (Yes/No) option.
377 #
378 function l_bool () {
379         if [ -n "$2" ]
380         then
381                 case "$2" in
382                 y|m)    eval $1=y ;;
383                 c)      eval x=\$$1
384                         case $x in
385                         y) eval $1=n ;;
386                         n) eval $1=y ;;
387                         *) eval $1=y ;;
388                         esac ;;
389                 *)      eval $1=n ;;
390                 esac
391         else
392                 echo -ne "\007"
393         fi
394 }
395
396 #
397 # Create a dialog for entering an integer into a option.
398 #
399 function l_int () {
400         while true
401         do
402                 if $DIALOG --title "$1" \
403                         --backtitle "$backtitle" \
404                         --inputbox "$inputbox_instructions_int" \
405                         10 75 "$4" 2>MCdialog.out
406                 then
407                         answer="`cat MCdialog.out`"
408                         answer="${answer:-$3}"
409
410                         # Semantics of + and ? in GNU expr changed, so
411                         # we avoid them:
412                         if expr "$answer" : '0$' '|' "$answer" : '[1-9][0-9]*$' '|' "$answer" : '-[1-9][0-9]*$' >/dev/null
413                         then
414                                 eval $2="$answer"
415                         else
416                                 eval $2="$3"
417                                 echo -en "\007"
418                                 ${DIALOG} --backtitle "$backtitle" \
419                                         --infobox "You have made an invalid entry." 3 43
420                                 sleep 2
421                         fi
422
423                         break
424                 fi
425
426                 help "$2" "$1"
427         done
428 }
429
430 #
431 # Create a dialog for entering a hexadecimal into an option.
432 #
433 function l_hex () {
434         while true
435         do
436                 if $DIALOG --title "$1" \
437                         --backtitle "$backtitle" \
438                         --inputbox "$inputbox_instructions_hex" \
439                         10 75 "$4" 2>MCdialog.out
440                 then
441                         answer="`cat MCdialog.out`"
442                         answer="${answer:-$3}"
443                         answer="${answer##*[x,X]}"
444
445                         if expr "$answer" : '[0-9a-fA-F][0-9a-fA-F]*$' >/dev/null
446                         then
447                                 eval $2="$answer"
448                         else
449                                 eval $2="$3"
450                                 echo -en "\007"
451                                 ${DIALOG} --backtitle "$backtitle" \
452                                         --infobox "You have made an invalid entry." 3 43
453                                 sleep 2
454                         fi
455
456                         break
457                 fi
458
459                 help "$2" "$1"
460         done
461 }
462
463 #
464 # Create a dialog for entering a string into an option.
465 #
466 function l_string () {
467         while true
468         do
469                 if $DIALOG --title "$1" \
470                         --backtitle "$backtitle" \
471                         --inputbox "$inputbox_instructions_string" \
472                         10 75 "$4" 2>MCdialog.out
473                 then
474                         answer="`cat MCdialog.out`"
475                         answer="${answer:-$3}"
476
477                         #
478                         # Someone may add a nice check for the entered
479                         # string here...
480                         #
481                         eval $2=\"$answer\"
482
483                         break
484                 fi
485
486                 help "$2" "$1"
487         done
488 }
489
490
491 #
492 # Handle a one-of-many choice list.
493 #
494 function l_choice () {
495         #
496         # Need to remember params cause they're gonna get reset.
497         #
498         title="$1"
499         choices="$2"
500         current="$3"
501         chosen=
502
503         #
504         # Scan current value of choices and set radiolist switches.
505         #
506         list=
507         set -- $choices
508         firstchoice=$2
509         while [ -n "$2" ]
510         do
511                 case "$1" in
512                 "$current"*)    if [ -z "$chosen" ]; then
513                                         list="$list $2 $1 ON "
514                                         chosen=1
515                                 else
516                                         list="$list $2 $1 OFF "
517                                 fi  ;;
518                 *)              list="$list $2 $1 OFF " ;;
519                 esac
520                         
521                 shift ; shift
522         done
523
524         while true
525         do
526                 if $DIALOG --title "$title" \
527                         --backtitle "$backtitle" \
528                         --radiolist "$radiolist_instructions" \
529                         15 70 6 $list 2>MCdialog.out
530                 then
531                         choice=`cat MCdialog.out`
532                         break
533                 fi
534
535                 help "$firstchoice" "$title"
536         done
537
538         #
539         # Now set the boolean value of each option based on
540         # the selection made from the radiolist.
541         #
542         set -- $choices
543         while [ -n "$2" ]
544         do
545                 if [ "$2" = "$choice" ]
546                 then
547                         eval $2="y"
548                 else
549                         eval $2="n"
550                 fi
551                 
552                 shift ; shift
553         done
554 }
555
556 #
557 # Call awk, and watch for error codes, etc.
558 #
559 function callawk () {
560 awk "$1" || echo "Awk died with error code $?. Giving up." || exit 1
561 }
562
563 #
564 # A faster awk based recursive parser. (I hope)
565 #
566 function parser1 () {
567 callawk '
568 BEGIN {
569         menu_no = 0
570         comment_is_option = 0
571         parser("'$CONFIG_IN'","MCmenu0")
572 }
573
574 function parser(ifile,menu) {
575
576         while (getline <ifile) {
577                 if ($1 == "mainmenu_option") {
578                         comment_is_option = "1"
579                 }
580                 else if ($1 == "comment" && comment_is_option == "1") {
581                         comment_is_option= "0"
582                         sub($1,"",$0)
583                         ++menu_no
584
585                         printf("submenu %s MCmenu%s\n", $0, menu_no) >>menu
586
587                         newmenu = sprintf("MCmenu%d", menu_no);
588                         printf( "function MCmenu%s () {\n"\
589                                 "default=$1\n"\
590                                 "menu_name %s\n",\
591                                  menu_no, $0) >newmenu
592
593                         parser(ifile, newmenu)
594                 }
595                 else if ($0 ~ /^#|\$MAKE|mainmenu_name/) {
596                         printf("") >>menu
597                 }
598                 else if ($1 ~ "endmenu") {
599                         printf("}\n") >>menu
600                         return
601                 } 
602                 else if ($1 == "source") {
603                         parser($2,menu)
604                 }
605                 else {
606                         print >>menu
607                 }
608         }
609 }'
610 }
611
612 #
613 # Secondary parser for single menu mode.
614 #
615 function parser2 () {
616 callawk '
617 BEGIN {
618         parser("'$CONFIG_IN'","MCmenu0")
619 }
620
621 function parser(ifile,menu) {
622
623         while (getline <ifile) {
624                 if ($0 ~ /^#|$MAKE|mainmenu_name/) {
625                         printf("") >>menu
626                 }
627                 else if ($1 ~ /mainmenu_option|endmenu/) {
628                         printf("") >>menu
629                 } 
630                 else if ($1 == "source") {
631                         parser($2,menu)
632                 }
633                 else {
634                         print >>menu
635                 }
636         }
637 }'
638 }
639
640 #
641 # Parse all the config.in files into mini scripts.
642 #
643 function parse_config_files () {
644         rm -f MCmenu*
645
646         echo "function MCmenu0 () {" >MCmenu0
647         echo 'default=$1' >>MCmenu0
648         echo "menu_name 'Main Menu'" >>MCmenu0
649
650         if [ "_$single_menu_mode" = "_TRUE" ]
651         then
652                 parser2
653         else
654                 parser1
655         fi
656
657         echo "comment ''"       >>MCmenu0
658         echo "g_alt_config"     >>MCmenu0
659         echo "s_alt_config"     >>MCmenu0
660
661         echo "}" >>MCmenu0
662
663         #
664         # These mini scripts must be sourced into the current
665         # environment in order for all of this to work.  Leaving
666         # them on the disk as executables screws up the recursion
667         # in activate_menu(), among other things.  Once they are
668         # sourced we can discard them.
669         #
670         for i in MCmenu*
671         do
672                 echo -n "."
673                 source ./$i
674         done
675         rm -f MCmenu*
676 }
677
678 #
679 # This is the menu tree's bootstrap.
680 #
681 # Executes the parsed menus on demand and creates a set of functions,
682 # one per configuration option.  These functions will in turn execute
683 # dialog commands or recursively call other menus.
684 #
685 function activate_menu () {
686         rm -f lxdialog.scrltmp
687         while true
688         do
689                 comment_ctr=0           #So comment lines get unique tags
690
691                 $1 "$default" 2> MCerror #Create the lxdialog menu & functions
692
693                 if [ "$?" != "0" ]
694                 then
695                         clear
696                         cat <<EOM
697
698 Menuconfig has encountered a possible error in one of BusyBox's
699 configuration files and is unable to continue.  Here is the error
700 report:
701
702 EOM
703                         sed 's/^/ Q> /' MCerror
704                         cat <<EOM
705
706 Please report this to the maintainer <mec@shout.net>.  You may also
707 send a problem report to <busybox@busybox.net>.
708
709 Please indicate the BusyBox version you are trying to configure and
710 which menu you were trying to enter when this error occurred.
711
712 EOM
713                         cleanup
714                         exit 1
715                 fi
716                 rm -f MCerror
717
718                 . ./MCradiolists                #Source the menu's functions
719
720                 . ./MCmenu 2>MCdialog.out       #Activate the lxdialog menu
721                 ret=$?
722
723                 read selection <MCdialog.out
724
725                 case "$ret" in
726                 0|3|4|5|6)
727                         defaults="$selection\12$defaults"  #pseudo stack
728                         case "$ret" in
729                         0) eval $selection   ;;
730                         3) eval $selection y ;;
731                         4) eval $selection n ;;
732                         5) eval $selection m ;;
733                         6) eval $selection c ;;
734                         esac
735                         default="${defaults%%\12*}" defaults="${defaults#*\12}"
736                         ;;
737                 2)      
738                         default="${selection%%\ *}"
739
740                         case "$selection" in
741                         *"-->"*|*"alt_config"*)
742                                 show_readme ;;
743                         *)
744                                 eval help $selection ;;
745                         esac
746                         ;;
747                 255|1)
748                         break
749                         ;;
750                 139)
751                         stty sane
752                         clear
753                         cat <<EOM
754
755 There seems to be a problem with the lxdialog companion utility which is
756 built prior to running Menuconfig.  Usually this is an indicator that you
757 have upgraded/downgraded your ncurses libraries and did not remove the 
758 old ncurses header file(s) in /usr/include or /usr/include/ncurses.
759
760 It is VERY important that you have only one set of ncurses header files
761 and that those files are properly version matched to the ncurses libraries 
762 installed on your machine.
763
764 You may also need to rebuild lxdialog.  This can be done by moving to
765 the /usr/src/linux/scripts/lxdialog directory and issuing the 
766 "make clean all" command.
767
768 If you have verified that your ncurses install is correct, you may email
769 the maintainer <andersen@codepoet.org> or post a message to
770 <busybox@busybox.net> for additional assistance. 
771
772 EOM
773                         cleanup
774                         exit 139
775                         ;;
776                 esac
777         done
778 }
779
780 #
781 # Create a menu item to load an alternate configuration file.
782 #
783 g_alt_config () {
784         echo -n "get_alt_config 'Load an Alternate Configuration File' "\
785                 >>MCmenu
786 }
787
788 #
789 # Get alternate config file name and load the 
790 # configuration from it.
791 #
792 get_alt_config () {
793         set -f ## Switch file expansion OFF
794
795         while true
796         do
797                 ALT_CONFIG="${ALT_CONFIG:-$DEFAULTS}"
798
799                 $DIALOG --backtitle "$backtitle" \
800                         --inputbox "\
801 Enter the name of the configuration file you wish to load.  \
802 Accept the name shown to restore the configuration you \
803 last retrieved.  Leave blank to abort."\
804                         11 55 "$ALT_CONFIG" 2>MCdialog.out
805
806                 if [ "$?" = "0" ]
807                 then
808                         ALT_CONFIG=`cat MCdialog.out`
809
810                         [ "_" = "_$ALT_CONFIG" ] && break
811
812                         if eval [ -r "$ALT_CONFIG" ]
813                         then
814                                 eval load_config_file "$ALT_CONFIG"
815                                 break
816                         else
817                                 echo -ne "\007"
818                                 $DIALOG --backtitle "$backtitle" \
819                                         --infobox "File does not exist!"  3 38
820                                 sleep 2
821                         fi
822                 else
823                         cat <<EOM >help.out
824
825 For various reasons, one may wish to keep several different BusyBox
826 configurations available on a single machine.  
827
828 If you have saved a previous configuration in a file other than the
829 busybox default, entering the name of the file here will allow you
830 to modify that configuration.
831
832 If you are uncertain, then you have probably never used alternate 
833 configuration files.  You should therefor leave this blank to abort.
834
835 EOM
836                         $DIALOG --backtitle "$backtitle"\
837                                 --title "Load Alternate Configuration"\
838                                 --textbox help.out $ROWS $COLS
839                 fi
840         done
841
842         set +f ## Switch file expansion ON
843         rm -f help.out MCdialog.out
844 }
845
846 #
847 # Create a menu item to store an alternate config file.
848 #
849 s_alt_config () {
850         echo -n "save_alt_config 'Save Configuration to an Alternate File' "\
851                  >>MCmenu
852 }
853
854 #
855 # Get an alternate config file name and save the current
856 # configuration to it.
857 #
858 save_alt_config () {
859         set -f  ## Switch file expansion OFF
860                         
861         while true
862         do
863                 $DIALOG --backtitle "$backtitle" \
864                         --inputbox "\
865 Enter a filename to which this configuration should be saved \
866 as an alternate.  Leave blank to abort."\
867                         10 55 "$ALT_CONFIG" 2>MCdialog.out
868
869                 if [ "$?" = "0" ]
870                 then
871                         ALT_CONFIG=`cat MCdialog.out`
872
873                         [ "_" = "_$ALT_CONFIG" ] && break
874
875                         if eval touch $ALT_CONFIG 2>/dev/null
876                         then
877                                 eval save_configuration $ALT_CONFIG
878                                 load_functions  ## RELOAD
879                                 break
880                         else
881                                 echo -ne "\007"
882                                 $DIALOG --backtitle "$backtitle" \
883                                         --infobox "Can't create file!  Probably a nonexistent directory." 3 60
884                                 sleep 2
885                         fi
886                 else
887                         cat <<EOM >help.out
888
889 For various reasons, one may wish to keep different BusyBox
890 configurations available on a single machine.  
891
892 Entering a file name here will allow you to later retrieve, modify
893 and use the current configuration as an alternate to whatever 
894 configuration options you have selected at that time.
895
896 If you are uncertain what all this means then you should probably
897 leave this blank.
898 EOM
899                         $DIALOG --backtitle "$backtitle"\
900                                 --title "Save Alternate Configuration"\
901                                 --textbox help.out $ROWS $COLS
902                 fi
903         done
904
905         set +f  ## Switch file expansion ON
906         rm -f help.out MCdialog.out
907 }
908
909 #
910 # Load config options from a file.
911 # Converts all "# OPTION is not set" lines to "OPTION=n" lines
912 #
913 function load_config_file () {
914         awk '
915           /# .* is not set.*/ { printf("%s=n\n", $2) }
916         ! /# .* is not set.*/ { print }
917         ' $1 >.tmpconfig
918
919         source ./.tmpconfig
920         rm -f .tmpconfig
921 }
922
923 #
924 # Just what it says.
925 #
926 save_configuration () {
927         echo
928         echo -n "Saving your BusyBox configuration."
929
930         #
931         # Now, let's redefine the configuration functions for final
932         # output to the config files.
933         #
934         # Nested function definitions, YIPEE!
935         #
936         function bool () {
937                 set_x_info "$2" "n"
938                 eval define_bool "$2" "$x"
939         }
940
941         function dep_bool () {
942                 set_x_info "$2" "n"
943                 var="$2"
944                 shift 2
945                 while [ $# -gt 0 ]; do
946                         if   [ "$1" = y ]; then
947                                 shift
948                         else 
949                                 x=n; shift $#
950                         fi
951                 done
952                 define_bool "$var" "$x"
953         }
954
955         function int () {
956                 set_x_info "$2" "$3"
957                 echo "$2=$x"            >>$CONFIG
958                 echo "#define $2 ($x)"  >>$CONFIG_H
959         }
960
961         function hex () {
962                 set_x_info "$2" "$3"
963                 echo "$2=$x"                     >>$CONFIG
964                 echo "#define $2 0x${x##*[x,X]}" >>$CONFIG_H
965         }
966
967         function string () {
968                 set_x_info "$2" "$3"
969                 echo "$2=\"$x\""                         >>$CONFIG
970                 echo "#define $2 \"$x\""        >>$CONFIG_H
971         }
972
973         function define_hex () {
974                 eval $1="$2"
975                 echo "$1=$2"                    >>$CONFIG
976                 echo "#define $1 0x${2##*[x,X]}"        >>$CONFIG_H
977         }
978
979         function define_int () {
980                 eval $1="$2"
981                 echo "$1=$2"                    >>$CONFIG
982                 echo "#define $1 ($2)"          >>$CONFIG_H
983         }
984
985         function define_string () {
986                 eval $1="$2"
987                 echo "$1=\"$2\""                >>$CONFIG
988                 echo "#define $1 \"$2\""        >>$CONFIG_H
989         }
990
991         function define_bool () {
992                 define_tristate "$1" "$2"
993         }
994
995         function define_tristate () {
996                 eval $1="$2"
997
998                 case "$2" in
999                 y)
1000                         echo "$1=y"             >>$CONFIG
1001                         echo "#define $1 1"     >>$CONFIG_H
1002                         ;;
1003
1004                 n)
1005                         echo "# $1 is not set"  >>$CONFIG
1006                         echo "#undef  $1"       >>$CONFIG_H
1007                         ;;
1008                 esac
1009         }
1010
1011         function choice () {
1012                 #
1013                 # Find the first choice that's already set to 'y'
1014                 #
1015                 choices="$2"
1016                 default="$3"
1017                 current=
1018                 chosen=
1019
1020                 set -- $choices
1021                 while [ -n "$2" ]
1022                 do
1023                         if eval [ "_\$$2" = "_y" ]
1024                         then
1025                                 current=$1
1026                                 break
1027                         fi
1028                         shift ; shift
1029                 done
1030
1031                 #
1032                 # Use the default if none were set.  
1033                 #
1034                 : ${current:=$default}
1035
1036                 #
1037                 # Output all choices (to be compatible with other configs).
1038                 #
1039                 set -- $choices
1040                 while [ -n "$2" ]
1041                 do
1042                         case "$1" in
1043                         "$current"*)    if [ -z "$chosen" ]; then
1044                                                 define_bool "$2" "y"
1045                                                 chosen=1
1046                                         else
1047                                                 define_bool "$2" "n"
1048                                         fi ;;
1049                         *)              define_bool "$2" "n" ;;
1050                         esac
1051                         shift ; shift
1052                 done
1053         }
1054
1055         function mainmenu_name () {
1056                 :
1057         }
1058
1059         function mainmenu_option () {
1060                 comment_is_option=TRUE
1061         }
1062
1063         function endmenu () {
1064                 :
1065         }
1066
1067         function comment () {
1068                 if [ "$comment_is_option" ]
1069                 then
1070                         comment_is_option=
1071                         echo        >>$CONFIG
1072                         echo "#"    >>$CONFIG
1073                         echo "# $1" >>$CONFIG
1074                         echo "#"    >>$CONFIG
1075
1076                         echo         >>$CONFIG_H
1077                         echo "/*"    >>$CONFIG_H
1078                         echo " * $1" >>$CONFIG_H
1079                         echo " */"   >>$CONFIG_H
1080                 fi
1081         }
1082
1083         echo -n "."
1084
1085         DEF_CONFIG="${1:-.config}"
1086         DEF_CONFIG_H="include/config.h"
1087
1088         CONFIG=.tmpconfig
1089         CONFIG_H=.tmpconfig.h
1090
1091         echo "#" >$CONFIG
1092         echo "# Automatically generated by make menuconfig: don't edit" >>$CONFIG
1093         echo "#" >>$CONFIG
1094
1095         echo "/*" >$CONFIG_H
1096         echo " * Automatically generated by make menuconfig: don't edit" >>$CONFIG_H
1097         echo " */" >>$CONFIG_H
1098         echo "#define AUTOCONF_INCLUDED" >> $CONFIG_H
1099
1100         echo -n "."
1101         if . $CONFIG_IN >>.menuconfig.log 2>&1
1102         then
1103                 if [ "$DEF_CONFIG" = ".config" ]
1104                 then
1105                         mv $CONFIG_H $DEF_CONFIG_H
1106                 fi
1107
1108                 if [ -f "$DEF_CONFIG" ]
1109                 then
1110                         rm -f ${DEF_CONFIG}.old
1111                         mv $DEF_CONFIG ${DEF_CONFIG}.old
1112                 fi
1113
1114                 mv $CONFIG $DEF_CONFIG
1115                         
1116                 return 0
1117         else
1118                 return 1
1119         fi
1120 }
1121
1122 #
1123 # Remove temporary files
1124 #
1125 cleanup () {
1126         cleanup1
1127         cleanup2
1128 }
1129
1130 cleanup1 () {
1131         rm -f MCmenu* MCradiolists MCdialog.out help.out
1132 }
1133
1134 cleanup2 () {
1135         rm -f .tmpconfig .tmpconfig.h
1136 }
1137
1138 set_geometry () {
1139         # Some distributions export these with incorrect values
1140         # which can really screw up some ncurses programs.
1141         LINES=  COLUMNS=
1142
1143         ROWS=${1:-24}  COLS=${2:-80} 
1144
1145         # Just in case the nasty rlogin bug returns.
1146         #
1147         [ $ROWS = 0 ] && ROWS=24
1148         [ $COLS = 0 ] && COLS=80
1149
1150         if [ $ROWS -lt 19 -o $COLS -lt 80 ]
1151         then
1152                 echo -e "\n\007Your display is too small to run Menuconfig!"
1153                 echo "It must be at least 19 lines by 80 columns."
1154                 exit 1
1155         fi 
1156
1157         ROWS=$((ROWS-4))  COLS=$((COLS-5))
1158 }
1159
1160
1161 set_geometry `stty size 2>/dev/null`
1162
1163 menu_instructions="\
1164 Enabling options will increase the size of busybox.  \
1165 Arrow keys navigate the menu.  \
1166 Pressing <Enter> selects submenus --->.  \
1167 Highlighted letters are hotkeys.  \
1168 Pressing <Y> includes, and <N> excludes.  \
1169 Press <Esc><Esc> to exit, <?> for Help.  \
1170 Legend: [*] built-in  [ ] excluded"
1171
1172
1173 radiolist_instructions="\
1174 Use the arrow keys to navigate this window or \
1175 press the hotkey of the item you wish to select \
1176 followed by the <SPACE BAR>.
1177 Press <?> for additional information about this option."
1178
1179 inputbox_instructions_int="\
1180 Please enter a decimal value. \
1181 Fractions will not be accepted.  \
1182 Use the <TAB> key to move from the input field to the buttons below it."
1183
1184 inputbox_instructions_hex="\
1185 Please enter a hexadecimal value. \
1186 Use the <TAB> key to move from the input field to the buttons below it."
1187
1188 inputbox_instructions_string="\
1189 Please enter a string value. \
1190 Use the <TAB> key to move from the input field to the buttons below it."
1191
1192 DIALOG="./scripts/lxdialog/lxdialog"
1193
1194 bb_version="${VERSION}"
1195 backtitle="BusyBox v$bb_version Configuration"
1196
1197 trap "cleanup ; exit 1" 1 2 15
1198
1199
1200 #
1201 # Locate default files.
1202 #
1203 CONFIG_IN=./config.in
1204 if [ "$1" != "" ] ; then
1205         CONFIG_IN=$1
1206 fi
1207
1208 DEFAULTS=sysdeps/$TARGET_OS/defconfig
1209 if [ -f .config ]; then
1210   DEFAULTS=.config
1211 fi
1212
1213 if [ -f $DEFAULTS ]
1214 then
1215   echo "Using defaults found in" $DEFAULTS
1216   load_config_file $DEFAULTS
1217 else
1218   echo "No defaults found"
1219 fi
1220
1221
1222 # Fresh new log.
1223 >.menuconfig.log
1224
1225 # Load the functions used by the config.in files.
1226 echo -n "Preparing scripts: functions" 
1227 load_functions
1228
1229 if [ ! -e $CONFIG_IN ]
1230 then
1231         echo "Your main config.in file ($CONFIG_IN) does not exist"
1232         exit 1
1233 fi
1234
1235 if [ ! -x $DIALOG ]
1236 then
1237         echo "Your lxdialog utility does not exist"
1238         exit 1
1239 fi
1240
1241 #
1242 # Read config.in files and parse them into one shell function per menu.
1243 #
1244 echo -n ", parsing"
1245 parse_config_files $CONFIG_IN
1246
1247 echo "done."
1248 #
1249 # Start the ball rolling from the top.
1250 #
1251 activate_menu MCmenu0
1252
1253 #
1254 # All done!
1255 #
1256 cleanup1
1257
1258 #
1259 # Confirm and Save
1260 #
1261 if $DIALOG --backtitle "$backtitle" \
1262            --yesno "Do you wish to save your new BusyBox configuration?" 5 60
1263 then
1264         save_configuration
1265         echo
1266         echo
1267         echo "*** End of BusyBox configuration."
1268         echo "*** Check the top-level Makefile for additional configuration."
1269         if [ ! -f .hdepend ] ; then
1270             echo "*** Next, you must run 'make dep'."
1271         else
1272             echo "*** Next, you should run 'make' or 'make install'."
1273         fi
1274         echo
1275 else
1276         echo
1277         echo 
1278         echo Your BusyBox configuration changes were NOT saved.
1279         echo
1280 fi
1281
1282 # Remove log if empty.
1283 if [ ! -s .menuconfig.log ] ; then
1284         rm -f .menuconfig.log
1285 fi
1286
1287 exit 0