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

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

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