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