menu.4th revision 254108
1222417Sjulian\ Copyright (c) 2003 Scott Long <scottl@freebsd.org>
2222417Sjulian\ Copyright (c) 2003 Aleksander Fafula <alex@fafula.com>
3254105Sdteske\ Copyright (c) 2006-2013 Devin Teske <dteske@FreeBSD.org>
4222417Sjulian\ All rights reserved.
5222417Sjulian\ 
6222417Sjulian\ Redistribution and use in source and binary forms, with or without
7222417Sjulian\ modification, are permitted provided that the following conditions
8222417Sjulian\ are met:
9222417Sjulian\ 1. Redistributions of source code must retain the above copyright
10222417Sjulian\    notice, this list of conditions and the following disclaimer.
11222417Sjulian\ 2. Redistributions in binary form must reproduce the above copyright
12222417Sjulian\    notice, this list of conditions and the following disclaimer in the
13222417Sjulian\    documentation and/or other materials provided with the distribution.
14222417Sjulian\ 
15222417Sjulian\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16222417Sjulian\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17222417Sjulian\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18222417Sjulian\ ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19222417Sjulian\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20222417Sjulian\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21222417Sjulian\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22222417Sjulian\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23222417Sjulian\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24222417Sjulian\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25222417Sjulian\ SUCH DAMAGE.
26222417Sjulian\ 
27222417Sjulian\ $FreeBSD: head/sys/boot/forth/menu.4th 254108 2013-08-08 22:34:00Z dteske $
28222417Sjulian
29222417Sjulianmarker task-menu.4th
30222417Sjulian
31222417Sjulian\ Frame drawing
32222417Sjulianinclude /boot/frames.4th
33222417Sjulian
34222417Sjulianf_double        \ Set frames to double (see frames.4th). Replace with
35222417Sjulian                \ f_single if you want single frames.
36222417Sjulian46 constant dot \ ASCII definition of a period (in decimal)
37222417Sjulian
38254108Sdteske 5 constant menu_default_x         \ default column position of timeout
39254108Sdteske10 constant menu_default_y         \ default row position of timeout msg
40222417Sjulian 4 constant menu_timeout_default_x \ default column position of timeout
41222417Sjulian23 constant menu_timeout_default_y \ default row position of timeout msg
42222417Sjulian10 constant menu_timeout_default   \ default timeout (in seconds)
43222417Sjulian
44222417Sjulian\ Customize the following values with care
45222417Sjulian
46222417Sjulian  1 constant menu_start \ Numerical prefix of first menu item
47222417Sjuliandot constant bullet     \ Menu bullet (appears after numerical prefix)
48222417Sjulian  5 constant menu_x     \ Row position of the menu (from the top)
49222417Sjulian 10 constant menu_y     \ Column position of the menu (from left side)
50222417Sjulian
51222417Sjulian\ Menu Appearance
52222417Sjulianvariable menuidx   \ Menu item stack for number prefixes
53222417Sjulianvariable menurow   \ Menu item stack for positioning
54222417Sjulianvariable menubllt  \ Menu item bullet
55222417Sjulian
56222417Sjulian\ Menu Positioning
57222417Sjulianvariable menuX     \ Menu X offset (columns)
58222417Sjulianvariable menuY     \ Menu Y offset (rows)
59222417Sjulian
60222417Sjulian\ Menu-item key association/detection
61222417Sjulianvariable menukey1
62222417Sjulianvariable menukey2
63222417Sjulianvariable menukey3
64222417Sjulianvariable menukey4
65222417Sjulianvariable menukey5
66222417Sjulianvariable menukey6
67222417Sjulianvariable menukey7
68222417Sjulianvariable menukey8
69222417Sjulianvariable menureboot
70222417Sjulianvariable menurebootadded
71222417Sjulianvariable menuacpi
72222417Sjulianvariable menuoptions
73222417Sjulian
74222417Sjulian\ Menu timer [count-down] variables
75222417Sjulianvariable menu_timeout_enabled \ timeout state (internal use only)
76222417Sjulianvariable menu_time            \ variable for tracking the passage of time
77222417Sjulianvariable menu_timeout         \ determined configurable delay duration
78222417Sjulianvariable menu_timeout_x       \ column position of timeout message
79222417Sjulianvariable menu_timeout_y       \ row position of timeout message
80222417Sjulian
81241523Sdteske\ Menu initialization status variables
82241523Sdteskevariable init_state1
83241523Sdteskevariable init_state2
84241523Sdteskevariable init_state3
85241523Sdteskevariable init_state4
86241523Sdteskevariable init_state5
87241523Sdteskevariable init_state6
88241523Sdteskevariable init_state7
89241523Sdteskevariable init_state8
90241523Sdteske
91222417Sjulian\ Boolean option status variables
92222417Sjulianvariable toggle_state1
93222417Sjulianvariable toggle_state2
94222417Sjulianvariable toggle_state3
95222417Sjulianvariable toggle_state4
96222417Sjulianvariable toggle_state5
97222417Sjulianvariable toggle_state6
98222417Sjulianvariable toggle_state7
99222417Sjulianvariable toggle_state8
100222417Sjulian
101222417Sjulian\ Array option status variables
102222417Sjulianvariable cycle_state1
103222417Sjulianvariable cycle_state2
104222417Sjulianvariable cycle_state3
105222417Sjulianvariable cycle_state4
106222417Sjulianvariable cycle_state5
107222417Sjulianvariable cycle_state6
108222417Sjulianvariable cycle_state7
109222417Sjulianvariable cycle_state8
110222417Sjulian
111222417Sjulian\ Containers for storing the initial caption text
112222417Sjuliancreate init_text1 255 allot
113222417Sjuliancreate init_text2 255 allot
114222417Sjuliancreate init_text3 255 allot
115222417Sjuliancreate init_text4 255 allot
116222417Sjuliancreate init_text5 255 allot
117222417Sjuliancreate init_text6 255 allot
118222417Sjuliancreate init_text7 255 allot
119222417Sjuliancreate init_text8 255 allot
120222417Sjulian
121243114Sdteske: +c! ( N C-ADDR/U K -- C-ADDR/U )
122243114Sdteske	3 pick 3 pick	( n c-addr/u k -- n c-addr/u k n c-addr )
123243114Sdteske	rot + c!	( n c-addr/u k n c-addr -- n c-addr/u )
124243114Sdteske	rot drop	( n c-addr/u -- c-addr/u )
125243114Sdteske;
126243114Sdteske
127243114Sdteske: menukeyN      ( N -- ADDR )   s" menukeyN"       7 +c! evaluate ;
128243114Sdteske: init_stateN   ( N -- ADDR )   s" init_stateN"   10 +c! evaluate ;
129243114Sdteske: toggle_stateN ( N -- ADDR )   s" toggle_stateN" 12 +c! evaluate ;
130243114Sdteske: cycle_stateN  ( N -- ADDR )   s" cycle_stateN"  11 +c! evaluate ;
131243114Sdteske: init_textN    ( N -- C-ADDR ) s" init_textN"     9 +c! evaluate ;
132243114Sdteske
133254108Sdteske: str_loader_menu_frame       ( -- C-ADDR/U ) s" loader_menu_frame" ;
134254108Sdteske: str_loader_menu_title       ( -- C-ADDR/U ) s" loader_menu_title" ;
135254108Sdteske: str_loader_menu_title_align ( -- C-ADDR/U ) s" loader_menu_title_align" ;
136254108Sdteske: str_loader_menu_x           ( -- C-ADDR/U ) s" loader_menu_x" ;
137254108Sdteske: str_loader_menu_y           ( -- C-ADDR/U ) s" loader_menu_y" ;
138254108Sdteske: str_loader_menu_timeout_x   ( -- C-ADDR/U ) s" loader_menu_timeout_x" ;
139254108Sdteske: str_loader_menu_timeout_y   ( -- C-ADDR/U ) s" loader_menu_timeout_y" ;
140254108Sdteske: str_menu_init               ( -- C-ADDR/U ) s" menu_init" ;
141254108Sdteske: str_menu_timeout_command    ( -- C-ADDR/U ) s" menu_timeout_command" ;
142254108Sdteske: str_menu_reboot             ( -- C-ADDR/U ) s" menu_reboot" ;
143254108Sdteske: str_menu_acpi               ( -- C-ADDR/U ) s" menu_acpi" ;
144254108Sdteske: str_menu_options            ( -- C-ADDR/U ) s" menu_options" ;
145254108Sdteske: str_menu_optionstext        ( -- C-ADDR/U ) s" menu_optionstext" ;
146243114Sdteske
147243114Sdteske: str_menu_init[x]          ( -- C-ADDR/U ) s" menu_init[x]" ;
148243114Sdteske: str_menu_command[x]       ( -- C-ADDR/U ) s" menu_command[x]" ;
149243114Sdteske: str_menu_caption[x]       ( -- C-ADDR/U ) s" menu_caption[x]" ;
150243114Sdteske: str_ansi_caption[x]       ( -- C-ADDR/U ) s" ansi_caption[x]" ;
151243114Sdteske: str_menu_keycode[x]       ( -- C-ADDR/U ) s" menu_keycode[x]" ;
152243114Sdteske: str_toggled_text[x]       ( -- C-ADDR/U ) s" toggled_text[x]" ;
153243114Sdteske: str_toggled_ansi[x]       ( -- C-ADDR/U ) s" toggled_ansi[x]" ;
154243114Sdteske: str_menu_caption[x][y]    ( -- C-ADDR/U ) s" menu_caption[x][y]" ;
155243114Sdteske: str_ansi_caption[x][y]    ( -- C-ADDR/U ) s" ansi_caption[x][y]" ;
156243114Sdteske
157243114Sdteske: menu_init[x]       ( N -- C-ADDR/U )   str_menu_init[x]       10 +c! ;
158243114Sdteske: menu_command[x]    ( N -- C-ADDR/U )   str_menu_command[x]    13 +c! ;
159243114Sdteske: menu_caption[x]    ( N -- C-ADDR/U )   str_menu_caption[x]    13 +c! ;
160243114Sdteske: ansi_caption[x]    ( N -- C-ADDR/U )   str_ansi_caption[x]    13 +c! ;
161243114Sdteske: menu_keycode[x]    ( N -- C-ADDR/U )   str_menu_keycode[x]    13 +c! ;
162243114Sdteske: toggled_text[x]    ( N -- C-ADDR/U )   str_toggled_text[x]    13 +c! ;
163243114Sdteske: toggled_ansi[x]    ( N -- C-ADDR/U )   str_toggled_ansi[x]    13 +c! ;
164243114Sdteske: menu_caption[x][y] ( N M -- C-ADDR/U ) str_menu_caption[x][y] 16 +c! 13 +c! ;
165243114Sdteske: ansi_caption[x][y] ( N M -- C-ADDR/U ) str_ansi_caption[x][y] 16 +c! 13 +c! ;
166243114Sdteske
167222417Sjulian: arch-i386? ( -- BOOL ) \ Returns TRUE (-1) on i386, FALSE (0) otherwise.
168222417Sjulian	s" arch-i386" environment? dup if
169222417Sjulian		drop
170222417Sjulian	then
171222417Sjulian;
172222417Sjulian
173222417Sjulian\ This function prints a menu item at menuX (row) and menuY (column), returns
174222417Sjulian\ the incremental decimal ASCII value associated with the menu item, and
175222417Sjulian\ increments the cursor position to the next row for the creation of the next
176222417Sjulian\ menu item. This function is called by the menu-create function. You need not
177222417Sjulian\ call it directly.
178222417Sjulian\ 
179222417Sjulian: printmenuitem ( menu_item_str -- ascii_keycode )
180222417Sjulian
181222417Sjulian	menurow dup @ 1+ swap ! ( increment menurow )
182222417Sjulian	menuidx dup @ 1+ swap ! ( increment menuidx )
183222417Sjulian
184222417Sjulian	\ Calculate the menuitem row position
185222417Sjulian	menurow @ menuY @ +
186222417Sjulian
187222417Sjulian	\ Position the cursor at the menuitem position
188222417Sjulian	dup menuX @ swap at-xy
189222417Sjulian
190222417Sjulian	\ Print the value of menuidx
191222417Sjulian	loader_color? if
192228985Spluknet		." [1m" ( [22m )
193222417Sjulian	then
194222417Sjulian	menuidx @ .
195222417Sjulian	loader_color? if
196228985Spluknet		." [37m" ( [39m )
197222417Sjulian	then
198222417Sjulian
199222417Sjulian	\ Move the cursor forward 1 column
200222417Sjulian	dup menuX @ 1+ swap at-xy
201222417Sjulian
202222417Sjulian	menubllt @ emit	\ Print the menu bullet using the emit function
203222417Sjulian
204222417Sjulian	\ Move the cursor to the 3rd column from the current position
205222417Sjulian	\ to allow for a space between the numerical prefix and the
206222417Sjulian	\ text caption
207222417Sjulian	menuX @ 3 + swap at-xy
208222417Sjulian
209222417Sjulian	\ Print the menu caption (we expect a string to be on the stack
210222417Sjulian	\ prior to invoking this function)
211222417Sjulian	type
212222417Sjulian
213222417Sjulian	\ Here we will add the ASCII decimal of the numerical prefix
214222417Sjulian	\ to the stack (decimal ASCII for `1' is 49) as a "return value"
215222417Sjulian	menuidx @ 48 +
216222417Sjulian;
217222417Sjulian
218222417Sjulian: toggle_menuitem ( N -- N ) \ toggles caption text and internal menuitem state
219222417Sjulian
220222417Sjulian	\ ASCII numeral equal to user-selected menu item must be on the stack.
221222417Sjulian	\ We do not modify the stack, so the ASCII numeral is left on top.
222222417Sjulian
223243114Sdteske	dup init_textN c@ 0= if
224222417Sjulian		\ NOTE: no need to check toggle_stateN since the first time we
225222417Sjulian		\ are called, we will populate init_textN. Further, we don't
226222417Sjulian		\ need to test whether menu_caption[x] (ansi_caption[x] when
227254105Sdteske		\ loader_color?=1) is available since we would not have been
228222417Sjulian		\ called if the caption was NULL.
229222417Sjulian
230222417Sjulian		\ base name of environment variable
231243114Sdteske		dup ( n -- n n ) \ key pressed
232222417Sjulian		loader_color? if
233243114Sdteske			ansi_caption[x]
234222417Sjulian		else
235243114Sdteske			menu_caption[x]
236222417Sjulian		then	
237222417Sjulian		getenv dup -1 <> if
238222417Sjulian
239243114Sdteske			2 pick ( n c-addr/u -- n c-addr/u n )
240243114Sdteske			init_textN ( n c-addr/u n -- n c-addr/u c-addr )
241222417Sjulian
242222417Sjulian			\ now we have the buffer c-addr on top
243222417Sjulian			\ ( followed by c-addr/u of current caption )
244222417Sjulian
245222417Sjulian			\ Copy the current caption into our buffer
246222417Sjulian			2dup c! -rot \ store strlen at first byte
247222417Sjulian			begin
248222417Sjulian				rot 1+    \ bring alt addr to top and increment
249222417Sjulian				-rot -rot \ bring buffer addr to top
250222417Sjulian				2dup c@ swap c! \ copy current character
251222417Sjulian				1+     \ increment buffer addr
252222417Sjulian				rot 1- \ bring buffer len to top and decrement
253222417Sjulian				dup 0= \ exit loop if buffer len is zero
254222417Sjulian			until
255222417Sjulian			2drop \ buffer len/addr
256222417Sjulian			drop  \ alt addr
257222417Sjulian
258222417Sjulian		else
259222417Sjulian			drop
260222417Sjulian		then
261222417Sjulian	then
262222417Sjulian
263222417Sjulian	\ Now we are certain to have init_textN populated with the initial
264222417Sjulian	\ value of menu_caption[x] (ansi_caption[x] with loader_color enabled).
265222417Sjulian	\ We can now use init_textN as the untoggled caption and
266222417Sjulian	\ toggled_text[x] (toggled_ansi[x] with loader_color enabled) as the
267222417Sjulian	\ toggled caption and store the appropriate value into menu_caption[x]
268222417Sjulian	\ (again, ansi_caption[x] with loader_color enabled). Last, we'll
269222417Sjulian	\ negate the toggled state so that we reverse the flow on subsequent
270222417Sjulian	\ calls.
271222417Sjulian
272243114Sdteske	dup toggle_stateN @ 0= if
273222417Sjulian		\ state is OFF, toggle to ON
274222417Sjulian
275243114Sdteske		dup ( n -- n n ) \ key pressed
276222417Sjulian		loader_color? if
277243114Sdteske			toggled_ansi[x]
278222417Sjulian		else
279243114Sdteske			toggled_text[x]
280222417Sjulian		then
281222417Sjulian		getenv dup -1 <> if
282222417Sjulian			\ Assign toggled text to menu caption
283243114Sdteske			2 pick ( n c-addr/u -- n c-addr/u n ) \ key pressed
284222417Sjulian			loader_color? if
285243114Sdteske				ansi_caption[x]
286222417Sjulian			else
287243114Sdteske				menu_caption[x]
288222417Sjulian			then
289243114Sdteske			setenv
290222417Sjulian		else
291222417Sjulian			\ No toggled text, keep the same caption
292243114Sdteske			drop ( n -1 -- n ) \ getenv cruft
293222417Sjulian		then
294222417Sjulian
295222417Sjulian		true \ new value of toggle state var (to be stored later)
296222417Sjulian	else
297222417Sjulian		\ state is ON, toggle to OFF
298222417Sjulian
299243114Sdteske		dup init_textN count ( n -- n c-addr/u )
300222417Sjulian
301243114Sdteske		\ Assign init_textN text to menu caption
302243114Sdteske		2 pick ( n c-addr/u -- n c-addr/u n ) \ key pressed
303222417Sjulian		loader_color? if
304243114Sdteske			ansi_caption[x]
305222417Sjulian		else
306243114Sdteske			menu_caption[x]
307222417Sjulian		then
308243114Sdteske		setenv
309222417Sjulian
310243114Sdteske		false \ new value of toggle state var (to be stored below)
311222417Sjulian	then
312222417Sjulian
313222417Sjulian	\ now we'll store the new toggle state (on top of stack)
314243114Sdteske	over toggle_stateN !
315222417Sjulian;
316222417Sjulian
317222417Sjulian: cycle_menuitem ( N -- N ) \ cycles through array of choices for a menuitem
318222417Sjulian
319222417Sjulian	\ ASCII numeral equal to user-selected menu item must be on the stack.
320222417Sjulian	\ We do not modify the stack, so the ASCII numeral is left on top.
321222417Sjulian
322243114Sdteske	dup cycle_stateN dup @ 1+ \ get value and increment
323222417Sjulian
324222417Sjulian	\ Before assigning the (incremented) value back to the pointer,
325222417Sjulian	\ let's test for the existence of this particular array element.
326222417Sjulian	\ If the element exists, we'll store index value and move on.
327222417Sjulian	\ Otherwise, we'll loop around to zero and store that.
328222417Sjulian
329243114Sdteske	dup 48 + ( n addr k -- n addr k k' )
330243114Sdteske	         \ duplicate array index and convert to ASCII numeral
331222417Sjulian
332243114Sdteske	3 pick swap ( n addr k k' -- n addr k n k' ) \ (n,k') as (x,y)
333222417Sjulian	loader_color? if
334243114Sdteske		ansi_caption[x][y]
335222417Sjulian	else
336243114Sdteske		menu_caption[x][y]
337222417Sjulian	then
338243114Sdteske	( n addr k n k' -- n addr k c-addr/u )
339222417Sjulian
340222417Sjulian	\ Now test for the existence of our incremented array index in the
341222417Sjulian	\ form of $menu_caption[x][y] ($ansi_caption[x][y] with loader_color
342222417Sjulian	\ enabled) as set in loader.rc(5), et. al.
343222417Sjulian
344222417Sjulian	getenv dup -1 = if
345222417Sjulian		\ No caption set for this array index. Loop back to zero.
346222417Sjulian
347243114Sdteske		drop ( n addr k -1 -- n addr k ) \ getenv cruft
348243114Sdteske		drop 0 ( n addr k -- n addr 0 )  \ new value to store later
349222417Sjulian
350243114Sdteske		2 pick [char] 0 ( n addr 0 -- n addr 0 n 48 ) \ (n,48) as (x,y)
351222417Sjulian		loader_color? if
352243114Sdteske			ansi_caption[x][y]
353222417Sjulian		else
354243114Sdteske			menu_caption[x][y]
355222417Sjulian		then
356243114Sdteske		( n addr 0 n 48 -- n addr 0 c-addr/u )
357222417Sjulian		getenv dup -1 = if
358222417Sjulian			\ This is highly unlikely to occur, but to make
359222417Sjulian			\ sure that things move along smoothly, allocate
360222417Sjulian			\ a temporary NULL string
361222417Sjulian
362243114Sdteske			drop ( n addr 0 -1 -- n addr 0 ) \ getenv cruft
363243114Sdteske			s" " ( n addr 0 -- n addr 0 c-addr/u )
364222417Sjulian		then
365222417Sjulian	then
366222417Sjulian
367222417Sjulian	\ At this point, we should have the following on the stack (in order,
368222417Sjulian	\ from bottom to top):
369222417Sjulian	\ 
370243114Sdteske	\    n        - Ascii numeral representing the menu choice (inherited)
371243114Sdteske	\    addr     - address of our internal cycle_stateN variable
372243114Sdteske	\    k        - zero-based number we intend to store to the above
373243114Sdteske	\    c-addr/u - string value we intend to store to menu_caption[x]
374243114Sdteske	\               (or ansi_caption[x] with loader_color enabled)
375222417Sjulian	\ 
376222417Sjulian	\ Let's perform what we need to with the above.
377222417Sjulian
378243114Sdteske	\ Assign array value text to menu caption
379243114Sdteske	4 pick ( n addr k c-addr/u -- n addr k c-addr/u n )
380222417Sjulian	loader_color? if
381243114Sdteske		ansi_caption[x]
382222417Sjulian	else
383243114Sdteske		menu_caption[x]
384222417Sjulian	then
385243114Sdteske	setenv
386222417Sjulian
387243114Sdteske	swap ! ( n addr k -- n ) \ update array state variable
388222417Sjulian;
389222417Sjulian
390222417Sjulian: acpipresent? ( -- flag ) \ Returns TRUE if ACPI is present, FALSE otherwise
391222417Sjulian	s" hint.acpi.0.rsdp" getenv
392222417Sjulian	dup -1 = if
393222417Sjulian		drop false exit
394222417Sjulian	then
395222417Sjulian	2drop
396222417Sjulian	true
397222417Sjulian;
398222417Sjulian
399222417Sjulian: acpienabled? ( -- flag ) \ Returns TRUE if ACPI is enabled, FALSE otherwise
400222417Sjulian	s" hint.acpi.0.disabled" getenv
401222417Sjulian	dup -1 <> if
402222417Sjulian		s" 0" compare 0<> if
403222417Sjulian			false exit
404222417Sjulian		then
405222417Sjulian	else
406222417Sjulian		drop
407222417Sjulian	then
408222417Sjulian	true
409222417Sjulian;
410222417Sjulian
411222417Sjulian\ This function prints the appropriate menuitem basename to the stack if an
412222417Sjulian\ ACPI option is to be presented to the user, otherwise returns -1. Used
413222417Sjulian\ internally by menu-create, you need not (nor should you) call this directly.
414222417Sjulian\ 
415241310Sdteske: acpimenuitem ( -- C-Addr/U | -1 )
416222417Sjulian
417222417Sjulian	arch-i386? if
418222417Sjulian		acpipresent? if
419222417Sjulian			acpienabled? if
420222417Sjulian				loader_color? if
421243114Sdteske					str_toggled_ansi[x]
422222417Sjulian				else
423243114Sdteske					str_toggled_text[x]
424222417Sjulian				then
425222417Sjulian			else
426222417Sjulian				loader_color? if
427243114Sdteske					str_ansi_caption[x]
428222417Sjulian				else
429243114Sdteske					str_menu_caption[x]
430222417Sjulian				then
431222417Sjulian			then
432222417Sjulian		else
433222417Sjulian			menuidx dup @ 1+ swap ! ( increment menuidx )
434222417Sjulian			-1
435222417Sjulian		then
436222417Sjulian	else
437222417Sjulian		-1
438222417Sjulian	then
439222417Sjulian;
440222417Sjulian
441222417Sjulian\ This function creates the list of menu items. This function is called by the
442222417Sjulian\ menu-display function. You need not be call it directly.
443222417Sjulian\ 
444222417Sjulian: menu-create ( -- )
445222417Sjulian
446222417Sjulian	\ Print the frame caption at (x,y)
447243114Sdteske	str_loader_menu_title getenv dup -1 = if
448222417Sjulian		drop s" Welcome to FreeBSD"
449222417Sjulian	then
450254108Sdteske	TRUE ( use default alignment )
451254108Sdteske	str_loader_menu_title_align getenv dup -1 <> if
452254108Sdteske		2dup s" left" compare-insensitive 0= if ( 1 )
453254108Sdteske			2drop ( c-addr/u ) drop ( bool )
454254108Sdteske			menuX @ menuY @ 1-
455254108Sdteske			FALSE ( don't use default alignment )
456254108Sdteske		else ( 1 ) 2dup s" right" compare-insensitive 0= if ( 2 )
457254108Sdteske			2drop ( c-addr/u ) drop ( bool )
458254108Sdteske			menuX @ 42 + 4 - over - menuY @ 1-
459254108Sdteske			FALSE ( don't use default alignment )
460254108Sdteske		else ( 2 ) 2drop ( c-addr/u ) then ( 1 ) then
461254108Sdteske	else
462254108Sdteske		drop ( getenv cruft )
463254108Sdteske	then
464254108Sdteske	if ( use default center alignement? )
465254108Sdteske		menuX @ 19 + over 2 / - menuY @ 1-
466254108Sdteske	then
467254108Sdteske	at-xy type 
468222417Sjulian
469241523Sdteske	\ If $menu_init is set, evaluate it (allowing for whole menus to be
470241523Sdteske	\ constructed dynamically -- as this function could conceivably set
471241523Sdteske	\ the remaining environment variables to construct the menu entirely).
472241523Sdteske	\ 
473243114Sdteske	str_menu_init getenv dup -1 <> if
474241523Sdteske		evaluate
475241523Sdteske	else
476241523Sdteske		drop
477241523Sdteske	then
478241523Sdteske
479222417Sjulian	\ Print our menu options with respective key/variable associations.
480222417Sjulian	\ `printmenuitem' ends by adding the decimal ASCII value for the
481222417Sjulian	\ numerical prefix to the stack. We store the value left on the stack
482222417Sjulian	\ to the key binding variable for later testing against a character
483222417Sjulian	\ captured by the `getkey' function.
484222417Sjulian
485222417Sjulian	\ Note that any menu item beyond 9 will have a numerical prefix on the
486222417Sjulian	\ screen consisting of the first digit (ie. 1 for the tenth menu item)
487222417Sjulian	\ and the key required to activate that menu item will be the decimal
488222417Sjulian	\ ASCII of 48 plus the menu item (ie. 58 for the tenth item, aka. `:')
489222417Sjulian	\ which is misleading and not desirable.
490222417Sjulian	\ 
491222417Sjulian	\ Thus, we do not allow more than 8 configurable items on the menu
492222417Sjulian	\ (with "Reboot" as the optional ninth and highest numbered item).
493222417Sjulian
494222417Sjulian	\ 
495222417Sjulian	\ Initialize the ACPI option status.
496222417Sjulian	\ 
497222417Sjulian	0 menuacpi !
498243114Sdteske	str_menu_acpi getenv -1 <> if
499222417Sjulian		c@ dup 48 > over 57 < and if ( '1' <= c1 <= '8' )
500222417Sjulian			menuacpi !
501222417Sjulian			arch-i386? if acpipresent? if
502222417Sjulian				\ 
503222417Sjulian				\ Set menu toggle state to active state
504222417Sjulian				\ (required by generic toggle_menuitem)
505222417Sjulian				\ 
506243114Sdteske				acpienabled? menuacpi @ toggle_stateN !
507222417Sjulian			then then
508222417Sjulian		else
509222417Sjulian			drop
510222417Sjulian		then
511222417Sjulian	then
512222417Sjulian
513222417Sjulian	\ 
514222417Sjulian	\ Initialize the menu_options visual separator.
515222417Sjulian	\ 
516222417Sjulian	0 menuoptions !
517243114Sdteske	str_menu_options getenv -1 <> if
518222417Sjulian		c@ dup 48 > over 57 < and if ( '1' <= c1 <= '8' )
519222417Sjulian			menuoptions !
520222417Sjulian		else
521222417Sjulian			drop
522222417Sjulian		then
523222417Sjulian	then
524222417Sjulian
525222417Sjulian	\ Initialize "Reboot" menu state variable (prevents double-entry)
526222417Sjulian	false menurebootadded !
527222417Sjulian
528242667Sdteske	menu_start
529242667Sdteske	1- menuidx !    \ Initialize the starting index for the menu
530242667Sdteske	0 menurow !     \ Initialize the starting position for the menu
531242667Sdteske
532222417Sjulian	49 \ Iterator start (loop range 49 to 56; ASCII '1' to '8')
533222417Sjulian	begin
534222417Sjulian		\ If the "Options:" separator, print it.
535222417Sjulian		dup menuoptions @ = if
536222417Sjulian			\ Optionally add a reboot option to the menu
537243114Sdteske			str_menu_reboot getenv -1 <> if
538222417Sjulian				drop
539222417Sjulian				s" Reboot" printmenuitem menureboot !
540222417Sjulian				true menurebootadded !
541222417Sjulian			then
542222417Sjulian
543222417Sjulian			menuX @
544222417Sjulian			menurow @ 2 + menurow !
545222417Sjulian			menurow @ menuY @ +
546222417Sjulian			at-xy
547243114Sdteske			str_menu_optionstext getenv dup -1 <> if
548241363Sdteske				type
549241363Sdteske			else
550241363Sdteske				drop ." Options:"
551241363Sdteske			then
552222417Sjulian		then
553222417Sjulian
554222417Sjulian		\ If this is the ACPI menu option, act accordingly.
555222417Sjulian		dup menuacpi @ = if
556243114Sdteske			dup acpimenuitem ( n -- n n c-addr/u | n n -1 )
557243114Sdteske			dup -1 <> if
558243114Sdteske				13 +c! ( n n c-addr/u -- n c-addr/u )
559243114Sdteske				       \ replace 'x' with n
560243114Sdteske			else
561243114Sdteske				swap drop ( n n -1 -- n -1 )
562243114Sdteske				over menu_command[x] unsetenv
563243114Sdteske			then
564222417Sjulian		else
565241523Sdteske			\ make sure we have not already initialized this item
566243114Sdteske			dup init_stateN dup @ 0= if
567241523Sdteske				1 swap !
568241523Sdteske
569241523Sdteske				\ If this menuitem has an initializer, run it
570243114Sdteske				dup menu_init[x]
571241523Sdteske				getenv dup -1 <> if
572241523Sdteske					evaluate
573241523Sdteske				else
574241523Sdteske					drop
575241523Sdteske				then
576241523Sdteske			else
577241523Sdteske				drop
578241523Sdteske			then
579241523Sdteske
580243114Sdteske			dup
581222417Sjulian			loader_color? if
582243114Sdteske				ansi_caption[x]
583222417Sjulian			else
584243114Sdteske				menu_caption[x]
585222417Sjulian			then
586222417Sjulian		then
587222417Sjulian
588222417Sjulian		dup -1 <> if
589222417Sjulian			\ test for environment variable
590222417Sjulian			getenv dup -1 <> if
591243114Sdteske				printmenuitem ( c-addr/u -- n )
592243114Sdteske				dup menukeyN !
593222417Sjulian			else
594222417Sjulian				drop
595222417Sjulian			then
596222417Sjulian		else
597222417Sjulian			drop
598222417Sjulian		then
599222417Sjulian
600222417Sjulian		1+ dup 56 > \ add 1 to iterator, continue if less than 57
601222417Sjulian	until
602222417Sjulian	drop \ iterator
603222417Sjulian
604222417Sjulian	\ Optionally add a reboot option to the menu
605222417Sjulian	menurebootadded @ true <> if
606243114Sdteske		str_menu_reboot getenv -1 <> if
607222417Sjulian			drop       \ no need for the value
608222417Sjulian			s" Reboot" \ menu caption (required by printmenuitem)
609222417Sjulian
610222417Sjulian			printmenuitem
611222417Sjulian			menureboot !
612222417Sjulian		else
613222417Sjulian			0 menureboot !
614222417Sjulian		then
615222417Sjulian	then
616222417Sjulian;
617222417Sjulian
618222417Sjulian\ Takes a single integer on the stack and updates the timeout display. The
619222417Sjulian\ integer must be between 0 and 9 (we will only update a single digit in the
620222417Sjulian\ source message).
621222417Sjulian\ 
622222417Sjulian: menu-timeout-update ( N -- )
623222417Sjulian
624243114Sdteske	\ Enforce minimum/maximum
625243114Sdteske	dup 9 > if drop 9 then
626243114Sdteske	dup 0 < if drop 0 then
627222417Sjulian
628243114Sdteske	s" Autoboot in N seconds. [Space] to pause" ( n -- n c-addr/u )
629222417Sjulian
630243114Sdteske	2 pick 0> if
631243114Sdteske		rot 48 + -rot ( n c-addr/u -- n' c-addr/u ) \ convert to ASCII
632243114Sdteske		12 +c!        ( n' c-addr/u -- c-addr/u )   \ replace 'N' above
633222417Sjulian
634243114Sdteske		menu_timeout_x @ menu_timeout_y @ at-xy \ position cursor
635243114Sdteske		type ( c-addr/u -- ) \ print message
636243114Sdteske	else
637243114Sdteske		menu_timeout_x @ menu_timeout_y @ at-xy \ position cursor
638243114Sdteske		spaces ( n c-addr/u -- n c-addr ) \ erase message
639243114Sdteske		2drop ( n c-addr -- )
640222417Sjulian	then
641222417Sjulian
642222417Sjulian	0 25 at-xy ( position cursor back at bottom-left )
643222417Sjulian;
644222417Sjulian
645222417Sjulian\ This function blocks program flow (loops forever) until a key is pressed.
646222417Sjulian\ The key that was pressed is added to the top of the stack in the form of its
647222417Sjulian\ decimal ASCII representation. This function is called by the menu-display
648222417Sjulian\ function. You need not call it directly.
649222417Sjulian\ 
650222417Sjulian: getkey ( -- ascii_keycode )
651222417Sjulian
652222417Sjulian	begin \ loop forever
653222417Sjulian
654222417Sjulian		menu_timeout_enabled @ 1 = if
655222417Sjulian			( -- )
656222417Sjulian			seconds ( get current time: -- N )
657222417Sjulian			dup menu_time @ <> if ( has time elapsed?: N N N -- N )
658222417Sjulian
659222417Sjulian				\ At least 1 second has elapsed since last loop
660222417Sjulian				\ so we will decrement our "timeout" (really a
661222417Sjulian				\ counter, insuring that we do not proceed too
662222417Sjulian				\ fast) and update our timeout display.
663222417Sjulian
664222417Sjulian				menu_time ! ( update time record: N -- )
665222417Sjulian				menu_timeout @ ( "time" remaining: -- N )
666222417Sjulian				dup 0> if ( greater than 0?: N N 0 -- N )
667222417Sjulian					1- ( decrement counter: N -- N )
668222417Sjulian					dup menu_timeout !
669222417Sjulian						( re-assign: N N Addr -- N )
670222417Sjulian				then
671222417Sjulian				( -- N )
672222417Sjulian
673222417Sjulian				dup 0= swap 0< or if ( N <= 0?: N N -- )
674222417Sjulian					\ halt the timer
675222417Sjulian					0 menu_timeout ! ( 0 Addr -- )
676222417Sjulian					0 menu_timeout_enabled ! ( 0 Addr -- )
677222417Sjulian				then
678222417Sjulian
679222417Sjulian				\ update the timer display ( N -- )
680222417Sjulian				menu_timeout @ menu-timeout-update
681222417Sjulian
682222417Sjulian				menu_timeout @ 0= if
683222417Sjulian					\ We've reached the end of the timeout
684222417Sjulian					\ (user did not cancel by pressing ANY
685222417Sjulian					\ key)
686222417Sjulian
687243114Sdteske					str_menu_timeout_command getenv dup
688222417Sjulian					-1 = if
689222417Sjulian						drop \ clean-up
690222417Sjulian					else
691222417Sjulian						evaluate
692222417Sjulian					then
693222417Sjulian				then
694222417Sjulian
695222417Sjulian			else ( -- N )
696222417Sjulian				\ No [detectable] time has elapsed (in seconds)
697222417Sjulian				drop ( N -- )
698222417Sjulian			then
699222417Sjulian			( -- )
700222417Sjulian		then
701222417Sjulian
702222417Sjulian		key? if \ Was a key pressed? (see loader(8))
703222417Sjulian
704222417Sjulian			\ An actual key was pressed (if the timeout is running,
705222417Sjulian			\ kill it regardless of which key was pressed)
706222417Sjulian			menu_timeout @ 0<> if
707222417Sjulian				0 menu_timeout !
708222417Sjulian				0 menu_timeout_enabled !
709222417Sjulian
710222417Sjulian				\ clear screen of timeout message
711222417Sjulian				0 menu-timeout-update
712222417Sjulian			then
713222417Sjulian
714222417Sjulian			\ get the key that was pressed and exit (if we
715222417Sjulian			\ get a non-zero ASCII code)
716222417Sjulian			key dup 0<> if
717222417Sjulian				exit
718222417Sjulian			else
719222417Sjulian				drop
720222417Sjulian			then
721222417Sjulian		then
722222417Sjulian		50 ms \ sleep for 50 milliseconds (see loader(8))
723222417Sjulian
724222417Sjulian	again
725222417Sjulian;
726222417Sjulian
727222417Sjulian: menu-erase ( -- ) \ Erases menu and resets positioning variable to positon 1.
728222417Sjulian
729222417Sjulian	\ Clear the screen area associated with the interactive menu
730222417Sjulian	menuX @ menuY @
731222417Sjulian	2dup at-xy 38 spaces 1+		2dup at-xy 38 spaces 1+
732222417Sjulian	2dup at-xy 38 spaces 1+		2dup at-xy 38 spaces 1+
733222417Sjulian	2dup at-xy 38 spaces 1+		2dup at-xy 38 spaces 1+
734222417Sjulian	2dup at-xy 38 spaces 1+		2dup at-xy 38 spaces 1+
735222417Sjulian	2dup at-xy 38 spaces 1+		2dup at-xy 38 spaces 1+
736222417Sjulian	2dup at-xy 38 spaces 1+		2dup at-xy 38 spaces
737222417Sjulian	2drop
738222417Sjulian
739222417Sjulian	\ Reset the starting index and position for the menu
740222417Sjulian	menu_start 1- menuidx !
741222417Sjulian	0 menurow !
742222417Sjulian;
743222417Sjulian
744222417Sjulian\ Erase and redraw the menu. Useful if you change a caption and want to
745222417Sjulian\ update the menu to reflect the new value.
746222417Sjulian\ 
747222417Sjulian: menu-redraw ( -- )
748222417Sjulian	menu-erase
749222417Sjulian	menu-create
750222417Sjulian;
751222417Sjulian
752222417Sjulian\ This function initializes the menu. Call this from your `loader.rc' file
753222417Sjulian\ before calling any other menu-related functions.
754222417Sjulian\ 
755222417Sjulian: menu-init ( -- )
756222417Sjulian	menu_start
757222417Sjulian	1- menuidx !    \ Initialize the starting index for the menu
758222417Sjulian	0 menurow !     \ Initialize the starting position for the menu
759254108Sdteske
760254108Sdteske	\ Assign configuration values
761254108Sdteske	str_loader_menu_y getenv dup -1 = if
762254108Sdteske		drop \ no custom row position
763254108Sdteske		menu_default_y
764254108Sdteske	else
765254108Sdteske		\ make sure custom position is a number
766254108Sdteske		?number 0= if
767254108Sdteske			menu_default_y \ or use default
768254108Sdteske		then
769254108Sdteske	then
770254108Sdteske	menuY !
771254108Sdteske	str_loader_menu_x getenv dup -1 = if
772254108Sdteske		drop \ no custom column position
773254108Sdteske		menu_default_x
774254108Sdteske	else
775254108Sdteske		\ make sure custom position is a number
776254108Sdteske		?number 0= if
777254108Sdteske			menu_default_x \ or use default
778254108Sdteske		then
779254108Sdteske	then
780254108Sdteske	menuX !
781254108Sdteske
782254108Sdteske	\ Interpret a custom frame type for the menu
783254108Sdteske	TRUE ( draw a box? default yes, but might be altered below )
784254108Sdteske	str_loader_menu_frame getenv dup -1 = if ( 1 )
785254108Sdteske		drop \ no custom frame type
786254108Sdteske	else ( 1 )  2dup s" single" compare-insensitive 0= if ( 2 )
787254108Sdteske		f_single ( see frames.4th )
788254108Sdteske	else ( 2 )  2dup s" double" compare-insensitive 0= if ( 3 )
789254108Sdteske		f_double ( see frames.4th )
790254108Sdteske	else ( 3 ) s" none" compare-insensitive 0= if ( 4 )
791254108Sdteske		drop FALSE \ don't draw a box
792254108Sdteske	( 4 ) then ( 3 ) then ( 2 )  then ( 1 ) then
793254108Sdteske	if
794254108Sdteske		42 13 menuX @ 3 - menuY @ 1- box \ Draw frame (w,h,x,y)
795254108Sdteske	then
796254108Sdteske
797254108Sdteske	0 25 at-xy \ Move cursor to the bottom for output
798222417Sjulian;
799222417Sjulian
800222417Sjulian\ Main function. Call this from your `loader.rc' file.
801222417Sjulian\ 
802222417Sjulian: menu-display ( -- )
803222417Sjulian
804222417Sjulian	0 menu_timeout_enabled ! \ start with automatic timeout disabled
805222417Sjulian
806222417Sjulian	\ check indication that automatic execution after delay is requested
807243114Sdteske	str_menu_timeout_command getenv -1 <> if ( Addr C -1 -- | Addr )
808222417Sjulian		drop ( just testing existence right now: Addr -- )
809222417Sjulian
810222417Sjulian		\ initialize state variables
811222417Sjulian		seconds menu_time ! ( store the time we started )
812222417Sjulian		1 menu_timeout_enabled ! ( enable automatic timeout )
813222417Sjulian
814222417Sjulian		\ read custom time-duration (if set)
815222417Sjulian		s" autoboot_delay" getenv dup -1 = if
816222417Sjulian			drop \ no custom duration (remove dup'd bunk -1)
817222417Sjulian			menu_timeout_default \ use default setting
818222417Sjulian		else
819222417Sjulian			2dup ?number 0= if ( if not a number )
820222417Sjulian				\ disable timeout if "NO", else use default
821222417Sjulian				s" NO" compare-insensitive 0= if
822222417Sjulian					0 menu_timeout_enabled !
823222417Sjulian					0 ( assigned to menu_timeout below )
824222417Sjulian				else
825222417Sjulian					menu_timeout_default
826222417Sjulian				then
827222417Sjulian			else
828222417Sjulian				-rot 2drop
829222417Sjulian
830225353Sjh				\ boot immediately if less than zero
831222417Sjulian				dup 0< if
832222417Sjulian					drop
833225353Sjh					menu-create
834225353Sjh					0 25 at-xy
835225353Sjh					0 boot
836222417Sjulian				then
837222417Sjulian			then
838222417Sjulian		then
839222417Sjulian		menu_timeout ! ( store value on stack from above )
840222417Sjulian
841222417Sjulian		menu_timeout_enabled @ 1 = if
842222417Sjulian			\ read custom column position (if set)
843243114Sdteske			str_loader_menu_timeout_x getenv dup -1 = if
844222417Sjulian				drop \ no custom column position
845222417Sjulian				menu_timeout_default_x \ use default setting
846222417Sjulian			else
847222417Sjulian				\ make sure custom position is a number
848222417Sjulian				?number 0= if
849222417Sjulian					menu_timeout_default_x \ or use default
850222417Sjulian				then
851222417Sjulian			then
852222417Sjulian			menu_timeout_x ! ( store value on stack from above )
853222417Sjulian        
854222417Sjulian			\ read custom row position (if set)
855243114Sdteske			str_loader_menu_timeout_y getenv dup -1 = if
856222417Sjulian				drop \ no custom row position
857222417Sjulian				menu_timeout_default_y \ use default setting
858222417Sjulian			else
859222417Sjulian				\ make sure custom position is a number
860222417Sjulian				?number 0= if
861222417Sjulian					menu_timeout_default_y \ or use default
862222417Sjulian				then
863222417Sjulian			then
864222417Sjulian			menu_timeout_y ! ( store value on stack from above )
865222417Sjulian		then
866222417Sjulian	then
867222417Sjulian
868222417Sjulian	menu-create
869222417Sjulian
870222417Sjulian	begin \ Loop forever
871222417Sjulian
872222417Sjulian		0 25 at-xy \ Move cursor to the bottom for output
873222417Sjulian		getkey     \ Block here, waiting for a key to be pressed
874222417Sjulian
875222417Sjulian		dup -1 = if
876222417Sjulian			drop exit \ Caught abort (abnormal return)
877222417Sjulian		then
878222417Sjulian
879222417Sjulian		\ Boot if the user pressed Enter/Ctrl-M (13) or
880222417Sjulian		\ Ctrl-Enter/Ctrl-J (10)
881222417Sjulian		dup over 13 = swap 10 = or if
882222417Sjulian			drop ( no longer needed )
883222417Sjulian			s" boot" evaluate
884222417Sjulian			exit ( pedantic; never reached )
885222417Sjulian		then
886222417Sjulian
887242667Sdteske		dup menureboot @ = if 0 reboot then
888242667Sdteske
889222417Sjulian		\ Evaluate the decimal ASCII value against known menu item
890222417Sjulian		\ key associations and act accordingly
891222417Sjulian
892222417Sjulian		49 \ Iterator start (loop range 49 to 56; ASCII '1' to '8')
893222417Sjulian		begin
894243114Sdteske			dup menukeyN @
895243114Sdteske			rot tuck = if
896222417Sjulian
897222417Sjulian				\ Adjust for missing ACPI menuitem on non-i386
898222417Sjulian				arch-i386? true <> menuacpi @ 0<> and if
899222417Sjulian					menuacpi @ over 2dup < -rot = or
900222417Sjulian					over 58 < and if
901222417Sjulian					( key >= menuacpi && key < 58: N -- N )
902222417Sjulian						1+
903222417Sjulian					then
904222417Sjulian				then
905222417Sjulian
906222417Sjulian				\ Test for the environment variable
907243114Sdteske				dup menu_command[x]
908222417Sjulian				getenv dup -1 <> if
909222417Sjulian					\ Execute the stored procedure
910222417Sjulian					evaluate
911222417Sjulian
912222417Sjulian					\ We expect there to be a non-zero
913222417Sjulian					\  value left on the stack after
914222417Sjulian					\ executing the stored procedure.
915222417Sjulian					\ If so, continue to run, else exit.
916222417Sjulian
917222417Sjulian					0= if
918222417Sjulian						drop \ key pressed
919222417Sjulian						drop \ loop iterator
920222417Sjulian						exit
921222417Sjulian					else
922222417Sjulian						swap \ need iterator on top
923222417Sjulian					then
924222417Sjulian				then
925222417Sjulian
926222417Sjulian				\ Re-adjust for missing ACPI menuitem
927222417Sjulian				arch-i386? true <> menuacpi @ 0<> and if
928222417Sjulian					swap
929222417Sjulian					menuacpi @ 1+ over 2dup < -rot = or
930222417Sjulian					over 59 < and if
931222417Sjulian						1-
932222417Sjulian					then
933222417Sjulian					swap
934222417Sjulian				then
935222417Sjulian			else
936222417Sjulian				swap \ need iterator on top
937222417Sjulian			then
938222417Sjulian
939222417Sjulian			\ 
940222417Sjulian			\ Check for menu keycode shortcut(s)
941222417Sjulian			\ 
942243114Sdteske			dup menu_keycode[x]
943222417Sjulian			getenv dup -1 = if
944222417Sjulian				drop
945222417Sjulian			else
946222417Sjulian				?number 0<> if
947222417Sjulian					rot tuck = if
948222417Sjulian						swap
949243114Sdteske						dup menu_command[x]
950222417Sjulian						getenv dup -1 <> if
951222417Sjulian							evaluate
952222417Sjulian							0= if
953222417Sjulian								2drop
954222417Sjulian								exit
955222417Sjulian							then
956222417Sjulian						else
957222417Sjulian							drop
958222417Sjulian						then
959222417Sjulian					else
960222417Sjulian						swap
961222417Sjulian					then
962222417Sjulian				then
963222417Sjulian			then
964222417Sjulian
965222417Sjulian			1+ dup 56 > \ increment iterator
966222417Sjulian			            \ continue if less than 57
967222417Sjulian		until
968222417Sjulian		drop \ loop iterator
969242667Sdteske		drop \ key pressed
970222417Sjulian
971222417Sjulian	again	\ Non-operational key was pressed; repeat
972222417Sjulian;
973222417Sjulian
974222417Sjulian\ This function unsets all the possible environment variables associated with
975228985Spluknet\ creating the interactive menu.
976222417Sjulian\ 
977228985Spluknet: menu-unset ( -- )
978222417Sjulian
979222417Sjulian	49 \ Iterator start (loop range 49 to 56; ASCII '1' to '8')
980222417Sjulian	begin
981243114Sdteske		dup menu_init[x]    unsetenv	\ menu initializer
982243114Sdteske		dup menu_command[x] unsetenv	\ menu command
983243114Sdteske		dup menu_caption[x] unsetenv	\ menu caption
984243114Sdteske		dup ansi_caption[x] unsetenv	\ ANSI caption
985243114Sdteske		dup menu_keycode[x] unsetenv	\ menu keycode
986243114Sdteske		dup toggled_text[x] unsetenv	\ toggle_menuitem caption
987243114Sdteske		dup toggled_ansi[x] unsetenv	\ toggle_menuitem ANSI caption
988228985Spluknet
989243114Sdteske		48 \ Iterator start (inner range 48 to 57; ASCII '0' to '9')
990228985Spluknet		begin
991243114Sdteske			\ cycle_menuitem caption and ANSI caption
992243114Sdteske			2dup menu_caption[x][y] unsetenv
993243114Sdteske			2dup ansi_caption[x][y] unsetenv
994243114Sdteske			1+ dup 57 >
995228985Spluknet		until
996243114Sdteske		drop \ inner iterator
997228985Spluknet
998243114Sdteske		0 over menukeyN      !	\ used by menu-create, menu-display
999243114Sdteske		0 over init_stateN   !	\ used by menu-create
1000243114Sdteske		0 over toggle_stateN !	\ used by toggle_menuitem
1001243114Sdteske		0 over init_textN   c!	\ used by toggle_menuitem
1002243114Sdteske		0 over cycle_stateN  !	\ used by cycle_menuitem
1003228985Spluknet
1004222417Sjulian		1+ dup 56 >	\ increment, continue if less than 57
1005222417Sjulian	until
1006222417Sjulian	drop \ iterator
1007222417Sjulian
1008243114Sdteske	str_menu_timeout_command unsetenv	\ menu timeout command
1009243114Sdteske	str_menu_reboot          unsetenv	\ Reboot menu option flag
1010243114Sdteske	str_menu_acpi            unsetenv	\ ACPI menu option flag
1011243114Sdteske	str_menu_options         unsetenv	\ Options separator flag
1012243114Sdteske	str_menu_optionstext     unsetenv	\ separator display text
1013243114Sdteske	str_menu_init            unsetenv	\ menu initializer
1014228985Spluknet
1015222417Sjulian	0 menureboot !
1016222417Sjulian	0 menuacpi !
1017222417Sjulian	0 menuoptions !
1018228985Spluknet;
1019228985Spluknet
1020228985Spluknet\ This function both unsets menu variables and visually erases the menu area
1021228985Spluknet\ in-preparation for another menu.
1022228985Spluknet\ 
1023228985Spluknet: menu-clear ( -- )
1024228985Spluknet	menu-unset
1025222417Sjulian	menu-erase
1026222417Sjulian;
1027222417Sjulian
1028222417Sjulianbullet menubllt !
1029222417Sjulian
1030241523Sdteske\ Initialize our menu initialization state variables
1031241523Sdteske0 init_state1 !
1032241523Sdteske0 init_state2 !
1033241523Sdteske0 init_state3 !
1034241523Sdteske0 init_state4 !
1035241523Sdteske0 init_state5 !
1036241523Sdteske0 init_state6 !
1037241523Sdteske0 init_state7 !
1038241523Sdteske0 init_state8 !
1039241523Sdteske
1040222417Sjulian\ Initialize our boolean state variables
1041222417Sjulian0 toggle_state1 !
1042222417Sjulian0 toggle_state2 !
1043222417Sjulian0 toggle_state3 !
1044222417Sjulian0 toggle_state4 !
1045222417Sjulian0 toggle_state5 !
1046222417Sjulian0 toggle_state6 !
1047222417Sjulian0 toggle_state7 !
1048222417Sjulian0 toggle_state8 !
1049222417Sjulian
1050222417Sjulian\ Initialize our array state variables
1051222417Sjulian0 cycle_state1 !
1052222417Sjulian0 cycle_state2 !
1053222417Sjulian0 cycle_state3 !
1054222417Sjulian0 cycle_state4 !
1055222417Sjulian0 cycle_state5 !
1056222417Sjulian0 cycle_state6 !
1057222417Sjulian0 cycle_state7 !
1058222417Sjulian0 cycle_state8 !
1059222417Sjulian
1060222417Sjulian\ Initialize string containers
1061222417Sjulian0 init_text1 c!
1062222417Sjulian0 init_text2 c!
1063222417Sjulian0 init_text3 c!
1064222417Sjulian0 init_text4 c!
1065222417Sjulian0 init_text5 c!
1066222417Sjulian0 init_text6 c!
1067222417Sjulian0 init_text7 c!
1068222417Sjulian0 init_text8 c!
1069