Current Path : /boot/ |
FreeBSD hs32.drive.ne.jp 9.1-RELEASE FreeBSD 9.1-RELEASE #1: Wed Jan 14 12:18:08 JST 2015 root@hs32.drive.ne.jp:/sys/amd64/compile/hs32 amd64 |
Current File : //boot/menu.4th |
\ 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: release/9.1.0/sys/boot/forth/menu.4th 230219 2012-01-16 14:55:42Z pluknet $ 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 ." [1m" ( [22m ) then menuidx @ . loader_color? if ." [37m" ( [39m ) 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 \ boot immediately if less than zero dup 0< if drop menu-create 0 25 at-xy 0 boot 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. \ : menu-unset ( -- ) 49 \ Iterator start (loop range 49 to 56; ASCII '1' to '8') begin \ Unset variables in-order of appearance in menu.4th(8) s" menu_caption[x]" \ basename for caption variable -rot 2dup 13 + c! rot \ replace 'x' with current iteration unsetenv \ not erroneous to unset unknown var s" menu_command[x]" \ command basename -rot 2dup 13 + c! rot \ replace 'x' unsetenv s" menu_keycode[x]" \ keycode basename -rot 2dup 13 + c! rot \ replace 'x' unsetenv s" ansi_caption[x]" \ ANSI caption basename -rot 2dup 13 + c! rot \ replace 'x' unsetenv s" toggled_text[x]" \ toggle_menuitem caption basename -rot 2dup 13 + c! rot \ replace 'x' unsetenv s" toggled_ansi[x]" \ toggle_menuitem ANSI caption basename -rot 2dup 13 + c! rot \ replace 'x' unsetenv s" menu_caption[x][y]" \ cycle_menuitem caption -rot 2dup 13 + c! rot \ replace 'x' 49 -rot begin 16 2over rot + c! \ replace 'y' 2dup unsetenv rot 1+ dup 56 > 2swap rot until 2drop drop s" ansi_caption[x][y]" \ cycle_menuitem ANSI caption -rot 2dup 13 + c! rot \ replace 'x' 49 -rot begin 16 2over rot + c! \ replace 'y' 2dup unsetenv rot 1+ dup 56 > 2swap rot until 2drop drop 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 \ unset the timeout command s" menu_timeout_command" unsetenv \ 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 ! ; \ This function both unsets menu variables and visually erases the menu area \ in-preparation for another menu. \ : menu-clear ( -- ) menu-unset 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!