1: \ Copyright (c) 2003 Scott Long <scottl@freebsd.org>
2: \ Copyright (c) 2003 Aleksander Fafula <alex@fafula.com>
3: \ Copyright (c) 2006-2011 Devin Teske <devinteske@hotmail.com>
4: \ All rights reserved.
5: \
6: \ Redistribution and use in source and binary forms, with or without
7: \ modification, are permitted provided that the following conditions
8: \ are met:
9: \ 1. Redistributions of source code must retain the above copyright
10: \ notice, this list of conditions and the following disclaimer.
11: \ 2. Redistributions in binary form must reproduce the above copyright
12: \ notice, this list of conditions and the following disclaimer in the
13: \ documentation and/or other materials provided with the distribution.
14: \
15: \ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16: \ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17: \ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18: \ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19: \ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20: \ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21: \ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22: \ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23: \ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24: \ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25: \ SUCH DAMAGE.
26: \
27: \ $FreeBSD: src/sys/boot/forth/menu.4th,v 1.2 2011/09/02 19:29:37 jh Exp $
28:
29: marker task-menu.4th
30:
31: \ Frame drawing
32: include /boot/frames.4th
33:
34: f_double \ Set frames to double (see frames.4th). Replace with
35: \ f_single if you want single frames.
36: 46 constant dot \ ASCII definition of a period (in decimal)
37:
38: 4 constant menu_timeout_default_x \ default column position of timeout
39: 23 constant menu_timeout_default_y \ default row position of timeout msg
40: 10 constant menu_timeout_default \ default timeout (in seconds)
41:
42: \ Customize the following values with care
43:
44: 1 constant menu_start \ Numerical prefix of first menu item
45: dot constant bullet \ Menu bullet (appears after numerical prefix)
46: 5 constant menu_x \ Row position of the menu (from the top)
47: 10 constant menu_y \ Column position of the menu (from left side)
48:
49: \ Menu Appearance
50: variable menuidx \ Menu item stack for number prefixes
51: variable menurow \ Menu item stack for positioning
52: variable menubllt \ Menu item bullet
53:
54: \ Menu Positioning
55: variable menuX \ Menu X offset (columns)
56: variable menuY \ Menu Y offset (rows)
57:
58: \ Menu-item key association/detection
59: variable menukey1
60: variable menukey2
61: variable menukey3
62: variable menukey4
63: variable menukey5
64: variable menukey6
65: variable menukey7
66: variable menukey8
67: variable menureboot
68: variable menurebootadded
69: variable menuacpi
70: variable menuoptions
71:
72: \ Menu timer [count-down] variables
73: variable menu_timeout_enabled \ timeout state (internal use only)
74: variable menu_time \ variable for tracking the passage of time
75: variable menu_timeout \ determined configurable delay duration
76: variable menu_timeout_x \ column position of timeout message
77: variable menu_timeout_y \ row position of timeout message
78:
79: \ Boolean option status variables
80: variable toggle_state1
81: variable toggle_state2
82: variable toggle_state3
83: variable toggle_state4
84: variable toggle_state5
85: variable toggle_state6
86: variable toggle_state7
87: variable toggle_state8
88:
89: \ Array option status variables
90: variable cycle_state1
91: variable cycle_state2
92: variable cycle_state3
93: variable cycle_state4
94: variable cycle_state5
95: variable cycle_state6
96: variable cycle_state7
97: variable cycle_state8
98:
99: \ Containers for storing the initial caption text
100: create init_text1 255 allot
101: create init_text2 255 allot
102: create init_text3 255 allot
103: create init_text4 255 allot
104: create init_text5 255 allot
105: create init_text6 255 allot
106: create init_text7 255 allot
107: create init_text8 255 allot
108:
109: : arch-i386? ( -- BOOL ) \ Returns TRUE (-1) on i386, FALSE (0) otherwise.
110: s" arch-i386" environment? dup if
111: drop
112: then
113: ;
114:
115: \ This function prints a menu item at menuX (row) and menuY (column), returns
116: \ the incremental decimal ASCII value associated with the menu item, and
117: \ increments the cursor position to the next row for the creation of the next
118: \ menu item. This function is called by the menu-create function. You need not
119: \ call it directly.
120: \
121: : printmenuitem ( menu_item_str -- ascii_keycode )
122:
123: menurow dup @ 1+ swap ! ( increment menurow )
124: menuidx dup @ 1+ swap ! ( increment menuidx )
125:
126: \ Calculate the menuitem row position
127: menurow @ menuY @ +
128:
129: \ Position the cursor at the menuitem position
130: dup menuX @ swap at-xy
131:
132: \ Print the value of menuidx
133: loader_color? if
134: ." [1m"
135: then
136: menuidx @ .
137: loader_color? if
138: ." [37m"
139: then
140:
141: \ Move the cursor forward 1 column
142: dup menuX @ 1+ swap at-xy
143:
144: menubllt @ emit \ Print the menu bullet using the emit function
145:
146: \ Move the cursor to the 3rd column from the current position
147: \ to allow for a space between the numerical prefix and the
148: \ text caption
149: menuX @ 3 + swap at-xy
150:
151: \ Print the menu caption (we expect a string to be on the stack
152: \ prior to invoking this function)
153: type
154:
155: \ Here we will add the ASCII decimal of the numerical prefix
156: \ to the stack (decimal ASCII for `1' is 49) as a "return value"
157: menuidx @ 48 +
158: ;
159:
160: : toggle_menuitem ( N -- N ) \ toggles caption text and internal menuitem state
161:
162: \ ASCII numeral equal to user-selected menu item must be on the stack.
163: \ We do not modify the stack, so the ASCII numeral is left on top.
164:
165: s" init_textN" \ base name of buffer
166: -rot 2dup 9 + c! rot \ replace 'N' with ASCII num
167:
168: evaluate c@ 0= if
169: \ NOTE: no need to check toggle_stateN since the first time we
170: \ are called, we will populate init_textN. Further, we don't
171: \ need to test whether menu_caption[x] (ansi_caption[x] when
172: \ loader_color=1) is available since we would not have been
173: \ called if the caption was NULL.
174:
175: \ base name of environment variable
176: loader_color? if
177: s" ansi_caption[x]"
178: else
179: s" menu_caption[x]"
180: then
181: -rot 2dup 13 + c! rot \ replace 'x' with ASCII numeral
182:
183: getenv dup -1 <> if
184:
185: s" init_textN" \ base name of buffer
186: 4 pick \ copy ASCII num to top
187: rot tuck 9 + c! swap \ replace 'N' with ASCII num
188: evaluate
189:
190: \ now we have the buffer c-addr on top
191: \ ( followed by c-addr/u of current caption )
192:
193: \ Copy the current caption into our buffer
194: 2dup c! -rot \ store strlen at first byte
195: begin
196: rot 1+ \ bring alt addr to top and increment
197: -rot -rot \ bring buffer addr to top
198: 2dup c@ swap c! \ copy current character
199: 1+ \ increment buffer addr
200: rot 1- \ bring buffer len to top and decrement
201: dup 0= \ exit loop if buffer len is zero
202: until
203: 2drop \ buffer len/addr
204: drop \ alt addr
205:
206: else
207: drop
208: then
209: then
210:
211: \ Now we are certain to have init_textN populated with the initial
212: \ value of menu_caption[x] (ansi_caption[x] with loader_color enabled).
213: \ We can now use init_textN as the untoggled caption and
214: \ toggled_text[x] (toggled_ansi[x] with loader_color enabled) as the
215: \ toggled caption and store the appropriate value into menu_caption[x]
216: \ (again, ansi_caption[x] with loader_color enabled). Last, we'll
217: \ negate the toggled state so that we reverse the flow on subsequent
218: \ calls.
219:
220: s" toggle_stateN @" \ base name of toggle state var
221: -rot 2dup 12 + c! rot \ replace 'N' with ASCII numeral
222:
223: evaluate 0= if
224: \ state is OFF, toggle to ON
225:
226: \ base name of toggled text var
227: loader_color? if
228: s" toggled_ansi[x]"
229: else
230: s" toggled_text[x]"
231: then
232: -rot 2dup 13 + c! rot \ replace 'x' with ASCII num
233:
234: getenv dup -1 <> if
235: \ Assign toggled text to menu caption
236:
237: \ base name of caption var
238: loader_color? if
239: s" ansi_caption[x]"
240: else
241: s" menu_caption[x]"
242: then
243: 4 pick \ copy ASCII num to top
244: rot tuck 13 + c! swap \ replace 'x' with ASCII num
245:
246: setenv \ set new caption
247: else
248: \ No toggled text, keep the same caption
249:
250: drop
251: then
252:
253: true \ new value of toggle state var (to be stored later)
254: else
255: \ state is ON, toggle to OFF
256:
257: s" init_textN" \ base name of initial text buffer
258: -rot 2dup 9 + c! rot \ replace 'N' with ASCII numeral
259: evaluate \ convert string to c-addr
260: count \ convert c-addr to c-addr/u
261:
262: \ base name of caption var
263: loader_color? if
264: s" ansi_caption[x]"
265: else
266: s" menu_caption[x]"
267: then
268: 4 pick \ copy ASCII num to top
269: rot tuck 13 + c! swap \ replace 'x' with ASCII numeral
270:
271: setenv \ set new caption
272: false \ new value of toggle state var (to be stored below)
273: then
274:
275: \ now we'll store the new toggle state (on top of stack)
276: s" toggle_stateN" \ base name of toggle state var
277: 3 pick \ copy ASCII numeral to top
278: rot tuck 12 + c! swap \ replace 'N' with ASCII numeral
279: evaluate \ convert string to addr
280: ! \ store new value
281: ;
282:
283: : cycle_menuitem ( N -- N ) \ cycles through array of choices for a menuitem
284:
285: \ ASCII numeral equal to user-selected menu item must be on the stack.
286: \ We do not modify the stack, so the ASCII numeral is left on top.
287:
288: s" cycle_stateN" \ base name of array state var
289: -rot 2dup 11 + c! rot \ replace 'N' with ASCII numeral
290:
291: evaluate \ we now have a pointer to the proper variable
292: dup @ \ resolve the pointer (but leave it on the stack)
293: 1+ \ increment the value
294:
295: \ Before assigning the (incremented) value back to the pointer,
296: \ let's test for the existence of this particular array element.
297: \ If the element exists, we'll store index value and move on.
298: \ Otherwise, we'll loop around to zero and store that.
299:
300: dup 48 + \ duplicate Array index and convert to ASCII numeral
301:
302: \ base name of array caption text
303: loader_color? if
304: s" ansi_caption[x][y]"
305: else
306: s" menu_caption[x][y]"
307: then
308: -rot tuck 16 + c! swap \ replace 'y' with Array index
309: 4 pick rot tuck 13 + c! swap \ replace 'x' with menu choice
310:
311: \ Now test for the existence of our incremented array index in the
312: \ form of $menu_caption[x][y] ($ansi_caption[x][y] with loader_color
313: \ enabled) as set in loader.rc(5), et. al.
314:
315: getenv dup -1 = if
316: \ No caption set for this array index. Loop back to zero.
317:
318: drop ( getenv cruft )
319: drop ( incremented array index )
320: 0 ( new array index that will be stored later )
321:
322: \ base name of caption var
323: loader_color? if
324: s" ansi_caption[x][0]"
325: else
326: s" menu_caption[x][0]"
327: then
328: 4 pick rot tuck 13 + c! swap \ replace 'x' with menu choice
329:
330: getenv dup -1 = if
331: \ This is highly unlikely to occur, but to make
332: \ sure that things move along smoothly, allocate
333: \ a temporary NULL string
334:
335: s" "
336: then
337: then
338:
339: \ At this point, we should have the following on the stack (in order,
340: \ from bottom to top):
341: \
342: \ N - Ascii numeral representing the menu choice (inherited)
343: \ Addr - address of our internal cycle_stateN variable
344: \ N - zero-based number we intend to store to the above
345: \ C-Addr - string value we intend to store to menu_caption[x]
346: \ (or ansi_caption[x] with loader_color enabled)
347: \
348: \ Let's perform what we need to with the above.
349:
350: \ base name of menuitem caption var
351: loader_color? if
352: s" ansi_caption[x]"
353: else
354: s" menu_caption[x]"
355: then
356: 6 pick rot tuck 13 + c! swap \ replace 'x' with menu choice
357: setenv \ set the new caption
358:
359: swap ! \ update array state variable
360: ;
361:
362: : acpipresent? ( -- flag ) \ Returns TRUE if ACPI is present, FALSE otherwise
363: s" hint.acpi.0.rsdp" getenv
364: dup -1 = if
365: drop false exit
366: then
367: 2drop
368: true
369: ;
370:
371: : acpienabled? ( -- flag ) \ Returns TRUE if ACPI is enabled, FALSE otherwise
372: s" hint.acpi.0.disabled" getenv
373: dup -1 <> if
374: s" 0" compare 0<> if
375: false exit
376: then
377: else
378: drop
379: then
380: true
381: ;
382:
383: \ This function prints the appropriate menuitem basename to the stack if an
384: \ ACPI option is to be presented to the user, otherwise returns -1. Used
385: \ internally by menu-create, you need not (nor should you) call this directly.
386: \
387: : acpimenuitem ( -- C-Addr | -1 )
388:
389: arch-i386? if
390: acpipresent? if
391: acpienabled? if
392: loader_color? if
393: s" toggled_ansi[x]"
394: else
395: s" toggled_text[x]"
396: then
397: else
398: loader_color? if
399: s" ansi_caption[x]"
400: else
401: s" menu_caption[x]"
402: then
403: then
404: else
405: menuidx dup @ 1+ swap ! ( increment menuidx )
406: -1
407: then
408: else
409: -1
410: then
411: ;
412:
413: \ This function creates the list of menu items. This function is called by the
414: \ menu-display function. You need not be call it directly.
415: \
416: : menu-create ( -- )
417:
418: \ Print the frame caption at (x,y)
419: s" loader_menu_title" getenv dup -1 = if
420: drop s" Welcome to -ELWIX-"
421: then
422: 24 over 2 / - 9 at-xy type
423:
424: \ Print our menu options with respective key/variable associations.
425: \ `printmenuitem' ends by adding the decimal ASCII value for the
426: \ numerical prefix to the stack. We store the value left on the stack
427: \ to the key binding variable for later testing against a character
428: \ captured by the `getkey' function.
429:
430: \ Note that any menu item beyond 9 will have a numerical prefix on the
431: \ screen consisting of the first digit (ie. 1 for the tenth menu item)
432: \ and the key required to activate that menu item will be the decimal
433: \ ASCII of 48 plus the menu item (ie. 58 for the tenth item, aka. `:')
434: \ which is misleading and not desirable.
435: \
436: \ Thus, we do not allow more than 8 configurable items on the menu
437: \ (with "Reboot" as the optional ninth and highest numbered item).
438:
439: \
440: \ Initialize the ACPI option status.
441: \
442: 0 menuacpi !
443: s" menu_acpi" getenv -1 <> if
444: c@ dup 48 > over 57 < and if ( '1' <= c1 <= '8' )
445: menuacpi !
446: arch-i386? if acpipresent? if
447: \
448: \ Set menu toggle state to active state
449: \ (required by generic toggle_menuitem)
450: \
451: menuacpi @
452: s" acpienabled? toggle_stateN !"
453: -rot tuck 25 + c! swap
454: evaluate
455: then then
456: else
457: drop
458: then
459: then
460:
461: \
462: \ Initialize the menu_options visual separator.
463: \
464: 0 menuoptions !
465: s" menu_options" getenv -1 <> if
466: c@ dup 48 > over 57 < and if ( '1' <= c1 <= '8' )
467: menuoptions !
468: else
469: drop
470: then
471: then
472:
473: \ Initialize "Reboot" menu state variable (prevents double-entry)
474: false menurebootadded !
475:
476: 49 \ Iterator start (loop range 49 to 56; ASCII '1' to '8')
477: begin
478: \ If the "Options:" separator, print it.
479: dup menuoptions @ = if
480: \ Optionally add a reboot option to the menu
481: s" menu_reboot" getenv -1 <> if
482: drop
483: s" Reboot" printmenuitem menureboot !
484: true menurebootadded !
485: then
486:
487: menuX @
488: menurow @ 2 + menurow !
489: menurow @ menuY @ +
490: at-xy
491: ." Options:"
492: then
493:
494: \ If this is the ACPI menu option, act accordingly.
495: dup menuacpi @ = if
496: acpimenuitem ( -- C-Addr | -1 )
497: else
498: loader_color? if
499: s" ansi_caption[x]"
500: else
501: s" menu_caption[x]"
502: then
503: then
504:
505: ( C-Addr | -1 )
506: dup -1 <> if
507: \ replace 'x' with current iteration
508: -rot 2dup 13 + c! rot
509:
510: \ test for environment variable
511: getenv dup -1 <> if
512: printmenuitem ( C-Addr -- N )
513:
514: s" menukeyN !" \ generate cmd to store result
515: -rot 2dup 7 + c! rot
516:
517: evaluate
518: else
519: drop
520: then
521: else
522: drop
523:
524: s" menu_command[x]"
525: -rot 2dup 13 + c! rot ( replace 'x' )
526: unsetenv
527: then
528:
529: 1+ dup 56 > \ add 1 to iterator, continue if less than 57
530: until
531: drop \ iterator
532:
533: \ Optionally add a reboot option to the menu
534: menurebootadded @ true <> if
535: s" menu_reboot" getenv -1 <> if
536: drop \ no need for the value
537: s" Reboot" \ menu caption (required by printmenuitem)
538:
539: printmenuitem
540: menureboot !
541: else
542: 0 menureboot !
543: then
544: then
545: ;
546:
547: \ Takes a single integer on the stack and updates the timeout display. The
548: \ integer must be between 0 and 9 (we will only update a single digit in the
549: \ source message).
550: \
551: : menu-timeout-update ( N -- )
552:
553: dup 9 > if ( N N 9 -- N )
554: drop ( N -- )
555: 9 ( maximum: -- N )
556: then
557:
558: dup 0 < if ( N N 0 -- N )
559: drop ( N -- )
560: 0 ( minimum: -- N )
561: then
562:
563: 48 + ( convert single-digit numeral to ASCII: N 48 -- N )
564:
565: s" Autoboot in N seconds. [Space] to pause" ( N -- N Addr C )
566:
567: 2 pick 48 - 0> if ( N Addr C N 48 -- N Addr C )
568:
569: \ Modify 'N' (Addr+12) above to reflect time-left
570:
571: -rot ( N Addr C -- C N Addr )
572: tuck ( C N Addr -- C Addr N Addr )
573: 12 + ( C Addr N Addr -- C Addr N Addr2 )
574: c! ( C Addr N Addr2 -- C Addr )
575: swap ( C Addr -- Addr C )
576:
577: menu_timeout_x @
578: menu_timeout_y @
579: at-xy ( position cursor: Addr C N N -- Addr C )
580:
581: type ( print message: Addr C -- )
582:
583: else ( N Addr C N -- N Addr C )
584:
585: menu_timeout_x @
586: menu_timeout_y @
587: at-xy ( position cursor: N Addr C N N -- N Addr C )
588:
589: spaces ( erase message: N Addr C -- N Addr )
590: 2drop ( N Addr -- )
591:
592: then
593:
594: 0 25 at-xy ( position cursor back at bottom-left )
595: ;
596:
597: \ This function blocks program flow (loops forever) until a key is pressed.
598: \ The key that was pressed is added to the top of the stack in the form of its
599: \ decimal ASCII representation. This function is called by the menu-display
600: \ function. You need not call it directly.
601: \
602: : getkey ( -- ascii_keycode )
603:
604: begin \ loop forever
605:
606: menu_timeout_enabled @ 1 = if
607: ( -- )
608: seconds ( get current time: -- N )
609: dup menu_time @ <> if ( has time elapsed?: N N N -- N )
610:
611: \ At least 1 second has elapsed since last loop
612: \ so we will decrement our "timeout" (really a
613: \ counter, insuring that we do not proceed too
614: \ fast) and update our timeout display.
615:
616: menu_time ! ( update time record: N -- )
617: menu_timeout @ ( "time" remaining: -- N )
618: dup 0> if ( greater than 0?: N N 0 -- N )
619: 1- ( decrement counter: N -- N )
620: dup menu_timeout !
621: ( re-assign: N N Addr -- N )
622: then
623: ( -- N )
624:
625: dup 0= swap 0< or if ( N <= 0?: N N -- )
626: \ halt the timer
627: 0 menu_timeout ! ( 0 Addr -- )
628: 0 menu_timeout_enabled ! ( 0 Addr -- )
629: then
630:
631: \ update the timer display ( N -- )
632: menu_timeout @ menu-timeout-update
633:
634: menu_timeout @ 0= if
635: \ We've reached the end of the timeout
636: \ (user did not cancel by pressing ANY
637: \ key)
638:
639: s" menu_timeout_command" getenv dup
640: -1 = if
641: drop \ clean-up
642: else
643: evaluate
644: then
645: then
646:
647: else ( -- N )
648: \ No [detectable] time has elapsed (in seconds)
649: drop ( N -- )
650: then
651: ( -- )
652: then
653:
654: key? if \ Was a key pressed? (see loader(8))
655:
656: \ An actual key was pressed (if the timeout is running,
657: \ kill it regardless of which key was pressed)
658: menu_timeout @ 0<> if
659: 0 menu_timeout !
660: 0 menu_timeout_enabled !
661:
662: \ clear screen of timeout message
663: 0 menu-timeout-update
664: then
665:
666: \ get the key that was pressed and exit (if we
667: \ get a non-zero ASCII code)
668: key dup 0<> if
669: exit
670: else
671: drop
672: then
673: then
674: 50 ms \ sleep for 50 milliseconds (see loader(8))
675:
676: again
677: ;
678:
679: : menu-erase ( -- ) \ Erases menu and resets positioning variable to positon 1.
680:
681: \ Clear the screen area associated with the interactive menu
682: menuX @ menuY @
683: 2dup at-xy 38 spaces 1+ 2dup at-xy 38 spaces 1+
684: 2dup at-xy 38 spaces 1+ 2dup at-xy 38 spaces 1+
685: 2dup at-xy 38 spaces 1+ 2dup at-xy 38 spaces 1+
686: 2dup at-xy 38 spaces 1+ 2dup at-xy 38 spaces 1+
687: 2dup at-xy 38 spaces 1+ 2dup at-xy 38 spaces 1+
688: 2dup at-xy 38 spaces 1+ 2dup at-xy 38 spaces
689: 2drop
690:
691: \ Reset the starting index and position for the menu
692: menu_start 1- menuidx !
693: 0 menurow !
694: ;
695:
696: \ Erase and redraw the menu. Useful if you change a caption and want to
697: \ update the menu to reflect the new value.
698: \
699: : menu-redraw ( -- )
700: menu-erase
701: menu-create
702: ;
703:
704: \ This function initializes the menu. Call this from your `loader.rc' file
705: \ before calling any other menu-related functions.
706: \
707: : menu-init ( -- )
708: menu_start
709: 1- menuidx ! \ Initialize the starting index for the menu
710: 0 menurow ! \ Initialize the starting position for the menu
711: 42 13 2 9 box \ Draw frame (w,h,x,y)
712: 0 25 at-xy \ Move cursor to the bottom for output
713: ;
714:
715: \ Main function. Call this from your `loader.rc' file.
716: \
717: : menu-display ( -- )
718:
719: 0 menu_timeout_enabled ! \ start with automatic timeout disabled
720:
721: \ check indication that automatic execution after delay is requested
722: s" menu_timeout_command" getenv -1 <> if ( Addr C -1 -- | Addr )
723: drop ( just testing existence right now: Addr -- )
724:
725: \ initialize state variables
726: seconds menu_time ! ( store the time we started )
727: 1 menu_timeout_enabled ! ( enable automatic timeout )
728:
729: \ read custom time-duration (if set)
730: s" autoboot_delay" getenv dup -1 = if
731: drop \ no custom duration (remove dup'd bunk -1)
732: menu_timeout_default \ use default setting
733: else
734: 2dup ?number 0= if ( if not a number )
735: \ disable timeout if "NO", else use default
736: s" NO" compare-insensitive 0= if
737: 0 menu_timeout_enabled !
738: 0 ( assigned to menu_timeout below )
739: else
740: menu_timeout_default
741: then
742: else
743: -rot 2drop
744:
745: \ boot immediately if less than zero
746: dup 0< if
747: drop
748: menu-create
749: 0 25 at-xy
750: 0 boot
751: then
752: then
753: then
754: menu_timeout ! ( store value on stack from above )
755:
756: menu_timeout_enabled @ 1 = if
757: \ read custom column position (if set)
758: s" loader_menu_timeout_x" getenv dup -1 = if
759: drop \ no custom column position
760: menu_timeout_default_x \ use default setting
761: else
762: \ make sure custom position is a number
763: ?number 0= if
764: menu_timeout_default_x \ or use default
765: then
766: then
767: menu_timeout_x ! ( store value on stack from above )
768:
769: \ read custom row position (if set)
770: s" loader_menu_timeout_y" getenv dup -1 = if
771: drop \ no custom row position
772: menu_timeout_default_y \ use default setting
773: else
774: \ make sure custom position is a number
775: ?number 0= if
776: menu_timeout_default_y \ or use default
777: then
778: then
779: menu_timeout_y ! ( store value on stack from above )
780: then
781: then
782:
783: menu-create
784:
785: begin \ Loop forever
786:
787: 0 25 at-xy \ Move cursor to the bottom for output
788: getkey \ Block here, waiting for a key to be pressed
789:
790: dup -1 = if
791: drop exit \ Caught abort (abnormal return)
792: then
793:
794: \ Boot if the user pressed Enter/Ctrl-M (13) or
795: \ Ctrl-Enter/Ctrl-J (10)
796: dup over 13 = swap 10 = or if
797: drop ( no longer needed )
798: s" boot" evaluate
799: exit ( pedantic; never reached )
800: then
801:
802: \ Evaluate the decimal ASCII value against known menu item
803: \ key associations and act accordingly
804:
805: 49 \ Iterator start (loop range 49 to 56; ASCII '1' to '8')
806: begin
807: s" menukeyN @"
808:
809: \ replace 'N' with current iteration
810: -rot 2dup 7 + c! rot
811:
812: evaluate rot tuck = if
813:
814: \ Adjust for missing ACPI menuitem on non-i386
815: arch-i386? true <> menuacpi @ 0<> and if
816: menuacpi @ over 2dup < -rot = or
817: over 58 < and if
818: ( key >= menuacpi && key < 58: N -- N )
819: 1+
820: then
821: then
822:
823: \ base env name for the value (x is a number)
824: s" menu_command[x]"
825:
826: \ Copy ASCII number to string at offset 13
827: -rot 2dup 13 + c! rot
828:
829: \ Test for the environment variable
830: getenv dup -1 <> if
831: \ Execute the stored procedure
832: evaluate
833:
834: \ We expect there to be a non-zero
835: \ value left on the stack after
836: \ executing the stored procedure.
837: \ If so, continue to run, else exit.
838:
839: 0= if
840: drop \ key pressed
841: drop \ loop iterator
842: exit
843: else
844: swap \ need iterator on top
845: then
846: then
847:
848: \ Re-adjust for missing ACPI menuitem
849: arch-i386? true <> menuacpi @ 0<> and if
850: swap
851: menuacpi @ 1+ over 2dup < -rot = or
852: over 59 < and if
853: 1-
854: then
855: swap
856: then
857: else
858: swap \ need iterator on top
859: then
860:
861: \
862: \ Check for menu keycode shortcut(s)
863: \
864: s" menu_keycode[x]"
865: -rot 2dup 13 + c! rot
866: getenv dup -1 = if
867: drop
868: else
869: ?number 0<> if
870: rot tuck = if
871: swap
872: s" menu_command[x]"
873: -rot 2dup 13 + c! rot
874: getenv dup -1 <> if
875: evaluate
876: 0= if
877: 2drop
878: exit
879: then
880: else
881: drop
882: then
883: else
884: swap
885: then
886: then
887: then
888:
889: 1+ dup 56 > \ increment iterator
890: \ continue if less than 57
891: until
892: drop \ loop iterator
893:
894: menureboot @ = if 0 reboot then
895:
896: again \ Non-operational key was pressed; repeat
897: ;
898:
899: \ This function unsets all the possible environment variables associated with
900: \ creating the interactive menu. Call this when you want to clear the menu
901: \ area in preparation for another menu.
902: \
903: : menu-clear ( -- )
904:
905: 49 \ Iterator start (loop range 49 to 56; ASCII '1' to '8')
906: begin
907: \ basename for caption variable
908: loader_color? if
909: s" ansi_caption[x]"
910: else
911: s" menu_caption[x]"
912: then
913: -rot 2dup 13 + c! rot \ replace 'x' with current iteration
914: unsetenv \ not erroneous to unset unknown var
915:
916: s" 0 menukeyN !" \ basename for key association var
917: -rot 2dup 9 + c! rot \ replace 'N' with current iteration
918: evaluate \ assign zero (0) to key assoc. var
919:
920: 1+ dup 56 > \ increment, continue if less than 57
921: until
922: drop \ iterator
923:
924: \ clear the "Reboot" menu option flag
925: s" menu_reboot" unsetenv
926: 0 menureboot !
927:
928: \ clear the ACPI menu option flag
929: s" menu_acpi" unsetenv
930: 0 menuacpi !
931:
932: \ clear the "Options" menu separator flag
933: s" menu_options" unsetenv
934: 0 menuoptions !
935:
936: menu-erase
937: ;
938:
939: \ Assign configuration values
940: bullet menubllt !
941: 10 menuY !
942: 5 menuX !
943:
944: \ Initialize our boolean state variables
945: 0 toggle_state1 !
946: 0 toggle_state2 !
947: 0 toggle_state3 !
948: 0 toggle_state4 !
949: 0 toggle_state5 !
950: 0 toggle_state6 !
951: 0 toggle_state7 !
952: 0 toggle_state8 !
953:
954: \ Initialize our array state variables
955: 0 cycle_state1 !
956: 0 cycle_state2 !
957: 0 cycle_state3 !
958: 0 cycle_state4 !
959: 0 cycle_state5 !
960: 0 cycle_state6 !
961: 0 cycle_state7 !
962: 0 cycle_state8 !
963:
964: \ Initialize string containers
965: 0 init_text1 c!
966: 0 init_text2 c!
967: 0 init_text3 c!
968: 0 init_text4 c!
969: 0 init_text5 c!
970: 0 init_text6 c!
971: 0 init_text7 c!
972: 0 init_text8 c!
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>