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 $
27 \ Loader.rc support functions:
29 \ initialize_support ( -- ) initialize global variables
30 \ initialize ( addr len -- ) as above, plus load_conf_files
31 \ load_conf ( addr len -- ) load conf file given
32 \ include_conf_files ( -- ) load all conf files in load_conf_files
33 \ print_syntax_error ( -- ) print line and marker of where a syntax
35 \ print_line ( -- ) print last line processed
36 \ load_kernel ( -- ) load kernel
37 \ load_modules ( -- ) load modules flagged
39 \ Exported structures:
41 \ string counted string structure
42 \ cell .addr string address
43 \ cell .len string length
44 \ module module loading information structure
45 \ cell module.flag should we load it?
46 \ string module.name module's name
47 \ string module.loadname name to be used in loading the module
48 \ string module.type module's type
49 \ string module.args flags to be passed during load
50 \ string module.beforeload command to be executed before load
51 \ string module.afterload command to be executed after load
52 \ string module.loaderror command to be executed if load fails
53 \ cell module.next list chain
55 \ Exported global variables;
57 \ string conf_files configuration files to be loaded
58 \ string password password
59 \ cell modules_options pointer to first module information
60 \ value verbose? indicates if user wants a verbose loading
61 \ value any_conf_read? indicates if a conf file was succesfully read
63 \ Other exported words:
65 \ strdup ( addr len -- addr' len) similar to strdup(3)
66 \ strcat ( addr len addr' len' -- addr len+len' ) similar to strcat(3)
67 \ strlen ( addr -- len ) similar to strlen(3)
68 \ s' ( | string' -- addr len | ) similar to s"
69 \ rudimentary structure support
73 1 constant syntax_error
74 2 constant out_of_memory
80 8 constant before_load_error
81 9 constant after_load_error
83 \ Crude structure support
85 : structure: create here 0 , 0 does> create @ allot ;
86 : member: create dup , over , + does> cell+ @ + ;
88 : sizeof ' >body @ state @ if postpone literal then ; immediate
89 : offsetof ' >body cell+ @ state @ if postpone literal then ; immediate
90 : ptr 1 cells member: ;
91 : int 1 cells member: ;
100 \ Module options linked list
104 sizeof string member: module.name
105 sizeof string member: module.loadname
106 sizeof string member: module.type
107 sizeof string member: module.args
108 sizeof string member: module.beforeload
109 sizeof string member: module.afterload
110 sizeof string member: module.loaderror
118 create module_options sizeof module.next allot
119 create last_module_option sizeof module.next allot
122 \ Support string functions
124 : strdup ( addr len -- addr' len )
125 >r r@ allocate if out_of_memory throw then
130 : strcat { addr len addr' len' -- addr len+len' }
131 addr' addr len + len' move
135 : strlen ( addr -- len )
150 : 2>r postpone >r postpone >r ; immediate
151 : 2r> postpone r> postpone r> ; immediate
153 \ Private definitions
155 vocabulary support-functions
156 only forth also support-functions definitions
158 \ Some control characters constants
168 80 constant read_buffer_size
172 : load_module_suffix s" _load" ;
173 : module_loadname_suffix s" _name" ;
174 : module_type_suffix s" _type" ;
175 : module_args_suffix s" _flags" ;
176 : module_beforeload_suffix s" _before" ;
177 : module_afterload_suffix s" _after" ;
178 : module_loaderror_suffix s" _error" ;
185 \ Assorted support funcitons
187 : free-memory free if free_error throw then ;
189 \ Assignment data temporary storage
194 \ File data temporary storage
198 0 value read_buffer_ptr
200 \ File's line reading function
207 read_buffer .len @ read_buffer_ptr >
209 read_buffer .addr @ read_buffer_ptr + c@ lf = if
210 read_buffer_ptr char+ to read_buffer_ptr
217 : scan_buffer ( -- addr len )
220 read_buffer .len @ r@ >
222 read_buffer .addr @ r@ + c@ lf = if
223 read_buffer .addr @ read_buffer_ptr + ( -- addr )
224 r@ read_buffer_ptr - ( -- len )
225 r> to read_buffer_ptr
230 read_buffer .addr @ read_buffer_ptr + ( -- addr )
231 r@ read_buffer_ptr - ( -- len )
232 r> to read_buffer_ptr
235 : line_buffer_resize ( len -- len )
237 line_buffer .len @ if
239 line_buffer .len @ r@ +
240 resize if out_of_memory throw then
242 r@ allocate if out_of_memory throw then
248 : append_to_line_buffer ( addr len -- )
249 line_buffer .addr @ line_buffer .len @
256 scan_buffer ( -- addr len )
257 line_buffer_resize ( len -- len )
258 append_to_line_buffer ( addr len -- )
262 read_buffer .len @ read_buffer_ptr =
268 read_buffer .addr @ 0= if
269 read_buffer_size allocate if out_of_memory throw then
272 fd @ read_buffer .addr @ read_buffer_size fread
273 dup -1 = if read_error throw then
274 dup 0= if true to end_of_file? then
279 0 line_buffer .addr !
294 \ Conf file line parser:
295 \ <line> ::= <spaces><name><spaces>'='<spaces><value><spaces>[<comment>] |
296 \ <spaces>[<comment>]
297 \ <name> ::= <letter>{<letter>|<digit>|'_'}
298 \ <value> ::= '"'{<character_set>|'\'<anything>}'"' | <name>
299 \ <character_set> ::= ASCII 32 to 126, except '\' and '"'
300 \ <comment> ::= '#'{<anything>}
302 0 value parsing_function
308 line_pointer end_of_line =
327 line_pointer c@ [char] " =
331 line_pointer c@ [char] = =
335 line_pointer c@ [char] # =
340 line_pointer c@ tab = or
344 line_pointer c@ [char] \ =
348 line_pointer c@ [char] _ =
352 line_pointer c@ [char] . =
356 line_pointer char+ to line_pointer
359 : skip_to_end_of_line
360 end_of_line to line_pointer
368 end_of_line? if exit then
372 : parse_name ( -- addr len )
375 letter? digit? underscore? dot? or or or
388 : remove_backslashes { addr len | addr' len' -- addr' len' }
389 len allocate if out_of_memory throw then
393 addr c@ [char] \ <> if
394 addr c@ addr' len' + c!
404 : parse_quote ( -- addr len )
407 end_of_line? if syntax_error throw then
413 end_of_line? if syntax_error throw then
416 end_of_line? if syntax_error throw then
424 parse_name ( -- addr len )
431 parse_quote ( -- addr len )
433 parse_name ( -- addr len )
445 comment? if ['] comment to parsing_function exit then
446 end_of_line? 0= if syntax_error throw then
451 ['] white_space_4 to parsing_function
456 letter? digit? quote? or or if
457 ['] variable_value to parsing_function exit
464 ['] white_space_3 to parsing_function
469 assignment_sign? if ['] assignment_sign to parsing_function exit then
475 ['] white_space_2 to parsing_function
480 letter? if ['] variable_name to parsing_function exit then
481 comment? if ['] comment to parsing_function exit then
482 end_of_line? 0= if syntax_error throw then
486 line_buffer .addr @ line_buffer .len @ + to end_of_line
487 line_buffer .addr @ to line_pointer
488 ['] white_space_1 to parsing_function
492 parsing_function execute
494 parsing_function ['] comment =
495 parsing_function ['] white_space_1 =
496 parsing_function ['] white_space_4 =
497 or or 0= if syntax_error throw then
502 : assignment_type? ( addr len -- flag )
503 name_buffer .addr @ name_buffer .len @
507 : suffix_type? ( addr len -- flag )
508 name_buffer .len @ over <= if 2drop false exit then
509 name_buffer .len @ over - name_buffer .addr @ +
514 s" loader_conf_files" assignment_type?
518 s" verbose_loading" assignment_type?
522 s" exec" assignment_type?
526 s" password" assignment_type?
530 load_module_suffix suffix_type?
534 module_loadname_suffix suffix_type?
538 module_type_suffix suffix_type?
542 module_args_suffix suffix_type?
546 module_beforeload_suffix suffix_type?
550 module_afterload_suffix suffix_type?
554 module_loaderror_suffix suffix_type?
558 conf_files .addr @ ?dup if
561 value_buffer .addr @ c@ [char] " = if
562 value_buffer .addr @ char+ value_buffer .len @ 2 chars -
564 value_buffer .addr @ value_buffer .len @
567 conf_files .len ! conf_files .addr !
570 : append_to_module_options_list ( addr -- )
571 module_options @ 0= if
575 dup last_module_option @ module.next !
580 : set_module_name ( addr -- )
581 name_buffer .addr @ name_buffer .len @
583 >r over module.name .addr !
584 r> swap module.name .len !
588 value_buffer .addr @ value_buffer .len @
589 2dup s' "YES"' compare >r
590 2dup s' "yes"' compare >r
591 2dup s" YES" compare >r
592 s" yes" compare r> r> r> and and and 0=
595 : find_module_option ( -- addr | 0 )
600 dup module.name dup .addr @ swap .len @
601 name_buffer .addr @ name_buffer .len @
602 compare 0= if exit then
607 : new_module_option ( -- addr )
608 sizeof module allocate if out_of_memory throw then
609 dup sizeof module erase
610 dup append_to_module_options_list
614 : get_module_option ( -- addr )
616 ?dup 0= if new_module_option then
620 name_buffer .len @ load_module_suffix nip - name_buffer .len !
621 yes_value? get_module_option module.flag !
625 name_buffer .len @ module_args_suffix nip - name_buffer .len !
626 get_module_option module.args
627 dup .addr @ ?dup if free-memory then
628 value_buffer .addr @ value_buffer .len @
629 over c@ [char] " = if
630 2 chars - swap char+ swap
637 : set_module_loadname
638 name_buffer .len @ module_loadname_suffix nip - name_buffer .len !
639 get_module_option module.loadname
640 dup .addr @ ?dup if free-memory then
641 value_buffer .addr @ value_buffer .len @
642 over c@ [char] " = if
643 2 chars - swap char+ swap
651 name_buffer .len @ module_type_suffix nip - name_buffer .len !
652 get_module_option module.type
653 dup .addr @ ?dup if free-memory then
654 value_buffer .addr @ value_buffer .len @
655 over c@ [char] " = if
656 2 chars - swap char+ swap
663 : set_module_beforeload
664 name_buffer .len @ module_beforeload_suffix nip - name_buffer .len !
665 get_module_option module.beforeload
666 dup .addr @ ?dup if free-memory then
667 value_buffer .addr @ value_buffer .len @
668 over c@ [char] " = if
669 2 chars - swap char+ swap
676 : set_module_afterload
677 name_buffer .len @ module_afterload_suffix nip - name_buffer .len !
678 get_module_option module.afterload
679 dup .addr @ ?dup if free-memory then
680 value_buffer .addr @ value_buffer .len @
681 over c@ [char] " = if
682 2 chars - swap char+ swap
689 : set_module_loaderror
690 name_buffer .len @ module_loaderror_suffix nip - name_buffer .len !
691 get_module_option module.loaderror
692 dup .addr @ ?dup if free-memory then
693 value_buffer .addr @ value_buffer .len @
694 over c@ [char] " = if
695 2 chars - swap char+ swap
702 : set_environment_variable
704 value_buffer .len @ +
706 allocate if out_of_memory throw then
707 dup 0 ( addr -- addr addr len )
709 name_buffer .addr @ name_buffer .len @ strcat
711 value_buffer .addr @ value_buffer .len @ strcat
712 ['] evaluate catch if
721 yes_value? to verbose?
725 value_buffer .addr @ value_buffer .len @
726 over c@ [char] " = if
729 ['] evaluate catch if exec_error throw then
733 password .addr @ ?dup if free if free_error throw then then
734 value_buffer .addr @ c@ [char] " = if
735 value_buffer .addr @ char+ value_buffer .len @ 2 - strdup
736 value_buffer .addr @ free if free_error throw then
738 value_buffer .addr @ value_buffer .len @
740 password .len ! password .addr !
741 0 value_buffer .addr !
745 name_buffer .len @ 0= if exit then
746 loader_conf_files? if set_conf_files exit then
747 verbose_flag? if set_verbose exit then
748 execute? if execute_command exit then
749 password? if set_password exit then
750 module_load? if set_module_flag exit then
751 module_loadname? if set_module_loadname exit then
752 module_type? if set_module_type exit then
753 module_args? if set_module_args exit then
754 module_beforeload? if set_module_beforeload exit then
755 module_afterload? if set_module_afterload exit then
756 module_loaderror? if set_module_loaderror exit then
757 set_environment_variable
762 \ Free some pointers if needed. The code then tests for errors
763 \ in freeing, and throws an exception if needed. If a pointer is
764 \ not allocated, it's value (0) is used as flag.
767 line_buffer .addr @ dup if free then
768 name_buffer .addr @ dup if free then
769 value_buffer .addr @ dup if free then
770 or or if free_error throw then
773 : reset_assignment_buffers
774 0 name_buffer .addr !
776 0 value_buffer .addr !
777 0 value_buffer .len !
780 \ Higher level file processing
786 reset_assignment_buffers
789 ['] process_assignment catch
790 ['] free_buffers catch
795 : create_null_terminated_string { addr len -- addr' len }
796 len char+ allocate if out_of_memory throw then
803 \ Interface to loading conf files
805 : load_conf ( addr len -- )
808 create_null_terminated_string
812 fd @ -1 = if open_error throw then
813 ['] process_conf catch
819 0 read_buffer .addr !
823 0 last_module_option !
828 line_buffer .addr @ line_buffer .len @ type cr
832 line_buffer .addr @ line_buffer .len @ type cr
844 \ Depuration support functions
846 only forth definitions also support-functions
849 ['] load_conf catch dup .
850 syntax_error = if cr print_syntax_error then
853 : show-module-options
858 ." Name: " dup module.name dup .addr @ swap .len @ type cr
859 ." Path: " dup module.loadname dup .addr @ swap .len @ type cr
860 ." Type: " dup module.type dup .addr @ swap .len @ type cr
861 ." Flags: " dup module.args dup .addr @ swap .len @ type cr
862 ." Before load: " dup module.beforeload dup .addr @ swap .len @ type cr
863 ." After load: " dup module.afterload dup .addr @ swap .len @ type cr
864 ." Error: " dup module.loaderror dup .addr @ swap .len @ type cr
865 ." Status: " dup module.flag @ if ." Load" else ." Don't load" then cr
870 only forth also support-functions definitions
872 \ Variables used for processing multiple conf files
874 string current_file_name
875 variable current_conf_files
877 \ Indicates if any conf file was succesfully read
879 0 value any_conf_read?
881 \ loader_conf_files processing support functions
883 : set_current_conf_files
884 conf_files .addr @ current_conf_files !
888 conf_files .addr @ conf_files .len @ strdup
891 : recurse_on_conf_files?
892 current_conf_files @ conf_files .addr @ <>
895 : skip_leading_spaces { addr len pos -- addr len pos' }
897 pos len = if addr len pos exit then
905 : get_file_name { addr len pos -- addr len pos' addr' len' || 0 }
907 addr free abort" Fatal error freeing memory"
916 addr len pos addr r@ + pos r> - exit
919 addr len pos addr r@ + pos r> -
922 : get_next_file ( addr len ptr -- addr len ptr' addr' len' | 0 )
927 : set_current_file_name
928 over current_file_name .addr !
929 dup current_file_name .len !
933 current_file_name .addr @ current_file_name .len @ type
936 : process_conf_errors
937 dup 0= if true to any_conf_read? drop exit then
939 dup syntax_error = if
940 ." Warning: syntax error on file " print_current_file cr
941 print_syntax_error drop exit
944 ." Warning: bad definition on file " print_current_file cr
948 ." Warning: error reading file " print_current_file cr drop exit
951 verbose? if ." Warning: unable to open file " print_current_file cr then
954 dup free_error = abort" Fatal error freeing memory"
955 dup out_of_memory = abort" Out of memory"
956 throw \ Unknown error -- pass ahead
959 \ Process loader_conf_files recursively
960 \ Interface to loader_conf_files processing
963 set_current_conf_files
968 set_current_file_name
971 recurse_on_conf_files? if recurse then
975 \ Module loading functions
981 : load_parameters ( addr -- addr addrN lenN ... addr1 len1 N )
983 r@ module.args .addr @ r@ module.args .len @
984 r@ module.loadname .len @ if
985 r@ module.loadname .addr @ r@ module.loadname .len @
987 r@ module.name .addr @ r@ module.name .len @
989 r@ module.type .len @ if
990 r@ module.type .addr @ r@ module.type .len @
992 4 ( -t type name flags )
999 : before_load ( addr -- addr )
1000 dup module.beforeload .len @ if
1001 dup module.beforeload .addr @ over module.beforeload .len @
1002 ['] evaluate catch if before_load_error throw then
1006 : after_load ( addr -- addr )
1007 dup module.afterload .len @ if
1008 dup module.afterload .addr @ over module.afterload .len @
1009 ['] evaluate catch if after_load_error throw then
1013 : load_error ( addr -- addr )
1014 dup module.loaderror .len @ if
1015 dup module.loaderror .addr @ over module.loaderror .len @
1016 evaluate \ This we do not intercept so it can throw errors
1020 : pre_load_message ( addr -- addr )
1022 dup module.name .addr @ over module.name .len @ type
1027 : load_error_message verbose? if ." failed!" cr then ;
1029 : load_succesful_message verbose? if ." ok" cr then ;
1032 load_parameters load
1035 : process_module ( addr -- addr )
1039 ['] load_module catch if
1040 dup module.loaderror .len @ if
1041 load_error \ Command should return a flag!
1043 load_error_message true \ Do not retry
1047 load_succesful_message true \ Succesful, do not retry
1052 : process_module_errors ( addr ior -- )
1053 dup before_load_error = if
1056 dup module.name .addr @ over module.name .len @ type
1057 dup module.loadname .len @ if
1058 ." (" dup module.loadname .addr @ over module.loadname .len @ type ." )"
1061 ." Error executing "
1062 dup module.beforeload .addr @ over module.afterload .len @ type cr
1066 dup after_load_error = if
1069 dup module.name .addr @ over module.name .len @ type
1070 dup module.loadname .len @ if
1071 ." (" dup module.loadname .addr @ over module.loadname .len @ type ." )"
1074 ." Error executing "
1075 dup module.afterload .addr @ over module.afterload .len @ type cr
1079 throw \ Don't know what it is all about -- pass ahead
1082 \ Module loading interface
1084 : load_modules ( -- ) ( throws: abort & user-defined )
1090 ['] process_module catch
1091 process_module_errors
1097 \ Additional functions used in "start"
1099 : initialize ( addr len -- )
1101 strdup conf_files .len ! conf_files .addr !
1104 : load_kernel ( -- ) ( throws: abort )
1105 s" load ${kernel} ${kernel_options}" ['] evaluate catch
1106 if s" echo Unable to load kernel: ${kernel_name}" evaluate abort then
1109 : read-password { size | buf len -- }
1110 size allocate if out_of_memory throw then
1118 backspace emit bl emit backspace emit
1124 dup <cr> = if cr drop buf len exit then
1136 \ Go back to straight forth vocabulary
1138 only forth also definitions