menu.4th revision 222417
1222417Sjulian\ Copyright (c) 2003 Scott Long <scottl@freebsd.org> 2222417Sjulian\ Copyright (c) 2003 Aleksander Fafula <alex@fafula.com> 3222417Sjulian\ Copyright (c) 2006-2011 Devin Teske <devinteske@hotmail.com> 4222417Sjulian\ All rights reserved. 5222417Sjulian\ 6222417Sjulian\ Redistribution and use in source and binary forms, with or without 7222417Sjulian\ modification, are permitted provided that the following conditions 8222417Sjulian\ are met: 9222417Sjulian\ 1. Redistributions of source code must retain the above copyright 10222417Sjulian\ notice, this list of conditions and the following disclaimer. 11222417Sjulian\ 2. Redistributions in binary form must reproduce the above copyright 12222417Sjulian\ notice, this list of conditions and the following disclaimer in the 13222417Sjulian\ documentation and/or other materials provided with the distribution. 14222417Sjulian\ 15222417Sjulian\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 16222417Sjulian\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 17222417Sjulian\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 18222417Sjulian\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 19222417Sjulian\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20222417Sjulian\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 21222417Sjulian\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 22222417Sjulian\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 23222417Sjulian\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 24222417Sjulian\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 25222417Sjulian\ SUCH DAMAGE. 26222417Sjulian\ 27222417Sjulian\ $FreeBSD: head/sys/boot/forth/menu.4th 222417 2011-05-28 08:50:38Z julian $ 28222417Sjulian 29222417Sjulianmarker task-menu.4th 30222417Sjulian 31222417Sjulian\ Frame drawing 32222417Sjulianinclude /boot/frames.4th 33222417Sjulian 34222417Sjulianf_double \ Set frames to double (see frames.4th). Replace with 35222417Sjulian \ f_single if you want single frames. 36222417Sjulian46 constant dot \ ASCII definition of a period (in decimal) 37222417Sjulian 38222417Sjulian 4 constant menu_timeout_default_x \ default column position of timeout 39222417Sjulian23 constant menu_timeout_default_y \ default row position of timeout msg 40222417Sjulian10 constant menu_timeout_default \ default timeout (in seconds) 41222417Sjulian 42222417Sjulian\ Customize the following values with care 43222417Sjulian 44222417Sjulian 1 constant menu_start \ Numerical prefix of first menu item 45222417Sjuliandot constant bullet \ Menu bullet (appears after numerical prefix) 46222417Sjulian 5 constant menu_x \ Row position of the menu (from the top) 47222417Sjulian 10 constant menu_y \ Column position of the menu (from left side) 48222417Sjulian 49222417Sjulian\ Menu Appearance 50222417Sjulianvariable menuidx \ Menu item stack for number prefixes 51222417Sjulianvariable menurow \ Menu item stack for positioning 52222417Sjulianvariable menubllt \ Menu item bullet 53222417Sjulian 54222417Sjulian\ Menu Positioning 55222417Sjulianvariable menuX \ Menu X offset (columns) 56222417Sjulianvariable menuY \ Menu Y offset (rows) 57222417Sjulian 58222417Sjulian\ Menu-item key association/detection 59222417Sjulianvariable menukey1 60222417Sjulianvariable menukey2 61222417Sjulianvariable menukey3 62222417Sjulianvariable menukey4 63222417Sjulianvariable menukey5 64222417Sjulianvariable menukey6 65222417Sjulianvariable menukey7 66222417Sjulianvariable menukey8 67222417Sjulianvariable menureboot 68222417Sjulianvariable menurebootadded 69222417Sjulianvariable menuacpi 70222417Sjulianvariable menuoptions 71222417Sjulian 72222417Sjulian\ Menu timer [count-down] variables 73222417Sjulianvariable menu_timeout_enabled \ timeout state (internal use only) 74222417Sjulianvariable menu_time \ variable for tracking the passage of time 75222417Sjulianvariable menu_timeout \ determined configurable delay duration 76222417Sjulianvariable menu_timeout_x \ column position of timeout message 77222417Sjulianvariable menu_timeout_y \ row position of timeout message 78222417Sjulian 79222417Sjulian\ Boolean option status variables 80222417Sjulianvariable toggle_state1 81222417Sjulianvariable toggle_state2 82222417Sjulianvariable toggle_state3 83222417Sjulianvariable toggle_state4 84222417Sjulianvariable toggle_state5 85222417Sjulianvariable toggle_state6 86222417Sjulianvariable toggle_state7 87222417Sjulianvariable toggle_state8 88222417Sjulian 89222417Sjulian\ Array option status variables 90222417Sjulianvariable cycle_state1 91222417Sjulianvariable cycle_state2 92222417Sjulianvariable cycle_state3 93222417Sjulianvariable cycle_state4 94222417Sjulianvariable cycle_state5 95222417Sjulianvariable cycle_state6 96222417Sjulianvariable cycle_state7 97222417Sjulianvariable cycle_state8 98222417Sjulian 99222417Sjulian\ Containers for storing the initial caption text 100222417Sjuliancreate init_text1 255 allot 101222417Sjuliancreate init_text2 255 allot 102222417Sjuliancreate init_text3 255 allot 103222417Sjuliancreate init_text4 255 allot 104222417Sjuliancreate init_text5 255 allot 105222417Sjuliancreate init_text6 255 allot 106222417Sjuliancreate init_text7 255 allot 107222417Sjuliancreate init_text8 255 allot 108222417Sjulian 109222417Sjulian: arch-i386? ( -- BOOL ) \ Returns TRUE (-1) on i386, FALSE (0) otherwise. 110222417Sjulian s" arch-i386" environment? dup if 111222417Sjulian drop 112222417Sjulian then 113222417Sjulian; 114222417Sjulian 115222417Sjulian\ This function prints a menu item at menuX (row) and menuY (column), returns 116222417Sjulian\ the incremental decimal ASCII value associated with the menu item, and 117222417Sjulian\ increments the cursor position to the next row for the creation of the next 118222417Sjulian\ menu item. This function is called by the menu-create function. You need not 119222417Sjulian\ call it directly. 120222417Sjulian\ 121222417Sjulian: printmenuitem ( menu_item_str -- ascii_keycode ) 122222417Sjulian 123222417Sjulian menurow dup @ 1+ swap ! ( increment menurow ) 124222417Sjulian menuidx dup @ 1+ swap ! ( increment menuidx ) 125222417Sjulian 126222417Sjulian \ Calculate the menuitem row position 127222417Sjulian menurow @ menuY @ + 128222417Sjulian 129222417Sjulian \ Position the cursor at the menuitem position 130222417Sjulian dup menuX @ swap at-xy 131222417Sjulian 132222417Sjulian \ Print the value of menuidx 133222417Sjulian loader_color? if 134222417Sjulian ." [1m" 135222417Sjulian then 136222417Sjulian menuidx @ . 137222417Sjulian loader_color? if 138222417Sjulian ." [37m" 139222417Sjulian then 140222417Sjulian 141222417Sjulian \ Move the cursor forward 1 column 142222417Sjulian dup menuX @ 1+ swap at-xy 143222417Sjulian 144222417Sjulian menubllt @ emit \ Print the menu bullet using the emit function 145222417Sjulian 146222417Sjulian \ Move the cursor to the 3rd column from the current position 147222417Sjulian \ to allow for a space between the numerical prefix and the 148222417Sjulian \ text caption 149222417Sjulian menuX @ 3 + swap at-xy 150222417Sjulian 151222417Sjulian \ Print the menu caption (we expect a string to be on the stack 152222417Sjulian \ prior to invoking this function) 153222417Sjulian type 154222417Sjulian 155222417Sjulian \ Here we will add the ASCII decimal of the numerical prefix 156222417Sjulian \ to the stack (decimal ASCII for `1' is 49) as a "return value" 157222417Sjulian menuidx @ 48 + 158222417Sjulian; 159222417Sjulian 160222417Sjulian: toggle_menuitem ( N -- N ) \ toggles caption text and internal menuitem state 161222417Sjulian 162222417Sjulian \ ASCII numeral equal to user-selected menu item must be on the stack. 163222417Sjulian \ We do not modify the stack, so the ASCII numeral is left on top. 164222417Sjulian 165222417Sjulian s" init_textN" \ base name of buffer 166222417Sjulian -rot 2dup 9 + c! rot \ replace 'N' with ASCII num 167222417Sjulian 168222417Sjulian evaluate c@ 0= if 169222417Sjulian \ NOTE: no need to check toggle_stateN since the first time we 170222417Sjulian \ are called, we will populate init_textN. Further, we don't 171222417Sjulian \ need to test whether menu_caption[x] (ansi_caption[x] when 172222417Sjulian \ loader_color=1) is available since we would not have been 173222417Sjulian \ called if the caption was NULL. 174222417Sjulian 175222417Sjulian \ base name of environment variable 176222417Sjulian loader_color? if 177222417Sjulian s" ansi_caption[x]" 178222417Sjulian else 179222417Sjulian s" menu_caption[x]" 180222417Sjulian then 181222417Sjulian -rot 2dup 13 + c! rot \ replace 'x' with ASCII numeral 182222417Sjulian 183222417Sjulian getenv dup -1 <> if 184222417Sjulian 185222417Sjulian s" init_textN" \ base name of buffer 186222417Sjulian 4 pick \ copy ASCII num to top 187222417Sjulian rot tuck 9 + c! swap \ replace 'N' with ASCII num 188222417Sjulian evaluate 189222417Sjulian 190222417Sjulian \ now we have the buffer c-addr on top 191222417Sjulian \ ( followed by c-addr/u of current caption ) 192222417Sjulian 193222417Sjulian \ Copy the current caption into our buffer 194222417Sjulian 2dup c! -rot \ store strlen at first byte 195222417Sjulian begin 196222417Sjulian rot 1+ \ bring alt addr to top and increment 197222417Sjulian -rot -rot \ bring buffer addr to top 198222417Sjulian 2dup c@ swap c! \ copy current character 199222417Sjulian 1+ \ increment buffer addr 200222417Sjulian rot 1- \ bring buffer len to top and decrement 201222417Sjulian dup 0= \ exit loop if buffer len is zero 202222417Sjulian until 203222417Sjulian 2drop \ buffer len/addr 204222417Sjulian drop \ alt addr 205222417Sjulian 206222417Sjulian else 207222417Sjulian drop 208222417Sjulian then 209222417Sjulian then 210222417Sjulian 211222417Sjulian \ Now we are certain to have init_textN populated with the initial 212222417Sjulian \ value of menu_caption[x] (ansi_caption[x] with loader_color enabled). 213222417Sjulian \ We can now use init_textN as the untoggled caption and 214222417Sjulian \ toggled_text[x] (toggled_ansi[x] with loader_color enabled) as the 215222417Sjulian \ toggled caption and store the appropriate value into menu_caption[x] 216222417Sjulian \ (again, ansi_caption[x] with loader_color enabled). Last, we'll 217222417Sjulian \ negate the toggled state so that we reverse the flow on subsequent 218222417Sjulian \ calls. 219222417Sjulian 220222417Sjulian s" toggle_stateN @" \ base name of toggle state var 221222417Sjulian -rot 2dup 12 + c! rot \ replace 'N' with ASCII numeral 222222417Sjulian 223222417Sjulian evaluate 0= if 224222417Sjulian \ state is OFF, toggle to ON 225222417Sjulian 226222417Sjulian \ base name of toggled text var 227222417Sjulian loader_color? if 228222417Sjulian s" toggled_ansi[x]" 229222417Sjulian else 230222417Sjulian s" toggled_text[x]" 231222417Sjulian then 232222417Sjulian -rot 2dup 13 + c! rot \ replace 'x' with ASCII num 233222417Sjulian 234222417Sjulian getenv dup -1 <> if 235222417Sjulian \ Assign toggled text to menu caption 236222417Sjulian 237222417Sjulian \ base name of caption var 238222417Sjulian loader_color? if 239222417Sjulian s" ansi_caption[x]" 240222417Sjulian else 241222417Sjulian s" menu_caption[x]" 242222417Sjulian then 243222417Sjulian 4 pick \ copy ASCII num to top 244222417Sjulian rot tuck 13 + c! swap \ replace 'x' with ASCII num 245222417Sjulian 246222417Sjulian setenv \ set new caption 247222417Sjulian else 248222417Sjulian \ No toggled text, keep the same caption 249222417Sjulian 250222417Sjulian drop 251222417Sjulian then 252222417Sjulian 253222417Sjulian true \ new value of toggle state var (to be stored later) 254222417Sjulian else 255222417Sjulian \ state is ON, toggle to OFF 256222417Sjulian 257222417Sjulian s" init_textN" \ base name of initial text buffer 258222417Sjulian -rot 2dup 9 + c! rot \ replace 'N' with ASCII numeral 259222417Sjulian evaluate \ convert string to c-addr 260222417Sjulian count \ convert c-addr to c-addr/u 261222417Sjulian 262222417Sjulian \ base name of caption var 263222417Sjulian loader_color? if 264222417Sjulian s" ansi_caption[x]" 265222417Sjulian else 266222417Sjulian s" menu_caption[x]" 267222417Sjulian then 268222417Sjulian 4 pick \ copy ASCII num to top 269222417Sjulian rot tuck 13 + c! swap \ replace 'x' with ASCII numeral 270222417Sjulian 271222417Sjulian setenv \ set new caption 272222417Sjulian false \ new value of toggle state var (to be stored below) 273222417Sjulian then 274222417Sjulian 275222417Sjulian \ now we'll store the new toggle state (on top of stack) 276222417Sjulian s" toggle_stateN" \ base name of toggle state var 277222417Sjulian 3 pick \ copy ASCII numeral to top 278222417Sjulian rot tuck 12 + c! swap \ replace 'N' with ASCII numeral 279222417Sjulian evaluate \ convert string to addr 280222417Sjulian ! \ store new value 281222417Sjulian; 282222417Sjulian 283222417Sjulian: cycle_menuitem ( N -- N ) \ cycles through array of choices for a menuitem 284222417Sjulian 285222417Sjulian \ ASCII numeral equal to user-selected menu item must be on the stack. 286222417Sjulian \ We do not modify the stack, so the ASCII numeral is left on top. 287222417Sjulian 288222417Sjulian s" cycle_stateN" \ base name of array state var 289222417Sjulian -rot 2dup 11 + c! rot \ replace 'N' with ASCII numeral 290222417Sjulian 291222417Sjulian evaluate \ we now have a pointer to the proper variable 292222417Sjulian dup @ \ resolve the pointer (but leave it on the stack) 293222417Sjulian 1+ \ increment the value 294222417Sjulian 295222417Sjulian \ Before assigning the (incremented) value back to the pointer, 296222417Sjulian \ let's test for the existence of this particular array element. 297222417Sjulian \ If the element exists, we'll store index value and move on. 298222417Sjulian \ Otherwise, we'll loop around to zero and store that. 299222417Sjulian 300222417Sjulian dup 48 + \ duplicate Array index and convert to ASCII numeral 301222417Sjulian 302222417Sjulian \ base name of array caption text 303222417Sjulian loader_color? if 304222417Sjulian s" ansi_caption[x][y]" 305222417Sjulian else 306222417Sjulian s" menu_caption[x][y]" 307222417Sjulian then 308222417Sjulian -rot tuck 16 + c! swap \ replace 'y' with Array index 309222417Sjulian 4 pick rot tuck 13 + c! swap \ replace 'x' with menu choice 310222417Sjulian 311222417Sjulian \ Now test for the existence of our incremented array index in the 312222417Sjulian \ form of $menu_caption[x][y] ($ansi_caption[x][y] with loader_color 313222417Sjulian \ enabled) as set in loader.rc(5), et. al. 314222417Sjulian 315222417Sjulian getenv dup -1 = if 316222417Sjulian \ No caption set for this array index. Loop back to zero. 317222417Sjulian 318222417Sjulian drop ( getenv cruft ) 319222417Sjulian drop ( incremented array index ) 320222417Sjulian 0 ( new array index that will be stored later ) 321222417Sjulian 322222417Sjulian \ base name of caption var 323222417Sjulian loader_color? if 324222417Sjulian s" ansi_caption[x][0]" 325222417Sjulian else 326222417Sjulian s" menu_caption[x][0]" 327222417Sjulian then 328222417Sjulian 4 pick rot tuck 13 + c! swap \ replace 'x' with menu choice 329222417Sjulian 330222417Sjulian getenv dup -1 = if 331222417Sjulian \ This is highly unlikely to occur, but to make 332222417Sjulian \ sure that things move along smoothly, allocate 333222417Sjulian \ a temporary NULL string 334222417Sjulian 335222417Sjulian s" " 336222417Sjulian then 337222417Sjulian then 338222417Sjulian 339222417Sjulian \ At this point, we should have the following on the stack (in order, 340222417Sjulian \ from bottom to top): 341222417Sjulian \ 342222417Sjulian \ N - Ascii numeral representing the menu choice (inherited) 343222417Sjulian \ Addr - address of our internal cycle_stateN variable 344222417Sjulian \ N - zero-based number we intend to store to the above 345222417Sjulian \ C-Addr - string value we intend to store to menu_caption[x] 346222417Sjulian \ (or ansi_caption[x] with loader_color enabled) 347222417Sjulian \ 348222417Sjulian \ Let's perform what we need to with the above. 349222417Sjulian 350222417Sjulian \ base name of menuitem caption var 351222417Sjulian loader_color? if 352222417Sjulian s" ansi_caption[x]" 353222417Sjulian else 354222417Sjulian s" menu_caption[x]" 355222417Sjulian then 356222417Sjulian 6 pick rot tuck 13 + c! swap \ replace 'x' with menu choice 357222417Sjulian setenv \ set the new caption 358222417Sjulian 359222417Sjulian swap ! \ update array state variable 360222417Sjulian; 361222417Sjulian 362222417Sjulian: acpipresent? ( -- flag ) \ Returns TRUE if ACPI is present, FALSE otherwise 363222417Sjulian s" hint.acpi.0.rsdp" getenv 364222417Sjulian dup -1 = if 365222417Sjulian drop false exit 366222417Sjulian then 367222417Sjulian 2drop 368222417Sjulian true 369222417Sjulian; 370222417Sjulian 371222417Sjulian: acpienabled? ( -- flag ) \ Returns TRUE if ACPI is enabled, FALSE otherwise 372222417Sjulian s" hint.acpi.0.disabled" getenv 373222417Sjulian dup -1 <> if 374222417Sjulian s" 0" compare 0<> if 375222417Sjulian false exit 376222417Sjulian then 377222417Sjulian else 378222417Sjulian drop 379222417Sjulian then 380222417Sjulian true 381222417Sjulian; 382222417Sjulian 383222417Sjulian\ This function prints the appropriate menuitem basename to the stack if an 384222417Sjulian\ ACPI option is to be presented to the user, otherwise returns -1. Used 385222417Sjulian\ internally by menu-create, you need not (nor should you) call this directly. 386222417Sjulian\ 387222417Sjulian: acpimenuitem ( -- C-Addr | -1 ) 388222417Sjulian 389222417Sjulian arch-i386? if 390222417Sjulian acpipresent? if 391222417Sjulian acpienabled? if 392222417Sjulian loader_color? if 393222417Sjulian s" toggled_ansi[x]" 394222417Sjulian else 395222417Sjulian s" toggled_text[x]" 396222417Sjulian then 397222417Sjulian else 398222417Sjulian loader_color? if 399222417Sjulian s" ansi_caption[x]" 400222417Sjulian else 401222417Sjulian s" menu_caption[x]" 402222417Sjulian then 403222417Sjulian then 404222417Sjulian else 405222417Sjulian menuidx dup @ 1+ swap ! ( increment menuidx ) 406222417Sjulian -1 407222417Sjulian then 408222417Sjulian else 409222417Sjulian -1 410222417Sjulian then 411222417Sjulian; 412222417Sjulian 413222417Sjulian\ This function creates the list of menu items. This function is called by the 414222417Sjulian\ menu-display function. You need not be call it directly. 415222417Sjulian\ 416222417Sjulian: menu-create ( -- ) 417222417Sjulian 418222417Sjulian \ Print the frame caption at (x,y) 419222417Sjulian s" loader_menu_title" getenv dup -1 = if 420222417Sjulian drop s" Welcome to FreeBSD" 421222417Sjulian then 422222417Sjulian 24 over 2 / - 9 at-xy type 423222417Sjulian 424222417Sjulian \ Print our menu options with respective key/variable associations. 425222417Sjulian \ `printmenuitem' ends by adding the decimal ASCII value for the 426222417Sjulian \ numerical prefix to the stack. We store the value left on the stack 427222417Sjulian \ to the key binding variable for later testing against a character 428222417Sjulian \ captured by the `getkey' function. 429222417Sjulian 430222417Sjulian \ Note that any menu item beyond 9 will have a numerical prefix on the 431222417Sjulian \ screen consisting of the first digit (ie. 1 for the tenth menu item) 432222417Sjulian \ and the key required to activate that menu item will be the decimal 433222417Sjulian \ ASCII of 48 plus the menu item (ie. 58 for the tenth item, aka. `:') 434222417Sjulian \ which is misleading and not desirable. 435222417Sjulian \ 436222417Sjulian \ Thus, we do not allow more than 8 configurable items on the menu 437222417Sjulian \ (with "Reboot" as the optional ninth and highest numbered item). 438222417Sjulian 439222417Sjulian \ 440222417Sjulian \ Initialize the ACPI option status. 441222417Sjulian \ 442222417Sjulian 0 menuacpi ! 443222417Sjulian s" menu_acpi" getenv -1 <> if 444222417Sjulian c@ dup 48 > over 57 < and if ( '1' <= c1 <= '8' ) 445222417Sjulian menuacpi ! 446222417Sjulian arch-i386? if acpipresent? if 447222417Sjulian \ 448222417Sjulian \ Set menu toggle state to active state 449222417Sjulian \ (required by generic toggle_menuitem) 450222417Sjulian \ 451222417Sjulian menuacpi @ 452222417Sjulian s" acpienabled? toggle_stateN !" 453222417Sjulian -rot tuck 25 + c! swap 454222417Sjulian evaluate 455222417Sjulian then then 456222417Sjulian else 457222417Sjulian drop 458222417Sjulian then 459222417Sjulian then 460222417Sjulian 461222417Sjulian \ 462222417Sjulian \ Initialize the menu_options visual separator. 463222417Sjulian \ 464222417Sjulian 0 menuoptions ! 465222417Sjulian s" menu_options" getenv -1 <> if 466222417Sjulian c@ dup 48 > over 57 < and if ( '1' <= c1 <= '8' ) 467222417Sjulian menuoptions ! 468222417Sjulian else 469222417Sjulian drop 470222417Sjulian then 471222417Sjulian then 472222417Sjulian 473222417Sjulian \ Initialize "Reboot" menu state variable (prevents double-entry) 474222417Sjulian false menurebootadded ! 475222417Sjulian 476222417Sjulian 49 \ Iterator start (loop range 49 to 56; ASCII '1' to '8') 477222417Sjulian begin 478222417Sjulian \ If the "Options:" separator, print it. 479222417Sjulian dup menuoptions @ = if 480222417Sjulian \ Optionally add a reboot option to the menu 481222417Sjulian s" menu_reboot" getenv -1 <> if 482222417Sjulian drop 483222417Sjulian s" Reboot" printmenuitem menureboot ! 484222417Sjulian true menurebootadded ! 485222417Sjulian then 486222417Sjulian 487222417Sjulian menuX @ 488222417Sjulian menurow @ 2 + menurow ! 489222417Sjulian menurow @ menuY @ + 490222417Sjulian at-xy 491222417Sjulian ." Options:" 492222417Sjulian then 493222417Sjulian 494222417Sjulian \ If this is the ACPI menu option, act accordingly. 495222417Sjulian dup menuacpi @ = if 496222417Sjulian acpimenuitem ( -- C-Addr | -1 ) 497222417Sjulian else 498222417Sjulian loader_color? if 499222417Sjulian s" ansi_caption[x]" 500222417Sjulian else 501222417Sjulian s" menu_caption[x]" 502222417Sjulian then 503222417Sjulian then 504222417Sjulian 505222417Sjulian ( C-Addr | -1 ) 506222417Sjulian dup -1 <> if 507222417Sjulian \ replace 'x' with current iteration 508222417Sjulian -rot 2dup 13 + c! rot 509222417Sjulian 510222417Sjulian \ test for environment variable 511222417Sjulian getenv dup -1 <> if 512222417Sjulian printmenuitem ( C-Addr -- N ) 513222417Sjulian 514222417Sjulian s" menukeyN !" \ generate cmd to store result 515222417Sjulian -rot 2dup 7 + c! rot 516222417Sjulian 517222417Sjulian evaluate 518222417Sjulian else 519222417Sjulian drop 520222417Sjulian then 521222417Sjulian else 522222417Sjulian drop 523222417Sjulian 524222417Sjulian s" menu_command[x]" 525222417Sjulian -rot 2dup 13 + c! rot ( replace 'x' ) 526222417Sjulian unsetenv 527222417Sjulian then 528222417Sjulian 529222417Sjulian 1+ dup 56 > \ add 1 to iterator, continue if less than 57 530222417Sjulian until 531222417Sjulian drop \ iterator 532222417Sjulian 533222417Sjulian \ Optionally add a reboot option to the menu 534222417Sjulian menurebootadded @ true <> if 535222417Sjulian s" menu_reboot" getenv -1 <> if 536222417Sjulian drop \ no need for the value 537222417Sjulian s" Reboot" \ menu caption (required by printmenuitem) 538222417Sjulian 539222417Sjulian printmenuitem 540222417Sjulian menureboot ! 541222417Sjulian else 542222417Sjulian 0 menureboot ! 543222417Sjulian then 544222417Sjulian then 545222417Sjulian; 546222417Sjulian 547222417Sjulian\ Takes a single integer on the stack and updates the timeout display. The 548222417Sjulian\ integer must be between 0 and 9 (we will only update a single digit in the 549222417Sjulian\ source message). 550222417Sjulian\ 551222417Sjulian: menu-timeout-update ( N -- ) 552222417Sjulian 553222417Sjulian dup 9 > if ( N N 9 -- N ) 554222417Sjulian drop ( N -- ) 555222417Sjulian 9 ( maximum: -- N ) 556222417Sjulian then 557222417Sjulian 558222417Sjulian dup 0 < if ( N N 0 -- N ) 559222417Sjulian drop ( N -- ) 560222417Sjulian 0 ( minimum: -- N ) 561222417Sjulian then 562222417Sjulian 563222417Sjulian 48 + ( convert single-digit numeral to ASCII: N 48 -- N ) 564222417Sjulian 565222417Sjulian s" Autoboot in N seconds. [Space] to pause" ( N -- N Addr C ) 566222417Sjulian 567222417Sjulian 2 pick 48 - 0> if ( N Addr C N 48 -- N Addr C ) 568222417Sjulian 569222417Sjulian \ Modify 'N' (Addr+12) above to reflect time-left 570222417Sjulian 571222417Sjulian -rot ( N Addr C -- C N Addr ) 572222417Sjulian tuck ( C N Addr -- C Addr N Addr ) 573222417Sjulian 12 + ( C Addr N Addr -- C Addr N Addr2 ) 574222417Sjulian c! ( C Addr N Addr2 -- C Addr ) 575222417Sjulian swap ( C Addr -- Addr C ) 576222417Sjulian 577222417Sjulian menu_timeout_x @ 578222417Sjulian menu_timeout_y @ 579222417Sjulian at-xy ( position cursor: Addr C N N -- Addr C ) 580222417Sjulian 581222417Sjulian type ( print message: Addr C -- ) 582222417Sjulian 583222417Sjulian else ( N Addr C N -- N Addr C ) 584222417Sjulian 585222417Sjulian menu_timeout_x @ 586222417Sjulian menu_timeout_y @ 587222417Sjulian at-xy ( position cursor: N Addr C N N -- N Addr C ) 588222417Sjulian 589222417Sjulian spaces ( erase message: N Addr C -- N Addr ) 590222417Sjulian 2drop ( N Addr -- ) 591222417Sjulian 592222417Sjulian then 593222417Sjulian 594222417Sjulian 0 25 at-xy ( position cursor back at bottom-left ) 595222417Sjulian; 596222417Sjulian 597222417Sjulian\ This function blocks program flow (loops forever) until a key is pressed. 598222417Sjulian\ The key that was pressed is added to the top of the stack in the form of its 599222417Sjulian\ decimal ASCII representation. This function is called by the menu-display 600222417Sjulian\ function. You need not call it directly. 601222417Sjulian\ 602222417Sjulian: getkey ( -- ascii_keycode ) 603222417Sjulian 604222417Sjulian begin \ loop forever 605222417Sjulian 606222417Sjulian menu_timeout_enabled @ 1 = if 607222417Sjulian ( -- ) 608222417Sjulian seconds ( get current time: -- N ) 609222417Sjulian dup menu_time @ <> if ( has time elapsed?: N N N -- N ) 610222417Sjulian 611222417Sjulian \ At least 1 second has elapsed since last loop 612222417Sjulian \ so we will decrement our "timeout" (really a 613222417Sjulian \ counter, insuring that we do not proceed too 614222417Sjulian \ fast) and update our timeout display. 615222417Sjulian 616222417Sjulian menu_time ! ( update time record: N -- ) 617222417Sjulian menu_timeout @ ( "time" remaining: -- N ) 618222417Sjulian dup 0> if ( greater than 0?: N N 0 -- N ) 619222417Sjulian 1- ( decrement counter: N -- N ) 620222417Sjulian dup menu_timeout ! 621222417Sjulian ( re-assign: N N Addr -- N ) 622222417Sjulian then 623222417Sjulian ( -- N ) 624222417Sjulian 625222417Sjulian dup 0= swap 0< or if ( N <= 0?: N N -- ) 626222417Sjulian \ halt the timer 627222417Sjulian 0 menu_timeout ! ( 0 Addr -- ) 628222417Sjulian 0 menu_timeout_enabled ! ( 0 Addr -- ) 629222417Sjulian then 630222417Sjulian 631222417Sjulian \ update the timer display ( N -- ) 632222417Sjulian menu_timeout @ menu-timeout-update 633222417Sjulian 634222417Sjulian menu_timeout @ 0= if 635222417Sjulian \ We've reached the end of the timeout 636222417Sjulian \ (user did not cancel by pressing ANY 637222417Sjulian \ key) 638222417Sjulian 639222417Sjulian s" menu_timeout_command" getenv dup 640222417Sjulian -1 = if 641222417Sjulian drop \ clean-up 642222417Sjulian else 643222417Sjulian evaluate 644222417Sjulian then 645222417Sjulian then 646222417Sjulian 647222417Sjulian else ( -- N ) 648222417Sjulian \ No [detectable] time has elapsed (in seconds) 649222417Sjulian drop ( N -- ) 650222417Sjulian then 651222417Sjulian ( -- ) 652222417Sjulian then 653222417Sjulian 654222417Sjulian key? if \ Was a key pressed? (see loader(8)) 655222417Sjulian 656222417Sjulian \ An actual key was pressed (if the timeout is running, 657222417Sjulian \ kill it regardless of which key was pressed) 658222417Sjulian menu_timeout @ 0<> if 659222417Sjulian 0 menu_timeout ! 660222417Sjulian 0 menu_timeout_enabled ! 661222417Sjulian 662222417Sjulian \ clear screen of timeout message 663222417Sjulian 0 menu-timeout-update 664222417Sjulian then 665222417Sjulian 666222417Sjulian \ get the key that was pressed and exit (if we 667222417Sjulian \ get a non-zero ASCII code) 668222417Sjulian key dup 0<> if 669222417Sjulian exit 670222417Sjulian else 671222417Sjulian drop 672222417Sjulian then 673222417Sjulian then 674222417Sjulian 50 ms \ sleep for 50 milliseconds (see loader(8)) 675222417Sjulian 676222417Sjulian again 677222417Sjulian; 678222417Sjulian 679222417Sjulian: menu-erase ( -- ) \ Erases menu and resets positioning variable to positon 1. 680222417Sjulian 681222417Sjulian \ Clear the screen area associated with the interactive menu 682222417Sjulian menuX @ menuY @ 683222417Sjulian 2dup at-xy 38 spaces 1+ 2dup at-xy 38 spaces 1+ 684222417Sjulian 2dup at-xy 38 spaces 1+ 2dup at-xy 38 spaces 1+ 685222417Sjulian 2dup at-xy 38 spaces 1+ 2dup at-xy 38 spaces 1+ 686222417Sjulian 2dup at-xy 38 spaces 1+ 2dup at-xy 38 spaces 1+ 687222417Sjulian 2dup at-xy 38 spaces 1+ 2dup at-xy 38 spaces 1+ 688222417Sjulian 2dup at-xy 38 spaces 1+ 2dup at-xy 38 spaces 689222417Sjulian 2drop 690222417Sjulian 691222417Sjulian \ Reset the starting index and position for the menu 692222417Sjulian menu_start 1- menuidx ! 693222417Sjulian 0 menurow ! 694222417Sjulian; 695222417Sjulian 696222417Sjulian\ Erase and redraw the menu. Useful if you change a caption and want to 697222417Sjulian\ update the menu to reflect the new value. 698222417Sjulian\ 699222417Sjulian: menu-redraw ( -- ) 700222417Sjulian menu-erase 701222417Sjulian menu-create 702222417Sjulian; 703222417Sjulian 704222417Sjulian\ This function initializes the menu. Call this from your `loader.rc' file 705222417Sjulian\ before calling any other menu-related functions. 706222417Sjulian\ 707222417Sjulian: menu-init ( -- ) 708222417Sjulian menu_start 709222417Sjulian 1- menuidx ! \ Initialize the starting index for the menu 710222417Sjulian 0 menurow ! \ Initialize the starting position for the menu 711222417Sjulian 42 13 2 9 box \ Draw frame (w,h,x,y) 712222417Sjulian 0 25 at-xy \ Move cursor to the bottom for output 713222417Sjulian; 714222417Sjulian 715222417Sjulian\ Main function. Call this from your `loader.rc' file. 716222417Sjulian\ 717222417Sjulian: menu-display ( -- ) 718222417Sjulian 719222417Sjulian 0 menu_timeout_enabled ! \ start with automatic timeout disabled 720222417Sjulian 721222417Sjulian \ check indication that automatic execution after delay is requested 722222417Sjulian s" menu_timeout_command" getenv -1 <> if ( Addr C -1 -- | Addr ) 723222417Sjulian drop ( just testing existence right now: Addr -- ) 724222417Sjulian 725222417Sjulian \ initialize state variables 726222417Sjulian seconds menu_time ! ( store the time we started ) 727222417Sjulian 1 menu_timeout_enabled ! ( enable automatic timeout ) 728222417Sjulian 729222417Sjulian \ read custom time-duration (if set) 730222417Sjulian s" autoboot_delay" getenv dup -1 = if 731222417Sjulian drop \ no custom duration (remove dup'd bunk -1) 732222417Sjulian menu_timeout_default \ use default setting 733222417Sjulian else 734222417Sjulian 2dup ?number 0= if ( if not a number ) 735222417Sjulian \ disable timeout if "NO", else use default 736222417Sjulian s" NO" compare-insensitive 0= if 737222417Sjulian 0 menu_timeout_enabled ! 738222417Sjulian 0 ( assigned to menu_timeout below ) 739222417Sjulian else 740222417Sjulian menu_timeout_default 741222417Sjulian then 742222417Sjulian else 743222417Sjulian -rot 2drop 744222417Sjulian 745222417Sjulian \ disable timeout if less than zero 746222417Sjulian dup 0< if 747222417Sjulian drop 748222417Sjulian 0 menu_timeout_enabled ! 749222417Sjulian 0 ( assigned to menu_timeout below ) 750222417Sjulian then 751222417Sjulian then 752222417Sjulian then 753222417Sjulian menu_timeout ! ( store value on stack from above ) 754222417Sjulian 755222417Sjulian menu_timeout_enabled @ 1 = if 756222417Sjulian \ read custom column position (if set) 757222417Sjulian s" loader_menu_timeout_x" getenv dup -1 = if 758222417Sjulian drop \ no custom column position 759222417Sjulian menu_timeout_default_x \ use default setting 760222417Sjulian else 761222417Sjulian \ make sure custom position is a number 762222417Sjulian ?number 0= if 763222417Sjulian menu_timeout_default_x \ or use default 764222417Sjulian then 765222417Sjulian then 766222417Sjulian menu_timeout_x ! ( store value on stack from above ) 767222417Sjulian 768222417Sjulian \ read custom row position (if set) 769222417Sjulian s" loader_menu_timeout_y" getenv dup -1 = if 770222417Sjulian drop \ no custom row position 771222417Sjulian menu_timeout_default_y \ use default setting 772222417Sjulian else 773222417Sjulian \ make sure custom position is a number 774222417Sjulian ?number 0= if 775222417Sjulian menu_timeout_default_y \ or use default 776222417Sjulian then 777222417Sjulian then 778222417Sjulian menu_timeout_y ! ( store value on stack from above ) 779222417Sjulian then 780222417Sjulian then 781222417Sjulian 782222417Sjulian menu-create 783222417Sjulian 784222417Sjulian begin \ Loop forever 785222417Sjulian 786222417Sjulian 0 25 at-xy \ Move cursor to the bottom for output 787222417Sjulian getkey \ Block here, waiting for a key to be pressed 788222417Sjulian 789222417Sjulian dup -1 = if 790222417Sjulian drop exit \ Caught abort (abnormal return) 791222417Sjulian then 792222417Sjulian 793222417Sjulian \ Boot if the user pressed Enter/Ctrl-M (13) or 794222417Sjulian \ Ctrl-Enter/Ctrl-J (10) 795222417Sjulian dup over 13 = swap 10 = or if 796222417Sjulian drop ( no longer needed ) 797222417Sjulian s" boot" evaluate 798222417Sjulian exit ( pedantic; never reached ) 799222417Sjulian then 800222417Sjulian 801222417Sjulian \ Evaluate the decimal ASCII value against known menu item 802222417Sjulian \ key associations and act accordingly 803222417Sjulian 804222417Sjulian 49 \ Iterator start (loop range 49 to 56; ASCII '1' to '8') 805222417Sjulian begin 806222417Sjulian s" menukeyN @" 807222417Sjulian 808222417Sjulian \ replace 'N' with current iteration 809222417Sjulian -rot 2dup 7 + c! rot 810222417Sjulian 811222417Sjulian evaluate rot tuck = if 812222417Sjulian 813222417Sjulian \ Adjust for missing ACPI menuitem on non-i386 814222417Sjulian arch-i386? true <> menuacpi @ 0<> and if 815222417Sjulian menuacpi @ over 2dup < -rot = or 816222417Sjulian over 58 < and if 817222417Sjulian ( key >= menuacpi && key < 58: N -- N ) 818222417Sjulian 1+ 819222417Sjulian then 820222417Sjulian then 821222417Sjulian 822222417Sjulian \ base env name for the value (x is a number) 823222417Sjulian s" menu_command[x]" 824222417Sjulian 825222417Sjulian \ Copy ASCII number to string at offset 13 826222417Sjulian -rot 2dup 13 + c! rot 827222417Sjulian 828222417Sjulian \ Test for the environment variable 829222417Sjulian getenv dup -1 <> if 830222417Sjulian \ Execute the stored procedure 831222417Sjulian evaluate 832222417Sjulian 833222417Sjulian \ We expect there to be a non-zero 834222417Sjulian \ value left on the stack after 835222417Sjulian \ executing the stored procedure. 836222417Sjulian \ If so, continue to run, else exit. 837222417Sjulian 838222417Sjulian 0= if 839222417Sjulian drop \ key pressed 840222417Sjulian drop \ loop iterator 841222417Sjulian exit 842222417Sjulian else 843222417Sjulian swap \ need iterator on top 844222417Sjulian then 845222417Sjulian then 846222417Sjulian 847222417Sjulian \ Re-adjust for missing ACPI menuitem 848222417Sjulian arch-i386? true <> menuacpi @ 0<> and if 849222417Sjulian swap 850222417Sjulian menuacpi @ 1+ over 2dup < -rot = or 851222417Sjulian over 59 < and if 852222417Sjulian 1- 853222417Sjulian then 854222417Sjulian swap 855222417Sjulian then 856222417Sjulian else 857222417Sjulian swap \ need iterator on top 858222417Sjulian then 859222417Sjulian 860222417Sjulian \ 861222417Sjulian \ Check for menu keycode shortcut(s) 862222417Sjulian \ 863222417Sjulian s" menu_keycode[x]" 864222417Sjulian -rot 2dup 13 + c! rot 865222417Sjulian getenv dup -1 = if 866222417Sjulian drop 867222417Sjulian else 868222417Sjulian ?number 0<> if 869222417Sjulian rot tuck = if 870222417Sjulian swap 871222417Sjulian s" menu_command[x]" 872222417Sjulian -rot 2dup 13 + c! rot 873222417Sjulian getenv dup -1 <> if 874222417Sjulian evaluate 875222417Sjulian 0= if 876222417Sjulian 2drop 877222417Sjulian exit 878222417Sjulian then 879222417Sjulian else 880222417Sjulian drop 881222417Sjulian then 882222417Sjulian else 883222417Sjulian swap 884222417Sjulian then 885222417Sjulian then 886222417Sjulian then 887222417Sjulian 888222417Sjulian 1+ dup 56 > \ increment iterator 889222417Sjulian \ continue if less than 57 890222417Sjulian until 891222417Sjulian drop \ loop iterator 892222417Sjulian 893222417Sjulian menureboot @ = if 0 reboot then 894222417Sjulian 895222417Sjulian again \ Non-operational key was pressed; repeat 896222417Sjulian; 897222417Sjulian 898222417Sjulian\ This function unsets all the possible environment variables associated with 899222417Sjulian\ creating the interactive menu. Call this when you want to clear the menu 900222417Sjulian\ area in preparation for another menu. 901222417Sjulian\ 902222417Sjulian: menu-clear ( -- ) 903222417Sjulian 904222417Sjulian 49 \ Iterator start (loop range 49 to 56; ASCII '1' to '8') 905222417Sjulian begin 906222417Sjulian \ basename for caption variable 907222417Sjulian loader_color? if 908222417Sjulian s" ansi_caption[x]" 909222417Sjulian else 910222417Sjulian s" menu_caption[x]" 911222417Sjulian then 912222417Sjulian -rot 2dup 13 + c! rot \ replace 'x' with current iteration 913222417Sjulian unsetenv \ not erroneous to unset unknown var 914222417Sjulian 915222417Sjulian s" 0 menukeyN !" \ basename for key association var 916222417Sjulian -rot 2dup 9 + c! rot \ replace 'N' with current iteration 917222417Sjulian evaluate \ assign zero (0) to key assoc. var 918222417Sjulian 919222417Sjulian 1+ dup 56 > \ increment, continue if less than 57 920222417Sjulian until 921222417Sjulian drop \ iterator 922222417Sjulian 923222417Sjulian \ clear the "Reboot" menu option flag 924222417Sjulian s" menu_reboot" unsetenv 925222417Sjulian 0 menureboot ! 926222417Sjulian 927222417Sjulian \ clear the ACPI menu option flag 928222417Sjulian s" menu_acpi" unsetenv 929222417Sjulian 0 menuacpi ! 930222417Sjulian 931222417Sjulian \ clear the "Options" menu separator flag 932222417Sjulian s" menu_options" unsetenv 933222417Sjulian 0 menuoptions ! 934222417Sjulian 935222417Sjulian menu-erase 936222417Sjulian; 937222417Sjulian 938222417Sjulian\ Assign configuration values 939222417Sjulianbullet menubllt ! 940222417Sjulian10 menuY ! 941222417Sjulian5 menuX ! 942222417Sjulian 943222417Sjulian\ Initialize our boolean state variables 944222417Sjulian0 toggle_state1 ! 945222417Sjulian0 toggle_state2 ! 946222417Sjulian0 toggle_state3 ! 947222417Sjulian0 toggle_state4 ! 948222417Sjulian0 toggle_state5 ! 949222417Sjulian0 toggle_state6 ! 950222417Sjulian0 toggle_state7 ! 951222417Sjulian0 toggle_state8 ! 952222417Sjulian 953222417Sjulian\ Initialize our array state variables 954222417Sjulian0 cycle_state1 ! 955222417Sjulian0 cycle_state2 ! 956222417Sjulian0 cycle_state3 ! 957222417Sjulian0 cycle_state4 ! 958222417Sjulian0 cycle_state5 ! 959222417Sjulian0 cycle_state6 ! 960222417Sjulian0 cycle_state7 ! 961222417Sjulian0 cycle_state8 ! 962222417Sjulian 963222417Sjulian\ Initialize string containers 964222417Sjulian0 init_text1 c! 965222417Sjulian0 init_text2 c! 966222417Sjulian0 init_text3 c! 967222417Sjulian0 init_text4 c! 968222417Sjulian0 init_text5 c! 969222417Sjulian0 init_text6 c! 970222417Sjulian0 init_text7 c! 971222417Sjulian0 init_text8 c! 972