Annotation of elwix/config/boot/menu.4th, revision 1.4

1.2       misho       1: \ Copyright (c) 2003 Scott Long <scottl@freebsd.org>
                      2: \ Copyright (c) 2003 Aleksander Fafula <alex@fafula.com>
1.4     ! misho       3: \ Copyright (c) 2006-2013 Devin Teske <dteske@FreeBSD.org>
1.2       misho       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: \ 
1.4     ! misho      27: \ $FreeBSD: head/sys/boot/forth/menu.4th 257650 2013-11-04 20:28:10Z dteske $
        !            28: \
        !            29: \ $Id: menu.4th,v 1.3.12.1 2014/01/07 15:50:18 misho Exp $
1.2       misho      30: 
                     31: marker task-menu.4th
                     32: 
                     33: \ Frame drawing
                     34: include /boot/frames.4th
                     35: 
                     36: f_double        \ Set frames to double (see frames.4th). Replace with
                     37:                 \ f_single if you want single frames.
                     38: 46 constant dot \ ASCII definition of a period (in decimal)
                     39: 
1.4     ! misho      40:  5 constant menu_default_x         \ default column position of timeout
        !            41: 10 constant menu_default_y         \ default row position of timeout msg
1.2       misho      42:  4 constant menu_timeout_default_x \ default column position of timeout
                     43: 23 constant menu_timeout_default_y \ default row position of timeout msg
                     44: 10 constant menu_timeout_default   \ default timeout (in seconds)
                     45: 
                     46: \ Customize the following values with care
                     47: 
                     48:   1 constant menu_start \ Numerical prefix of first menu item
                     49: dot constant bullet     \ Menu bullet (appears after numerical prefix)
                     50:   5 constant menu_x     \ Row position of the menu (from the top)
                     51:  10 constant menu_y     \ Column position of the menu (from left side)
                     52: 
                     53: \ Menu Appearance
                     54: variable menuidx   \ Menu item stack for number prefixes
                     55: variable menurow   \ Menu item stack for positioning
                     56: variable menubllt  \ Menu item bullet
                     57: 
                     58: \ Menu Positioning
                     59: variable menuX     \ Menu X offset (columns)
                     60: variable menuY     \ Menu Y offset (rows)
                     61: 
                     62: \ Menu-item key association/detection
                     63: variable menukey1
                     64: variable menukey2
                     65: variable menukey3
                     66: variable menukey4
                     67: variable menukey5
                     68: variable menukey6
                     69: variable menukey7
                     70: variable menukey8
                     71: variable menureboot
                     72: variable menurebootadded
                     73: variable menuacpi
                     74: variable menuoptions
1.4     ! misho      75: variable menukernel
        !            76: 
        !            77: \ Parsing of kernels into menu-items
        !            78: variable kernidx
        !            79: variable kernlen
        !            80: variable kernmenuidx
1.2       misho      81: 
                     82: \ Menu timer [count-down] variables
                     83: variable menu_timeout_enabled \ timeout state (internal use only)
                     84: variable menu_time            \ variable for tracking the passage of time
                     85: variable menu_timeout         \ determined configurable delay duration
                     86: variable menu_timeout_x       \ column position of timeout message
                     87: variable menu_timeout_y       \ row position of timeout message
                     88: 
1.3       misho      89: \ Menu initialization status variables
                     90: variable init_state1
                     91: variable init_state2
                     92: variable init_state3
                     93: variable init_state4
                     94: variable init_state5
                     95: variable init_state6
                     96: variable init_state7
                     97: variable init_state8
                     98: 
1.2       misho      99: \ Boolean option status variables
                    100: variable toggle_state1
                    101: variable toggle_state2
                    102: variable toggle_state3
                    103: variable toggle_state4
                    104: variable toggle_state5
                    105: variable toggle_state6
                    106: variable toggle_state7
                    107: variable toggle_state8
                    108: 
                    109: \ Array option status variables
                    110: variable cycle_state1
                    111: variable cycle_state2
                    112: variable cycle_state3
                    113: variable cycle_state4
                    114: variable cycle_state5
                    115: variable cycle_state6
                    116: variable cycle_state7
                    117: variable cycle_state8
                    118: 
                    119: \ Containers for storing the initial caption text
1.4     ! misho     120: create init_text1 64 allot
        !           121: create init_text2 64 allot
        !           122: create init_text3 64 allot
        !           123: create init_text4 64 allot
        !           124: create init_text5 64 allot
        !           125: create init_text6 64 allot
        !           126: create init_text7 64 allot
        !           127: create init_text8 64 allot
        !           128: 
        !           129: \ Containers for parsing kernels into menu-items
        !           130: create kerncapbuf 64 allot
        !           131: create kerndefault 64 allot
        !           132: create kernelsbuf 256 allot
1.2       misho     133: 
1.3       misho     134: : +c! ( N C-ADDR/U K -- C-ADDR/U )
                    135:        3 pick 3 pick   ( n c-addr/u k -- n c-addr/u k n c-addr )
                    136:        rot + c!        ( n c-addr/u k n c-addr -- n c-addr/u )
                    137:        rot drop        ( n c-addr/u -- c-addr/u )
                    138: ;
                    139: 
1.4     ! misho     140: : delim? ( C -- BOOL )
        !           141:        dup  32 =               ( c -- c bool )         \ [sp] space
        !           142:        over  9 = or            ( c bool -- c bool )    \ [ht] horizontal tab
        !           143:        over 10 = or            ( c bool -- c bool )    \ [nl] newline
        !           144:        over 13 = or            ( c bool -- c bool )    \ [cr] carriage return
        !           145:        over [char] , = or      ( c bool -- c bool )    \ comma
        !           146:        swap drop               ( c bool -- bool )      \ return boolean
        !           147: ;
        !           148: 
1.3       misho     149: : menukeyN      ( N -- ADDR )   s" menukeyN"       7 +c! evaluate ;
                    150: : init_stateN   ( N -- ADDR )   s" init_stateN"   10 +c! evaluate ;
                    151: : toggle_stateN ( N -- ADDR )   s" toggle_stateN" 12 +c! evaluate ;
                    152: : cycle_stateN  ( N -- ADDR )   s" cycle_stateN"  11 +c! evaluate ;
                    153: : init_textN    ( N -- C-ADDR ) s" init_textN"     9 +c! evaluate ;
                    154: 
1.4     ! misho     155: : kernel[x]          ( N -- C-ADDR/U )   s" kernel[x]"           7 +c! ;
        !           156: : menu_init[x]       ( N -- C-ADDR/U )   s" menu_init[x]"       10 +c! ;
        !           157: : menu_command[x]    ( N -- C-ADDR/U )   s" menu_command[x]"    13 +c! ;
        !           158: : menu_caption[x]    ( N -- C-ADDR/U )   s" menu_caption[x]"    13 +c! ;
        !           159: : ansi_caption[x]    ( N -- C-ADDR/U )   s" ansi_caption[x]"    13 +c! ;
        !           160: : menu_keycode[x]    ( N -- C-ADDR/U )   s" menu_keycode[x]"    13 +c! ;
        !           161: : toggled_text[x]    ( N -- C-ADDR/U )   s" toggled_text[x]"    13 +c! ;
        !           162: : toggled_ansi[x]    ( N -- C-ADDR/U )   s" toggled_ansi[x]"    13 +c! ;
        !           163: : menu_caption[x][y] ( N M -- C-ADDR/U ) s" menu_caption[x][y]" 16 +c! 13 +c! ;
        !           164: : ansi_caption[x][y] ( N M -- C-ADDR/U ) s" ansi_caption[x][y]" 16 +c! 13 +c! ;
