PageRenderTime 65ms CodeModel.GetById 32ms RepoModel.GetById 1ms app.codeStats 0ms

/usr/src/boot/forth/menu.4th

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