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