1.3       misho     165: 
1.2       misho     166: : arch-i386? ( -- BOOL ) \ Returns TRUE (-1) on i386, FALSE (0) otherwise.
                    167:        s" arch-i386" environment? dup if
                    168:                drop
                    169:        then
                    170: ;
                    171: 
                    172: \ This function prints a menu item at menuX (row) and menuY (column), returns
                    173: \ the incremental decimal ASCII value associated with the menu item, and
                    174: \ increments the cursor position to the next row for the creation of the next
                    175: \ menu item. This function is called by the menu-create function. You need not
                    176: \ call it directly.
                    177: \ 
                    178: : printmenuitem ( menu_item_str -- ascii_keycode )
                    179: 
                    180:        menurow dup @ 1+ swap ! ( increment menurow )
                    181:        menuidx dup @ 1+ swap ! ( increment menuidx )
                    182: 
                    183:        \ Calculate the menuitem row position
                    184:        menurow @ menuY @ +
                    185: 
                    186:        \ Position the cursor at the menuitem position
                    187:        dup menuX @ swap at-xy
                    188: 
                    189:        \ Print the value of menuidx
                    190:        loader_color? if
1.3       misho     191:                ." " (  )
1.2       misho     192:        then
                    193:        menuidx @ .
                    194:        loader_color? if
