summaryrefslogtreecommitdiffstats
path: root/sys/boot/forth/menu.4th
diff options
context:
space:
mode:
Diffstat (limited to 'sys/boot/forth/menu.4th')
-rw-r--r--sys/boot/forth/menu.4th971
1 files changed, 971 insertions, 0 deletions
diff --git a/sys/boot/forth/menu.4th b/sys/boot/forth/menu.4th
new file mode 100644
index 0000000..110ec1c
--- /dev/null
+++ b/sys/boot/forth/menu.4th
@@ -0,0 +1,971 @@
+\ Copyright (c) 2003 Scott Long <scottl@freebsd.org>
+\ Copyright (c) 2003 Aleksander Fafula <alex@fafula.com>
+\ Copyright (c) 2006-2011 Devin Teske <devinteske@hotmail.com>
+\ All rights reserved.
+\
+\ Redistribution and use in source and binary forms, with or without
+\ modification, are permitted provided that the following conditions
+\ are met:
+\ 1. Redistributions of source code must retain the above copyright
+\ notice, this list of conditions and the following disclaimer.
+\ 2. Redistributions in binary form must reproduce the above copyright
+\ notice, this list of conditions and the following disclaimer in the
+\ documentation and/or other materials provided with the distribution.
+\
+\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+\ SUCH DAMAGE.
+\
+\ $FreeBSD$
+
+marker task-menu.4th
+
+\ Frame drawing
+include /boot/frames.4th
+
+f_double \ Set frames to double (see frames.4th). Replace with
+ \ f_single if you want single frames.
+46 constant dot \ ASCII definition of a period (in decimal)
+
+ 4 constant menu_timeout_default_x \ default column position of timeout
+23 constant menu_timeout_default_y \ default row position of timeout msg
+10 constant menu_timeout_default \ default timeout (in seconds)
+
+\ Customize the following values with care
+
+ 1 constant menu_start \ Numerical prefix of first menu item
+dot constant bullet \ Menu bullet (appears after numerical prefix)
+ 5 constant menu_x \ Row position of the menu (from the top)
+ 10 constant menu_y \ Column position of the menu (from left side)
+
+\ Menu Appearance
+variable menuidx \ Menu item stack for number prefixes
+variable menurow \ Menu item stack for positioning
+variable menubllt \ Menu item bullet
+
+\ Menu Positioning
+variable menuX \ Menu X offset (columns)
+variable menuY \ Menu Y offset (rows)
+
+\ Menu-item key association/detection
+variable menukey1
+variable menukey2
+variable menukey3
+variable menukey4
+variable menukey5
+variable menukey6
+variable menukey7
+variable menukey8
+variable menureboot
+variable menurebootadded
+variable menuacpi
+variable menuoptions
+
+\ Menu timer [count-down] variables
+variable menu_timeout_enabled \ timeout state (internal use only)
+variable menu_time \ variable for tracking the passage of time
+variable menu_timeout \ determined configurable delay duration
+variable menu_timeout_x \ column position of timeout message
+variable menu_timeout_y \ row position of timeout message
+
+\ Boolean option status variables
+variable toggle_state1
+variable toggle_state2
+variable toggle_state3
+variable toggle_state4
+variable toggle_state5
+variable toggle_state6
+variable toggle_state7
+variable toggle_state8
+
+\ Array option status variables
+variable cycle_state1
+variable cycle_state2
+variable cycle_state3
+variable cycle_state4
+variable cycle_state5
+variable cycle_state6
+variable cycle_state7
+variable cycle_state8
+
+\ Containers for storing the initial caption text
+create init_text1 255 allot
+create init_text2 255 allot
+create init_text3 255 allot
+create init_text4 255 allot
+create init_text5 255 allot
+create init_text6 255 allot
+create init_text7 255 allot
+create init_text8 255 allot
+
+: arch-i386? ( -- BOOL ) \ Returns TRUE (-1) on i386, FALSE (0) otherwise.
+ s" arch-i386" environment? dup if
+ drop
+ then
+;
+
+\ This function prints a menu item at menuX (row) and menuY (column), returns
+\ the incremental decimal ASCII value associated with the menu item, and
+\ increments the cursor position to the next row for the creation of the next
+\ menu item. This function is called by the menu-create function. You need not
+\ call it directly.
+\
+: printmenuitem ( menu_item_str -- ascii_keycode )
+
+ menurow dup @ 1+ swap ! ( increment menurow )
+ menuidx dup @ 1+ swap ! ( increment menuidx )
+
+ \ Calculate the menuitem row position
+ menurow @ menuY @ +
+
+ \ Position the cursor at the menuitem position
+ dup menuX @ swap at-xy
+
+ \ Print the value of menuidx
+ loader_color? if
+ ." "
+ then
+ menuidx @ .
+ loader_color? if
+ ." "
+ then
+
+ \ Move the cursor forward 1 column
+ dup menuX @ 1+ swap at-xy
+
+ menubllt @ emit \ Print the menu bullet using the emit function
+
+ \ Move the cursor to the 3rd column from the current position
+ \ to allow for a space between the numerical prefix and the
+ \ text caption
+ menuX @ 3 + swap at-xy
+
+ \ Print the menu caption (we expect a string to be on the stack
+ \ prior to invoking this function)
+ type
+
+ \ Here we will add the ASCII decimal of the numerical prefix
+ \ to the stack (decimal ASCII for `1' is 49) as a "return value"
+ menuidx @ 48 +
+;
+
+: toggle_menuitem ( N -- N ) \ toggles caption text and internal menuitem state
+
+ \ ASCII numeral equal to user-selected menu item must be on the stack.
+ \ We do not modify the stack, so the ASCII numeral is left on top.
+
+ s" init_textN" \ base name of buffer
+ -rot 2dup 9 + c! rot \ replace 'N' with ASCII num
+
+ evaluate c@ 0= if
+ \ NOTE: no need to check toggle_stateN since the first time we
+ \ are called, we will populate init_textN. Further, we don't
+ \ need to test whether menu_caption[x] (ansi_caption[x] when
+ \ loader_color=1) is available since we would not have been
+ \ called if the caption was NULL.
+
+ \ base name of environment variable
+ loader_color? if
+ s" ansi_caption[x]"
+ else
+ s" menu_caption[x]"
+ then
+ -rot 2dup 13 + c! rot \ replace 'x' with ASCII numeral
+
+ getenv dup -1 <> if
+
+ s" init_textN" \ base name of buffer
+ 4 pick \ copy ASCII num to top
+ rot tuck 9 + c! swap \ replace 'N' with ASCII num
+ evaluate
+
+ \ now we have the buffer c-addr on top
+ \ ( followed by c-addr/u of current caption )
+
+ \ Copy the current caption into our buffer
+ 2dup c! -rot \ store strlen at first byte
+ begin
+ rot 1+ \ bring alt addr to top and increment
+ -rot -rot \ bring buffer addr to top
+ 2dup c@ swap c! \ copy current character
+ 1+ \ increment buffer addr
+ rot 1- \ bring buffer len to top and decrement
+ dup 0= \ exit loop if buffer len is zero
+ until
+ 2drop \ buffer len/addr
+ drop \ alt addr
+
+ else
+ drop
+ then
+ then
+
+ \ Now we are certain to have init_textN populated with the initial
+ \ value of menu_caption[x] (ansi_caption[x] with loader_color enabled).
+ \ We can now use init_textN as the untoggled caption and
+ \ toggled_text[x] (toggled_ansi[x] with loader_color enabled) as the
+ \ toggled caption and store the appropriate value into menu_caption[x]
+ \ (again, ansi_caption[x] with loader_color enabled). Last, we'll
+ \ negate the toggled state so that we reverse the flow on subsequent
+ \ calls.
+
+ s" toggle_stateN @" \ base name of toggle state var
+ -rot 2dup 12 + c! rot \ replace 'N' with ASCII numeral
+
+ evaluate 0= if
+ \ state is OFF, toggle to ON
+
+ \ base name of toggled text var
+ loader_color? if
+ s" toggled_ansi[x]"
+ else
+ s" toggled_text[x]"
+ then
+ -rot 2dup 13 + c! rot \ replace 'x' with ASCII num
+
+ getenv dup -1 <> if
+ \ Assign toggled text to menu caption
+
+ \ base name of caption var
+ loader_color? if
+ s" ansi_caption[x]"
+ else
+ s" menu_caption[x]"
+ then
+ 4 pick \ copy ASCII num to top
+ rot tuck 13 + c! swap \ replace 'x' with ASCII num
+
+ setenv \ set new caption
+ else
+ \ No toggled text, keep the same caption
+
+ drop
+ then
+
+ true \ new value of toggle state var (to be stored later)
+ else
+ \ state is ON, toggle to OFF
+
+ s" init_textN" \ base name of initial text buffer
+ -rot 2dup 9 + c! rot \ replace 'N' with ASCII numeral
+ evaluate \ convert string to c-addr
+ count \ convert c-addr to c-addr/u
+
+ \ base name of caption var
+ loader_color? if
+ s" ansi_caption[x]"
+ else
+ s" menu_caption[x]"
+ then
+ 4 pick \ copy ASCII num to top
+ rot tuck 13 + c! swap \ replace 'x' with ASCII numeral
+
+ setenv \ set new caption
+ false \ new value of toggle state var (to be stored below)
+ then
+
+ \ now we'll store the new toggle state (on top of stack)
+ s" toggle_stateN" \ base name of toggle state var
+ 3 pick \ copy ASCII numeral to top
+ rot tuck 12 + c! swap \ replace 'N' with ASCII numeral
+ evaluate \ convert string to addr
+ ! \ store new value
+;
+
+: cycle_menuitem ( N -- N ) \ cycles through array of choices for a menuitem
+
+ \ ASCII numeral equal to user-selected menu item must be on the stack.
+ \ We do not modify the stack, so the ASCII numeral is left on top.
+
+ s" cycle_stateN" \ base name of array state var
+ -rot 2dup 11 + c! rot \ replace 'N' with ASCII numeral
+
+ evaluate \ we now have a pointer to the proper variable
+ dup @ \ resolve the pointer (but leave it on the stack)
+ 1+ \ increment the value
+
+ \ Before assigning the (incremented) value back to the pointer,
+ \ let's test for the existence of this particular array element.
+ \ If the element exists, we'll store index value and move on.
+ \ Otherwise, we'll loop around to zero and store that.
+
+ dup 48 + \ duplicate Array index and convert to ASCII numeral
+
+ \ base name of array caption text
+ loader_color? if
+ s" ansi_caption[x][y]"
+ else
+ s" menu_caption[x][y]"
+ then
+ -rot tuck 16 + c! swap \ replace 'y' with Array index
+ 4 pick rot tuck 13 + c! swap \ replace 'x' with menu choice
+
+ \ Now test for the existence of our incremented array index in the
+ \ form of $menu_caption[x][y] ($ansi_caption[x][y] with loader_color
+ \ enabled) as set in loader.rc(5), et. al.
+
+ getenv dup -1 = if
+ \ No caption set for this array index. Loop back to zero.
+
+ drop ( getenv cruft )
+ drop ( incremented array index )
+ 0 ( new array index that will be stored later )
+
+ \ base name of caption var
+ loader_color? if
+ s" ansi_caption[x][0]"
+ else
+ s" menu_caption[x][0]"
+ then
+ 4 pick rot tuck 13 + c! swap \ replace 'x' with menu choice
+
+ getenv dup -1 = if
+ \ This is highly unlikely to occur, but to make
+ \ sure that things move along smoothly, allocate
+ \ a temporary NULL string
+
+ s" "
+ then
+ then
+
+ \ At this point, we should have the following on the stack (in order,
+ \ from bottom to top):
+ \
+ \ N - Ascii numeral representing the menu choice (inherited)
+ \ Addr - address of our internal cycle_stateN variable
+ \ N - zero-based number we intend to store to the above
+ \ C-Addr - string value we intend to store to menu_caption[x]
+ \ (or ansi_caption[x] with loader_color enabled)
+ \
+ \ Let's perform what we need to with the above.
+
+ \ base name of menuitem caption var
+ loader_color? if
+ s" ansi_caption[x]"
+ else
+ s" menu_caption[x]"
+ then
+ 6 pick rot tuck 13 + c! swap \ replace 'x' with menu choice
+ setenv \ set the new caption
+
+ swap ! \ update array state variable
+;
+
+: acpipresent? ( -- flag ) \ Returns TRUE if ACPI is present, FALSE otherwise
+ s" hint.acpi.0.rsdp" getenv
+ dup -1 = if
+ drop false exit
+ then
+ 2drop
+ true
+;
+
+: acpienabled? ( -- flag ) \ Returns TRUE if ACPI is enabled, FALSE otherwise
+ s" hint.acpi.0.disabled" getenv
+ dup -1 <> if
+ s" 0" compare 0<> if
+ false exit
+ then
+ else
+ drop
+ then
+ true
+;
+
+\ This function prints the appropriate menuitem basename to the stack if an
+\ ACPI option is to be presented to the user, otherwise returns -1. Used
+\ internally by menu-create, you need not (nor should you) call this directly.
+\
+: acpimenuitem ( -- C-Addr | -1 )
+
+ arch-i386? if
+ acpipresent? if
+ acpienabled? if
+ loader_color? if
+ s" toggled_ansi[x]"
+ else
+ s" toggled_text[x]"
+ then
+ else
+ loader_color? if
+ s" ansi_caption[x]"
+ else
+ s" menu_caption[x]"
+ then
+ then
+ else
+ menuidx dup @ 1+ swap ! ( increment menuidx )
+ -1
+ then
+ else
+ -1
+ then
+;
+
+\ This function creates the list of menu items. This function is called by the
+\ menu-display function. You need not be call it directly.
+\
+: menu-create ( -- )
+
+ \ Print the frame caption at (x,y)
+ s" loader_menu_title" getenv dup -1 = if
+ drop s" Welcome to FreeBSD"
+ then
+ 24 over 2 / - 9 at-xy type
+
+ \ Print our menu options with respective key/variable associations.
+ \ `printmenuitem' ends by adding the decimal ASCII value for the
+ \ numerical prefix to the stack. We store the value left on the stack
+ \ to the key binding variable for later testing against a character
+ \ captured by the `getkey' function.
+
+ \ Note that any menu item beyond 9 will have a numerical prefix on the
+ \ screen consisting of the first digit (ie. 1 for the tenth menu item)
+ \ and the key required to activate that menu item will be the decimal
+ \ ASCII of 48 plus the menu item (ie. 58 for the tenth item, aka. `:')
+ \ which is misleading and not desirable.
+ \
+ \ Thus, we do not allow more than 8 configurable items on the menu
+ \ (with "Reboot" as the optional ninth and highest numbered item).
+
+ \
+ \ Initialize the ACPI option status.
+ \
+ 0 menuacpi !
+ s" menu_acpi" getenv -1 <> if
+ c@ dup 48 > over 57 < and if ( '1' <= c1 <= '8' )
+ menuacpi !
+ arch-i386? if acpipresent? if
+ \
+ \ Set menu toggle state to active state
+ \ (required by generic toggle_menuitem)
+ \
+ menuacpi @
+ s" acpienabled? toggle_stateN !"
+ -rot tuck 25 + c! swap
+ evaluate
+ then then
+ else
+ drop
+ then
+ then
+
+ \
+ \ Initialize the menu_options visual separator.
+ \
+ 0 menuoptions !
+ s" menu_options" getenv -1 <> if
+ c@ dup 48 > over 57 < and if ( '1' <= c1 <= '8' )
+ menuoptions !
+ else
+ drop
+ then
+ then
+
+ \ Initialize "Reboot" menu state variable (prevents double-entry)
+ false menurebootadded !
+
+ 49 \ Iterator start (loop range 49 to 56; ASCII '1' to '8')
+ begin
+ \ If the "Options:" separator, print it.
+ dup menuoptions @ = if
+ \ Optionally add a reboot option to the menu
+ s" menu_reboot" getenv -1 <> if
+ drop
+ s" Reboot" printmenuitem menureboot !
+ true menurebootadded !
+ then
+
+ menuX @
+ menurow @ 2 + menurow !
+ menurow @ menuY @ +
+ at-xy
+ ." Options:"
+ then
+
+ \ If this is the ACPI menu option, act accordingly.
+ dup menuacpi @ = if
+ acpimenuitem ( -- C-Addr | -1 )
+ else
+ loader_color? if
+ s" ansi_caption[x]"
+ else
+ s" menu_caption[x]"
+ then
+ then
+
+ ( C-Addr | -1 )
+ dup -1 <> if
+ \ replace 'x' with current iteration
+ -rot 2dup 13 + c! rot
+
+ \ test for environment variable
+ getenv dup -1 <> if
+ printmenuitem ( C-Addr -- N )
+
+ s" menukeyN !" \ generate cmd to store result
+ -rot 2dup 7 + c! rot
+
+ evaluate
+ else
+ drop
+ then
+ else
+ drop
+
+ s" menu_command[x]"
+ -rot 2dup 13 + c! rot ( replace 'x' )
+ unsetenv
+ then
+
+ 1+ dup 56 > \ add 1 to iterator, continue if less than 57
+ until
+ drop \ iterator
+
+ \ Optionally add a reboot option to the menu
+ menurebootadded @ true <> if
+ s" menu_reboot" getenv -1 <> if
+ drop \ no need for the value
+ s" Reboot" \ menu caption (required by printmenuitem)
+
+ printmenuitem
+ menureboot !
+ else
+ 0 menureboot !
+ then
+ then
+;
+
+\ Takes a single integer on the stack and updates the timeout display. The
+\ integer must be between 0 and 9 (we will only update a single digit in the
+\ source message).
+\
+: menu-timeout-update ( N -- )
+
+ dup 9 > if ( N N 9 -- N )
+ drop ( N -- )
+ 9 ( maximum: -- N )
+ then
+
+ dup 0 < if ( N N 0 -- N )
+ drop ( N -- )
+ 0 ( minimum: -- N )
+ then
+
+ 48 + ( convert single-digit numeral to ASCII: N 48 -- N )
+
+ s" Autoboot in N seconds. [Space] to pause" ( N -- N Addr C )
+
+ 2 pick 48 - 0> if ( N Addr C N 48 -- N Addr C )
+
+ \ Modify 'N' (Addr+12) above to reflect time-left
+
+ -rot ( N Addr C -- C N Addr )
+ tuck ( C N Addr -- C Addr N Addr )
+ 12 + ( C Addr N Addr -- C Addr N Addr2 )
+ c! ( C Addr N Addr2 -- C Addr )
+ swap ( C Addr -- Addr C )
+
+ menu_timeout_x @
+ menu_timeout_y @
+ at-xy ( position cursor: Addr C N N -- Addr C )
+
+ type ( print message: Addr C -- )
+
+ else ( N Addr C N -- N Addr C )
+
+ menu_timeout_x @
+ menu_timeout_y @
+ at-xy ( position cursor: N Addr C N N -- N Addr C )
+
+ spaces ( erase message: N Addr C -- N Addr )
+ 2drop ( N Addr -- )
+
+ then
+
+ 0 25 at-xy ( position cursor back at bottom-left )
+;
+
+\ This function blocks program flow (loops forever) until a key is pressed.
+\ The key that was pressed is added to the top of the stack in the form of its
+\ decimal ASCII representation. This function is called by the menu-display
+\ function. You need not call it directly.
+\
+: getkey ( -- ascii_keycode )
+
+ begin \ loop forever
+
+ menu_timeout_enabled @ 1 = if
+ ( -- )
+ seconds ( get current time: -- N )
+ dup menu_time @ <> if ( has time elapsed?: N N N -- N )
+
+ \ At least 1 second has elapsed since last loop
+ \ so we will decrement our "timeout" (really a
+ \ counter, insuring that we do not proceed too
+ \ fast) and update our timeout display.
+
+ menu_time ! ( update time record: N -- )
+ menu_timeout @ ( "time" remaining: -- N )
+ dup 0> if ( greater than 0?: N N 0 -- N )
+ 1- ( decrement counter: N -- N )
+ dup menu_timeout !
+ ( re-assign: N N Addr -- N )
+ then
+ ( -- N )
+
+ dup 0= swap 0< or if ( N <= 0?: N N -- )
+ \ halt the timer
+ 0 menu_timeout ! ( 0 Addr -- )
+ 0 menu_timeout_enabled ! ( 0 Addr -- )
+ then
+
+ \ update the timer display ( N -- )
+ menu_timeout @ menu-timeout-update
+
+ menu_timeout @ 0= if
+ \ We've reached the end of the timeout
+ \ (user did not cancel by pressing ANY
+ \ key)
+
+ s" menu_timeout_command" getenv dup
+ -1 = if
+ drop \ clean-up
+ else
+ evaluate
+ then
+ then
+
+ else ( -- N )
+ \ No [detectable] time has elapsed (in seconds)
+ drop ( N -- )
+ then
+ ( -- )
+ then
+
+ key? if \ Was a key pressed? (see loader(8))
+
+ \ An actual key was pressed (if the timeout is running,
+ \ kill it regardless of which key was pressed)
+ menu_timeout @ 0<> if
+ 0 menu_timeout !
+ 0 menu_timeout_enabled !
+
+ \ clear screen of timeout message
+ 0 menu-timeout-update
+ then
+
+ \ get the key that was pressed and exit (if we
+ \ get a non-zero ASCII code)
+ key dup 0<> if
+ exit
+ else
+ drop
+ then
+ then
+ 50 ms \ sleep for 50 milliseconds (see loader(8))
+
+ again
+;
+
+: menu-erase ( -- ) \ Erases menu and resets positioning variable to positon 1.
+
+ \ Clear the screen area associated with the interactive menu
+ menuX @ menuY @
+ 2dup at-xy 38 spaces 1+ 2dup at-xy 38 spaces 1+
+ 2dup at-xy 38 spaces 1+ 2dup at-xy 38 spaces 1+
+ 2dup at-xy 38 spaces 1+ 2dup at-xy 38 spaces 1+
+ 2dup at-xy 38 spaces 1+ 2dup at-xy 38 spaces 1+
+ 2dup at-xy 38 spaces 1+ 2dup at-xy 38 spaces 1+
+ 2dup at-xy 38 spaces 1+ 2dup at-xy 38 spaces
+ 2drop
+
+ \ Reset the starting index and position for the menu
+ menu_start 1- menuidx !
+ 0 menurow !
+;
+
+\ Erase and redraw the menu. Useful if you change a caption and want to
+\ update the menu to reflect the new value.
+\
+: menu-redraw ( -- )
+ menu-erase
+ menu-create
+;
+
+\ This function initializes the menu. Call this from your `loader.rc' file
+\ before calling any other menu-related functions.
+\
+: menu-init ( -- )
+ menu_start
+ 1- menuidx ! \ Initialize the starting index for the menu
+ 0 menurow ! \ Initialize the starting position for the menu
+ 42 13 2 9 box \ Draw frame (w,h,x,y)
+ 0 25 at-xy \ Move cursor to the bottom for output
+;
+
+\ Main function. Call this from your `loader.rc' file.
+\
+: menu-display ( -- )
+
+ 0 menu_timeout_enabled ! \ start with automatic timeout disabled
+
+ \ check indication that automatic execution after delay is requested
+ s" menu_timeout_command" getenv -1 <> if ( Addr C -1 -- | Addr )
+ drop ( just testing existence right now: Addr -- )
+
+ \ initialize state variables
+ seconds menu_time ! ( store the time we started )
+ 1 menu_timeout_enabled ! ( enable automatic timeout )
+
+ \ read custom time-duration (if set)
+ s" autoboot_delay" getenv dup -1 = if
+ drop \ no custom duration (remove dup'd bunk -1)
+ menu_timeout_default \ use default setting
+ else
+ 2dup ?number 0= if ( if not a number )
+ \ disable timeout if "NO", else use default
+ s" NO" compare-insensitive 0= if
+ 0 menu_timeout_enabled !
+ 0 ( assigned to menu_timeout below )
+ else
+ menu_timeout_default
+ then
+ else
+ -rot 2drop
+
+ \ disable timeout if less than zero
+ dup 0< if
+ drop
+ 0 menu_timeout_enabled !
+ 0 ( assigned to menu_timeout below )
+ then
+ then
+ then
+ menu_timeout ! ( store value on stack from above )
+
+ menu_timeout_enabled @ 1 = if
+ \ read custom column position (if set)
+ s" loader_menu_timeout_x" getenv dup -1 = if
+ drop \ no custom column position
+ menu_timeout_default_x \ use default setting
+ else
+ \ make sure custom position is a number
+ ?number 0= if
+ menu_timeout_default_x \ or use default
+ then
+ then
+ menu_timeout_x ! ( store value on stack from above )
+
+ \ read custom row position (if set)
+ s" loader_menu_timeout_y" getenv dup -1 = if
+ drop \ no custom row position
+ menu_timeout_default_y \ use default setting
+ else
+ \ make sure custom position is a number
+ ?number 0= if
+ menu_timeout_default_y \ or use default
+ then
+ then
+ menu_timeout_y ! ( store value on stack from above )
+ then
+ then
+
+ menu-create
+
+ begin \ Loop forever
+
+ 0 25 at-xy \ Move cursor to the bottom for output
+ getkey \ Block here, waiting for a key to be pressed
+
+ dup -1 = if
+ drop exit \ Caught abort (abnormal return)
+ then
+
+ \ Boot if the user pressed Enter/Ctrl-M (13) or
+ \ Ctrl-Enter/Ctrl-J (10)
+ dup over 13 = swap 10 = or if
+ drop ( no longer needed )
+ s" boot" evaluate
+ exit ( pedantic; never reached )
+ then
+
+ \ Evaluate the decimal ASCII value against known menu item
+ \ key associations and act accordingly
+
+ 49 \ Iterator start (loop range 49 to 56; ASCII '1' to '8')
+ begin
+ s" menukeyN @"
+
+ \ replace 'N' with current iteration
+ -rot 2dup 7 + c! rot
+
+ evaluate rot tuck = if
+
+ \ Adjust for missing ACPI menuitem on non-i386
+ arch-i386? true <> menuacpi @ 0<> and if
+ menuacpi @ over 2dup < -rot = or
+ over 58 < and if
+ ( key >= menuacpi && key < 58: N -- N )
+ 1+
+ then
+ then
+
+ \ base env name for the value (x is a number)
+ s" menu_command[x]"
+
+ \ Copy ASCII number to string at offset 13
+ -rot 2dup 13 + c! rot
+
+ \ Test for the environment variable
+ getenv dup -1 <> if
+ \ Execute the stored procedure
+ evaluate
+
+ \ We expect there to be a non-zero
+ \ value left on the stack after
+ \ executing the stored procedure.
+ \ If so, continue to run, else exit.
+
+ 0= if
+ drop \ key pressed
+ drop \ loop iterator
+ exit
+ else
+ swap \ need iterator on top
+ then
+ then
+
+ \ Re-adjust for missing ACPI menuitem
+ arch-i386? true <> menuacpi @ 0<> and if
+ swap
+ menuacpi @ 1+ over 2dup < -rot = or
+ over 59 < and if
+ 1-
+ then
+ swap
+ then
+ else
+ swap \ need iterator on top
+ then
+
+ \
+ \ Check for menu keycode shortcut(s)
+ \
+ s" menu_keycode[x]"
+ -rot 2dup 13 + c! rot
+ getenv dup -1 = if
+ drop
+ else
+ ?number 0<> if
+ rot tuck = if
+ swap
+ s" menu_command[x]"
+ -rot 2dup 13 + c! rot
+ getenv dup -1 <> if
+ evaluate
+ 0= if
+ 2drop
+ exit
+ then
+ else
+ drop
+ then
+ else
+ swap
+ then
+ then
+ then
+
+ 1+ dup 56 > \ increment iterator
+ \ continue if less than 57
+ until
+ drop \ loop iterator
+
+ menureboot @ = if 0 reboot then
+
+ again \ Non-operational key was pressed; repeat
+;
+
+\ This function unsets all the possible environment variables associated with
+\ creating the interactive menu. Call this when you want to clear the menu
+\ area in preparation for another menu.
+\
+: menu-clear ( -- )
+
+ 49 \ Iterator start (loop range 49 to 56; ASCII '1' to '8')
+ begin
+ \ basename for caption variable
+ loader_color? if
+ s" ansi_caption[x]"
+ else
+ s" menu_caption[x]"
+ then
+ -rot 2dup 13 + c! rot \ replace 'x' with current iteration
+ unsetenv \ not erroneous to unset unknown var
+
+ s" 0 menukeyN !" \ basename for key association var
+ -rot 2dup 9 + c! rot \ replace 'N' with current iteration
+ evaluate \ assign zero (0) to key assoc. var
+
+ 1+ dup 56 > \ increment, continue if less than 57
+ until
+ drop \ iterator
+
+ \ clear the "Reboot" menu option flag
+ s" menu_reboot" unsetenv
+ 0 menureboot !
+
+ \ clear the ACPI menu option flag
+ s" menu_acpi" unsetenv
+ 0 menuacpi !
+
+ \ clear the "Options" menu separator flag
+ s" menu_options" unsetenv
+ 0 menuoptions !
+
+ menu-erase
+;
+
+\ Assign configuration values
+bullet menubllt !
+10 menuY !
+5 menuX !
+
+\ Initialize our boolean state variables
+0 toggle_state1 !
+0 toggle_state2 !
+0 toggle_state3 !
+0 toggle_state4 !
+0 toggle_state5 !
+0 toggle_state6 !
+0 toggle_state7 !
+0 toggle_state8 !
+
+\ Initialize our array state variables
+0 cycle_state1 !
+0 cycle_state2 !
+0 cycle_state3 !
+0 cycle_state4 !
+0 cycle_state5 !
+0 cycle_state6 !
+0 cycle_state7 !
+0 cycle_state8 !
+
+\ Initialize string containers
+0 init_text1 c!
+0 init_text2 c!
+0 init_text3 c!
+0 init_text4 c!
+0 init_text5 c!
+0 init_text6 c!
+0 init_text7 c!
+0 init_text8 c!
OpenPOWER on IntegriCloud