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

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

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