1.3       misho     195:                ." " (  )
1.2       misho     196:        then
                    197: 
                    198:        \ Move the cursor forward 1 column
                    199:        dup menuX @ 1+ swap at-xy
                    200: 
                    201:        menubllt @ emit \ Print the menu bullet using the emit function
                    202: 
                    203:        \ Move the cursor to the 3rd column from the current position
                    204:        \ to allow for a space between the numerical prefix and the
                    205:        \ text caption
                    206:        menuX @ 3 + swap at-xy
                    207: 
                    208:        \ Print the menu caption (we expect a string to be on the stack
                    209:        \ prior to invoking this function)
                    210:        type
                    211: 
                    212:        \ Here we will add the ASCII decimal of the numerical prefix
                    213:        \ to the stack (decimal ASCII for `1' is 49) as a "return value"
                    214:        menuidx @ 48 +
                    215: ;
                    216: 
                    217: : toggle_menuitem ( N -- N ) \ toggles caption text and internal menuitem state
                    218: 
                    219:        \ ASCII numeral equal to user-selected menu item must be on the stack.
                    220:        \ We do not modify the stack, so the ASCII numeral is left on top.
                    221: 
1.3       misho     222:        dup init_textN c@ 0= if
1.2       misho     223:                \ NOTE: no need to check toggle_stateN since the first time we
                    224:                \ are called, we will populate init_textN. Further, we don't
                    225:                \ need to test whether menu_caption[x] (ansi_caption[x] when
1.4     ! misho     226:                \ loader_color?=1) is available since we would not have been
1.2       misho     227:                \ called if the caption was NULL.
                    228: 
                    229:                \ base name of environment variable
1.3       misho     230:                dup ( n -- n n ) \ key pressed
1.2       misho     231:                loader_color? if
1.3       misho     232:                        ansi_caption[x]
1.2       misho     233:                else
1.3       misho     234:                        menu_caption[x]
1.2       misho     235:                then    
                    236:                getenv dup -1 <> if
                    237: 
1.3       misho     238:                        2 pick ( n c-addr/u -- n c-addr/u n )
                    239:                        init_textN ( n c-addr/u n -- n c-addr/u c-addr )
1.2       misho     240: 
                    241:                        \ now we have the buffer c-addr on top
                    242:                        \ ( followed by c-addr/u of current caption )
                    243: 
                    244:                        \ Copy the current caption into our buffer
                    245:                        2dup c! -rot \ store strlen at first byte
                    246:                        begin
                    247:                                rot 1+    \ bring alt addr to top and increment
                    248:                                -rot -rot \ bring buffer addr to top
                    249:                                2dup c@ swap c! \ copy current character
                    250:                                1+     \ increment buffer addr
                    251:                                rot 1- \ bring buffer len to top and decrement
                    252:                                dup 0= \ exit loop if buffer len is zero
                    253:                        until
                    254:                        2drop \ buffer len/addr
                    255:                        drop  \ alt addr
                    256: 
                    257:                else
                    258:                        drop
                    259:                then
                    260:        then
                    261: 
                    262:        \ Now we are certain to have init_textN populated with the initial
                    263:        \ value of menu_caption[x] (ansi_caption[x] with loader_color enabled).
                    264:        \ We can now use init_textN as the untoggled caption and
                    265:        \ toggled_text[x] (toggled_ansi[x] with loader_color enabled) as the
                    266:        \ toggled caption and store the appropriate value into menu_caption[x]
                    267:        \ (again, ansi_caption[x] with loader_color enabled). Last, we'll
                    268:        \ negate the toggled state so that we reverse the flow on subsequent
                    269:        \ calls.
                    270: 
1.3       misho     271:        dup toggle_stateN @ 0= if
1.2       misho     272:                \ state is OFF, toggle to ON
                    273: 
1.3       misho     274:                dup ( n -- n n ) \ key pressed
1.2       misho     275:                loader_color? if
1.3       misho     276:                        toggled_ansi[x]
1.2       misho     277:                else
1.3       misho     278:                        toggled_text[x]
1.2       misho     279:                then
                    280:                getenv dup -1 <> if
                    281:                        \ Assign toggled text to menu caption
1.3       misho     282:                        2 pick ( n c-addr/u -- n c-addr/u n ) \ key pressed
1.2       misho     283:                        loader_color? if
1.3       misho     284:                                ansi_caption[x]
1.2       misho     285:                        else
1.3       misho     286:                                menu_caption[x]
1.2       misho     287:                        then
1.3       misho     288:                        setenv
1.2       misho     289:                else
                    290:                        \ No toggled text, keep the same caption
1.3       misho     291:                        drop ( n -1 -- n ) \ getenv cruft
1.2       misho     292:                then
                    293: 
                    294:                true \ new value of toggle state var (to be stored later)
                    295:        else
                    296:                \ state is ON, toggle to OFF
                    297: 
1.3       misho     298:                dup init_textN count ( n -- n c-addr/u )
1.2       misho     299: 
1.3       misho     300:                \ Assign init_textN text to menu caption
                    301:                2 pick ( n c-addr/u -- n c-addr/u n ) \ key pressed
1.2       misho     302:                loader_color? if
1.3       misho     303:                        ansi_caption[x]
1.2       misho     304:                else
1.3       misho     305:                        menu_caption[x]
1.2       misho     306:                then
1.3       misho     307:                setenv
1.2       misho     308: 
1.3       misho     309:                false \ new value of toggle state var (to be stored below)
1.2       misho     310:        then
                    311: 
                    312:        \ now we'll store the new toggle state (on top of stack)
1.3       misho     313:        over toggle_stateN !
1.2       misho     314: ;
                    315: 
                    316: : cycle_menuitem ( N -- N ) \ cycles through array of choices for a menuitem
                    317: 
                    318:        \ ASCII numeral equal to user-selected menu item must be on the stack.
                    319:        \ We do not modify the stack, so the ASCII numeral is left on top.
                    320: 
1.3       misho     321:        dup cycle_stateN dup @ 1+ \ get value and increment
1.2       misho     322: 
                    323:        \ Before assigning the (incremented) value back to the pointer,
                    324:        \ let's test for the existence of this particular array element.
                    325:        \ If the element exists, we'll store index value and move on.
                    326:        \ Otherwise, we'll loop around to zero and store that.
                    327: 
1.3       misho     328:        dup 48 + ( n addr k -- n addr k k' )
                    329:                 \ duplicate array index and convert to ASCII numeral
1.2       misho     330: 
1.3       misho     331:        3 pick swap ( n addr k k' -- n addr k n k' ) \ (n,k') as (x,y)
1.2       misho     332:        loader_color? if
1.3       misho     333:                ansi_caption[x][y]
1.2       misho     334:        else
1.3       misho     335:                menu_caption[x][y]
1.2       misho     336:        then
1.3       misho     337:        ( n addr k n k' -- n addr k c-addr/u )
1.2       misho     338: 
                    339:        \ Now test for the existence of our incremented array index in the
                    340:        \ form of $menu_caption[x][y] ($ansi_caption[x][y] with loader_color
                    341:        \ enabled) as set in loader.rc(5), et. al.
                    342: 
                    343:        getenv dup -1 = if
                    344:                \ No caption set for this array index. Loop back to zero.
                    345: 
1.3       misho     346:                drop ( n addr k -1 -- n addr k ) \ getenv cruft
                    347:                drop 0 ( n addr k -- n addr 0 )  \ new value to store later
1.2       misho     348: 
1.3       misho     349:                2 pick [char] 0 ( n addr 0 -- n addr 0 n 48 ) \ (n,48) as (x,y)
1.2       misho     350:                loader_color? if
1.3       misho     351:                        ansi_caption[x][y]
1.2       misho     352:                else
1.3       misho     353:                        menu_caption[x][y]
1.2       misho     354:                then
1.3       misho     355:                ( n addr 0 n 48 -- n addr 0 c-addr/u )
1.2       misho     356:                getenv dup -1 = if
1.4     ! misho     357:                        \ Highly unlikely to occur, but to ensure things move
        !           358:                        \ along smoothly, allocate a temporary NULL string
        !           359:                        drop ( cruft ) s" "
1.2       misho     360:                then
                    361:        then
                    362: 
                    363:        \ At this point, we should have the following on the stack (in order,
                    364:        \ from bottom to top):
                    365:        \ 
1.3       misho     366:        \    n        - Ascii numeral representing the menu choice (inherited)
                    367:        \    addr     - address of our internal cycle_stateN variable
                    368:        \    k        - zero-based number we intend to store to the above
                    369:        \    c-addr/u - string value we intend to store to menu_caption[x]
                    370:        \               (or ansi_caption[x] with loader_color enabled)
1.2       misho     371:        \ 
                    372:        \ Let's perform what we need to with the above.
                    373: 
1.3       misho     374:        \ Assign array value text to menu caption
                    375:        4 pick ( n addr k c-addr/u -- n addr k c-addr/u n )
1.2       misho     376:        loader_color? if
1.3       misho     377:                ansi_caption[x]
1.2       misho     378:        else
1.3       misho     379:                menu_caption[x]
1.2       misho     380:        then
1.3       misho     381:        setenv
1.2       misho     382: 
1.3       misho     383:        swap ! ( n addr k -- n ) \ update array state variable
1.2       misho     384: ;
                    385: 
                    386: : acpipresent? ( -- flag ) \ Returns TRUE if ACPI is present, FALSE otherwise
                    387:        s" hint.acpi.0.rsdp" getenv
                    388:        dup -1 = if
                    389:                drop false exit
                    390:        then
                    391:        2drop
                    392:        true
                    393: ;
                    394: 
                    395: : acpienabled? ( -- flag ) \ Returns TRUE if ACPI is enabled, FALSE otherwise
                    396:        s" hint.acpi.0.disabled" getenv
                    397:        dup -1 <> if
                    398:                s" 0" compare 0<> if
                    399:                        false exit
                    400:                then
                    401:        else
                    402:                drop
                    403:        then
                    404:        true
                    405: ;
                    406: 
                    407: \ This function prints the appropriate menuitem basename to the stack if an
                    408: \ ACPI option is to be presented to the user, otherwise returns -1. Used
                    409: \ internally by menu-create, you need not (nor should you) call this directly.
                    410: \ 
1.3       misho     411: : acpimenuitem ( -- C-Addr/U | -1 )
1.2       misho     412: 
                    413:        arch-i386? if
                    414:                acpipresent? if
                    415:                        acpienabled? if
                    416:                                loader_color? if
1.4     ! misho     417:                                        s" toggled_ansi[x]"
1.2       misho     418:                                else
1.4     ! misho     419:                                        s" toggled_text[x]"
1.2       misho     420:                                then
                    421:                        else
                    422:                                loader_color? if
1.4     ! misho     423:                                        s" ansi_caption[x]"
1.2       misho     424:                                else
1.4     ! misho     425:                                        s" menu_caption[x]"
1.2       misho     426:                                then
                    427:                        then
                    428:                else
                    429:                        menuidx dup @ 1+ swap ! ( increment menuidx )
                    430:                        -1
                    431:                then
                    432:        else
                    433:                -1
                    434:        then
                    435: ;
                    436: 
1.4     ! misho     437: \ This function parses $kernels into variables that are used by the menu to
        !           438: \ display wich kernel to boot when the [overloaded] `boot' word is interpreted.
        !           439: \ Used internally by menu-create, you need not (nor should you) call this
        !           440: \ directly.
        !           441: \ 
        !           442: : parse-kernels ( N -- ) \ kernidx
        !           443:        kernidx ! ( n -- )      \ store provided `x' value
        !           444:        [char] 0 kernmenuidx !  \ initialize `y' value for menu_caption[x][y]
        !           445: 
        !           446:        \ Attempt to get a list of kernels, fall back to sensible default
        !           447:        s" kernels" getenv dup -1 = if
        !           448:                drop ( cruft )
        !           449:                s" kernel kernel.old"
        !           450:        then ( -- c-addr/u )
        !           451: 
        !           452:        \ Check to see if the user has altered $kernel by comparing it against
        !           453:        \ $kernel[N] where N is kernel_state (the actively displayed kernel).
        !           454:        s" kernel_state" evaluate @ 48 + s" kernel[N]" 7 +c! getenv
        !           455:        dup -1 <> if
        !           456:                s" kernel" getenv dup -1 = if
        !           457:                        drop ( cruft ) s" "
        !           458:                then
        !           459:                2swap 2over compare 0= if
        !           460:                        2drop FALSE ( skip below conditional )
        !           461:                else \ User has changed $kernel
        !           462:                        TRUE ( slurp in new value )
        !           463:                then
        !           464:        else \ We haven't yet parsed $kernels into $kernel[N]
        !           465:                drop ( getenv cruft )
        !           466:                s" kernel" getenv dup -1 = if
        !           467:                        drop ( cruft ) s" "
        !           468:                then
        !           469:                TRUE ( slurp in initial value )
        !           470:        then ( c-addr/u -- c-addr/u c-addr/u,-1 | 0 )
        !           471:        if \ slurp new value into kerndefault
        !           472:                kerndefault 1+ 0 2swap strcat swap 1- c!
        !           473:        then
        !           474: 
        !           475:        \ Clear out existing parsed-kernels
        !           476:        kernidx @ [char] 0
        !           477:        begin
        !           478:                dup kernel[x] unsetenv
        !           479:                2dup menu_caption[x][y] unsetenv
        !           480:                2dup ansi_caption[x][y] unsetenv
        !           481:                1+ dup [char] 8 >
        !           482:        until
        !           483:        2drop
        !           484: 
        !           485:        \ Step through the string until we find the end
        !           486:        begin
        !           487:                0 kernlen ! \ initialize length of value
        !           488: 
        !           489:                \ Skip leading whitespace and/or comma delimiters
        !           490:                begin
        !           491:                        dup 0<> if
        !           492:                                over c@ delim? ( c-addr/u -- c-addr/u bool )
        !           493:                        else
        !           494:                                false ( c-addr/u -- c-addr/u bool )
        !           495:                        then
        !           496:                while
        !           497:                        1- swap 1+ swap ( c-addr/u -- c-addr'/u' )
        !           498:                repeat
        !           499:                ( c-addr/u -- c-addr'/u' )
        !           500: 
        !           501:                dup 0= if \ end of string while eating whitespace
        !           502:                        2drop ( c-addr/u -- )
        !           503:                        kernmenuidx @ [char] 0 <> if \ found at least one
        !           504:                                exit \ all done
        !           505:                        then
        !           506: 
        !           507:                        \ No entries in $kernels; use $kernel instead
        !           508:                        s" kernel" getenv dup -1 = if
        !           509:                                drop ( cruft ) s" "
        !           510:                        then ( -- c-addr/u )
        !           511:                        dup kernlen ! \ store entire value length as kernlen
        !           512:                else
        !           513:                        \ We're still within $kernels parsing toward the end;
        !           514:                        \ find delimiter/end to determine kernlen
        !           515:                        2dup ( c-addr/u -- c-addr/u c-addr/u )
        !           516:                        begin dup 0<> while
        !           517:                                over c@ delim? if
        !           518:                                        drop 0 ( break ) \ found delimiter
        !           519:                                else
        !           520:                                        kernlen @ 1+ kernlen ! \ incrememnt
        !           521:                                        1- swap 1+ swap \ c-addr++ u--
        !           522:                                then
        !           523:                        repeat
        !           524:                        2drop ( c-addr/u c-addr'/u' -- c-addr/u )
        !           525: 
        !           526:                        \ If this is the first entry, compare it to $kernel
        !           527:                        \ If different, then insert $kernel beforehand
        !           528:                        kernmenuidx @ [char] 0 = if
        !           529:                                over kernlen @ kerndefault count compare if
        !           530:                                        kernelsbuf 0 kerndefault count strcat
        !           531:                                        s" ," strcat 2swap strcat
        !           532:                                        kerndefault count swap drop kernlen !
        !           533:                                then
        !           534:                        then
        !           535:                then
        !           536:                ( c-addr/u -- c-addr'/u' )
        !           537: 
        !           538:                \ At this point, we should have something on the stack to store
        !           539:                \ as the next kernel menu option; start assembling variables
        !           540: 
        !           541:                over kernlen @ ( c-addr/u -- c-addr/u c-addr/u2 )
        !           542: 
        !           543:                \ Assign first to kernel[x]
        !           544:                2dup kernmenuidx @ kernel[x] setenv
        !           545: 
        !           546:                \ Assign second to menu_caption[x][y]
        !           547:                kerncapbuf 0 s" [K]ernel: " strcat
        !           548:                2over strcat
        !           549:                kernidx @ kernmenuidx @ menu_caption[x][y]
        !           550:                setenv
        !           551: 
        !           552:                \ Assign third to ansi_caption[x][y]
        !           553:                kerncapbuf 0 s" Kernel: " strcat
        !           554:                kernmenuidx @ [char] 0 = if
        !           555:                        s" default/"
        !           556:                else
        !           557:                        s" "
        !           558:                then strcat
        !           559:                2over strcat
        !           560:                s" " strcat
        !           561:                kernidx @ kernmenuidx @ ansi_caption[x][y]
        !           562:                setenv
        !           563: 
        !           564:                2drop ( c-addr/u c-addr/u2 -- c-addr/u )
        !           565: 
        !           566:                kernmenuidx @ 1+ dup kernmenuidx ! [char] 8 > if
        !           567:                        2drop ( c-addr/u -- ) exit
        !           568:                then
        !           569: 
        !           570:                kernlen @ - swap kernlen @ + swap ( c-addr/u -- c-addr'/u' )
        !           571:        again
        !           572: ;
        !           573: 
        !           574: \ This function goes through the kernels that were discovered by the
        !           575: \ parse-kernels function [above], adding " (# of #)" text to the end of each
        !           576: \ caption.
        !           577: \ 
        !           578: : tag-kernels ( -- )
        !           579:        kernidx @ ( -- x ) dup 0= if exit then
        !           580:        [char] 0 s"  (Y of Z)" ( x -- x y c-addr/u )
        !           581:        kernmenuidx @ -rot 7 +c! \ Replace 'Z' with number of kernels parsed
        !           582:        begin
        !           583:                2 pick 1+ -rot 2 +c! \ Replace 'Y' with current ASCII num
        !           584: 
        !           585:                2over menu_caption[x][y] getenv dup -1 <> if
        !           586:                        2dup + 1- c@ [char] ) = if
        !           587:                                2drop \ Already tagged
        !           588:                        else
        !           589:                                kerncapbuf 0 2swap strcat
        !           590:                                2over strcat
        !           591:                                5 pick 5 pick menu_caption[x][y] setenv
        !           592:                        then
        !           593:                else
        !           594:                        drop ( getenv cruft )
        !           595:                then
        !           596: 
        !           597:                2over ansi_caption[x][y] getenv dup -1 <> if
        !           598:                        2dup + 1- c@ [char] ) = if
        !           599:                                2drop \ Already tagged
        !           600:                        else
        !           601:                                kerncapbuf 0 2swap strcat
        !           602:                                2over strcat
        !           603:                                5 pick 5 pick ansi_caption[x][y] setenv
        !           604:                        then
        !           605:                else
        !           606:                        drop ( getenv cruft )
        !           607:                then
        !           608: 
        !           609:                rot 1+ dup [char] 8 > if
        !           610:                        -rot 2drop TRUE ( break )
        !           611:                else
        !           612:                        -rot FALSE
        !           613:                then
        !           614:        until
        !           615:        2drop ( x y -- )
        !           616: ;
        !           617: 
