1280924Sdteske\ Copyright (c) 1999 Daniel C. Sobral <dcs@FreeBSD.org>
244603Sdcs\ All rights reserved.
344603Sdcs\ 
444603Sdcs\ Redistribution and use in source and binary forms, with or without
544603Sdcs\ modification, are permitted provided that the following conditions
644603Sdcs\ are met:
744603Sdcs\ 1. Redistributions of source code must retain the above copyright
844603Sdcs\    notice, this list of conditions and the following disclaimer.
944603Sdcs\ 2. Redistributions in binary form must reproduce the above copyright
1044603Sdcs\    notice, this list of conditions and the following disclaimer in the
1144603Sdcs\    documentation and/or other materials provided with the distribution.
1244603Sdcs\
1344603Sdcs\ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
1444603Sdcs\ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1544603Sdcs\ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1644603Sdcs\ ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
1744603Sdcs\ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
1844603Sdcs\ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
1944603Sdcs\ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
2044603Sdcs\ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
2144603Sdcs\ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
2244603Sdcs\ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
2344603Sdcs\ SUCH DAMAGE.
2444603Sdcs\
2550477Speter\ $FreeBSD: releng/11.0/sys/boot/forth/support.4th 298831 2016-04-30 02:47:41Z pfg $
2644603Sdcs
2744603Sdcs\ Loader.rc support functions:
2844603Sdcs\
2944603Sdcs\ initialize ( addr len -- )	as above, plus load_conf_files
3044603Sdcs\ load_conf ( addr len -- )	load conf file given
3144603Sdcs\ include_conf_files ( -- )	load all conf files in load_conf_files
3244603Sdcs\ print_syntax_error ( -- )	print line and marker of where a syntax
3344603Sdcs\				error was detected
3444603Sdcs\ print_line ( -- )		print last line processed
3544603Sdcs\ load_kernel ( -- )		load kernel
3644603Sdcs\ load_modules ( -- )		load modules flagged
3744603Sdcs\
3844603Sdcs\ Exported structures:
3944603Sdcs\
4044603Sdcs\ string			counted string structure
4144603Sdcs\	cell .addr			string address
4244603Sdcs\	cell .len			string length
4344603Sdcs\ module			module loading information structure
4444603Sdcs\	cell module.flag		should we load it?
4544603Sdcs\	string module.name		module's name
4644603Sdcs\	string module.loadname		name to be used in loading the module
4744603Sdcs\	string module.type		module's type
4844603Sdcs\	string module.args		flags to be passed during load
4944603Sdcs\	string module.beforeload	command to be executed before load
5044603Sdcs\	string module.afterload		command to be executed after load
5144603Sdcs\	string module.loaderror		command to be executed if load fails
5244603Sdcs\	cell module.next		list chain
5344603Sdcs\
5444603Sdcs\ Exported global variables;
5544603Sdcs\
5644603Sdcs\ string conf_files		configuration files to be loaded
5744603Sdcs\ cell modules_options		pointer to first module information
5844603Sdcs\ value verbose?		indicates if user wants a verbose loading
59298831Spfg\ value any_conf_read?		indicates if a conf file was successfully read
6044603Sdcs\
6144603Sdcs\ Other exported words:
62186789Sluigi\    note, strlen is internal
6344603Sdcs\ strdup ( addr len -- addr' len)			similar to strdup(3)
6444603Sdcs\ strcat ( addr len addr' len' -- addr len+len' )	similar to strcat(3)
6544603Sdcs\ s' ( | string' -- addr len | )			similar to s"
6644603Sdcs\ rudimentary structure support
6744603Sdcs
6844603Sdcs\ Exception values
6944603Sdcs
70186789Sluigi1 constant ESYNTAX
71186789Sluigi2 constant ENOMEM
72186789Sluigi3 constant EFREE
73186789Sluigi4 constant ESETERROR	\ error setting environment variable
74186789Sluigi5 constant EREAD	\ error reading
75186789Sluigi6 constant EOPEN
76186789Sluigi7 constant EEXEC	\ XXX never catched
77186789Sluigi8 constant EBEFORELOAD
78186789Sluigi9 constant EAFTERLOAD
7944603Sdcs
8087636Sjhb\ I/O constants
8187636Sjhb
8287636Sjhb0 constant SEEK_SET
8387636Sjhb1 constant SEEK_CUR
8487636Sjhb2 constant SEEK_END
8587636Sjhb
8687636Sjhb0 constant O_RDONLY
8787636Sjhb1 constant O_WRONLY
8887636Sjhb2 constant O_RDWR
8987636Sjhb
9044603Sdcs\ Crude structure support
9144603Sdcs
9265615Sdcs: structure:
9365615Sdcs  create here 0 , ['] drop , 0
9465615Sdcs  does> create here swap dup @ allot cell+ @ execute
9565615Sdcs;
9644603Sdcs: member: create dup , over , + does> cell+ @ + ;
9744603Sdcs: ;structure swap ! ;
9865615Sdcs: constructor! >body cell+ ! ;
9965615Sdcs: constructor: over :noname ;
10065615Sdcs: ;constructor postpone ; swap cell+ ! ; immediate
10144603Sdcs: sizeof ' >body @ state @ if postpone literal then ; immediate
10244603Sdcs: offsetof ' >body cell+ @ state @ if postpone literal then ; immediate
10344603Sdcs: ptr 1 cells member: ;
10444603Sdcs: int 1 cells member: ;
10544603Sdcs
10644603Sdcs\ String structure
10744603Sdcs
10844603Sdcsstructure: string
10944603Sdcs	ptr .addr
11044603Sdcs	int .len
11165615Sdcs	constructor:
11265615Sdcs	  0 over .addr !
11365615Sdcs	  0 swap .len !
11465615Sdcs	;constructor
11544603Sdcs;structure
11644603Sdcs
11765615Sdcs
11844603Sdcs\ Module options linked list
11944603Sdcs
12044603Sdcsstructure: module
12144603Sdcs	int module.flag
12244603Sdcs	sizeof string member: module.name
12344603Sdcs	sizeof string member: module.loadname
12444603Sdcs	sizeof string member: module.type
12544603Sdcs	sizeof string member: module.args
12644603Sdcs	sizeof string member: module.beforeload
12744603Sdcs	sizeof string member: module.afterload
12844603Sdcs	sizeof string member: module.loaderror
12944603Sdcs	ptr module.next
13044603Sdcs;structure
13144603Sdcs
132186789Sluigi\ Internal loader structures (preloaded_file, kernel_module, file_metadata)
133186789Sluigi\ must be in sync with the C struct in sys/boot/common/bootstrap.h
13465615Sdcsstructure: preloaded_file
13565615Sdcs	ptr pf.name
13665615Sdcs	ptr pf.type
13765615Sdcs	ptr pf.args
13865615Sdcs	ptr pf.metadata	\ file_metadata
13965615Sdcs	int pf.loader
14065615Sdcs	int pf.addr
14165615Sdcs	int pf.size
14265615Sdcs	ptr pf.modules	\ kernel_module
14365615Sdcs	ptr pf.next	\ preloaded_file
14465615Sdcs;structure
14565615Sdcs
14665615Sdcsstructure: kernel_module
14765615Sdcs	ptr km.name
14865615Sdcs	\ ptr km.args
14965615Sdcs	ptr km.fp	\ preloaded_file
15065615Sdcs	ptr km.next	\ kernel_module
15165615Sdcs;structure
15265615Sdcs
15365615Sdcsstructure: file_metadata
15465615Sdcs	int		md.size
15565615Sdcs	2 member:	md.type	\ this is not ANS Forth compatible (XXX)
15665615Sdcs	ptr		md.next	\ file_metadata
15765615Sdcs	0 member:	md.data	\ variable size
15865615Sdcs;structure
15965615Sdcs
160186789Sluigi\ end of structures
16165615Sdcs
16244603Sdcs\ Global variables
16344603Sdcs
16444603Sdcsstring conf_files
16597201Sgordonstring nextboot_conf_file
16665615Sdcscreate module_options sizeof module.next allot 0 module_options !
16765615Sdcscreate last_module_option sizeof module.next allot 0 last_module_option !
16844603Sdcs0 value verbose?
16997201Sgordon0 value nextboot?
17044603Sdcs
17144603Sdcs\ Support string functions
172186789Sluigi: strdup { addr len -- addr' len' }
173186789Sluigi  len allocate if ENOMEM throw then
174186789Sluigi  addr over len move len
17544603Sdcs;
17644603Sdcs
17744603Sdcs: strcat  { addr len addr' len' -- addr len+len' }
17844603Sdcs  addr' addr len + len' move
17944603Sdcs  addr len len' +
18044603Sdcs;
18144603Sdcs
182186789Sluigi: strchr { addr len c -- addr' len' }
18361373Sdcs  begin
184186789Sluigi    len
185186789Sluigi  while
186186789Sluigi    addr c@ c = if addr len exit then
187186789Sluigi    addr 1 + to addr
188186789Sluigi    len 1 - to len
189186789Sluigi  repeat
190186789Sluigi  0 0
19161373Sdcs;
19261373Sdcs
193186789Sluigi: s' \ same as s", allows " in the string
19444603Sdcs  [char] ' parse
195186789Sluigi  state @ if postpone sliteral then
19644603Sdcs; immediate
19744603Sdcs
19861373Sdcs: 2>r postpone >r postpone >r ; immediate
19961373Sdcs: 2r> postpone r> postpone r> ; immediate
20065883Sdcs: 2r@ postpone 2r> postpone 2dup postpone 2>r ; immediate
20153672Sdcs
202186789Sluigi: getenv?  getenv -1 = if false else drop true then ;
20365938Sdcs
204244048Sdteske\ determine if a word appears in a string, case-insensitive
205244048Sdteske: contains? ( addr1 len1 addr2 len2 -- 0 | -1 )
206244048Sdteske	2 pick 0= if 2drop 2drop true exit then
207244048Sdteske	dup 0= if 2drop 2drop false exit then
208244048Sdteske	begin
209244048Sdteske		begin
210244089Sdteske			swap dup c@ dup 32 = over 9 = or over 10 = or
211244089Sdteske			over 13 = or over 44 = or swap drop
212244048Sdteske		while 1+ swap 1- repeat
213244048Sdteske		swap 2 pick 1- over <
214244048Sdteske	while
215244048Sdteske		2over 2over drop over compare-insensitive 0= if
216244048Sdteske			2 pick over = if 2drop 2drop true exit then
217244048Sdteske			2 pick tuck - -rot + swap over c@ dup 32 =
218244089Sdteske			over 9 = or over 10 = or over 13 = or over 44 = or
219244048Sdteske			swap drop if 2drop 2drop true exit then
220244048Sdteske		then begin
221244089Sdteske			swap dup c@ dup 32 = over 9 = or over 10 = or
222244089Sdteske			over 13 = or over 44 = or swap drop
223244089Sdteske			if false else true then 2 pick 0> and
224244048Sdteske		while 1+ swap 1- repeat
225244048Sdteske		swap
226244048Sdteske	repeat
227244048Sdteske	2drop 2drop false
228244048Sdteske;
229244048Sdteske
230244048Sdteske: boot_serial? ( -- 0 | -1 )
231244048Sdteske	s" console" getenv dup -1 <> if
232244048Sdteske		s" comconsole" 2swap contains?
233244048Sdteske	else drop false then
234244048Sdteske	s" boot_serial" getenv dup -1 <> if
235244048Sdteske		swap drop 0>
236244048Sdteske	else drop false then
237244048Sdteske	or \ console contains comconsole ( or ) boot_serial
238244048Sdteske	s" boot_multicons" getenv dup -1 <> if
239244048Sdteske		swap drop 0>
240244048Sdteske	else drop false then
241244048Sdteske	or \ previous boolean ( or ) boot_multicons
242244048Sdteske;
243244048Sdteske
24444603Sdcs\ Private definitions
24544603Sdcs
24644603Sdcsvocabulary support-functions
24744603Sdcsonly forth also support-functions definitions
24844603Sdcs
24944603Sdcs\ Some control characters constants
25044603Sdcs
25153672Sdcs7 constant bell
25253672Sdcs8 constant backspace
25344603Sdcs9 constant tab
25444603Sdcs10 constant lf
25553672Sdcs13 constant <cr>
25644603Sdcs
25744603Sdcs\ Read buffer size
25844603Sdcs
25944603Sdcs80 constant read_buffer_size
26044603Sdcs
26144603Sdcs\ Standard suffixes
26244603Sdcs
263186789Sluigi: load_module_suffix		s" _load" ;
264186789Sluigi: module_loadname_suffix	s" _name" ;
265186789Sluigi: module_type_suffix		s" _type" ;
266186789Sluigi: module_args_suffix		s" _flags" ;
267186789Sluigi: module_beforeload_suffix	s" _before" ;
268186789Sluigi: module_afterload_suffix	s" _after" ;
269186789Sluigi: module_loaderror_suffix	s" _error" ;
27044603Sdcs
27144603Sdcs\ Support operators
27244603Sdcs
27344603Sdcs: >= < 0= ;
27444603Sdcs: <= > 0= ;
27544603Sdcs
276186789Sluigi\ Assorted support functions
27744603Sdcs
278186789Sluigi: free-memory free if EFREE throw then ;
27944603Sdcs
280185746Sluigi: strget { var -- addr len } var .addr @ var .len @ ;
281185746Sluigi
282185746Sluigi\ assign addr len to variable.
283186789Sluigi: strset  { addr len var -- } addr var .addr !  len var .len !  ;
284185746Sluigi
285185746Sluigi\ free memory and reset fields
286185746Sluigi: strfree { var -- } var .addr @ ?dup if free-memory 0 0 var strset then ;
287185746Sluigi
288185746Sluigi\ free old content, make a copy of the string and assign to variable
289185746Sluigi: string= { addr len var -- } var strfree addr len strdup var strset ;
290185746Sluigi
291186789Sluigi: strtype ( str -- ) strget type ;
292186789Sluigi
293186789Sluigi\ assign a reference to what is on the stack
294186789Sluigi: strref { addr len var -- addr len }
295186789Sluigi  addr var .addr ! len var .len ! addr len
296186789Sluigi;
297186789Sluigi
298186789Sluigi\ unquote a string
299186789Sluigi: unquote ( addr len -- addr len )
300186789Sluigi  over c@ [char] " = if 2 chars - swap char+ swap then
301186789Sluigi;
302186789Sluigi
30344603Sdcs\ Assignment data temporary storage
30444603Sdcs
30544603Sdcsstring name_buffer
30644603Sdcsstring value_buffer
30744603Sdcs
30865615Sdcs\ Line by line file reading functions
30965615Sdcs\
31065615Sdcs\ exported:
31165615Sdcs\	line_buffer
31265615Sdcs\	end_of_file?
31365615Sdcs\	fd
31465615Sdcs\	read_line
31565615Sdcs\	reset_line_reading
31665615Sdcs
31765615Sdcsvocabulary line-reading
318280937Sdteskealso line-reading definitions
31965615Sdcs
32044603Sdcs\ File data temporary storage
32144603Sdcs
32244603Sdcsstring read_buffer
32344603Sdcs0 value read_buffer_ptr
32444603Sdcs
32544603Sdcs\ File's line reading function
32644603Sdcs
327280937Sdteskeget-current ( -- wid ) previous definitions
32865615Sdcs
32965615Sdcsstring line_buffer
33044603Sdcs0 value end_of_file?
33144603Sdcsvariable fd
33244603Sdcs
333280937Sdteske>search ( wid -- ) definitions
33465615Sdcs
33544603Sdcs: skip_newlines
33644603Sdcs  begin
33744603Sdcs    read_buffer .len @ read_buffer_ptr >
33844603Sdcs  while
33944603Sdcs    read_buffer .addr @ read_buffer_ptr + c@ lf = if
34044603Sdcs      read_buffer_ptr char+ to read_buffer_ptr
34144603Sdcs    else
34244603Sdcs      exit
34344603Sdcs    then
34444603Sdcs  repeat
34544603Sdcs;
34644603Sdcs
34744603Sdcs: scan_buffer  ( -- addr len )
34844603Sdcs  read_buffer_ptr >r
34944603Sdcs  begin
35044603Sdcs    read_buffer .len @ r@ >
35144603Sdcs  while
35244603Sdcs    read_buffer .addr @ r@ + c@ lf = if
35344603Sdcs      read_buffer .addr @ read_buffer_ptr +  ( -- addr )
35444603Sdcs      r@ read_buffer_ptr -                   ( -- len )
35544603Sdcs      r> to read_buffer_ptr
35644603Sdcs      exit
35744603Sdcs    then
35844603Sdcs    r> char+ >r
35944603Sdcs  repeat
36044603Sdcs  read_buffer .addr @ read_buffer_ptr +  ( -- addr )
36144603Sdcs  r@ read_buffer_ptr -                   ( -- len )
36244603Sdcs  r> to read_buffer_ptr
36344603Sdcs;
36444603Sdcs
36544603Sdcs: line_buffer_resize  ( len -- len )
36644603Sdcs  >r
36744603Sdcs  line_buffer .len @ if
36844603Sdcs    line_buffer .addr @
36944603Sdcs    line_buffer .len @ r@ +
370186789Sluigi    resize if ENOMEM throw then
37144603Sdcs  else
372186789Sluigi    r@ allocate if ENOMEM throw then
37344603Sdcs  then
37444603Sdcs  line_buffer .addr !
37544603Sdcs  r>
37644603Sdcs;
37744603Sdcs    
37844603Sdcs: append_to_line_buffer  ( addr len -- )
379186789Sluigi  line_buffer strget
38044603Sdcs  2swap strcat
38144603Sdcs  line_buffer .len !
38244603Sdcs  drop
38344603Sdcs;
38444603Sdcs
38544603Sdcs: read_from_buffer
38644603Sdcs  scan_buffer            ( -- addr len )
38744603Sdcs  line_buffer_resize     ( len -- len )
38844603Sdcs  append_to_line_buffer  ( addr len -- )
38944603Sdcs;
39044603Sdcs
39144603Sdcs: refill_required?
39244603Sdcs  read_buffer .len @ read_buffer_ptr =
39344603Sdcs  end_of_file? 0= and
39444603Sdcs;
39544603Sdcs
39644603Sdcs: refill_buffer
39744603Sdcs  0 to read_buffer_ptr
39844603Sdcs  read_buffer .addr @ 0= if
399186789Sluigi    read_buffer_size allocate if ENOMEM throw then
40044603Sdcs    read_buffer .addr !
40144603Sdcs  then
40244603Sdcs  fd @ read_buffer .addr @ read_buffer_size fread
403186789Sluigi  dup -1 = if EREAD throw then
40444603Sdcs  dup 0= if true to end_of_file? then
40544603Sdcs  read_buffer .len !
40644603Sdcs;
40744603Sdcs
408280937Sdteskeget-current ( -- wid ) previous definitions >search ( wid -- )
40965615Sdcs
41065615Sdcs: reset_line_reading
41165615Sdcs  0 to read_buffer_ptr
41265615Sdcs;
41365615Sdcs
41444603Sdcs: read_line
415186789Sluigi  line_buffer strfree
41644603Sdcs  skip_newlines
41744603Sdcs  begin
41844603Sdcs    read_from_buffer
41944603Sdcs    refill_required?
42044603Sdcs  while
42144603Sdcs    refill_buffer
42244603Sdcs  repeat
42344603Sdcs;
42444603Sdcs
42565615Sdcsonly forth also support-functions definitions
42665615Sdcs
42744603Sdcs\ Conf file line parser:
42844603Sdcs\ <line> ::= <spaces><name><spaces>'='<spaces><value><spaces>[<comment>] |
42944603Sdcs\            <spaces>[<comment>]
43044603Sdcs\ <name> ::= <letter>{<letter>|<digit>|'_'}
43144603Sdcs\ <value> ::= '"'{<character_set>|'\'<anything>}'"' | <name>
43244603Sdcs\ <character_set> ::= ASCII 32 to 126, except '\' and '"'
43344603Sdcs\ <comment> ::= '#'{<anything>}
43465615Sdcs\
43565615Sdcs\ exported:
43665615Sdcs\	line_pointer
43765615Sdcs\	process_conf
43844603Sdcs
43965615Sdcs0 value line_pointer
44065615Sdcs
44165615Sdcsvocabulary file-processing
44265615Sdcsalso file-processing definitions
44365615Sdcs
44465615Sdcs\ parser functions
44565615Sdcs\
44665615Sdcs\ exported:
44765615Sdcs\	get_assignment
44865615Sdcs
44965615Sdcsvocabulary parser
450280937Sdteskealso parser definitions
45165615Sdcs
45244603Sdcs0 value parsing_function
45344603Sdcs0 value end_of_line
45444603Sdcs
455186789Sluigi: end_of_line?  line_pointer end_of_line = ;
45644603Sdcs
457186789Sluigi\ classifiers for various character classes in the input line
458186789Sluigi
45944603Sdcs: letter?
46044603Sdcs  line_pointer c@ >r
46144603Sdcs  r@ [char] A >=
46244603Sdcs  r@ [char] Z <= and
46344603Sdcs  r@ [char] a >=
46444603Sdcs  r> [char] z <= and
46544603Sdcs  or
46644603Sdcs;
46744603Sdcs
46844603Sdcs: digit?
46944603Sdcs  line_pointer c@ >r
470174777Sambrisko  r@ [char] - =
47144603Sdcs  r@ [char] 0 >=
47244603Sdcs  r> [char] 9 <= and
473174777Sambrisko  or
47444603Sdcs;
47544603Sdcs
476186789Sluigi: quote?  line_pointer c@ [char] " = ;
47744603Sdcs
478186789Sluigi: assignment_sign?  line_pointer c@ [char] = = ;
47944603Sdcs
480186789Sluigi: comment?  line_pointer c@ [char] # = ;
48144603Sdcs
482186789Sluigi: space?  line_pointer c@ bl = line_pointer c@ tab = or ;
48344603Sdcs
484186789Sluigi: backslash?  line_pointer c@ [char] \ = ;
48544603Sdcs
486186789Sluigi: underscore?  line_pointer c@ [char] _ = ;
48744603Sdcs
488186789Sluigi: dot?  line_pointer c@ [char] . = ;
48944603Sdcs
490186789Sluigi\ manipulation of input line
491186789Sluigi: skip_character line_pointer char+ to line_pointer ;
49244603Sdcs
493186789Sluigi: skip_to_end_of_line end_of_line to line_pointer ;
49444603Sdcs
49544603Sdcs: eat_space
49644603Sdcs  begin
497186789Sluigi    end_of_line? if 0 else space? then
49844603Sdcs  while
49944603Sdcs    skip_character
50044603Sdcs  repeat
50144603Sdcs;
50244603Sdcs
50344603Sdcs: parse_name  ( -- addr len )
50444603Sdcs  line_pointer
50544603Sdcs  begin
506186789Sluigi    end_of_line? if 0 else letter? digit? underscore? dot? or or or then
50744603Sdcs  while
50844603Sdcs    skip_character
50944603Sdcs  repeat
51044603Sdcs  line_pointer over -
51144603Sdcs  strdup
51244603Sdcs;
51344603Sdcs
51444603Sdcs: remove_backslashes  { addr len | addr' len' -- addr' len' }
515186789Sluigi  len allocate if ENOMEM throw then
51644603Sdcs  to addr'
51744603Sdcs  addr >r
51844603Sdcs  begin
51944603Sdcs    addr c@ [char] \ <> if
52044603Sdcs      addr c@ addr' len' + c!
52144603Sdcs      len' char+ to len'
52244603Sdcs    then
52344603Sdcs    addr char+ to addr
52444603Sdcs    r@ len + addr =
52544603Sdcs  until
52644603Sdcs  r> drop
52744603Sdcs  addr' len'
52844603Sdcs;
52944603Sdcs
53044603Sdcs: parse_quote  ( -- addr len )
53144603Sdcs  line_pointer
53244603Sdcs  skip_character
533186789Sluigi  end_of_line? if ESYNTAX throw then
53444603Sdcs  begin
53544603Sdcs    quote? 0=
53644603Sdcs  while
53744603Sdcs    backslash? if
53844603Sdcs      skip_character
539186789Sluigi      end_of_line? if ESYNTAX throw then
54044603Sdcs    then
54144603Sdcs    skip_character
542186789Sluigi    end_of_line? if ESYNTAX throw then 
54344603Sdcs  repeat
54444603Sdcs  skip_character
54544603Sdcs  line_pointer over -
54644603Sdcs  remove_backslashes
54744603Sdcs;
54844603Sdcs
54944603Sdcs: read_name
55044603Sdcs  parse_name		( -- addr len )
551186789Sluigi  name_buffer strset
55244603Sdcs;
55344603Sdcs
55444603Sdcs: read_value
55544603Sdcs  quote? if
55644603Sdcs    parse_quote		( -- addr len )
55744603Sdcs  else
55844603Sdcs    parse_name		( -- addr len )
55944603Sdcs  then
560186789Sluigi  value_buffer strset
56144603Sdcs;
56244603Sdcs
56344603Sdcs: comment
56444603Sdcs  skip_to_end_of_line
56544603Sdcs;
56644603Sdcs
56744603Sdcs: white_space_4
56844603Sdcs  eat_space
56944603Sdcs  comment? if ['] comment to parsing_function exit then
570186789Sluigi  end_of_line? 0= if ESYNTAX throw then
57144603Sdcs;
57244603Sdcs
57344603Sdcs: variable_value
57444603Sdcs  read_value
57544603Sdcs  ['] white_space_4 to parsing_function
57644603Sdcs;
57744603Sdcs
57844603Sdcs: white_space_3
57944603Sdcs  eat_space
58044603Sdcs  letter? digit? quote? or or if
58144603Sdcs    ['] variable_value to parsing_function exit
58244603Sdcs  then
583186789Sluigi  ESYNTAX throw
58444603Sdcs;
58544603Sdcs
58644603Sdcs: assignment_sign
58744603Sdcs  skip_character
58844603Sdcs  ['] white_space_3 to parsing_function
58944603Sdcs;
59044603Sdcs
59144603Sdcs: white_space_2
59244603Sdcs  eat_space
59344603Sdcs  assignment_sign? if ['] assignment_sign to parsing_function exit then
594186789Sluigi  ESYNTAX throw
59544603Sdcs;
59644603Sdcs
59744603Sdcs: variable_name
59844603Sdcs  read_name
59944603Sdcs  ['] white_space_2 to parsing_function
60044603Sdcs;
60144603Sdcs
60244603Sdcs: white_space_1
60344603Sdcs  eat_space
60444603Sdcs  letter?  if ['] variable_name to parsing_function exit then
60544603Sdcs  comment? if ['] comment to parsing_function exit then
606186789Sluigi  end_of_line? 0= if ESYNTAX throw then
60744603Sdcs;
60844603Sdcs
609280937Sdteskeget-current ( -- wid ) previous definitions >search ( wid -- )
61065615Sdcs
61144603Sdcs: get_assignment
612186789Sluigi  line_buffer strget + to end_of_line
61344603Sdcs  line_buffer .addr @ to line_pointer
61444603Sdcs  ['] white_space_1 to parsing_function
61544603Sdcs  begin
61644603Sdcs    end_of_line? 0=
61744603Sdcs  while
61844603Sdcs    parsing_function execute
61944603Sdcs  repeat
62044603Sdcs  parsing_function ['] comment =
62144603Sdcs  parsing_function ['] white_space_1 =
62244603Sdcs  parsing_function ['] white_space_4 =
623186789Sluigi  or or 0= if ESYNTAX throw then
62444603Sdcs;
62544603Sdcs
626280937Sdteskeonly forth also support-functions also file-processing definitions
62765615Sdcs
62844603Sdcs\ Process line
62944603Sdcs
63044603Sdcs: assignment_type?  ( addr len -- flag )
631186789Sluigi  name_buffer strget
63244603Sdcs  compare 0=
63344603Sdcs;
63444603Sdcs
63544603Sdcs: suffix_type?  ( addr len -- flag )
63644603Sdcs  name_buffer .len @ over <= if 2drop false exit then
63744603Sdcs  name_buffer .len @ over - name_buffer .addr @ +
63844603Sdcs  over compare 0=
63944603Sdcs;
64044603Sdcs
641186789Sluigi: loader_conf_files?  s" loader_conf_files" assignment_type?  ;
64244603Sdcs
643186789Sluigi: nextboot_flag?  s" nextboot_enable" assignment_type?  ;
64497201Sgordon
645186789Sluigi: nextboot_conf? s" nextboot_conf" assignment_type?  ;
64697201Sgordon
647186789Sluigi: verbose_flag? s" verbose_loading" assignment_type?  ;
64844603Sdcs
649186789Sluigi: execute? s" exec" assignment_type?  ;
65044603Sdcs
651186789Sluigi: module_load? load_module_suffix suffix_type? ;
65244603Sdcs
653186789Sluigi: module_loadname?  module_loadname_suffix suffix_type?  ;
65444603Sdcs
655186789Sluigi: module_type?  module_type_suffix suffix_type?  ;
65644603Sdcs
657186789Sluigi: module_args?  module_args_suffix suffix_type?  ;
65844603Sdcs
659186789Sluigi: module_beforeload?  module_beforeload_suffix suffix_type?  ;
66044603Sdcs
661186789Sluigi: module_afterload?  module_afterload_suffix suffix_type?  ;
66244603Sdcs
663186789Sluigi: module_loaderror?  module_loaderror_suffix suffix_type?  ;
66444603Sdcs
665186789Sluigi\ build a 'set' statement and execute it
666186789Sluigi: set_environment_variable
667186789Sluigi  name_buffer .len @ value_buffer .len @ + 5 chars + \ size of result string
668186789Sluigi  allocate if ENOMEM throw then
669186789Sluigi  dup 0  \ start with an empty string and append the pieces
670186789Sluigi  s" set " strcat
671186789Sluigi  name_buffer strget strcat
672186789Sluigi  s" =" strcat
673186789Sluigi  value_buffer strget strcat
674186789Sluigi  ['] evaluate catch if
675186789Sluigi    2drop free drop
676186789Sluigi    ESETERROR throw
677186789Sluigi  else
67897201Sgordon    free-memory
67997201Sgordon  then
68097201Sgordon;
68197201Sgordon
682186789Sluigi: set_conf_files
683186789Sluigi  set_environment_variable
684186789Sluigi  s" loader_conf_files" getenv conf_files string=
685186789Sluigi;
686186789Sluigi
687293000Sdteske: set_nextboot_conf
688186789Sluigi  value_buffer strget unquote nextboot_conf_file string=
689186789Sluigi;
690186789Sluigi
69144603Sdcs: append_to_module_options_list  ( addr -- )
69244603Sdcs  module_options @ 0= if
69344603Sdcs    dup module_options !
69444603Sdcs    last_module_option !
69544603Sdcs  else
69644603Sdcs    dup last_module_option @ module.next !
69744603Sdcs    last_module_option !
69844603Sdcs  then
69944603Sdcs;
70044603Sdcs
701186789Sluigi: set_module_name  { addr -- }	\ check leaks
702186789Sluigi  name_buffer strget addr module.name string=
70344603Sdcs;
70444603Sdcs
70544603Sdcs: yes_value?
706186789Sluigi  value_buffer strget	\ XXX could use unquote
70744603Sdcs  2dup s' "YES"' compare >r
70844603Sdcs  2dup s' "yes"' compare >r
70944603Sdcs  2dup s" YES" compare >r
71044603Sdcs  s" yes" compare r> r> r> and and and 0=
71144603Sdcs;
71244603Sdcs
713186789Sluigi: find_module_option  ( -- addr | 0 ) \ return ptr to entry matching name_buffer
71444603Sdcs  module_options @
71544603Sdcs  begin
71644603Sdcs    dup
71744603Sdcs  while
718186789Sluigi    dup module.name strget
719186789Sluigi    name_buffer strget
72044603Sdcs    compare 0= if exit then
72144603Sdcs    module.next @
72244603Sdcs  repeat
72344603Sdcs;
72444603Sdcs
72544603Sdcs: new_module_option  ( -- addr )
726186789Sluigi  sizeof module allocate if ENOMEM throw then
72744603Sdcs  dup sizeof module erase
72844603Sdcs  dup append_to_module_options_list
72944603Sdcs  dup set_module_name
73044603Sdcs;
73144603Sdcs
73244603Sdcs: get_module_option  ( -- addr )
73344603Sdcs  find_module_option
73444603Sdcs  ?dup 0= if new_module_option then
73544603Sdcs;
73644603Sdcs
73744603Sdcs: set_module_flag
73844603Sdcs  name_buffer .len @ load_module_suffix nip - name_buffer .len !
73944603Sdcs  yes_value? get_module_option module.flag !
74044603Sdcs;
74144603Sdcs
74244603Sdcs: set_module_args
74344603Sdcs  name_buffer .len @ module_args_suffix nip - name_buffer .len !
744186789Sluigi  value_buffer strget unquote
745186789Sluigi  get_module_option module.args string=
74644603Sdcs;
74744603Sdcs
74844603Sdcs: set_module_loadname
74944603Sdcs  name_buffer .len @ module_loadname_suffix nip - name_buffer .len !
750186789Sluigi  value_buffer strget unquote
751186789Sluigi  get_module_option module.loadname string=
75244603Sdcs;
75344603Sdcs
75444603Sdcs: set_module_type
75544603Sdcs  name_buffer .len @ module_type_suffix nip - name_buffer .len !
756186789Sluigi  value_buffer strget unquote
757186789Sluigi  get_module_option module.type string=
75844603Sdcs;
75944603Sdcs
76044603Sdcs: set_module_beforeload
76144603Sdcs  name_buffer .len @ module_beforeload_suffix nip - name_buffer .len !
762186789Sluigi  value_buffer strget unquote
763186789Sluigi  get_module_option module.beforeload string=
76444603Sdcs;
76544603Sdcs
76644603Sdcs: set_module_afterload
76744603Sdcs  name_buffer .len @ module_afterload_suffix nip - name_buffer .len !
768186789Sluigi  value_buffer strget unquote
769186789Sluigi  get_module_option module.afterload string=
77044603Sdcs;
77144603Sdcs
77244603Sdcs: set_module_loaderror
77344603Sdcs  name_buffer .len @ module_loaderror_suffix nip - name_buffer .len !
774186789Sluigi  value_buffer strget unquote
775186789Sluigi  get_module_option module.loaderror string=
77644603Sdcs;
77744603Sdcs
77897201Sgordon: set_nextboot_flag
77997201Sgordon  yes_value? to nextboot?
78097201Sgordon;
78197201Sgordon
78244603Sdcs: set_verbose
78344603Sdcs  yes_value? to verbose?
78444603Sdcs;
78544603Sdcs
78644603Sdcs: execute_command
787186789Sluigi  value_buffer strget unquote
788186789Sluigi  ['] evaluate catch if EEXEC throw then
78944603Sdcs;
79044603Sdcs
79144603Sdcs: process_assignment
79244603Sdcs  name_buffer .len @ 0= if exit then
79344603Sdcs  loader_conf_files?	if set_conf_files exit then
79497201Sgordon  nextboot_flag?	if set_nextboot_flag exit then
79597201Sgordon  nextboot_conf?	if set_nextboot_conf exit then
79644603Sdcs  verbose_flag?		if set_verbose exit then
79744603Sdcs  execute?		if execute_command exit then
79844603Sdcs  module_load?		if set_module_flag exit then
79944603Sdcs  module_loadname?	if set_module_loadname exit then
80044603Sdcs  module_type?		if set_module_type exit then
80144603Sdcs  module_args?		if set_module_args exit then
80244603Sdcs  module_beforeload?	if set_module_beforeload exit then
80344603Sdcs  module_afterload?	if set_module_afterload exit then
80444603Sdcs  module_loaderror?	if set_module_loaderror exit then
80544603Sdcs  set_environment_variable
80644603Sdcs;
80744603Sdcs
80853672Sdcs\ free_buffer  ( -- )
80953672Sdcs\
81053672Sdcs\ Free some pointers if needed. The code then tests for errors
81153672Sdcs\ in freeing, and throws an exception if needed. If a pointer is
81253672Sdcs\ not allocated, it's value (0) is used as flag.
81353672Sdcs
81444603Sdcs: free_buffers
815186789Sluigi  name_buffer strfree
816186789Sluigi  value_buffer strfree
81744603Sdcs;
81844603Sdcs
81944603Sdcs\ Higher level file processing
82044603Sdcs
821280937Sdteskeget-current ( -- wid ) previous definitions >search ( wid -- )
82265615Sdcs
82344603Sdcs: process_conf
82444603Sdcs  begin
82544603Sdcs    end_of_file? 0=
82644603Sdcs  while
827186789Sluigi    free_buffers
82844603Sdcs    read_line
82944603Sdcs    get_assignment
83044603Sdcs    ['] process_assignment catch
83144603Sdcs    ['] free_buffers catch
83244603Sdcs    swap throw throw
83344603Sdcs  repeat
83444603Sdcs;
83544603Sdcs
836292899Sdteske: peek_file ( addr len -- )
83797201Sgordon  0 to end_of_file?
83897201Sgordon  reset_line_reading
83997201Sgordon  O_RDONLY fopen fd !
840186789Sluigi  fd @ -1 = if EOPEN throw then
841186789Sluigi  free_buffers
84297201Sgordon  read_line
84397201Sgordon  get_assignment
84497201Sgordon  ['] process_assignment catch
84597201Sgordon  ['] free_buffers catch
84697201Sgordon  fd @ fclose
847292899Sdteske  swap throw throw
84897201Sgordon;
84997201Sgordon  
85065615Sdcsonly forth also support-functions definitions
85165615Sdcs
85244603Sdcs\ Interface to loading conf files
85344603Sdcs
85444603Sdcs: load_conf  ( addr len -- )
85544603Sdcs  0 to end_of_file?
85665615Sdcs  reset_line_reading
85787636Sjhb  O_RDONLY fopen fd !
858186789Sluigi  fd @ -1 = if EOPEN throw then
85944603Sdcs  ['] process_conf catch
86044603Sdcs  fd @ fclose
86144603Sdcs  throw
86244603Sdcs;
86344603Sdcs
864186789Sluigi: print_line line_buffer strtype cr ;
86544603Sdcs
86644603Sdcs: print_syntax_error
867186789Sluigi  line_buffer strtype cr
86844603Sdcs  line_buffer .addr @
86944603Sdcs  begin
87044603Sdcs    line_pointer over <>
87144603Sdcs  while
872186789Sluigi    bl emit char+
87344603Sdcs  repeat
87444603Sdcs  drop
87544603Sdcs  ." ^" cr
87644603Sdcs;
87744603Sdcs
878186789Sluigi
879163327Sru\ Debugging support functions
88044603Sdcs
88144603Sdcsonly forth definitions also support-functions
88244603Sdcs
88344603Sdcs: test-file 
88444603Sdcs  ['] load_conf catch dup .
885186789Sluigi  ESYNTAX = if cr print_syntax_error then
88644603Sdcs;
88744603Sdcs
888186789Sluigi\ find a module name, leave addr on the stack (0 if not found)
889186789Sluigi: find-module ( <module> -- ptr | 0 )
890186789Sluigi  bl parse ( addr len )
891186789Sluigi  module_options @ >r ( store current pointer )
892186789Sluigi  begin
893186789Sluigi    r@
894186789Sluigi  while
895186789Sluigi    2dup ( addr len addr len )
896186789Sluigi    r@ module.name strget
897186789Sluigi    compare 0= if drop drop r> exit then ( found it )
898186789Sluigi    r> module.next @ >r
899186789Sluigi  repeat
900186789Sluigi  type ."  was not found" cr r>
901186789Sluigi;
902186789Sluigi
903186789Sluigi: show-nonempty ( addr len mod -- )
904186789Sluigi  strget dup verbose? or if
905186789Sluigi    2swap type type cr
906186789Sluigi  else
907186789Sluigi    drop drop drop drop
908186789Sluigi  then ;
909186789Sluigi
910186789Sluigi: show-one-module { addr -- addr }
911186789Sluigi  ." Name:        " addr module.name strtype cr
912186789Sluigi  s" Path:        " addr module.loadname show-nonempty
913186789Sluigi  s" Type:        " addr module.type show-nonempty
914186789Sluigi  s" Flags:       " addr module.args show-nonempty
915186789Sluigi  s" Before load: " addr module.beforeload show-nonempty
916186789Sluigi  s" After load:  " addr module.afterload show-nonempty
917186789Sluigi  s" Error:       " addr module.loaderror show-nonempty
918186789Sluigi  ." Status:      " addr module.flag @ if ." Load" else ." Don't load" then cr
919186789Sluigi  cr
920186789Sluigi  addr
921186789Sluigi;
922186789Sluigi
92344603Sdcs: show-module-options
92444603Sdcs  module_options @
92544603Sdcs  begin
92644603Sdcs    ?dup
92744603Sdcs  while
928186789Sluigi    show-one-module
92944603Sdcs    module.next @
93044603Sdcs  repeat
93144603Sdcs;
93244603Sdcs
933293001Sallanjude: free-one-module { addr -- addr }
934293001Sallanjude  addr module.name strfree
935293001Sallanjude  addr module.loadname strfree
936293001Sallanjude  addr module.type strfree
937293001Sallanjude  addr module.args strfree
938293001Sallanjude  addr module.beforeload strfree
939293001Sallanjude  addr module.afterload strfree
940293001Sallanjude  addr module.loaderror strfree
941293001Sallanjude  addr
942293001Sallanjude;
943293001Sallanjude
944293001Sallanjude: free-module-options
945293001Sallanjude  module_options @
946293001Sallanjude  begin
947293001Sallanjude    ?dup
948293001Sallanjude  while
949293001Sallanjude    free-one-module
950293001Sallanjude    dup module.next @
951293001Sallanjude    swap free-memory
952293001Sallanjude  repeat
953293001Sallanjude  0 module_options !
954293001Sallanjude  0 last_module_option !
955293001Sallanjude;
956293001Sallanjude
95744603Sdcsonly forth also support-functions definitions
95844603Sdcs
95944603Sdcs\ Variables used for processing multiple conf files
96044603Sdcs
961186789Sluigistring current_file_name_ref	\ used to print the file name
96244603Sdcs
963298831Spfg\ Indicates if any conf file was successfully read
96444603Sdcs
96544603Sdcs0 value any_conf_read?
96644603Sdcs
96744603Sdcs\ loader_conf_files processing support functions
96844603Sdcs
969185746Sluigi: get_conf_files ( -- addr len )  \ put addr/len on stack, reset var
970185746Sluigi  conf_files strget 0 0 conf_files strset
97144603Sdcs;
97244603Sdcs
97353672Sdcs: skip_leading_spaces  { addr len pos -- addr len pos' }
97444603Sdcs  begin
975186789Sluigi    pos len = if 0 else addr pos + c@ bl = then
97644603Sdcs  while
97753672Sdcs    pos char+ to pos
97844603Sdcs  repeat
97953672Sdcs  addr len pos
98044603Sdcs;
98144603Sdcs
982186789Sluigi\ return the file name at pos, or free the string if nothing left
98353672Sdcs: get_file_name  { addr len pos -- addr len pos' addr' len' || 0 }
98453672Sdcs  pos len = if 
98544603Sdcs    addr free abort" Fatal error freeing memory"
98644603Sdcs    0 exit
98744603Sdcs  then
98853672Sdcs  pos >r
98944603Sdcs  begin
990186789Sluigi    \ stay in the loop until have chars and they are not blank
991186789Sluigi    pos len = if 0 else addr pos + c@ bl <> then
99244603Sdcs  while
99353672Sdcs    pos char+ to pos
99444603Sdcs  repeat
99553672Sdcs  addr len pos addr r@ + pos r> -
99644603Sdcs;
99744603Sdcs
99844603Sdcs: get_next_file  ( addr len ptr -- addr len ptr' addr' len' | 0 )
99944603Sdcs  skip_leading_spaces
100044603Sdcs  get_file_name
100144603Sdcs;
100244603Sdcs
100344603Sdcs: print_current_file
1004186789Sluigi  current_file_name_ref strtype
100544603Sdcs;
100644603Sdcs
100744603Sdcs: process_conf_errors
100844603Sdcs  dup 0= if true to any_conf_read? drop exit then
100944603Sdcs  >r 2drop r>
1010186789Sluigi  dup ESYNTAX = if
101144603Sdcs    ." Warning: syntax error on file " print_current_file cr
101244603Sdcs    print_syntax_error drop exit
101344603Sdcs  then
1014186789Sluigi  dup ESETERROR = if
101544603Sdcs    ." Warning: bad definition on file " print_current_file cr
101644603Sdcs    print_line drop exit
101744603Sdcs  then
1018186789Sluigi  dup EREAD = if
101944603Sdcs    ." Warning: error reading file " print_current_file cr drop exit
102044603Sdcs  then
1021186789Sluigi  dup EOPEN = if
102244603Sdcs    verbose? if ." Warning: unable to open file " print_current_file cr then
102344603Sdcs    drop exit
102444603Sdcs  then
1025186789Sluigi  dup EFREE = abort" Fatal error freeing memory"
1026186789Sluigi  dup ENOMEM = abort" Out of memory"
102744603Sdcs  throw  \ Unknown error -- pass ahead
102844603Sdcs;
102944603Sdcs
103044603Sdcs\ Process loader_conf_files recursively
103144603Sdcs\ Interface to loader_conf_files processing
103244603Sdcs
103344603Sdcs: include_conf_files
1034186789Sluigi  get_conf_files 0	( addr len offset )
103544603Sdcs  begin
1036186789Sluigi    get_next_file ?dup ( addr len 1 | 0 )
103744603Sdcs  while
1038186789Sluigi    current_file_name_ref strref
103944603Sdcs    ['] load_conf catch
104044603Sdcs    process_conf_errors
1041185746Sluigi    conf_files .addr @ if recurse then
104244603Sdcs  repeat
104344603Sdcs;
104444603Sdcs
104597201Sgordon: get_nextboot_conf_file ( -- addr len )
1046292999Sdteske  nextboot_conf_file strget
104797201Sgordon;
104897201Sgordon
104997201Sgordon: rewrite_nextboot_file ( -- )
105097201Sgordon  get_nextboot_conf_file
105197201Sgordon  O_WRONLY fopen fd !
1052186789Sluigi  fd @ -1 = if EOPEN throw then
1053292899Sdteske  fd @ s' nextboot_enable="NO" ' fwrite ( fd buf len -- nwritten ) drop
105497201Sgordon  fd @ fclose
105597201Sgordon;
105697201Sgordon
1057292899Sdteske: include_nextboot_file ( -- )
105897201Sgordon  get_nextboot_conf_file
1059292899Sdteske  ['] peek_file catch if 2drop then
106097201Sgordon  nextboot? if
106197201Sgordon    get_nextboot_conf_file
1062292899Sdteske    current_file_name_ref strref
106397201Sgordon    ['] load_conf catch
106497201Sgordon    process_conf_errors
1065292899Sdteske    ['] rewrite_nextboot_file catch if 2drop then
106697201Sgordon  then
106797201Sgordon;
106897201Sgordon
106944603Sdcs\ Module loading functions
107044603Sdcs
1071186789Sluigi: load_parameters  { addr -- addr addrN lenN ... addr1 len1 N }
1072186789Sluigi  addr
1073186789Sluigi  addr module.args strget
1074186789Sluigi  addr module.loadname .len @ if
1075186789Sluigi    addr module.loadname strget
107644603Sdcs  else
1077186789Sluigi    addr module.name strget
107844603Sdcs  then
1079186789Sluigi  addr module.type .len @ if
1080186789Sluigi    addr module.type strget
108144603Sdcs    s" -t "
108244603Sdcs    4 ( -t type name flags )
108344603Sdcs  else
108444603Sdcs    2 ( name flags )
108544603Sdcs  then
108644603Sdcs;
108744603Sdcs
108844603Sdcs: before_load  ( addr -- addr )
108944603Sdcs  dup module.beforeload .len @ if
1090186789Sluigi    dup module.beforeload strget
1091186789Sluigi    ['] evaluate catch if EBEFORELOAD throw then
109244603Sdcs  then
109344603Sdcs;
109444603Sdcs
109544603Sdcs: after_load  ( addr -- addr )
109644603Sdcs  dup module.afterload .len @ if
1097186789Sluigi    dup module.afterload strget
1098186789Sluigi    ['] evaluate catch if EAFTERLOAD throw then
109944603Sdcs  then
110044603Sdcs;
110144603Sdcs
110244603Sdcs: load_error  ( addr -- addr )
110344603Sdcs  dup module.loaderror .len @ if
1104186789Sluigi    dup module.loaderror strget
110544603Sdcs    evaluate  \ This we do not intercept so it can throw errors
110644603Sdcs  then
110744603Sdcs;
110844603Sdcs
110944603Sdcs: pre_load_message  ( addr -- addr )
111044603Sdcs  verbose? if
1111186789Sluigi    dup module.name strtype
111244603Sdcs    ." ..."
111344603Sdcs  then
111444603Sdcs;
111544603Sdcs
111644603Sdcs: load_error_message verbose? if ." failed!" cr then ;
111744603Sdcs
111844603Sdcs: load_succesful_message verbose? if ." ok" cr then ;
111944603Sdcs
112044603Sdcs: load_module
112144603Sdcs  load_parameters load
112244603Sdcs;
112344603Sdcs
112444603Sdcs: process_module  ( addr -- addr )
112544603Sdcs  pre_load_message
112644603Sdcs  before_load
112744603Sdcs  begin
112844603Sdcs    ['] load_module catch if
112944603Sdcs      dup module.loaderror .len @ if
113044603Sdcs        load_error			\ Command should return a flag!
113144603Sdcs      else 
113244603Sdcs        load_error_message true		\ Do not retry
113344603Sdcs      then
113444603Sdcs    else
113544603Sdcs      after_load
1136298831Spfg      load_succesful_message true	\ Successful, do not retry
113744603Sdcs    then
113844603Sdcs  until
113944603Sdcs;
114044603Sdcs
114144603Sdcs: process_module_errors  ( addr ior -- )
1142186789Sluigi  dup EBEFORELOAD = if
114344603Sdcs    drop
114444603Sdcs    ." Module "
1145186789Sluigi    dup module.name strtype
114644603Sdcs    dup module.loadname .len @ if
1147186789Sluigi      ." (" dup module.loadname strtype ." )"
114844603Sdcs    then
114944603Sdcs    cr
115044603Sdcs    ." Error executing "
1151186789Sluigi    dup module.beforeload strtype cr	\ XXX there was a typo here
115244603Sdcs    abort
115344603Sdcs  then
115444603Sdcs
1155186789Sluigi  dup EAFTERLOAD = if
115644603Sdcs    drop
115744603Sdcs    ." Module "
115844603Sdcs    dup module.name .addr @ over module.name .len @ type
115944603Sdcs    dup module.loadname .len @ if
1160186789Sluigi      ." (" dup module.loadname strtype ." )"
116144603Sdcs    then
116244603Sdcs    cr
116344603Sdcs    ." Error executing "
1164186789Sluigi    dup module.afterload strtype cr
116544603Sdcs    abort
116644603Sdcs  then
116744603Sdcs
116844603Sdcs  throw  \ Don't know what it is all about -- pass ahead
116944603Sdcs;
117044603Sdcs
117144603Sdcs\ Module loading interface
117244603Sdcs
1173186789Sluigi\ scan the list of modules, load enabled ones.
117444603Sdcs: load_modules  ( -- ) ( throws: abort & user-defined )
1175186789Sluigi  module_options @	( list_head )
117644603Sdcs  begin
117744603Sdcs    ?dup
117844603Sdcs  while
1179186789Sluigi    dup module.flag @ if
118044603Sdcs      ['] process_module catch
118144603Sdcs      process_module_errors
118244603Sdcs    then
118344603Sdcs    module.next @
118444603Sdcs  repeat
118544603Sdcs;
118644603Sdcs
118765630Sdcs\ h00h00 magic used to try loading either a kernel with a given name,
118865630Sdcs\ or a kernel with the default name in a directory of a given name
118965630Sdcs\ (the pain!)
119044603Sdcs
119165630Sdcs: bootpath s" /boot/" ;
119265630Sdcs: modulepath s" module_path" ;
119365630Sdcs
119465630Sdcs\ Functions used to save and restore module_path's value.
119565630Sdcs: saveenv ( addr len | -1 -- addr' len | 0 -1 )
119665630Sdcs  dup -1 = if 0 swap exit then
119765630Sdcs  strdup
119865630Sdcs;
119965630Sdcs: freeenv ( addr len | 0 -1 )
120065630Sdcs  -1 = if drop else free abort" Freeing error" then
120165630Sdcs;
120265630Sdcs: restoreenv  ( addr len | 0 -1 -- )
120365630Sdcs  dup -1 = if ( it wasn't set )
120465630Sdcs    2drop
120565630Sdcs    modulepath unsetenv
120665630Sdcs  else
120765630Sdcs    over >r
120865630Sdcs    modulepath setenv
120965630Sdcs    r> free abort" Freeing error"
121065630Sdcs  then
121165630Sdcs;
121265630Sdcs
121365630Sdcs: clip_args   \ Drop second string if only one argument is passed
121465630Sdcs  1 = if
121565630Sdcs    2swap 2drop
121665630Sdcs    1
121765630Sdcs  else
121865630Sdcs    2
121965630Sdcs  then
122065630Sdcs;
122165630Sdcs
122265630Sdcsalso builtins
122365630Sdcs
1224186789Sluigi\ Parse filename from a semicolon-separated list
122565630Sdcs
1226186789Sluigi\ replacement, not working yet
1227186789Sluigi: newparse-; { addr len | a1 -- a' len-x addr x }
1228186789Sluigi  addr len [char] ; strchr dup if	( a1 len1 )
1229186789Sluigi    swap to a1	( store address )
1230186789Sluigi    1 - a1 @ 1 + swap ( remove match )
1231186789Sluigi    addr a1 addr -
1232186789Sluigi  else
1233186789Sluigi    0 0 addr len
1234186789Sluigi  then
1235186789Sluigi;
1236186789Sluigi
123765630Sdcs: parse-; ( addr len -- addr' len-x addr x )
1238186789Sluigi  over 0 2swap			( addr 0 addr len )
123965630Sdcs  begin
1240186789Sluigi    dup 0 <>			( addr 0 addr len )
124165630Sdcs  while
1242186789Sluigi    over c@ [char] ; <>		( addr 0 addr len flag )
124365630Sdcs  while
124465630Sdcs    1- swap 1+ swap
124565630Sdcs    2swap 1+ 2swap
124665630Sdcs  repeat then
124765630Sdcs  dup 0 <> if
124865630Sdcs    1- swap 1+ swap
124965630Sdcs  then
125065630Sdcs  2swap
125165630Sdcs;
125265630Sdcs
125365630Sdcs\ Try loading one of multiple kernels specified
125465630Sdcs
125565630Sdcs: try_multiple_kernels ( addr len addr' len' args -- flag )
125665630Sdcs  >r
125765630Sdcs  begin
125865630Sdcs    parse-; 2>r
125965630Sdcs    2over 2r>
126065945Sdcs    r@ clip_args
126165945Sdcs    s" DEBUG" getenv? if
126265945Sdcs      s" echo Module_path: ${module_path}" evaluate
126365945Sdcs      ." Kernel     : " >r 2dup type r> cr
126465945Sdcs      dup 2 = if ." Flags      : " >r 2over type r> cr then
126565945Sdcs    then
126665945Sdcs    1 load
126765630Sdcs  while
126865630Sdcs    dup 0=
126965630Sdcs  until
127065630Sdcs    1 >r \ Failure
127165630Sdcs  else
127265630Sdcs    0 >r \ Success
127365630Sdcs  then
127465630Sdcs  2drop 2drop
127565630Sdcs  r>
127665630Sdcs  r> drop
127765630Sdcs;
127865630Sdcs
127965630Sdcs\ Try to load a kernel; the kernel name is taken from one of
128065630Sdcs\ the following lists, as ordered:
128165630Sdcs\
128265641Sdcs\   1. The "bootfile" environment variable
128365641Sdcs\   2. The "kernel" environment variable
128465630Sdcs\
128565938Sdcs\ Flags are passed, if available. If not, dummy values must be given.
128665630Sdcs\
128765630Sdcs\ The kernel gets loaded from the current module_path.
128865630Sdcs
128965938Sdcs: load_a_kernel ( flags len 1 | x x 0 -- flag )
129065630Sdcs  local args
129165630Sdcs  2local flags
129265630Sdcs  0 0 2local kernel
129365630Sdcs  end-locals
129465630Sdcs
129565630Sdcs  \ Check if a default kernel name exists at all, exits if not
129665641Sdcs  s" bootfile" getenv dup -1 <> if
129765630Sdcs    to kernel
129865883Sdcs    flags kernel args 1+ try_multiple_kernels
129965630Sdcs    dup 0= if exit then
130065630Sdcs  then
130165630Sdcs  drop
130265630Sdcs
130365641Sdcs  s" kernel" getenv dup -1 <> if
130465630Sdcs    to kernel
130565630Sdcs  else
130665630Sdcs    drop
130765630Sdcs    1 exit \ Failure
130865630Sdcs  then
130965630Sdcs
131065630Sdcs  \ Try all default kernel names
131165883Sdcs  flags kernel args 1+ try_multiple_kernels
131265630Sdcs;
131365630Sdcs
131465630Sdcs\ Try to load a kernel; the kernel name is taken from one of
131565630Sdcs\ the following lists, as ordered:
131665630Sdcs\
131765641Sdcs\   1. The "bootfile" environment variable
131865641Sdcs\   2. The "kernel" environment variable
131965630Sdcs\
132065630Sdcs\ Flags are passed, if provided.
132165630Sdcs\
132265630Sdcs\ The kernel will be loaded from a directory computed from the
132365630Sdcs\ path given. Two directories will be tried in the following order:
132465630Sdcs\
132565630Sdcs\   1. /boot/path
132665630Sdcs\   2. path
132765630Sdcs\
1328298831Spfg\ The module_path variable is overridden if load is successful, by
132965630Sdcs\ prepending the successful path.
133065630Sdcs
133165630Sdcs: load_from_directory ( path len 1 | flags len' path len 2 -- flag )
133265630Sdcs  local args
133365630Sdcs  2local path
133465630Sdcs  args 1 = if 0 0 then
133565630Sdcs  2local flags
1336186789Sluigi  0 0 2local oldmodulepath \ like a string
1337186789Sluigi  0 0 2local newmodulepath \ like a string
133865630Sdcs  end-locals
133965630Sdcs
134065630Sdcs  \ Set the environment variable module_path, and try loading
134165630Sdcs  \ the kernel again.
134265630Sdcs  modulepath getenv saveenv to oldmodulepath
134365630Sdcs
134465630Sdcs  \ Try prepending /boot/ first
1345186789Sluigi  bootpath nip path nip + 	\ total length
134665630Sdcs  oldmodulepath nip dup -1 = if
134765630Sdcs    drop
134865630Sdcs  else
1349186789Sluigi    1+ +			\ add oldpath -- XXX why the 1+ ?
135065630Sdcs  then
1351186789Sluigi  allocate if ( out of memory ) 1 exit then \ XXX throw ?
135265630Sdcs
135365630Sdcs  0
135465630Sdcs  bootpath strcat
135565630Sdcs  path strcat
135665630Sdcs  2dup to newmodulepath
135765630Sdcs  modulepath setenv
135865630Sdcs
135965630Sdcs  \ Try all default kernel names
136065938Sdcs  flags args 1- load_a_kernel
136165630Sdcs  0= if ( success )
136265630Sdcs    oldmodulepath nip -1 <> if
136365630Sdcs      newmodulepath s" ;" strcat
136465630Sdcs      oldmodulepath strcat
136565630Sdcs      modulepath setenv
136665630Sdcs      newmodulepath drop free-memory
136765630Sdcs      oldmodulepath drop free-memory
136865630Sdcs    then
136965630Sdcs    0 exit
137065630Sdcs  then
137165630Sdcs
137265630Sdcs  \ Well, try without the prepended /boot/
137365630Sdcs  path newmodulepath drop swap move
137465883Sdcs  newmodulepath drop path nip
137565630Sdcs  2dup to newmodulepath
137665630Sdcs  modulepath setenv
137765630Sdcs
137865630Sdcs  \ Try all default kernel names
137965938Sdcs  flags args 1- load_a_kernel
138065630Sdcs  if ( failed once more )
138165630Sdcs    oldmodulepath restoreenv
138265630Sdcs    newmodulepath drop free-memory
138365630Sdcs    1
138465630Sdcs  else
138565630Sdcs    oldmodulepath nip -1 <> if
138665630Sdcs      newmodulepath s" ;" strcat
138765630Sdcs      oldmodulepath strcat
138865630Sdcs      modulepath setenv
138965630Sdcs      newmodulepath drop free-memory
139065630Sdcs      oldmodulepath drop free-memory
139165630Sdcs    then
139265630Sdcs    0
139365630Sdcs  then
139465630Sdcs;
139565630Sdcs
139665630Sdcs\ Try to load a kernel; the kernel name is taken from one of
139765630Sdcs\ the following lists, as ordered:
139865630Sdcs\
139965641Sdcs\   1. The "bootfile" environment variable
140065641Sdcs\   2. The "kernel" environment variable
140165630Sdcs\   3. The "path" argument
140265630Sdcs\
140365630Sdcs\ Flags are passed, if provided.
140465630Sdcs\
140565630Sdcs\ The kernel will be loaded from a directory computed from the
140665630Sdcs\ path given. Two directories will be tried in the following order:
140765630Sdcs\
140865630Sdcs\   1. /boot/path
140965630Sdcs\   2. path
141065630Sdcs\
141165630Sdcs\ Unless "path" is meant to be kernel name itself. In that case, it
141265630Sdcs\ will first be tried as a full path, and, next, search on the
141365630Sdcs\ directories pointed by module_path.
141465630Sdcs\
1415298831Spfg\ The module_path variable is overridden if load is successful, by
141665630Sdcs\ prepending the successful path.
141765630Sdcs
141865630Sdcs: load_directory_or_file ( path len 1 | flags len' path len 2 -- flag )
141965630Sdcs  local args
142065630Sdcs  2local path
142165630Sdcs  args 1 = if 0 0 then
142265630Sdcs  2local flags
142365630Sdcs  end-locals
142465630Sdcs
142565630Sdcs  \ First, assume path is an absolute path to a directory
142665630Sdcs  flags path args clip_args load_from_directory
142765630Sdcs  dup 0= if exit else drop then
142865630Sdcs
142965630Sdcs  \ Next, assume path points to the kernel
143065630Sdcs  flags path args try_multiple_kernels
143165630Sdcs;
143265630Sdcs
143344603Sdcs: initialize  ( addr len -- )
1434186789Sluigi  strdup conf_files strset
143544603Sdcs;
143644603Sdcs
143765883Sdcs: kernel_options ( -- addr len 1 | 0 )
143865630Sdcs  s" kernel_options" getenv
143965883Sdcs  dup -1 = if drop 0 else 1 then
144065630Sdcs;
144165630Sdcs
144265938Sdcs: standard_kernel_search  ( flags 1 | 0 -- flag )
144365938Sdcs  local args
144465938Sdcs  args 0= if 0 0 then
144565938Sdcs  2local flags
144665630Sdcs  s" kernel" getenv
144765938Sdcs  dup -1 = if 0 swap then
144865938Sdcs  2local path
144965938Sdcs  end-locals
145065938Sdcs
145166349Sdcs  path nip -1 = if ( there isn't a "kernel" environment variable )
145265938Sdcs    flags args load_a_kernel
145365938Sdcs  else
145465938Sdcs    flags path args 1+ clip_args load_directory_or_file
145565938Sdcs  then
145665630Sdcs;
145765630Sdcs
145844603Sdcs: load_kernel  ( -- ) ( throws: abort )
145965938Sdcs  kernel_options standard_kernel_search
146065630Sdcs  abort" Unable to load a kernel!"
146144603Sdcs;
146265883Sdcs
1463283933Sdteske: load_xen ( -- flag )
1464277215Sroyger  s" xen_kernel" getenv dup -1 <> if
1465283933Sdteske    1 1 load ( c-addr/u flag N -- flag )
1466277215Sroyger  else
1467277215Sroyger    drop
1468283933Sdteske    0 ( -1 -- flag )
1469277215Sroyger  then
1470277215Sroyger;
1471277215Sroyger
1472277215Sroyger: load_xen_throw ( -- ) ( throws: abort )
1473277215Sroyger  load_xen
1474277215Sroyger  abort" Unable to load Xen!"
1475277215Sroyger;
1476277215Sroyger
147765949Sdcs: set_defaultoptions  ( -- )
147865883Sdcs  s" kernel_options" getenv dup -1 = if
147965883Sdcs    drop
148065883Sdcs  else
148165883Sdcs    s" temp_options" setenv
148265883Sdcs  then
148365883Sdcs;
148465883Sdcs
1485186789Sluigi\ pick the i-th argument, i starts at 0
148665883Sdcs: argv[]  ( aN uN ... a1 u1 N i -- aN uN ... a1 u1 N ai+1 ui+1 )
1487186789Sluigi  2dup = if 0 0 exit then	\ out of range
148865883Sdcs  dup >r
148965883Sdcs  1+ 2* ( skip N and ui )
149065883Sdcs  pick
149165883Sdcs  r>
149265883Sdcs  1+ 2* ( skip N and ai )
149365883Sdcs  pick
149465883Sdcs;
149565883Sdcs
149665949Sdcs: drop_args  ( aN uN ... a1 u1 N -- )
149765883Sdcs  0 ?do 2drop loop
149865883Sdcs;
149965883Sdcs
150065883Sdcs: argc
150165883Sdcs  dup
150265883Sdcs;
150365883Sdcs
150465949Sdcs: queue_argv  ( aN uN ... a1 u1 N a u -- a u aN uN ... a1 u1 N+1 )
150565883Sdcs  >r
150665883Sdcs  over 2* 1+ -roll
150765883Sdcs  r>
150865883Sdcs  over 2* 1+ -roll
150965883Sdcs  1+
151065883Sdcs;
151165883Sdcs
151265949Sdcs: unqueue_argv  ( aN uN ... a1 u1 N -- aN uN ... a2 u2 N-1 a1 u1 )
151365883Sdcs  1- -rot
151465883Sdcs;
151565883Sdcs
1516186789Sluigi\ compute the length of the buffer including the spaces between words
1517186789Sluigi: strlen(argv) ( aN uN .. a1 u1 N -- aN uN .. a1 u1 N len )
151865883Sdcs  dup 0= if 0 exit then
151965883Sdcs  0 >r	\ Size
152065883Sdcs  0 >r	\ Index
152165883Sdcs  begin
152265883Sdcs    argc r@ <>
152365883Sdcs  while
152465883Sdcs    r@ argv[]
152565883Sdcs    nip
152665883Sdcs    r> r> rot + 1+
152765883Sdcs    >r 1+ >r
152865883Sdcs  repeat
152965883Sdcs  r> drop
153065883Sdcs  r>
153165883Sdcs;
153265883Sdcs
153365949Sdcs: concat_argv  ( aN uN ... a1 u1 N -- a u )
1534186789Sluigi  strlen(argv) allocate if ENOMEM throw then
1535186789Sluigi  0 2>r ( save addr 0 on return stack )
153665883Sdcs
153765883Sdcs  begin
1538186789Sluigi    dup
153965883Sdcs  while
1540186789Sluigi    unqueue_argv ( ... N a1 u1 )
1541186789Sluigi    2r> 2swap	 ( old a1 u1 )
154265883Sdcs    strcat
1543186789Sluigi    s"  " strcat ( append one space ) \ XXX this gives a trailing space
1544186789Sluigi    2>r		( store string on the result stack )
154565883Sdcs  repeat
154665949Sdcs  drop_args
154765883Sdcs  2r>
154865883Sdcs;
154965883Sdcs
155065949Sdcs: set_tempoptions  ( addrN lenN ... addr1 len1 N -- addr len 1 | 0 )
155165883Sdcs  \ Save the first argument, if it exists and is not a flag
155265883Sdcs  argc if
155365883Sdcs    0 argv[] drop c@ [char] - <> if
155465949Sdcs      unqueue_argv 2>r  \ Filename
155565883Sdcs      1 >r		\ Filename present
155665883Sdcs    else
155765883Sdcs      0 >r		\ Filename not present
155865883Sdcs    then
155965883Sdcs  else
156065883Sdcs    0 >r		\ Filename not present
156165883Sdcs  then
156265883Sdcs
156365883Sdcs  \ If there are other arguments, assume they are flags
156465883Sdcs  ?dup if
156565949Sdcs    concat_argv
156665883Sdcs    2dup s" temp_options" setenv
1567186789Sluigi    drop free if EFREE throw then
156865883Sdcs  else
156965949Sdcs    set_defaultoptions
157065883Sdcs  then
157165883Sdcs
157265883Sdcs  \ Bring back the filename, if one was provided
157365883Sdcs  r> if 2r> 1 else 0 then
157465883Sdcs;
157565883Sdcs
157665949Sdcs: get_arguments ( -- addrN lenN ... addr1 len1 N )
157765883Sdcs  0
157865883Sdcs  begin
157965883Sdcs    \ Get next word on the command line
158065883Sdcs    parse-word
158165883Sdcs  ?dup while
158265949Sdcs    queue_argv
158365883Sdcs  repeat
158465883Sdcs  drop ( empty string )
158565883Sdcs;
158665883Sdcs
158765945Sdcs: load_kernel_and_modules  ( args -- flag )
158865949Sdcs  set_tempoptions
158965883Sdcs  argc >r
159065883Sdcs  s" temp_options" getenv dup -1 <> if
159165949Sdcs    queue_argv
159265883Sdcs  else
159365883Sdcs    drop
159465883Sdcs  then
1595277215Sroyger  load_xen
1596277215Sroyger  ?dup 0= if ( success )
1597277215Sroyger    r> if ( a path was passed )
1598277215Sroyger      load_directory_or_file
1599277215Sroyger    else
1600277215Sroyger      standard_kernel_search
1601277215Sroyger    then
1602277215Sroyger    ?dup 0= if ['] load_modules catch then
160365883Sdcs  then
160465883Sdcs;
160565883Sdcs
1606280937Sdteskeonly forth definitions
1607