freebsd-skq/sys/boot/forth/menusets.4th
dteske e520f64215 Solve dreaded "dictionary full" issue by segregating words into new
vocabularies delay-processing, password-processing, version-processing,
frame-drawing, menu-infrastructure, menu-namespace, menu-command-helpers,
and menusets-infrastructure. The net effect is to remove almost 200
definitions from the main forth vocabulary reducing the dictionary size
by over 50%. The chances of hitting "dictionary full" should be greatly
reduced by this patch.

MFC after:	3 days
X-MFC-to:	stable/10
2015-04-01 01:54:28 +00:00

625 lines
18 KiB
Forth

\ Copyright (c) 2012 Devin Teske <dteske@FreeBSD.org>
\ All rights reserved.
\
\ Redistribution and use in source and binary forms, with or without
\ modification, are permitted provided that the following conditions
\ are met:
\ 1. Redistributions of source code must retain the above copyright
\ notice, this list of conditions and the following disclaimer.
\ 2. Redistributions in binary form must reproduce the above copyright
\ notice, this list of conditions and the following disclaimer in the
\ documentation and/or other materials provided with the distribution.
\
\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
\ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
\ SUCH DAMAGE.
\
\ $FreeBSD$
marker task-menusets.4th
vocabulary menusets-infrastructure
only forth also menusets-infrastructure definitions
variable menuset_use_name
create menuset_affixbuf 255 allot
create menuset_x 1 allot
create menuset_y 1 allot
: menuset-loadvar ( -- )
\ menuset_use_name is true or false
\ $type should be set to one of:
\ menu toggled ansi
\ $var should be set to one of:
\ caption command keycode text ...
\ $affix is either prefix (menuset_use_name is true)
\ or infix (menuset_use_name is false)
s" set cmdbuf='set ${type}_${var}=\$'" evaluate
s" cmdbuf" getenv swap drop ( -- u1 ) \ get string length
menuset_use_name @ true = if
s" set cmdbuf=${cmdbuf}${affix}${type}_${var}"
( u1 -- u1 c-addr2 u2 )
else
s" set cmdbuf=${cmdbuf}${type}set${affix}_${var}"
( u1 -- u1 c-addr2 u2 )
then
evaluate ( u1 c-addr2 u2 -- u1 )
s" cmdbuf" getenv ( u1 -- u1 c-addr2 u2 )
rot 2 pick 2 pick over + -rot + tuck -
( u1 c-addr2 u2 -- c-addr2 u2 c-addr1 u1 )
\ Generate a string representing rvalue inheritance var
getenv dup -1 = if
( c-addr2 u2 c-addr1 u1 -- c-addr2 u2 -1 )
\ NOT set -- clean up the stack
drop ( c-addr2 u2 -1 -- c-addr2 u2 )
2drop ( c-addr2 u2 -- )
else
( c-addr2 u2 c-addr1 u1 -- c-addr2 u2 c-addr1 u1 )
\ SET -- execute cmdbuf (c-addr2/u2) to inherit value
2drop ( c-addr2 u2 c-addr1 u1 -- c-addr2 u2 )
evaluate ( c-addr2 u2 -- )
then
s" cmdbuf" unsetenv
;
: menuset-unloadvar ( -- )
\ menuset_use_name is true or false
\ $type should be set to one of:
\ menu toggled ansi
\ $var should be set to one of:
\ caption command keycode text ...
\ $affix is either prefix (menuset_use_name is true)
\ or infix (menuset_use_name is false)
menuset_use_name @ true = if
s" set buf=${affix}${type}_${var}"
else
s" set buf=${type}set${affix}_${var}"
then
evaluate
s" buf" getenv unsetenv
s" buf" unsetenv
;
: menuset-loadmenuvar ( -- )
s" set type=menu" evaluate
menuset-loadvar
;
: menuset-unloadmenuvar ( -- )
s" set type=menu" evaluate
menuset-unloadvar
;
: menuset-loadxvar ( -- )
\ menuset_use_name is true or false
\ $type should be set to one of:
\ menu toggled ansi
\ $var should be set to one of:
\ caption command keycode text ...
\ $x is "1" through "8"
\ $affix is either prefix (menuset_use_name is true)
\ or infix (menuset_use_name is false)
s" set cmdbuf='set ${type}_${var}[${x}]=\$'" evaluate
s" cmdbuf" getenv swap drop ( -- u1 ) \ get string length
menuset_use_name @ true = if
s" set cmdbuf=${cmdbuf}${affix}${type}_${var}[${x}]"
( u1 -- u1 c-addr2 u2 )
else
s" set cmdbuf=${cmdbuf}${type}set${affix}_${var}[${x}]"
( u1 -- u1 c-addr2 u2 )
then
evaluate ( u1 c-addr2 u2 -- u1 )
s" cmdbuf" getenv ( u1 -- u1 c-addr2 u2 )
rot 2 pick 2 pick over + -rot + tuck -
( u1 c-addr2 u2 -- c-addr2 u2 c-addr1 u1 )
\ Generate a string representing rvalue inheritance var
getenv dup -1 = if
( c-addr2 u2 c-addr1 u1 -- c-addr2 u2 -1 )
\ NOT set -- clean up the stack
drop ( c-addr2 u2 -1 -- c-addr2 u2 )
2drop ( c-addr2 u2 -- )
else
( c-addr2 u2 c-addr1 u1 -- c-addr2 u2 c-addr1 u1 )
\ SET -- execute cmdbuf (c-addr2/u2) to inherit value
2drop ( c-addr2 u2 c-addr1 u1 -- c-addr2 u2 )
evaluate ( c-addr2 u2 -- )
then
s" cmdbuf" unsetenv
;
: menuset-unloadxvar ( -- )
\ menuset_use_name is true or false
\ $type should be set to one of:
\ menu toggled ansi
\ $var should be set to one of:
\ caption command keycode text ...
\ $x is "1" through "8"
\ $affix is either prefix (menuset_use_name is true)
\ or infix (menuset_use_name is false)
menuset_use_name @ true = if
s" set buf=${affix}${type}_${var}[${x}]"
else
s" set buf=${type}set${affix}_${var}[${x}]"
then
evaluate
s" buf" getenv unsetenv
s" buf" unsetenv
;
: menuset-loadansixvar ( -- )
s" set type=ansi" evaluate
menuset-loadxvar
;
: menuset-unloadansixvar ( -- )
s" set type=ansi" evaluate
menuset-unloadxvar
;
: menuset-loadmenuxvar ( -- )
s" set type=menu" evaluate
menuset-loadxvar
;
: menuset-unloadmenuxvar ( -- )
s" set type=menu" evaluate
menuset-unloadxvar
;
: menuset-loadtoggledxvar ( -- )
s" set type=toggled" evaluate
menuset-loadxvar
;
: menuset-unloadtoggledxvar ( -- )
s" set type=toggled" evaluate
menuset-unloadxvar
;
: menuset-loadxyvar ( -- )
\ menuset_use_name is true or false
\ $type should be set to one of:
\ menu toggled ansi
\ $var should be set to one of:
\ caption command keycode text ...
\ $x is "1" through "8"
\ $y is "0" through "9"
\ $affix is either prefix (menuset_use_name is true)
\ or infix (menuset_use_name is false)
s" set cmdbuf='set ${type}_${var}[${x}][${y}]=\$'" evaluate
s" cmdbuf" getenv swap drop ( -- u1 ) \ get string length
menuset_use_name @ true = if
s" set cmdbuf=${cmdbuf}${affix}${type}_${var}[${x}][${y}]"
( u1 -- u1 c-addr2 u2 )
else
s" set cmdbuf=${cmdbuf}${type}set${affix}_${var}[${x}][${y}]"
( u1 -- u1 c-addr2 u2 )
then
evaluate ( u1 c-addr2 u2 -- u1 )
s" cmdbuf" getenv ( u1 -- u1 c-addr2 u2 )
rot 2 pick 2 pick over + -rot + tuck -
( u1 c-addr2 u2 -- c-addr2 u2 c-addr1 u1 )
\ Generate a string representing rvalue inheritance var
getenv dup -1 = if
( c-addr2 u2 c-addr1 u1 -- c-addr2 u2 -1 )
\ NOT set -- clean up the stack
drop ( c-addr2 u2 -1 -- c-addr2 u2 )
2drop ( c-addr2 u2 -- )
else
( c-addr2 u2 c-addr1 u1 -- c-addr2 u2 c-addr1 u1 )
\ SET -- execute cmdbuf (c-addr2/u2) to inherit value
2drop ( c-addr2 u2 c-addr1 u1 -- c-addr2 u2 )
evaluate ( c-addr2 u2 -- )
then
s" cmdbuf" unsetenv
;
: menuset-unloadxyvar ( -- )
\ menuset_use_name is true or false
\ $type should be set to one of:
\ menu toggled ansi
\ $var should be set to one of:
\ caption command keycode text ...
\ $x is "1" through "8"
\ $y is "0" through "9"
\ $affix is either prefix (menuset_use_name is true)
\ or infix (menuset_use_name is false)
menuset_use_name @ true = if
s" set buf=${affix}${type}_${var}[${x}][${y}]"
else
s" set buf=${type}set${affix}_${var}[${x}][${y}]"
then
evaluate
s" buf" getenv unsetenv
s" buf" unsetenv
;
: menuset-loadansixyvar ( -- )
s" set type=ansi" evaluate
menuset-loadxyvar
;
: menuset-unloadansixyvar ( -- )
s" set type=ansi" evaluate
menuset-unloadxyvar
;
: menuset-loadmenuxyvar ( -- )
s" set type=menu" evaluate
menuset-loadxyvar
;
: menuset-unloadmenuxyvar ( -- )
s" set type=menu" evaluate
menuset-unloadxyvar
;
: menuset-setnum-namevar ( N -- C-Addr/U )
s" menuset_nameNNNNN" ( n -- n c-addr1 u1 ) \ variable basename
drop 12 ( n c-addr1 u1 -- n c-addr1 12 ) \ remove "NNNNN"
rot ( n c-addr1 12 -- c-addr1 12 n ) \ move number on top
\ convert to string
s>d <# #s #> ( c-addr1 12 n -- c-addr1 12 c-addr2 u2 )
\ Combine strings
begin ( using u2 in c-addr2/u2 pair as countdown to zero )
over ( c-addr1 u1 c-addr2 u2 -- continued below )
( c-addr1 u1 c-addr2 u2 c-addr2 ) \ copy src-addr
c@ ( c-addr1 u1 c-addr2 u2 c-addr2 -- continued below )
( c-addr1 u1 c-addr2 u2 c ) \ get next src-addr byte
4 pick 4 pick
( c-addr1 u1 c-addr2 u2 c -- continued below )
( c-addr1 u1 c-addr2 u2 c c-addr1 u1 )
\ get destination c-addr1/u1 pair
+ ( c-addr1 u1 c-addr2 u2 c c-addr1 u1 -- cont. below )
( c-addr1 u1 c-addr2 u2 c c-addr3 )
\ combine dest-c-addr to get dest-addr for byte
c! ( c-addr1 u1 c-addr2 u2 c c-addr3 -- continued below )
( c-addr1 u1 c-addr2 u2 )
\ store the current src-addr byte into dest-addr
2swap 1+ 2swap \ increment u1 in destination c-addr1/u1 pair
swap 1+ swap \ increment c-addr2 in source c-addr2/u2 pair
1- \ decrement u2 in the source c-addr2/u2 pair
dup 0= \ time to break?
until
2drop ( c-addr1 u1 c-addr2 u2 -- c-addr1 u1 )
\ drop temporary number-format conversion c-addr2/u2
;
: menuset-checksetnum ( N -- )
\
\ adjust input to be both positive and no-higher than 65535
\
abs dup 65535 > if drop 65535 then ( n -- n )
\
\ The next few blocks will determine if we should use the default
\ methodology (referencing the original numeric stack-input), or if-
\ instead $menuset_name{N} has been defined wherein we would then
\ use the value thereof as the prefix to every menu variable.
\
false menuset_use_name ! \ assume name is not set
menuset-setnum-namevar
\
\ We now have a string that is the assembled variable name to check
\ for... $menuset_name{N}. Let's check for it.
\
2dup ( c-addr1 u1 -- c-addr1 u1 c-addr1 u1 ) \ save a copy
getenv dup -1 <> if ( c-addr1 u1 c-addr1 u1 -- c-addr1 u1 c-addr2 u2 )
\ The variable is set. Let's clean up the stack leaving only
\ its value for later use.
true menuset_use_name !
2swap 2drop ( c-addr1 u1 c-addr2 u2 -- c-addr2 u2 )
\ drop assembled variable name, leave the value
else ( c-addr1 u1 c-addr1 u1 -- c-addr1 u1 -1 ) \ no such variable
\ The variable is not set. Let's clean up the stack leaving the
\ string [portion] representing the original numeric input.
drop ( c-addr1 u1 -1 -- c-addr1 u1 ) \ drop -1 result
12 - swap 12 + swap ( c-addr1 u1 -- c-addr2 u2 )
\ truncate to original numeric stack-input
then
\
\ Now, depending on whether $menuset_name{N} has been set, we have
\ either the value thereof to be used as a prefix to all menu_*
\ variables or we have a string representing the numeric stack-input
\ to be used as a "set{N}" infix to the same menu_* variables.
\
\ For example, if the stack-input is 1 and menuset_name1 is NOT set
\ the following variables will be referenced:
\ ansiset1_caption[x] -> ansi_caption[x]
\ ansiset1_caption[x][y] -> ansi_caption[x][y]
\ menuset1_acpi -> menu_acpi
\ menuset1_caption[x] -> menu_caption[x]
\ menuset1_caption[x][y] -> menu_caption[x][y]
\ menuset1_command[x] -> menu_command[x]
\ menuset1_init -> ``evaluated''
\ menuset1_init[x] -> menu_init[x]
\ menuset1_kernel -> menu_kernel
\ menuset1_keycode[x] -> menu_keycode[x]
\ menuset1_options -> menu_options
\ menuset1_optionstext -> menu_optionstext
\ menuset1_reboot -> menu_reboot
\ toggledset1_ansi[x] -> toggled_ansi[x]
\ toggledset1_text[x] -> toggled_text[x]
\ otherwise, the following variables are referenced (where {name}
\ represents the value of $menuset_name1 (given 1 as stack-input):
\ {name}ansi_caption[x] -> ansi_caption[x]
\ {name}ansi_caption[x][y] -> ansi_caption[x][y]
\ {name}menu_acpi -> menu_acpi
\ {name}menu_caption[x] -> menu_caption[x]
\ {name}menu_caption[x][y] -> menu_caption[x][y]
\ {name}menu_command[x] -> menu_command[x]
\ {name}menu_init -> ``evaluated''
\ {name}menu_init[x] -> menu_init[x]
\ {name}menu_kernel -> menu_kernel
\ {name}menu_keycode[x] -> menu_keycode[x]
\ {name}menu_options -> menu_options
\ {name}menu_optionstext -> menu_optionstext
\ {name}menu_reboot -> menu_reboot
\ {name}toggled_ansi[x] -> toggled_ansi[x]
\ {name}toggled_text[x] -> toggled_text[x]
\
\ Note that menuset{N}_init and {name}menu_init are the initializers
\ for the entire menu (for wholly dynamic menus) opposed to the per-
\ menuitem initializers (with [x] afterward). The whole-menu init
\ routine is evaluated and not passed down to $menu_init (which
\ would result in double evaluation). By doing this, the initializer
\ can initialize the menuset before we transfer it to active-duty.
\
\
\ Copy our affixation (prefix or infix depending on menuset_use_name)
\ to our buffer so that we can safely use the s-quote (s") buf again.
\
menuset_affixbuf 0 2swap ( c-addr2 u2 -- c-addr1 0 c-addr2 u2 )
begin ( using u2 in c-addr2/u2 pair as countdown to zero )
over ( c-addr1 u1 c-addr2 u2 -- c-addr1 u1 c-addr2 u2 c-addr2 )
c@ ( c-addr1 u1 c-addr2 u2 -- c-addr1 u1 c-addr2 u2 c )
4 pick 4 pick
( c-addr1 u1 c-addr2 u2 c -- continued below )
( c-addr1 u1 c-addr2 u2 c c-addr1 u1 )
+ ( c-addr1 u1 c-addr2 u2 c c-addr1 u1 -- continued below )
( c-addr1 u1 c-addr2 u2 c c-addr3 )
c! ( c-addr1 u1 c-addr2 u2 c c-addr3 -- continued below )
( c-addr1 u1 c-addr2 u2 )
2swap 1+ 2swap \ increment affixbuf byte position/count
swap 1+ swap \ increment strbuf pointer (source c-addr2)
1- \ decrement strbuf byte count (source u2)
dup 0= \ time to break?
until
2drop ( c-addr1 u1 c-addr2 u2 -- c-addr1 u1 ) \ drop strbuf c-addr2/u2
\
\ Create a variable for referencing our affix data (prefix or infix
\ depending on menuset_use_name as described above). This variable will
\ be temporary and only used to simplify cmdbuf assembly.
\
s" affix" setenv ( c-addr1 u1 -- )
;
: menuset-cleanup ( -- )
s" type" unsetenv
s" var" unsetenv
s" x" unsetenv
s" y" unsetenv
s" affix" unsetenv
;
only forth definitions also menusets-infrastructure
: menuset-loadsetnum ( N -- )
menuset-checksetnum ( n -- )
\
\ From here out, we use temporary environment variables to make
\ dealing with variable-length strings easier.
\
\ menuset_use_name is true or false
\ $affix should be used appropriately w/respect to menuset_use_name
\
\ ... menu_init ...
s" set var=init" evaluate
menuset-loadmenuvar
\ If menu_init was set by the above, evaluate it here-and-now
\ so that the remaining variables are influenced by its actions
s" menu_init" 2dup getenv dup -1 <> if
2swap unsetenv \ don't want later menu-create to re-call this
evaluate
else
drop 2drop ( n c-addr u -1 -- n )
then
[char] 1 ( -- x ) \ Loop range ASCII '1' (49) to '8' (56)
begin
dup menuset_x tuck c! 1 s" x" setenv \ set loop iterator and $x
s" set var=caption" evaluate
\ ... menu_caption[x] ...
menuset-loadmenuxvar
\ ... ansi_caption[x] ...
menuset-loadansixvar
[char] 0 ( x -- x y ) \ Inner Loop ASCII '1' (48) to '9' (57)
begin
dup menuset_y tuck c! 1 s" y" setenv
\ set inner loop iterator and $y
\ ... menu_caption[x][y] ...
menuset-loadmenuxyvar
\ ... ansi_caption[x][y] ...
menuset-loadansixyvar
1+ dup 57 > ( x y -- y' 0|-1 ) \ increment and test
until
drop ( x y -- x )
\ ... menu_command[x] ...
s" set var=command" evaluate
menuset-loadmenuxvar
\ ... menu_init[x] ...
s" set var=init" evaluate
menuset-loadmenuxvar
\ ... menu_keycode[x] ...
s" set var=keycode" evaluate
menuset-loadmenuxvar
\ ... toggled_text[x] ...
s" set var=text" evaluate
menuset-loadtoggledxvar
\ ... toggled_ansi[x] ...
s" set var=ansi" evaluate
menuset-loadtoggledxvar
1+ dup 56 > ( x -- x' 0|-1 ) \ increment iterator
\ continue if less than 57
until
drop ( x -- ) \ loop iterator
\ ... menu_reboot ...
s" set var=reboot" evaluate
menuset-loadmenuvar
\ ... menu_acpi ...
s" set var=acpi" evaluate
menuset-loadmenuvar
\ ... menu_kernel ...
s" set var=kernel" evaluate
menuset-loadmenuvar
\ ... menu_options ...
s" set var=options" evaluate
menuset-loadmenuvar
\ ... menu_optionstext ...
s" set var=optionstext" evaluate
menuset-loadmenuvar
menuset-cleanup
;
: menusets-unset ( -- )
s" menuset_initial" unsetenv
1 begin
dup menuset-checksetnum ( n n -- n )
dup menuset-setnum-namevar ( n n -- n )
unsetenv
\ If the current menuset does not populate the first menuitem,
\ we stop completely.
menuset_use_name @ true = if
s" set buf=${affix}menu_caption[1]"
else
s" set buf=menuset${affix}_caption[1]"
then
evaluate s" buf" getenv getenv -1 = if
drop ( n -- )
s" buf" unsetenv
menuset-cleanup
exit
else
drop ( n c-addr2 -- n ) \ unused
then
[char] 1 ( n -- n x ) \ Loop range ASCII '1' (49) to '8' (56)
begin
dup menuset_x tuck c! 1 s" x" setenv \ set $x to x
s" set var=caption" evaluate
menuset-unloadmenuxvar
menuset-unloadmenuxvar
menuset-unloadansixvar
[char] 0 ( n x -- n x y ) \ Inner loop '0' to '9'
begin
dup menuset_y tuck c! 1 s" y" setenv
\ sets $y to y
menuset-unloadmenuxyvar
menuset-unloadansixyvar
1+ dup 57 > ( n x y -- n x y' 0|-1 )
until
drop ( n x y -- n x )
s" set var=command" evaluate menuset-unloadmenuxvar
s" set var=init" evaluate menuset-unloadmenuxvar
s" set var=keycode" evaluate menuset-unloadmenuxvar
s" set var=text" evaluate menuset-unloadtoggledxvar
s" set var=ansi" evaluate menuset-unloadtoggledxvar
1+ dup 56 > ( x -- x' 0|-1 ) \ increment and test
until
drop ( n x -- n ) \ loop iterator
s" set var=acpi" evaluate menuset-unloadmenuvar
s" set var=init" evaluate menuset-unloadmenuvar
s" set var=kernel" evaluate menuset-unloadmenuvar
s" set var=options" evaluate menuset-unloadmenuvar
s" set var=optionstext" evaluate menuset-unloadmenuvar
s" set var=reboot" evaluate menuset-unloadmenuvar
1+ dup 65535 > ( n -- n' 0|-1 ) \ increment and test
until
drop ( n' -- ) \ loop iterator
s" buf" unsetenv
menuset-cleanup
;
only forth definitions
: menuset-loadinitial ( -- )
s" menuset_initial" getenv dup -1 <> if
?number 0<> if
menuset-loadsetnum
then
else
drop \ cruft
then
;