1.2       misho     618: \ This function creates the list of menu items. This function is called by the
                    619: \ menu-display function. You need not be call it directly.
                    620: \ 
                    621: : menu-create ( -- )
                    622: 
                    623:        \ Print the frame caption at (x,y)
1.4     ! misho     624:        s" loader_menu_title" getenv dup -1 = if
1.2       misho     625:                drop s" Welcome to -ELWIX-"
                    626:        then
1.4     ! misho     627:        TRUE ( use default alignment )
        !           628:        s" loader_menu_title_align" getenv dup -1 <> if
        !           629:                2dup s" left" compare-insensitive 0= if ( 1 )
        !           630:                        2drop ( c-addr/u ) drop ( bool )
        !           631:                        menuX @ menuY @ 1-
        !           632:                        FALSE ( don't use default alignment )
        !           633:                else ( 1 ) 2dup s" right" compare-insensitive 0= if ( 2 )
        !           634:                        2drop ( c-addr/u ) drop ( bool )
        !           635:                        menuX @ 42 + 4 - over - menuY @ 1-
        !           636:                        FALSE ( don't use default alignment )
        !           637:                else ( 2 ) 2drop ( c-addr/u ) then ( 1 ) then
        !           638:        else
        !           639:                drop ( getenv cruft )
        !           640:        then
        !           641:        if ( use default center alignement? )
        !           642:                menuX @ 19 + over 2 / - menuY @ 1-
        !           643:        then
        !           644:        at-xy type 
1.2       misho     645: 
1.3       misho     646:        \ If $menu_init is set, evaluate it (allowing for whole menus to be
                    647:        \ constructed dynamically -- as this function could conceivably set
                    648:        \ the remaining environment variables to construct the menu entirely).
                    649:        \ 
1.4     ! misho     650:        s" menu_init" getenv dup -1 <> if
1.3       misho     651:                evaluate
                    652:        else
                    653:                drop
                    654:        then
                    655: 
1.2       misho     656:        \ Print our menu options with respective key/variable associations.
                    657:        \ `printmenuitem' ends by adding the decimal ASCII value for the
                    658:        \ numerical prefix to the stack. We store the value left on the stack
                    659:        \ to the key binding variable for later testing against a character
                    660:        \ captured by the `getkey' function.
                    661: 
                    662:        \ Note that any menu item beyond 9 will have a numerical prefix on the
                    663:        \ screen consisting of the first digit (ie. 1 for the tenth menu item)
                    664:        \ and the key required to activate that menu item will be the decimal
                    665:        \ ASCII of 48 plus the menu item (ie. 58 for the tenth item, aka. `:')
                    666:        \ which is misleading and not desirable.
                    667:        \ 
                    668:        \ Thus, we do not allow more than 8 configurable items on the menu
                    669:        \ (with "Reboot" as the optional ninth and highest numbered item).
                    670: 
                    671:        \ 
                    672:        \ Initialize the ACPI option status.
                    673:        \ 
                    674:        0 menuacpi !
1.4     ! misho     675:        s" menu_acpi" getenv -1 <> if
1.2       misho     676:                c@ dup 48 > over 57 < and if ( '1' <= c1 <= '8' )
                    677:                        menuacpi !
                    678:                        arch-i386? if acpipresent? if
                    679:                                \ 
                    680:                                \ Set menu toggle state to active state
                    681:                                \ (required by generic toggle_menuitem)
                    682:                                \ 
1.3       misho     683:                                acpienabled? menuacpi @ toggle_stateN !
1.2       misho     684:                        then then
                    685:                else
                    686:                        drop
                    687:                then
                    688:        then
                    689: 
                    690:        \ 
1.4     ! misho     691:        \ Initialize kernel captions after parsing $kernels
        !           692:        \ 
        !           693:        0 menukernel !
        !           694:        s" menu_kernel" getenv -1 <> if
        !           695:                c@ dup 48 > over 57 < and if ( '1' <= c1 <= '8' )
        !           696:                        dup menukernel !
        !           697:                        dup parse-kernels tag-kernels
        !           698: 
        !           699:                        \ Get the current cycle state (entry to use)
        !           700:                        s" kernel_state" evaluate @ 48 + ( n -- n y )
        !           701: 
        !           702:                        \ If state is invalid, reset
        !           703:                        dup kernmenuidx @ 1- > if
        !           704:                                drop [char] 0 ( n y -- n 48 )
        !           705:                                0 s" kernel_state" evaluate !
        !           706:                                over s" init_kernel" evaluate drop
        !           707:                        then
        !           708: 
        !           709:                        \ Set the current non-ANSI caption
        !           710:                        2dup swap dup ( n y -- n y y n n )
        !           711:                        s" set menu_caption[x]=$menu_caption[x][y]"
        !           712:                        17 +c! 34 +c! 37 +c! evaluate
        !           713:                        ( n y y n n c-addr/u -- n y  )
        !           714: 
        !           715:                        \ Set the current ANSI caption
        !           716:                        2dup swap dup ( n y -- n y y n n )
        !           717:                        s" set ansi_caption[x]=$ansi_caption[x][y]"
        !           718:                        17 +c! 34 +c! 37 +c! evaluate
        !           719:                        ( n y y n n c-addr/u -- n y )
        !           720: 
        !           721:                        \ Initialize cycle state from stored value
        !           722:                        48 - ( n y -- n k )
        !           723:                        s" init_cyclestate" evaluate ( n k -- n )
        !           724: 
        !           725:                        \ Set $kernel to $kernel[y]
        !           726:                        s" activate_kernel" evaluate ( n -- n )
        !           727:                then
        !           728:                drop
        !           729:        then
        !           730: 
        !           731:        \ 
1.2       misho     732:        \ Initialize the menu_options visual separator.
                    733:        \ 
                    734:        0 menuoptions !
1.4     ! misho     735:        s" menu_options" getenv -1 <> if
1.2       misho     736:                c@ dup 48 > over 57 < and if ( '1' <= c1 <= '8' )
                    737:                        menuoptions !
                    738:                else
                    739:                        drop
                    740:                then
                    741:        then
                    742: 
                    743:        \ Initialize "Reboot" menu state variable (prevents double-entry)
                    744:        false menurebootadded !
                    745: 
1.3       misho     746:        menu_start
                    747:        1- menuidx !    \ Initialize the starting index for the menu
                    748:        0 menurow !     \ Initialize the starting position for the menu
                    749: 
1.2       misho     750:        49 \ Iterator start (loop range 49 to 56; ASCII '1' to '8')
                    751:        begin
                    752:                \ If the "Options:" separator, print it.
                    753:                dup menuoptions @ = if
                    754:                        \ Optionally add a reboot option to the menu
1.4     ! misho     755:                        s" menu_reboot" getenv -1 <> if
1.2       misho     756:                                drop
                    757:                                s" Reboot" printmenuitem menureboot !
                    758:                                true menurebootadded !
                    759:                        then
                    760: 
                    761:                        menuX @
                    762:                        menurow @ 2 + menurow !
                    763:                        menurow @ menuY @ +
                    764:                        at-xy
1.4     ! misho     765:                        s" menu_optionstext" getenv dup -1 <> if
1.3       misho     766:                                type
                    767:                        else
                    768:                                drop ." Options:"
                    769:                        then
1.2       misho     770:                then
                    771: 
                    772:                \ If this is the ACPI menu option, act accordingly.
                    773:                dup menuacpi @ = if
1.3       misho     774:                        dup acpimenuitem ( n -- n n c-addr/u | n n -1 )
                    775:                        dup -1 <> if
                    776:                                13 +c! ( n n c-addr/u -- n c-addr/u )
                    777:                                       \ replace 'x' with n
                    778:                        else
                    779:                                swap drop ( n n -1 -- n -1 )
                    780:                                over menu_command[x] unsetenv
                    781:                        then
1.2       misho     782:                else
1.3       misho     783:                        \ make sure we have not already initialized this item
                    784:                        dup init_stateN dup @ 0= if
                    785:                                1 swap !
                    786: 
                    787:                                \ If this menuitem has an initializer, run it
                    788:                                dup menu_init[x]
                    789:                                getenv dup -1 <> if
                    790:                                        evaluate
                    791:                                else
                    792:                                        drop
                    793:                                then
                    794:                        else
                    795:                                drop
                    796:                        then
                    797: 
                    798:                        dup
1.2       misho     799:                        loader_color? if
1.3       misho     800:                                ansi_caption[x]
1.2       misho     801:                        else
1.3       misho     802:                                menu_caption[x]
1.2       misho     803:                        then
                    804:                then
                    805: 
                    806:                dup -1 <> if
                    807:                        \ test for environment variable
                    808:                        getenv dup -1 <> if
1.3       misho     809:                                printmenuitem ( c-addr/u -- n )
                    810:                                dup menukeyN !
1.2       misho     811:                        else
                    812:                                drop
                    813:                        then
                    814:                else
                    815:                        drop
                    816:                then
                    817: 
                    818:                1+ dup 56 > \ add 1 to iterator, continue if less than 57
                    819:        until
                    820:        drop \ iterator
                    821: 
                    822:        \ Optionally add a reboot option to the menu
                    823:        menurebootadded @ true <> if
1.4     ! misho     824:                s" menu_reboot" getenv -1 <> if
1.2       misho     825:                        drop       \ no need for the value
                    826:                        s" Reboot" \ menu caption (required by printmenuitem)
                    827: 
                    828:                        printmenuitem
                    829:                        menureboot !
                    830:                else
                    831:                        0 menureboot !
                    832:                then
                    833:        then
                    834: ;
                    835: 
                    836: \ Takes a single integer on the stack and updates the timeout display. The
                    837: \ integer must be between 0 and 9 (we will only update a single digit in the
                    838: \ source message).
                    839: \ 
                    840: : menu-timeout-update ( N -- )
                    841: 
1.3       misho     842:        \ Enforce minimum/maximum
                    843:        dup 9 > if drop 9 then
                    844:        dup 0 < if drop 0 then
                    845: 
                    846:        s" Autoboot in N seconds. [Space] to pause" ( n -- n c-addr/u )
                    847: 
                    848:        2 pick 0> if
                    849:                rot 48 + -rot ( n c-addr/u -- n' c-addr/u ) \ convert to ASCII
                    850:                12 +c!        ( n' c-addr/u -- c-addr/u )   \ replace 'N' above
1.2       misho     851: 
1.3       misho     852:                menu_timeout_x @ menu_timeout_y @ at-xy \ position cursor
                    853:                type ( c-addr/u -- ) \ print message
                    854:        else
                    855:                menu_timeout_x @ menu_timeout_y @ at-xy \ position cursor
                    856:                spaces ( n c-addr/u -- n c-addr ) \ erase message
                    857:                2drop ( n c-addr -- )
1.2       misho     858:        then
                    859: 
                    860:        0 25 at-xy ( position cursor back at bottom-left )
                    861: ;
                    862: 
                    863: \ This function blocks program flow (loops forever) until a key is pressed.
                    864: \ The key that was pressed is added to the top of the stack in the form of its
                    865: \ decimal ASCII representation. This function is called by the menu-display
                    866: \ function. You need not call it directly.
                    867: \ 
                    868: : getkey ( -- ascii_keycode )
                    869: 
                    870:        begin \ loop forever
                    871: 
                    872:                menu_timeout_enabled @ 1 = if
                    873:                        ( -- )
                    874:                        seconds ( get current time: -- N )
                    875:                        dup menu_time @ <> if ( has time elapsed?: N N N -- N )
                    876: 
                    877:                                \ At least 1 second has elapsed since last loop
                    878:                                \ so we will decrement our "timeout" (really a
                    879:                                \ counter, insuring that we do not proceed too
                    880:                                \ fast) and update our timeout display.
                    881: 
                    882:                                menu_time ! ( update time record: N -- )
                    883:                                menu_timeout @ ( "time" remaining: -- N )
                    884:                                dup 0> if ( greater than 0?: N N 0 -- N )
                    885:                                        1- ( decrement counter: N -- N )
                    886:                                        dup menu_timeout !
                    887:                                                ( re-assign: N N Addr -- N )
                    888:                                then
                    889:                                ( -- N )
                    890: 
                    891:                                dup 0= swap 0< or if ( N <= 0?: N N -- )
                    892:                                        \ halt the timer
                    893:                                        0 menu_timeout ! ( 0 Addr -- )
                    894:                                        0 menu_timeout_enabled ! ( 0 Addr -- )
                    895:                                then
                    896: 
                    897:                                \ update the timer display ( N -- )
                    898:                                menu_timeout @ menu-timeout-update
                    899: 
                    900:                                menu_timeout @ 0= if
                    901:                                        \ We've reached the end of the timeout
                    902:                                        \ (user did not cancel by pressing ANY
                    903:                                        \ key)
                    904: 
1.4     ! misho     905:                                        s" menu_timeout_command"  getenv dup
1.2       misho     906:                                        -1 = if
                    907:                                                drop \ clean-up
                    908:                                        else
                    909:                                                evaluate
                    910:                                        then
                    911:                                then
                    912: 
                    913:                        else ( -- N )
                    914:                                \ No [detectable] time has elapsed (in seconds)
                    915:                                drop ( N -- )
                    916:                        then
                    917:                        ( -- )
                    918:                then
                    919: 
                    920:                key? if \ Was a key pressed? (see loader(8))
                    921: 
                    922:                        \ An actual key was pressed (if the timeout is running,
                    923:                        \ kill it regardless of which key was pressed)
                    924:                        menu_timeout @ 0<> if
                    925:                                0 menu_timeout !
                    926:                                0 menu_timeout_enabled !
                    927: 
                    928:                                \ clear screen of timeout message
                    929:                                0 menu-timeout-update
                    930:                        then
                    931: 
                    932:                        \ get the key that was pressed and exit (if we
                    933:                        \ get a non-zero ASCII code)
                    934:                        key dup 0<> if
                    935:                                exit
                    936:                        else
                    937:                                drop
                    938:                        then
                    939:                then
                    940:                50 ms \ sleep for 50 milliseconds (see loader(8))
                    941: 
                    942:        again
                    943: ;
                    944: 
                    945: : menu-erase ( -- ) \ Erases menu and resets positioning variable to positon 1.
                    946: 
                    947:        \ Clear the screen area associated with the interactive menu
                    948:        menuX @ menuY @
                    949:        2dup at-xy 38 spaces 1+         2dup at-xy 38 spaces 1+
                    950:        2dup at-xy 38 spaces 1+         2dup at-xy 38 spaces 1+
                    951:        2dup at-xy 38 spaces 1+         2dup at-xy 38 spaces 1+
                    952:        2dup at-xy 38 spaces 1+         2dup at-xy 38 spaces 1+
                    953:        2dup at-xy 38 spaces 1+         2dup at-xy 38 spaces 1+
                    954:        2dup at-xy 38 spaces 1+         2dup at-xy 38 spaces
                    955:        2drop
                    956: 
                    957:        \ Reset the starting index and position for the menu
                    958:        menu_start 1- menuidx !
                    959:        0 menurow !
                    960: ;
                    961: 
                    962: \ Erase and redraw the menu. Useful if you change a caption and want to
                    963: \ update the menu to reflect the new value.
                    964: \ 
                    965: : menu-redraw ( -- )
                    966:        menu-erase
                    967:        menu-create
                    968: ;
                    969: 
                    970: \ This function initializes the menu. Call this from your `loader.rc' file
                    971: \ before calling any other menu-related functions.
                    972: \ 
                    973: : menu-init ( -- )
                    974:        menu_start
                    975:        1- menuidx !    \ Initialize the starting index for the menu
                    976:        0 menurow !     \ Initialize the starting position for the menu
1.4     ! misho     977: 
        !           978:        \ Assign configuration values
        !           979:        s" loader_menu_y" getenv dup -1 = if
        !           980:                drop \ no custom row position
        !           981:                menu_default_y
        !           982:        else
        !           983:                \ make sure custom position is a number
        !           984:                ?number 0= if
        !           985:                        menu_default_y \ or use default
        !           986:                then
        !           987:        then
        !           988:        menuY !
        !           989:        s" loader_menu_x" getenv dup -1 = if
        !           990:                drop \ no custom column position
        !           991:                menu_default_x
        !           992:        else
        !           993:                \ make sure custom position is a number
        !           994:                ?number 0= if
        !           995:                        menu_default_x \ or use default
        !           996:                then
        !           997:        then
        !           998:        menuX !
        !           999: 
        !          1000:        \ Interpret a custom frame type for the menu
        !          1001:        TRUE ( draw a box? default yes, but might be altered below )
        !          1002:        s" loader_menu_frame" getenv dup -1 = if ( 1 )
        !          1003:                drop \ no custom frame type
        !          1004:        else ( 1 )  2dup s" single" compare-insensitive 0= if ( 2 )
        !          1005:                f_single ( see frames.4th )
        !          1006:        else ( 2 )  2dup s" double" compare-insensitive 0= if ( 3 )
        !          1007:                f_double ( see frames.4th )
        !          1008:        else ( 3 ) s" none" compare-insensitive 0= if ( 4 )
        !          1009:                drop FALSE \ don't draw a box
        !          1010:        ( 4 ) then ( 3 ) then ( 2 )  then ( 1 ) then
        !          1011:        if
        !          1012:                42 13 menuX @ 3 - menuY @ 1- box \ Draw frame (w,h,x,y)
        !          1013:        then
        !          1014: 
        !          1015:        0 25 at-xy \ Move cursor to the bottom for output
1.2       misho    1016: ;
                   1017: 
                   1018: \ Main function. Call this from your `loader.rc' file.
                   1019: \ 
                   1020: : menu-display ( -- )
                   1021: 
                   1022:        0 menu_timeout_enabled ! \ start with automatic timeout disabled
                   1023: 
                   1024:        \ check indication that automatic execution after delay is requested
1.4     ! misho    1025:        s" menu_timeout_command" getenv -1 <> if ( Addr C -1 -- | Addr )
1.2       misho    1026:                drop ( just testing existence right now: Addr -- )
                   1027: 
                   1028:                \ initialize state variables
                   1029:                seconds menu_time ! ( store the time we started )
                   1030:                1 menu_timeout_enabled ! ( enable automatic timeout )
                   1031: 
                   1032:                \ read custom time-duration (if set)
                   1033:                s" autoboot_delay" getenv dup -1 = if
                   1034:                        drop \ no custom duration (remove dup'd bunk -1)
                   1035:                        menu_timeout_default \ use default setting
                   1036:                else
                   1037:                        2dup ?number 0= if ( if not a number )
                   1038:                                \ disable timeout if "NO", else use default
                   1039:                                s" NO" compare-insensitive 0= if
                   1040:                                        0 menu_timeout_enabled !
                   1041:                                        0 ( assigned to menu_timeout below )
                   1042:                                else
                   1043:                                        menu_timeout_default
                   1044:                                then
                   1045:                        else
                   1046:                                -rot 2drop
                   1047: 
                   1048:                                \ boot immediately if less than zero
                   1049:                                dup 0< if
                   1050:                                        drop
                   1051:                                        menu-create
                   1052:                                        0 25 at-xy
                   1053:                                        0 boot
                   1054:                                then
                   1055:                        then
                   1056:                then
                   1057:                menu_timeout ! ( store value on stack from above )
                   1058: 
                   1059:                menu_timeout_enabled @ 1 = if
                   1060:                        \ read custom column position (if set)
1.4     ! misho    1061:                        s" loader_menu_timeout_x" getenv dup -1 = if
1.2       misho    1062:                                drop \ no custom column position
                   1063:                                menu_timeout_default_x \ use default setting
                   1064:                        else
                   1065:                                \ make sure custom position is a number
                   1066:                                ?number 0= if
                   1067:                                        menu_timeout_default_x \ or use default
                   1068:                                then
                   1069:                        then
                   1070:                        menu_timeout_x ! ( store value on stack from above )
                   1071:         
                   1072:                        \ read custom row position (if set)
1.4     ! misho    1073:                        s" loader_menu_timeout_y" getenv dup -1 = if
1.2       misho    1074:                                drop \ no custom row position
                   1075:                                menu_timeout_default_y \ use default setting
                   1076:                        else
                   1077:                                \ make sure custom position is a number
                   1078:                                ?number 0= if
                   1079:                                        menu_timeout_default_y \ or use default
                   1080:                                then
                   1081:                        then
                   1082:                        menu_timeout_y ! ( store value on stack from above )
                   1083:                then
                   1084:        then
                   1085: 
                   1086:        menu-create
                   1087: 
                   1088:        begin \ Loop forever
                   1089: 
                   1090:                0 25 at-xy \ Move cursor to the bottom for output
                   1091:                getkey     \ Block here, waiting for a key to be pressed
                   1092: 
                   1093:                dup -1 = if
                   1094:                        drop exit \ Caught abort (abnormal return)
                   1095:                then
                   1096: 
                   1097:                \ Boot if the user pressed Enter/Ctrl-M (13) or
                   1098:                \ Ctrl-Enter/Ctrl-J (10)
                   1099:                dup over 13 = swap 10 = or if
                   1100:                        drop ( no longer needed )
                   1101:                        s" boot" evaluate
                   1102:                        exit ( pedantic; never reached )
                   1103:                then
                   1104: 
1.3       misho    1105:                dup menureboot @ = if 0 reboot then
                   1106: 
1.2       misho    1107:                \ Evaluate the decimal ASCII value against known menu item
                   1108:                \ key associations and act accordingly
                   1109: 
                   1110:                49 \ Iterator start (loop range 49 to 56; ASCII '1' to '8')
                   1111:                begin
1.3       misho    1112:                        dup menukeyN @
                   1113:                        rot tuck = if
1.2       misho    1114: 
                   1115:                                \ Adjust for missing ACPI menuitem on non-i386
                   1116:                                arch-i386? true <> menuacpi @ 0<> and if
                   1117:                                        menuacpi @ over 2dup < -rot = or
                   1118:                                        over 58 < and if
                   1119:                                        ( key >= menuacpi && key < 58: N -- N )
                   1120:                                                1+
                   1121:                                        then
                   1122:                                then
                   1123: 
                   1124:                                \ Test for the environment variable
1.3       misho    1125:                                dup menu_command[x]
1.2       misho    1126:                                getenv dup -1 <> if
                   1127:                                        \ Execute the stored procedure
                   1128:                                        evaluate
                   1129: 
                   1130:                                        \ We expect there to be a non-zero
                   1131:                                        \  value left on the stack after
                   1132:                                        \ executing the stored procedure.
                   1133:                                        \ If so, continue to run, else exit.
                   1134: 
                   1135:                                        0= if
                   1136:                                                drop \ key pressed
                   1137:                                                drop \ loop iterator
                   1138:                                                exit
                   1139:                                        else
                   1140:                                                swap \ need iterator on top
                   1141:                                        then
                   1142:                                then
                   1143: 
                   1144:                                \ Re-adjust for missing ACPI menuitem
                   1145:                                arch-i386? true <> menuacpi @ 0<> and if
                   1146:                                        swap
                   1147:                                        menuacpi @ 1+ over 2dup < -rot = or
                   1148:                                        over 59 < and if
                   1149:                                                1-
                   1150:                                        then
                   1151:                                        swap
                   1152:                                then
                   1153:                        else
                   1154:                                swap \ need iterator on top
                   1155:                        then
                   1156: 
                   1157:                        \ 
                   1158:                        \ Check for menu keycode shortcut(s)
                   1159:                        \ 
1.3       misho    1160:                        dup menu_keycode[x]
1.2       misho    1161:                        getenv dup -1 = if
                   1162:                                drop
                   1163:                        else
                   1164:                                ?number 0<> if
                   1165:                                        rot tuck = if
                   1166:                                                swap
1.3       misho    1167:                                                dup menu_command[x]
1.2       misho    1168:                                                getenv dup -1 <> if
                   1169:                                                        evaluate
                   1170:                                                        0= if
                   1171:                                                                2drop
                   1172:                                                                exit
                   1173:                                                        then
                   1174:                                                else
                   1175:                                                        drop
                   1176:                                                then
                   1177:                                        else
                   1178:                                                swap
                   1179:                                        then
                   1180:                                then
                   1181:                        then
                   1182: 
                   1183:                        1+ dup 56 > \ increment iterator
                   1184:                                    \ continue if less than 57
                   1185:                until
                   1186:                drop \ loop iterator
1.3       misho    1187:                drop \ key pressed
1.2       misho    1188: 
                   1189:        again   \ Non-operational key was pressed; repeat
                   1190: ;
                   1191: 
                   1192: \ This function unsets all the possible environment variables associated with
1.3       misho    1193: \ creating the interactive menu.
1.2       misho    1194: \ 
1.3       misho    1195: : menu-unset ( -- )
1.2       misho    1196: 
                   1197:        49 \ Iterator start (loop range 49 to 56; ASCII '1' to '8')
                   1198:        begin
1.3       misho    1199:                dup menu_init[x]    unsetenv    \ menu initializer
                   1200:                dup menu_command[x] unsetenv    \ menu command
                   1201:                dup menu_caption[x] unsetenv    \ menu caption
                   1202:                dup ansi_caption[x] unsetenv    \ ANSI caption
                   1203:                dup menu_keycode[x] unsetenv    \ menu keycode
                   1204:                dup toggled_text[x] unsetenv    \ toggle_menuitem caption
                   1205:                dup toggled_ansi[x] unsetenv    \ toggle_menuitem ANSI caption
                   1206: 
                   1207:                48 \ Iterator start (inner range 48 to 57; ASCII '0' to '9')
                   1208:                begin
                   1209:                        \ cycle_menuitem caption and ANSI caption
                   1210:                        2dup menu_caption[x][y] unsetenv
                   1211:                        2dup ansi_caption[x][y] unsetenv
                   1212:                        1+ dup 57 >
                   1213:                until
                   1214:                drop \ inner iterator
1.2       misho    1215: 
1.3       misho    1216:                0 over menukeyN      !  \ used by menu-create, menu-display
                   1217:                0 over init_stateN   !  \ used by menu-create
                   1218:                0 over toggle_stateN !  \ used by toggle_menuitem
                   1219:                0 over init_textN   c!  \ used by toggle_menuitem
                   1220:                0 over cycle_stateN  !  \ used by cycle_menuitem
1.2       misho    1221: 
                   1222:                1+ dup 56 >     \ increment, continue if less than 57
                   1223:        until
                   1224:        drop \ iterator
                   1225: 
1.4     ! misho    1226:        s" menu_timeout_command" unsetenv       \ menu timeout command
        !          1227:        s" menu_reboot"          unsetenv       \ Reboot menu option flag
        !          1228:        s" menu_acpi"            unsetenv       \ ACPI menu option flag
        !          1229:        s" menu_kernel"          unsetenv       \ Kernel menu option flag
        !          1230:        s" menu_options"         unsetenv       \ Options separator flag
        !          1231:        s" menu_optionstext"     unsetenv       \ separator display text
        !          1232:        s" menu_init"            unsetenv       \ menu initializer
1.3       misho    1233: 
1.2       misho    1234:        0 menureboot !
                   1235:        0 menuacpi !
                   1236:        0 menuoptions !
1.3       misho    1237: ;
1.2       misho    1238: 
1.3       misho    1239: \ This function both unsets menu variables and visually erases the menu area
                   1240: \ in-preparation for another menu.
                   1241: \ 
                   1242: : menu-clear ( -- )
                   1243:        menu-unset
1.2       misho    1244:        menu-erase
                   1245: ;
                   1246: 
                   1247: bullet menubllt !
                   1248: 
1.3       misho    1249: \ Initialize our menu initialization state variables
                   1250: 0 init_state1 !
                   1251: 0 init_state2 !
                   1252: 0 init_state3 !
                   1253: 0 init_state4 !
                   1254: 0 init_state5 !
                   1255: 0 init_state6 !
                   1256: 0 init_state7 !
                   1257: 0 init_state8 !
                   1258: 
1.2       misho    1259: \ Initialize our boolean state variables
                   1260: 0 toggle_state1 !
                   1261: 0 toggle_state2 !
                   1262: 0 toggle_state3 !
                   1263: 0 toggle_state4 !
                   1264: 0 toggle_state5 !
                   1265: 0 toggle_state6 !
                   1266: 0 toggle_state7 !
                   1267: 0 toggle_state8 !
                   1268: 
                   1269: \ Initialize our array state variables
                   1270: 0 cycle_state1 !
                   1271: 0 cycle_state2 !
                   1272: 0 cycle_state3 !
                   1273: 0 cycle_state4 !
                   1274: 0 cycle_state5 !
                   1275: 0 cycle_state6 !
                   1276: 0 cycle_state7 !
                   1277: 0 cycle_state8 !
                   1278: 
                   1279: \ Initialize string containers
                   1280: 0 init_text1 c!
                   1281: 0 init_text2 c!
                   1282: 0 init_text3 c!
                   1283: 0 init_text4 c!
                   1284: 0 init_text5 c!
                   1285: 0 init_text6 c!
                   1286: 0 init_text7 c!
                   1287: 0 init_text8 c!

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>