1 \ Copyright (c) 1999 Daniel C. Sobral <dcs@freebsd.org>
4 \ Redistribution and use in source and binary forms, with or without
5 \ modification, are permitted provided that the following conditions
7 \ 1. Redistributions of source code must retain the above copyright
8 \ notice, this list of conditions and the following disclaimer.
9 \ 2. Redistributions in binary form must reproduce the above copyright
10 \ notice, this list of conditions and the following disclaimer in the
11 \ documentation and/or other materials provided with the distribution.
13 \ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
14 \ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 \ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 \ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
17 \ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 \ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
19 \ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
20 \ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 \ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 \ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 \ $FreeBSD: src/sys/boot/forth/support.4th,v 1.3.2.1 2000/07/07 00:15:53 obrien Exp $
26 \ $DragonFly: src/sys/boot/forth/support.4th,v 1.2 2003/06/17 04:28:18 dillon Exp $
28 \ Loader.rc support functions:
30 \ initialize_support ( -- ) initialize global variables
31 \ initialize ( addr len -- ) as above, plus load_conf_files
32 \ load_conf ( addr len -- ) load conf file given
33 \ include_conf_files ( -- ) load all conf files in load_conf_files
34 \ print_syntax_error ( -- ) print line and marker of where a syntax
36 \ print_line ( -- ) print last line processed
37 \ load_kernel ( -- ) load kernel
38 \ load_modules ( -- ) load modules flagged
40 \ Exported structures:
42 \ string counted string structure
43 \ cell .addr string address
44 \ cell .len string length
45 \ module module loading information structure
46 \ cell module.flag should we load it?
47 \ string module.name module's name
48 \ string module.loadname name to be used in loading the module
49 \ string module.type module's type
50 \ string module.args flags to be passed during load
51 \ string module.beforeload command to be executed before load
52 \ string module.afterload command to be executed after load
53 \ string module.loaderror command to be executed if load fails
54 \ cell module.next list chain
56 \ Exported global variables;
58 \ string conf_files configuration files to be loaded
59 \ string password password
60 \ cell modules_options pointer to first module information
61 \ value verbose? indicates if user wants a verbose loading
62 \ value any_conf_read? indicates if a conf file was succesfully read
64 \ Other exported words:
66 \ strdup ( addr len -- addr' len) similar to strdup(3)
67 \ strcat ( addr len addr' len' -- addr len+len' ) similar to strcat(3)
68 \ strlen ( addr -- len ) similar to strlen(3)
69 \ s' ( | string' -- addr len | ) similar to s"
70 \ rudimentary structure support
74 1 constant syntax_error
75 2 constant out_of_memory
81 8 constant before_load_error
82 9 constant after_load_error
84 \ Crude structure support
86 : structure: create here 0 , 0 does> create @ allot ;
87 : member: create dup , over , + does> cell+ @ + ;
89 : sizeof ' >body @ state @ if postpone literal then ; immediate
90 : offsetof ' >body cell+ @ state @ if postpone literal then ; immediate
91 : ptr 1 cells member: ;
92 : int 1 cells member: ;
101 \ Module options linked list
105 sizeof string member: module.name
106 sizeof string member: module.loadname
107 sizeof string member: module.type
108 sizeof string member: module.args
109 sizeof string member: module.beforeload
110 sizeof string member: module.afterload
111 sizeof string member: module.loaderror
119 create module_options sizeof module.next allot
120 create last_module_option sizeof module.next allot
123 \ Support string functions
125 : strdup ( addr len -- addr' len )
126 >r r@ allocate if out_of_memory throw then
131 : strcat { addr len addr' len' -- addr len+len' }
132 addr' addr len + len' move
136 : strlen ( addr -- len )
151 : 2>r postpone >r postpone >r ; immediate
152 : 2r> postpone r> postpone r> ; immediate
154 \ Private definitions
156 vocabulary support-functions
157 only forth also support-functions definitions
159 \ Some control characters constants
169 80 constant read_buffer_size
173 : load_module_suffix s" _load" ;
174 : module_loadname_suffix s" _name" ;
175 : module_type_suffix s" _type" ;
176 : module_args_suffix s" _flags" ;
177 : module_beforeload_suffix s" _before" ;
178 : module_afterload_suffix s" _after" ;
179 : module_loaderror_suffix s" _error" ;
186 \ Assorted support funcitons
188 : free-memory free if free_error throw then ;
190 \ Assignment data temporary storage
195 \ File data temporary storage
199 0 value read_buffer_ptr
201 \ File's line reading function
208 read_buffer .len @ read_buffer_ptr >
210 read_buffer .addr @ read_buffer_ptr + c@ lf = if
211 read_buffer_ptr char+ to read_buffer_ptr
218 : scan_buffer ( -- addr len )
221 read_buffer .len @ r@ >
223 read_buffer .addr @ r@ + c@ lf = if
224 read_buffer .addr @ read_buffer_ptr + ( -- addr )
225 r@ read_buffer_ptr - ( -- len )
226 r> to read_buffer_ptr
231 read_buffer .addr @ read_buffer_ptr + ( -- addr )
232 r@ read_buffer_ptr - ( -- len )
233 r> to read_buffer_ptr
236 : line_buffer_resize ( len -- len )
238 line_buffer .len @ if
240 line_buffer .len @ r@ +
241 resize if out_of_memory throw then
243 r@ allocate if out_of_memory throw then
249 : append_to_line_buffer ( addr len -- )
250 line_buffer .addr @ line_buffer .len @
257 scan_buffer ( -- addr len )
258 line_buffer_resize ( len -- len )
259 append_to_line_buffer ( addr len -- )
263 read_buffer .len @ read_buffer_ptr =
269 read_buffer .addr @ 0= if
270 read_buffer_size allocate if out_of_memory throw then
273 fd @ read_buffer .addr @ read_buffer_size fread
274 dup -1 = if read_error throw then
275 dup 0= if true to end_of_file? then
280 0 line_buffer .addr !
295 \ Conf file line parser:
296 \ <line> ::= <spaces><name><spaces>'='<spaces><value><spaces>[<comment>] |
297 \ <spaces>[<comment>]
298 \ <name> ::= <letter>{<letter>|<digit>|'_'}
299 \ <value> ::= '"'{<character_set>|'\'<anything>}'"' | <name>
300 \ <character_set> ::= ASCII 32 to 126, except '\' and '"'
301 \ <comment> ::= '#'{<anything>}
303 0 value parsing_function
309 line_pointer end_of_line =
328 line_pointer c@ [char] " =
332 line_pointer c@ [char] = =
336 line_pointer c@ [char] # =
341 line_pointer c@ tab = or
345 line_pointer c@ [char] \ =
349 line_pointer c@ [char] _ =
353 line_pointer c@ [char] . =
357 line_pointer char+ to line_pointer
360 : skip_to_end_of_line
361 end_of_line to line_pointer
369 end_of_line? if exit then
373 : parse_name ( -- addr len )
376 letter? digit? underscore? dot? or or or
389 : remove_backslashes { addr len | addr' len' -- addr' len' }
390 len allocate if out_of_memory throw then
394 addr c@ [char] \ <> if
395 addr c@ addr' len' + c!
405 : parse_quote ( -- addr len )
408 end_of_line? if syntax_error throw then
414 end_of_line? if syntax_error throw then
417 end_of_line? if syntax_error throw then
425 parse_name ( -- addr len )
432 parse_quote ( -- addr len )
434 parse_name ( -- addr len )
446 comment? if ['] comment to parsing_function exit then
447 end_of_line? 0= if syntax_error throw then
452 ['] white_space_4 to parsing_function
457 letter? digit? quote? or or if
458 ['] variable_value to parsing_function exit
465 ['] white_space_3 to parsing_function
470 assignment_sign? if ['] assignment_sign to parsing_function exit then
476 ['] white_space_2 to parsing_function
481 letter? if ['] variable_name to parsing_function exit then
482 comment? if ['] comment to parsing_function exit then
483 end_of_line? 0= if syntax_error throw then
487 line_buffer .addr @ line_buffer .len @ + to end_of_line
488 line_buffer .addr @ to line_pointer
489 ['] white_space_1 to parsing_function
493 parsing_function execute
495 parsing_function ['] comment =
496 parsing_function ['] white_space_1 =
497 parsing_function ['] white_space_4 =
498 or or 0= if syntax_error throw then
503 : assignment_type? ( addr len -- flag )
504 name_buffer .addr @ name_buffer .len @
508 : suffix_type? ( addr len -- flag )
509 name_buffer .len @ over <= if 2drop false exit then
510 name_buffer .len @ over - name_buffer .addr @ +
515 s" loader_conf_files" assignment_type?
519 s" verbose_loading" assignment_type?
523 s" exec" assignment_type?
527 s" password" assignment_type?
531 load_module_suffix suffix_type?
535 module_loadname_suffix suffix_type?
539 module_type_suffix suffix_type?
543 module_args_suffix suffix_type?
547 module_beforeload_suffix suffix_type?
551 module_afterload_suffix suffix_type?
555 module_loaderror_suffix suffix_type?
559 conf_files .addr @ ?dup if
562 value_buffer .addr @ c@ [char] " = if
563 value_buffer .addr @ char+ value_buffer .len @ 2 chars -
565 value_buffer .addr @ value_buffer .len @
568 conf_files .len ! conf_files .addr !
571 : append_to_module_options_list ( addr -- )
572 module_options @ 0= if
576 dup last_module_option @ module.next !
581 : set_module_name ( addr -- )
582 name_buffer .addr @ name_buffer .len @
584 >r over module.name .addr !
585 r> swap module.name .len !
589 value_buffer .addr @ value_buffer .len @
590 2dup s' "YES"' compare >r
591 2dup s' "yes"' compare >r
592 2dup s" YES" compare >r
593 s" yes" compare r> r> r> and and and 0=
596 : find_module_option ( -- addr | 0 )
601 dup module.name dup .addr @ swap .len @
602 name_buffer .addr @ name_buffer .len @
603 compare 0= if exit then
608 : new_module_option ( -- addr )
609 sizeof module allocate if out_of_memory throw then
610 dup sizeof module erase
611 dup append_to_module_options_list
615 : get_module_option ( -- addr )
617 ?dup 0= if new_module_option then
621 name_buffer .len @ load_module_suffix nip - name_buffer .len !
622 yes_value? get_module_option module.flag !
626 name_buffer .len @ module_args_suffix nip - name_buffer .len !
627 get_module_option module.args
628 dup .addr @ ?dup if free-memory then
629 value_buffer .addr @ value_buffer .len @
630 over c@ [char] " = if
631 2 chars - swap char+ swap
638 : set_module_loadname
639 name_buffer .len @ module_loadname_suffix nip - name_buffer .len !
640 get_module_option module.loadname
641 dup .addr @ ?dup if free-memory then
642 value_buffer .addr @ value_buffer .len @
643 over c@ [char] " = if
644 2 chars - swap char+ swap
652 name_buffer .len @ module_type_suffix nip - name_buffer .len !
653 get_module_option module.type
654 dup .addr @ ?dup if free-memory then
655 value_buffer .addr @ value_buffer .len @
656 over c@ [char] " = if
657 2 chars - swap char+ swap
664 : set_module_beforeload
665 name_buffer .len @ module_beforeload_suffix nip - name_buffer .len !
666 get_module_option module.beforeload
667 dup .addr @ ?dup if free-memory then
668 value_buffer .addr @ value_buffer .len @
669 over c@ [char] " = if
670 2 chars - swap char+ swap
677 : set_module_afterload
678 name_buffer .len @ module_afterload_suffix nip - name_buffer .len !
679 get_module_option module.afterload
680 dup .addr @ ?dup if free-memory then
681 value_buffer .addr @ value_buffer .len @
682 over c@ [char] " = if
683 2 chars - swap char+ swap
690 : set_module_loaderror
691 name_buffer .len @ module_loaderror_suffix nip - name_buffer .len !
692 get_module_option module.loaderror
693 dup .addr @ ?dup if free-memory then
694 value_buffer .addr @ value_buffer .len @
695 over c@ [char] " = if
696 2 chars - swap char+ swap
703 : set_environment_variable
705 value_buffer .len @ +
707 allocate if out_of_memory throw then
708 dup 0 ( addr -- addr addr len )
710 name_buffer .addr @ name_buffer .len @ strcat
712 value_buffer .addr @ value_buffer .len @ strcat
713 ['] evaluate catch if
722 yes_value? to verbose?
726 value_buffer .addr @ value_buffer .len @
727 over c@ [char] " = if
730 ['] evaluate catch if exec_error throw then
734 password .addr @ ?dup if free if free_error throw then then
735 value_buffer .addr @ c@ [char] " = if
736 value_buffer .addr @ char+ value_buffer .len @ 2 - strdup
737 value_buffer .addr @ free if free_error throw then
739 value_buffer .addr @ value_buffer .len @
741 password .len ! password .addr !
742 0 value_buffer .addr !
746 name_buffer .len @ 0= if exit then
747 loader_conf_files? if set_conf_files exit then
748 verbose_flag? if set_verbose exit then
749 execute? if execute_command exit then
750 password? if set_password exit then
751 module_load? if set_module_flag exit then
752 module_loadname? if set_module_loadname exit then
753 module_type? if set_module_type exit then
754 module_args? if set_module_args exit then
755 module_beforeload? if set_module_beforeload exit then
756 module_afterload? if set_module_afterload exit then
757 module_loaderror? if set_module_loaderror exit then
758 set_environment_variable
763 \ Free some pointers if needed. The code then tests for errors
764 \ in freeing, and throws an exception if needed. If a pointer is
765 \ not allocated, it's value (0) is used as flag.
768 line_buffer .addr @ dup if free then
769 name_buffer .addr @ dup if free then
770 value_buffer .addr @ dup if free then
771 or or if free_error throw then
774 : reset_assignment_buffers
775 0 name_buffer .addr !
777 0 value_buffer .addr !
778 0 value_buffer .len !
781 \ Higher level file processing
787 reset_assignment_buffers
790 ['] process_assignment catch
791 ['] free_buffers catch
796 : create_null_terminated_string { addr len -- addr' len }
797 len char+ allocate if out_of_memory throw then
804 \ Interface to loading conf files
806 : load_conf ( addr len -- )
809 create_null_terminated_string
813 fd @ -1 = if open_error throw then
814 ['] process_conf catch
820 0 read_buffer .addr !
824 0 last_module_option !
829 line_buffer .addr @ line_buffer .len @ type cr
833 line_buffer .addr @ line_buffer .len @ type cr
845 \ Depuration support functions
847 only forth definitions also support-functions
850 ['] load_conf catch dup .
851 syntax_error = if cr print_syntax_error then
854 : show-module-options
859 ." Name: " dup module.name dup .addr @ swap .len @ type cr
860 ." Path: " dup module.loadname dup .addr @ swap .len @ type cr
861 ." Type: " dup module.type dup .addr @ swap .len @ type cr
862 ." Flags: " dup module.args dup .addr @ swap .len @ type cr
863 ." Before load: " dup module.beforeload dup .addr @ swap .len @ type cr
864 ." After load: " dup module.afterload dup .addr @ swap .len @ type cr
865 ." Error: " dup module.loaderror dup .addr @ swap .len @ type cr
866 ." Status: " dup module.flag @ if ." Load" else ." Don't load" then cr
871 only forth also support-functions definitions
873 \ Variables used for processing multiple conf files
875 string current_file_name
876 variable current_conf_files
878 \ Indicates if any conf file was succesfully read
880 0 value any_conf_read?
882 \ loader_conf_files processing support functions
884 : set_current_conf_files
885 conf_files .addr @ current_conf_files !
889 conf_files .addr @ conf_files .len @ strdup
892 : recurse_on_conf_files?
893 current_conf_files @ conf_files .addr @ <>
896 : skip_leading_spaces { addr len pos -- addr len pos' }
898 pos len = if addr len pos exit then
906 : get_file_name { addr len pos -- addr len pos' addr' len' || 0 }
908 addr free abort" Fatal error freeing memory"
917 addr len pos addr r@ + pos r> - exit
920 addr len pos addr r@ + pos r> -
923 : get_next_file ( addr len ptr -- addr len ptr' addr' len' | 0 )
928 : set_current_file_name
929 over current_file_name .addr !
930 dup current_file_name .len !
934 current_file_name .addr @ current_file_name .len @ type
937 : process_conf_errors
938 dup 0= if true to any_conf_read? drop exit then
940 dup syntax_error = if
941 ." Warning: syntax error on file " print_current_file cr
942 print_syntax_error drop exit
945 ." Warning: bad definition on file " print_current_file cr
949 ." Warning: error reading file " print_current_file cr drop exit
952 verbose? if ." Warning: unable to open file " print_current_file cr then
955 dup free_error = abort" Fatal error freeing memory"
956 dup out_of_memory = abort" Out of memory"
957 throw \ Unknown error -- pass ahead
960 \ Process loader_conf_files recursively
961 \ Interface to loader_conf_files processing
964 set_current_conf_files
969 set_current_file_name
972 recurse_on_conf_files? if recurse then
976 \ Module loading functions
982 : load_parameters ( addr -- addr addrN lenN ... addr1 len1 N )
984 r@ module.args .addr @ r@ module.args .len @
985 r@ module.loadname .len @ if
986 r@ module.loadname .addr @ r@ module.loadname .len @
988 r@ module.name .addr @ r@ module.name .len @
990 r@ module.type .len @ if
991 r@ module.type .addr @ r@ module.type .len @
993 4 ( -t type name flags )
1000 : before_load ( addr -- addr )
1001 dup module.beforeload .len @ if
1002 dup module.beforeload .addr @ over module.beforeload .len @
1003 ['] evaluate catch if before_load_error throw then
1007 : after_load ( addr -- addr )
1008 dup module.afterload .len @ if
1009 dup module.afterload .addr @ over module.afterload .len @
1010 ['] evaluate catch if after_load_error throw then
1014 : load_error ( addr -- addr )
1015 dup module.loaderror .len @ if
1016 dup module.loaderror .addr @ over module.loaderror .len @
1017 evaluate \ This we do not intercept so it can throw errors
1021 : pre_load_message ( addr -- addr )
1023 dup module.name .addr @ over module.name .len @ type
1028 : load_error_message verbose? if ." failed!" cr then ;
1030 : load_succesful_message verbose? if ." ok" cr then ;
1033 load_parameters load
1036 : process_module ( addr -- addr )
1040 ['] load_module catch if
1041 dup module.loaderror .len @ if
1042 load_error \ Command should return a flag!
1044 load_error_message true \ Do not retry
1048 load_succesful_message true \ Succesful, do not retry
1053 : process_module_errors ( addr ior -- )
1054 dup before_load_error = if
1057 dup module.name .addr @ over module.name .len @ type
1058 dup module.loadname .len @ if
1059 ." (" dup module.loadname .addr @ over module.loadname .len @ type ." )"
1062 ." Error executing "
1063 dup module.beforeload .addr @ over module.afterload .len @ type cr
1067 dup after_load_error = if
1070 dup module.name .addr @ over module.name .len @ type
1071 dup module.loadname .len @ if
1072 ." (" dup module.loadname .addr @ over module.loadname .len @ type ." )"
1075 ." Error executing "
1076 dup module.afterload .addr @ over module.afterload .len @ type cr
1080 throw \ Don't know what it is all about -- pass ahead
1083 \ Module loading interface
1085 : load_modules ( -- ) ( throws: abort & user-defined )
1091 ['] process_module catch
1092 process_module_errors
1098 \ Additional functions used in "start"
1100 : initialize ( addr len -- )
1102 strdup conf_files .len ! conf_files .addr !
1105 : load_kernel ( -- ) ( throws: abort )
1106 s" load ${kernel} ${kernel_options}" ['] evaluate catch
1107 if s" echo Unable to load kernel: ${kernel_name}" evaluate abort then
1110 : read-password { size | buf len -- }
1111 size allocate if out_of_memory throw then
1119 backspace emit bl emit backspace emit
1125 dup <cr> = if cr drop buf len exit then
1137 \ Go back to straight forth vocabulary
1139 only forth also definitions