home *** CD-ROM | disk | FTP | other *** search
/ PC Welt 2005 November / PCWELT_11_2005.ISO / pcwsoft / cdrom-1.11.iso / boot / support.4th < prev   
Encoding:
FORTH Source  |  2004-05-29  |  24.5 KB  |  1,140 lines

  1. \ Copyright (c) 1999 Daniel C. Sobral <dcs@freebsd.org>
  2. \ All rights reserved.
  3. \ Redistribution and use in source and binary forms, with or without
  4. \ modification, are permitted provided that the following conditions
  5. \ are met:
  6. \ 1. Redistributions of source code must retain the above copyright
  7. \    notice, this list of conditions and the following disclaimer.
  8. \ 2. Redistributions in binary form must reproduce the above copyright
  9. \    notice, this list of conditions and the following disclaimer in the
  10. \    documentation and/or other materials provided with the distribution.
  11. \
  12. \ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  13. \ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  14. \ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  15. \ ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  16. \ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  17. \ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  18. \ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  19. \ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  20. \ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  21. \ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  22. \ SUCH DAMAGE.
  23. \
  24. \ $FreeBSD: src/sys/boot/forth/support.4th,v 1.3.2.1 2000/07/07 00:15:53 obrien Exp $
  25.  
  26. \ Loader.rc support functions:
  27. \
  28. \ initialize_support ( -- )    initialize global variables
  29. \ initialize ( addr len -- )    as above, plus load_conf_files
  30. \ load_conf ( addr len -- )    load conf file given
  31. \ include_conf_files ( -- )    load all conf files in load_conf_files
  32. \ print_syntax_error ( -- )    print line and marker of where a syntax
  33. \                error was detected
  34. \ print_line ( -- )        print last line processed
  35. \ load_kernel ( -- )        load kernel
  36. \ load_modules ( -- )        load modules flagged
  37. \
  38. \ Exported structures:
  39. \
  40. \ string            counted string structure
  41. \    cell .addr            string address
  42. \    cell .len            string length
  43. \ module            module loading information structure
  44. \    cell module.flag        should we load it?
  45. \    string module.name        module's name
  46. \    string module.loadname        name to be used in loading the module
  47. \    string module.type        module's type
  48. \    string module.args        flags to be passed during load
  49. \    string module.beforeload    command to be executed before load
  50. \    string module.afterload        command to be executed after load
  51. \    string module.loaderror        command to be executed if load fails
  52. \    cell module.next        list chain
  53. \
  54. \ Exported global variables;
  55. \
  56. \ string conf_files        configuration files to be loaded
  57. \ string password        password
  58. \ cell modules_options        pointer to first module information
  59. \ value verbose?        indicates if user wants a verbose loading
  60. \ value any_conf_read?        indicates if a conf file was succesfully read
  61. \
  62. \ Other exported words:
  63. \
  64. \ strdup ( addr len -- addr' len)            similar to strdup(3)
  65. \ strcat ( addr len addr' len' -- addr len+len' )    similar to strcat(3)
  66. \ strlen ( addr -- len )                similar to strlen(3)
  67. \ s' ( | string' -- addr len | )            similar to s"
  68. \ rudimentary structure support
  69.  
  70. \ Exception values
  71.  
  72. 1 constant syntax_error
  73. 2 constant out_of_memory
  74. 3 constant free_error
  75. 4 constant set_error
  76. 5 constant read_error
  77. 6 constant open_error
  78. 7 constant exec_error
  79. 8 constant before_load_error
  80. 9 constant after_load_error
  81.  
  82. \ Crude structure support
  83.  
  84. : structure: create here 0 , 0 does> create @ allot ;
  85. : member: create dup , over , + does> cell+ @ + ;
  86. : ;structure swap ! ;
  87. : sizeof ' >body @ state @ if postpone literal then ; immediate
  88. : offsetof ' >body cell+ @ state @ if postpone literal then ; immediate
  89. : ptr 1 cells member: ;
  90. : int 1 cells member: ;
  91.  
  92. \ String structure
  93.  
  94. structure: string
  95.     ptr .addr
  96.     int .len
  97. ;structure
  98.  
  99. \ Module options linked list
  100.  
  101. structure: module
  102.     int module.flag
  103.     sizeof string member: module.name
  104.     sizeof string member: module.loadname
  105.     sizeof string member: module.type
  106.     sizeof string member: module.args
  107.     sizeof string member: module.beforeload
  108.     sizeof string member: module.afterload
  109.     sizeof string member: module.loaderror
  110.     ptr module.next
  111. ;structure
  112.  
  113. \ Global variables
  114.  
  115. string conf_files
  116. string password
  117. create module_options sizeof module.next allot
  118. create last_module_option sizeof module.next allot
  119. 0 value verbose?
  120.  
  121. \ Support string functions
  122.  
  123. : strdup  ( addr len -- addr' len )
  124.   >r r@ allocate if out_of_memory throw then
  125.   tuck r@ move
  126.   r>
  127. ;
  128.  
  129. : strcat  { addr len addr' len' -- addr len+len' }
  130.   addr' addr len + len' move
  131.   addr len len' +
  132. ;
  133.  
  134. : strlen ( addr -- len )
  135.   0 >r
  136.   begin
  137.     dup c@ while
  138.     1+ r> 1+ >r repeat
  139.   drop r>
  140. ;
  141.  
  142. : s' 
  143.   [char] ' parse
  144.   state @ if
  145.     postpone sliteral
  146.   then
  147. ; immediate
  148.  
  149. : 2>r postpone >r postpone >r ; immediate
  150. : 2r> postpone r> postpone r> ; immediate
  151.  
  152. \ Private definitions
  153.  
  154. vocabulary support-functions
  155. only forth also support-functions definitions
  156.  
  157. \ Some control characters constants
  158.  
  159. 7 constant bell
  160. 8 constant backspace
  161. 9 constant tab
  162. 10 constant lf
  163. 13 constant <cr>
  164.  
  165. \ Read buffer size
  166.  
  167. 80 constant read_buffer_size
  168.  
  169. \ Standard suffixes
  170.  
  171. : load_module_suffix s" _load" ;
  172. : module_loadname_suffix s" _name" ;
  173. : module_type_suffix s" _type" ;
  174. : module_args_suffix s" _flags" ;
  175. : module_beforeload_suffix s" _before" ;
  176. : module_afterload_suffix s" _after" ;
  177. : module_loaderror_suffix s" _error" ;
  178.  
  179. \ Support operators
  180.  
  181. : >= < 0= ;
  182. : <= > 0= ;
  183.  
  184. \ Assorted support funcitons
  185.  
  186. : free-memory free if free_error throw then ;
  187.  
  188. \ Assignment data temporary storage
  189.  
  190. string name_buffer
  191. string value_buffer
  192.  
  193. \ File data temporary storage
  194.  
  195. string line_buffer
  196. string read_buffer
  197. 0 value read_buffer_ptr
  198.  
  199. \ File's line reading function
  200.  
  201. 0 value end_of_file?
  202. variable fd
  203.  
  204. : skip_newlines
  205.   begin
  206.     read_buffer .len @ read_buffer_ptr >
  207.   while
  208.     read_buffer .addr @ read_buffer_ptr + c@ lf = if
  209.       read_buffer_ptr char+ to read_buffer_ptr
  210.     else
  211.       exit
  212.     then
  213.   repeat
  214. ;
  215.  
  216. : scan_buffer  ( -- addr len )
  217.   read_buffer_ptr >r
  218.   begin
  219.     read_buffer .len @ r@ >
  220.   while
  221.     read_buffer .addr @ r@ + c@ lf = if
  222.       read_buffer .addr @ read_buffer_ptr +  ( -- addr )
  223.       r@ read_buffer_ptr -                   ( -- len )
  224.       r> to read_buffer_ptr
  225.       exit
  226.     then
  227.     r> char+ >r
  228.   repeat
  229.   read_buffer .addr @ read_buffer_ptr +  ( -- addr )
  230.   r@ read_buffer_ptr -                   ( -- len )
  231.   r> to read_buffer_ptr
  232. ;
  233.  
  234. : line_buffer_resize  ( len -- len )
  235.   >r
  236.   line_buffer .len @ if
  237.     line_buffer .addr @
  238.     line_buffer .len @ r@ +
  239.     resize if out_of_memory throw then
  240.   else
  241.     r@ allocate if out_of_memory throw then
  242.   then
  243.   line_buffer .addr !
  244.   r>
  245. ;
  246.     
  247. : append_to_line_buffer  ( addr len -- )
  248.   line_buffer .addr @ line_buffer .len @
  249.   2swap strcat
  250.   line_buffer .len !
  251.   drop
  252. ;
  253.  
  254. : read_from_buffer
  255.   scan_buffer            ( -- addr len )
  256.   line_buffer_resize     ( len -- len )
  257.   append_to_line_buffer  ( addr len -- )
  258. ;
  259.  
  260. : refill_required?
  261.   read_buffer .len @ read_buffer_ptr =
  262.   end_of_file? 0= and
  263. ;
  264.  
  265. : refill_buffer
  266.   0 to read_buffer_ptr
  267.   read_buffer .addr @ 0= if
  268.     read_buffer_size allocate if out_of_memory throw then
  269.     read_buffer .addr !
  270.   then
  271.   fd @ read_buffer .addr @ read_buffer_size fread
  272.   dup -1 = if read_error throw then
  273.   dup 0= if true to end_of_file? then
  274.   read_buffer .len !
  275. ;
  276.  
  277. : reset_line_buffer
  278.   0 line_buffer .addr !
  279.   0 line_buffer .len !
  280. ;
  281.  
  282. : read_line
  283.   reset_line_buffer
  284.   skip_newlines
  285.   begin
  286.     read_from_buffer
  287.     refill_required?
  288.   while
  289.     refill_buffer
  290.   repeat
  291. ;
  292.  
  293. \ Conf file line parser:
  294. \ <line> ::= <spaces><name><spaces>'='<spaces><value><spaces>[<comment>] |
  295. \            <spaces>[<comment>]
  296. \ <name> ::= <letter>{<letter>|<digit>|'_'}
  297. \ <value> ::= '"'{<character_set>|'\'<anything>}'"' | <name>
  298. \ <character_set> ::= ASCII 32 to 126, except '\' and '"'
  299. \ <comment> ::= '#'{<anything>}
  300.  
  301. 0 value parsing_function
  302.  
  303. 0 value end_of_line
  304. 0 value line_pointer
  305.  
  306. : end_of_line?
  307.   line_pointer end_of_line =
  308. ;
  309.  
  310. : letter?
  311.   line_pointer c@ >r
  312.   r@ [char] A >=
  313.   r@ [char] Z <= and
  314.   r@ [char] a >=
  315.   r> [char] z <= and
  316.   or
  317. ;
  318.  
  319. : digit?
  320.   line_pointer c@ >r
  321.   r@ [char] 0 >=
  322.   r> [char] 9 <= and
  323. ;
  324.  
  325. : quote?
  326.   line_pointer c@ [char] " =
  327. ;
  328.  
  329. : assignment_sign?
  330.   line_pointer c@ [char] = =
  331. ;
  332.  
  333. : comment?
  334.   line_pointer c@ [char] # =
  335. ;
  336.  
  337. : space?
  338.   line_pointer c@ bl =
  339.   line_pointer c@ tab = or
  340. ;
  341.  
  342. : backslash?
  343.   line_pointer c@ [char] \ =
  344. ;
  345.  
  346. : underscore?
  347.   line_pointer c@ [char] _ =
  348. ;
  349.  
  350. : dot?
  351.   line_pointer c@ [char] . =
  352. ;
  353.  
  354. : skip_character
  355.   line_pointer char+ to line_pointer
  356. ;
  357.  
  358. : skip_to_end_of_line
  359.   end_of_line to line_pointer
  360. ;
  361.  
  362. : eat_space
  363.   begin
  364.     space?
  365.   while
  366.     skip_character
  367.     end_of_line? if exit then
  368.   repeat
  369. ;
  370.  
  371. : parse_name  ( -- addr len )
  372.   line_pointer
  373.   begin
  374.     letter? digit? underscore? dot? or or or
  375.   while
  376.     skip_character
  377.     end_of_line? if 
  378.       line_pointer over -
  379.       strdup
  380.       exit
  381.     then
  382.   repeat
  383.   line_pointer over -
  384.   strdup
  385. ;
  386.  
  387. : remove_backslashes  { addr len | addr' len' -- addr' len' }
  388.   len allocate if out_of_memory throw then
  389.   to addr'
  390.   addr >r
  391.   begin
  392.     addr c@ [char] \ <> if
  393.       addr c@ addr' len' + c!
  394.       len' char+ to len'
  395.     then
  396.     addr char+ to addr
  397.     r@ len + addr =
  398.   until
  399.   r> drop
  400.   addr' len'
  401. ;
  402.  
  403. : parse_quote  ( -- addr len )
  404.   line_pointer
  405.   skip_character
  406.   end_of_line? if syntax_error throw then
  407.   begin
  408.     quote? 0=
  409.   while
  410.     backslash? if
  411.       skip_character
  412.       end_of_line? if syntax_error throw then
  413.     then
  414.     skip_character
  415.     end_of_line? if syntax_error throw then 
  416.   repeat
  417.   skip_character
  418.   line_pointer over -
  419.   remove_backslashes
  420. ;
  421.  
  422. : read_name
  423.   parse_name        ( -- addr len )
  424.   name_buffer .len !
  425.   name_buffer .addr !
  426. ;
  427.  
  428. : read_value
  429.   quote? if
  430.     parse_quote        ( -- addr len )
  431.   else
  432.     parse_name        ( -- addr len )
  433.   then
  434.   value_buffer .len !
  435.   value_buffer .addr !
  436. ;
  437.  
  438. : comment
  439.   skip_to_end_of_line
  440. ;
  441.  
  442. : white_space_4
  443.   eat_space
  444.   comment? if ['] comment to parsing_function exit then
  445.   end_of_line? 0= if syntax_error throw then
  446. ;
  447.  
  448. : variable_value
  449.   read_value
  450.   ['] white_space_4 to parsing_function
  451. ;
  452.  
  453. : white_space_3
  454.   eat_space
  455.   letter? digit? quote? or or if
  456.     ['] variable_value to parsing_function exit
  457.   then
  458.   syntax_error throw
  459. ;
  460.  
  461. : assignment_sign
  462.   skip_character
  463.   ['] white_space_3 to parsing_function
  464. ;
  465.  
  466. : white_space_2
  467.   eat_space
  468.   assignment_sign? if ['] assignment_sign to parsing_function exit then
  469.   syntax_error throw
  470. ;
  471.  
  472. : variable_name
  473.   read_name
  474.   ['] white_space_2 to parsing_function
  475. ;
  476.  
  477. : white_space_1
  478.   eat_space
  479.   letter?  if ['] variable_name to parsing_function exit then
  480.   comment? if ['] comment to parsing_function exit then
  481.   end_of_line? 0= if syntax_error throw then
  482. ;
  483.  
  484. : get_assignment
  485.   line_buffer .addr @ line_buffer .len @ + to end_of_line
  486.   line_buffer .addr @ to line_pointer
  487.   ['] white_space_1 to parsing_function
  488.   begin
  489.     end_of_line? 0=
  490.   while
  491.     parsing_function execute
  492.   repeat
  493.   parsing_function ['] comment =
  494.   parsing_function ['] white_space_1 =
  495.   parsing_function ['] white_space_4 =
  496.   or or 0= if syntax_error throw then
  497. ;
  498.  
  499. \ Process line
  500.  
  501. : assignment_type?  ( addr len -- flag )
  502.   name_buffer .addr @ name_buffer .len @
  503.   compare 0=
  504. ;
  505.  
  506. : suffix_type?  ( addr len -- flag )
  507.   name_buffer .len @ over <= if 2drop false exit then
  508.   name_buffer .len @ over - name_buffer .addr @ +
  509.   over compare 0=
  510. ;
  511.  
  512. : loader_conf_files?
  513.   s" loader_conf_files" assignment_type?
  514. ;
  515.  
  516. : verbose_flag?
  517.   s" verbose_loading" assignment_type?
  518. ;
  519.  
  520. : execute?
  521.   s" exec" assignment_type?
  522. ;
  523.  
  524. : password?
  525.   s" password" assignment_type?
  526. ;
  527.  
  528. : module_load?
  529.   load_module_suffix suffix_type?
  530. ;
  531.  
  532. : module_loadname?
  533.   module_loadname_suffix suffix_type?
  534. ;
  535.  
  536. : module_type?
  537.   module_type_suffix suffix_type?
  538. ;
  539.  
  540. : module_args?
  541.   module_args_suffix suffix_type?
  542. ;
  543.  
  544. : module_beforeload?
  545.   module_beforeload_suffix suffix_type?
  546. ;
  547.  
  548. : module_afterload?
  549.   module_afterload_suffix suffix_type?
  550. ;
  551.  
  552. : module_loaderror?
  553.   module_loaderror_suffix suffix_type?
  554. ;
  555.  
  556. : set_conf_files
  557.   conf_files .addr @ ?dup if
  558.     free-memory
  559.   then
  560.   value_buffer .addr @ c@ [char] " = if
  561.     value_buffer .addr @ char+ value_buffer .len @ 2 chars -
  562.   else
  563.     value_buffer .addr @ value_buffer .len @
  564.   then
  565.   strdup
  566.   conf_files .len ! conf_files .addr !
  567. ;
  568.  
  569. : append_to_module_options_list  ( addr -- )
  570.   module_options @ 0= if
  571.     dup module_options !
  572.     last_module_option !
  573.   else
  574.     dup last_module_option @ module.next !
  575.     last_module_option !
  576.   then
  577. ;
  578.  
  579. : set_module_name  ( addr -- )
  580.   name_buffer .addr @ name_buffer .len @
  581.   strdup
  582.   >r over module.name .addr !
  583.   r> swap module.name .len !
  584. ;
  585.  
  586. : yes_value?
  587.   value_buffer .addr @ value_buffer .len @
  588.   2dup s' "YES"' compare >r
  589.   2dup s' "yes"' compare >r
  590.   2dup s" YES" compare >r
  591.   s" yes" compare r> r> r> and and and 0=
  592. ;
  593.  
  594. : find_module_option  ( -- addr | 0 )
  595.   module_options @
  596.   begin
  597.     dup
  598.   while
  599.     dup module.name dup .addr @ swap .len @
  600.     name_buffer .addr @ name_buffer .len @
  601.     compare 0= if exit then
  602.     module.next @
  603.   repeat
  604. ;
  605.  
  606. : new_module_option  ( -- addr )
  607.   sizeof module allocate if out_of_memory throw then
  608.   dup sizeof module erase
  609.   dup append_to_module_options_list
  610.   dup set_module_name
  611. ;
  612.  
  613. : get_module_option  ( -- addr )
  614.   find_module_option
  615.   ?dup 0= if new_module_option then
  616. ;
  617.  
  618. : set_module_flag
  619.   name_buffer .len @ load_module_suffix nip - name_buffer .len !
  620.   yes_value? get_module_option module.flag !
  621. ;
  622.  
  623. : set_module_args
  624.   name_buffer .len @ module_args_suffix nip - name_buffer .len !
  625.   get_module_option module.args
  626.   dup .addr @ ?dup if free-memory then
  627.   value_buffer .addr @ value_buffer .len @
  628.   over c@ [char] " = if
  629.     2 chars - swap char+ swap
  630.   then
  631.   strdup
  632.   >r over .addr !
  633.   r> swap .len !
  634. ;
  635.  
  636. : set_module_loadname
  637.   name_buffer .len @ module_loadname_suffix nip - name_buffer .len !
  638.   get_module_option module.loadname
  639.   dup .addr @ ?dup if free-memory then
  640.   value_buffer .addr @ value_buffer .len @
  641.   over c@ [char] " = if
  642.     2 chars - swap char+ swap
  643.   then
  644.   strdup
  645.   >r over .addr !
  646.   r> swap .len !
  647. ;
  648.  
  649. : set_module_type
  650.   name_buffer .len @ module_type_suffix nip - name_buffer .len !
  651.   get_module_option module.type
  652.   dup .addr @ ?dup if free-memory then
  653.   value_buffer .addr @ value_buffer .len @
  654.   over c@ [char] " = if
  655.     2 chars - swap char+ swap
  656.   then
  657.   strdup
  658.   >r over .addr !
  659.   r> swap .len !
  660. ;
  661.  
  662. : set_module_beforeload
  663.   name_buffer .len @ module_beforeload_suffix nip - name_buffer .len !
  664.   get_module_option module.beforeload
  665.   dup .addr @ ?dup if free-memory then
  666.   value_buffer .addr @ value_buffer .len @
  667.   over c@ [char] " = if
  668.     2 chars - swap char+ swap
  669.   then
  670.   strdup
  671.   >r over .addr !
  672.   r> swap .len !
  673. ;
  674.  
  675. : set_module_afterload
  676.   name_buffer .len @ module_afterload_suffix nip - name_buffer .len !
  677.   get_module_option module.afterload
  678.   dup .addr @ ?dup if free-memory then
  679.   value_buffer .addr @ value_buffer .len @
  680.   over c@ [char] " = if
  681.     2 chars - swap char+ swap
  682.   then
  683.   strdup
  684.   >r over .addr !
  685.   r> swap .len !
  686. ;
  687.  
  688. : set_module_loaderror
  689.   name_buffer .len @ module_loaderror_suffix nip - name_buffer .len !
  690.   get_module_option module.loaderror
  691.   dup .addr @ ?dup if free-memory then
  692.   value_buffer .addr @ value_buffer .len @
  693.   over c@ [char] " = if
  694.     2 chars - swap char+ swap
  695.   then
  696.   strdup
  697.   >r over .addr !
  698.   r> swap .len !
  699. ;
  700.  
  701. : set_environment_variable
  702.   name_buffer .len @
  703.   value_buffer .len @ +
  704.   5 chars +
  705.   allocate if out_of_memory throw then
  706.   dup 0  ( addr -- addr addr len )
  707.   s" set " strcat
  708.   name_buffer .addr @ name_buffer .len @ strcat
  709.   s" =" strcat
  710.   value_buffer .addr @ value_buffer .len @ strcat
  711.   ['] evaluate catch if
  712.     2drop free drop
  713.     set_error throw
  714.   else
  715.     free-memory
  716.   then
  717. ;
  718.  
  719. : set_verbose
  720.   yes_value? to verbose?
  721. ;
  722.  
  723. : execute_command
  724.   value_buffer .addr @ value_buffer .len @
  725.   over c@ [char] " = if
  726.     2 - swap char+ swap
  727.   then
  728.   ['] evaluate catch if exec_error throw then
  729. ;
  730.  
  731. : set_password
  732.   password .addr @ ?dup if free if free_error throw then then
  733.   value_buffer .addr @ c@ [char] " = if
  734.     value_buffer .addr @ char+ value_buffer .len @ 2 - strdup
  735.     value_buffer .addr @ free if free_error throw then
  736.   else
  737.     value_buffer .addr @ value_buffer .len @
  738.   then
  739.   password .len ! password .addr !
  740.   0 value_buffer .addr !
  741. ;
  742.  
  743. : process_assignment
  744.   name_buffer .len @ 0= if exit then
  745.   loader_conf_files?    if set_conf_files exit then
  746.   verbose_flag?        if set_verbose exit then
  747.   execute?        if execute_command exit then
  748.   password?        if set_password exit then
  749.   module_load?        if set_module_flag exit then
  750.   module_loadname?    if set_module_loadname exit then
  751.   module_type?        if set_module_type exit then
  752.   module_args?        if set_module_args exit then
  753.   module_beforeload?    if set_module_beforeload exit then
  754.   module_afterload?    if set_module_afterload exit then
  755.   module_loaderror?    if set_module_loaderror exit then
  756.   set_environment_variable
  757. ;
  758.  
  759. \ free_buffer  ( -- )
  760. \
  761. \ Free some pointers if needed. The code then tests for errors
  762. \ in freeing, and throws an exception if needed. If a pointer is
  763. \ not allocated, it's value (0) is used as flag.
  764.  
  765. : free_buffers
  766.   line_buffer .addr @ dup if free then
  767.   name_buffer .addr @ dup if free then
  768.   value_buffer .addr @ dup if free then
  769.   or or if free_error throw then
  770. ;
  771.  
  772. : reset_assignment_buffers
  773.   0 name_buffer .addr !
  774.   0 name_buffer .len !
  775.   0 value_buffer .addr !
  776.   0 value_buffer .len !
  777. ;
  778.  
  779. \ Higher level file processing
  780.  
  781. : process_conf
  782.   begin
  783.     end_of_file? 0=
  784.   while
  785.     reset_assignment_buffers
  786.     read_line
  787.     get_assignment
  788.     ['] process_assignment catch
  789.     ['] free_buffers catch
  790.     swap throw throw
  791.   repeat
  792. ;
  793.  
  794. : create_null_terminated_string  { addr len -- addr' len }
  795.   len char+ allocate if out_of_memory throw then
  796.   >r
  797.   addr r@ len move
  798.   0 r@ len + c!
  799.   r> len
  800. ;
  801.  
  802. \ Interface to loading conf files
  803.  
  804. : load_conf  ( addr len -- )
  805.   0 to end_of_file?
  806.   0 to read_buffer_ptr
  807.   create_null_terminated_string
  808.   over >r
  809.   fopen fd !
  810.   r> free-memory
  811.   fd @ -1 = if open_error throw then
  812.   ['] process_conf catch
  813.   fd @ fclose
  814.   throw
  815. ;
  816.  
  817. : initialize_support
  818.   0 read_buffer .addr !
  819.   0 conf_files .addr !
  820.   0 password .addr !
  821.   0 module_options !
  822.   0 last_module_option !
  823.   0 to verbose?
  824. ;
  825.  
  826. : print_line
  827.   line_buffer .addr @ line_buffer .len @ type cr
  828. ;
  829.  
  830. : print_syntax_error
  831.   line_buffer .addr @ line_buffer .len @ type cr
  832.   line_buffer .addr @
  833.   begin
  834.     line_pointer over <>
  835.   while
  836.     bl emit
  837.     char+
  838.   repeat
  839.   drop
  840.   ." ^" cr
  841. ;
  842.  
  843. \ Depuration support functions
  844.  
  845. only forth definitions also support-functions
  846.  
  847. : test-file 
  848.   ['] load_conf catch dup .
  849.   syntax_error = if cr print_syntax_error then
  850. ;
  851.  
  852. : show-module-options
  853.   module_options @
  854.   begin
  855.     ?dup
  856.   while
  857.     ." Name: " dup module.name dup .addr @ swap .len @ type cr
  858.     ." Path: " dup module.loadname dup .addr @ swap .len @ type cr
  859.     ." Type: " dup module.type dup .addr @ swap .len @ type cr
  860.     ." Flags: " dup module.args dup .addr @ swap .len @ type cr
  861.     ." Before load: " dup module.beforeload dup .addr @ swap .len @ type cr
  862.     ." After load: " dup module.afterload dup .addr @ swap .len @ type cr
  863.     ." Error: " dup module.loaderror dup .addr @ swap .len @ type cr
  864.     ." Status: " dup module.flag @ if ." Load" else ." Don't load" then cr
  865.     module.next @
  866.   repeat
  867. ;
  868.  
  869. only forth also support-functions definitions
  870.  
  871. \ Variables used for processing multiple conf files
  872.  
  873. string current_file_name
  874. variable current_conf_files
  875.  
  876. \ Indicates if any conf file was succesfully read
  877.  
  878. 0 value any_conf_read?
  879.  
  880. \ loader_conf_files processing support functions
  881.  
  882. : set_current_conf_files
  883.   conf_files .addr @ current_conf_files !
  884. ;
  885.  
  886. : get_conf_files
  887.   conf_files .addr @ conf_files .len @ strdup
  888. ;
  889.  
  890. : recurse_on_conf_files?
  891.   current_conf_files @ conf_files .addr @ <>
  892. ;
  893.  
  894. : skip_leading_spaces  { addr len pos -- addr len pos' }
  895.   begin
  896.     pos len = if addr len pos exit then
  897.     addr pos + c@ bl =
  898.   while
  899.     pos char+ to pos
  900.   repeat
  901.   addr len pos
  902. ;
  903.  
  904. : get_file_name  { addr len pos -- addr len pos' addr' len' || 0 }
  905.   pos len = if 
  906.     addr free abort" Fatal error freeing memory"
  907.     0 exit
  908.   then
  909.   pos >r
  910.   begin
  911.     addr pos + c@ bl <>
  912.   while
  913.     pos char+ to pos
  914.     pos len = if
  915.       addr len pos addr r@ + pos r> - exit
  916.     then
  917.   repeat
  918.   addr len pos addr r@ + pos r> -
  919. ;
  920.  
  921. : get_next_file  ( addr len ptr -- addr len ptr' addr' len' | 0 )
  922.   skip_leading_spaces
  923.   get_file_name
  924. ;
  925.  
  926. : set_current_file_name
  927.   over current_file_name .addr !
  928.   dup current_file_name .len !
  929. ;
  930.  
  931. : print_current_file
  932.   current_file_name .addr @ current_file_name .len @ type
  933. ;
  934.  
  935. : process_conf_errors
  936.   dup 0= if true to any_conf_read? drop exit then
  937.   >r 2drop r>
  938.   dup syntax_error = if
  939.     ." Warning: syntax error on file " print_current_file cr
  940.     print_syntax_error drop exit
  941.   then
  942.   dup set_error = if
  943.     ." Warning: bad definition on file " print_current_file cr
  944.     print_line drop exit
  945.   then
  946.   dup read_error = if
  947.     ." Warning: error reading file " print_current_file cr drop exit
  948.   then
  949.   dup open_error = if
  950.     verbose? if ." Warning: unable to open file " print_current_file cr then
  951.     drop exit
  952.   then
  953.   dup free_error = abort" Fatal error freeing memory"
  954.   dup out_of_memory = abort" Out of memory"
  955.   throw  \ Unknown error -- pass ahead
  956. ;
  957.  
  958. \ Process loader_conf_files recursively
  959. \ Interface to loader_conf_files processing
  960.  
  961. : include_conf_files
  962.   set_current_conf_files
  963.   get_conf_files 0
  964.   begin
  965.     get_next_file ?dup
  966.   while
  967.     set_current_file_name
  968.     ['] load_conf catch
  969.     process_conf_errors
  970.     recurse_on_conf_files? if recurse then
  971.   repeat
  972. ;
  973.  
  974. \ Module loading functions
  975.  
  976. : load_module?
  977.   module.flag @
  978. ;
  979.  
  980. : load_parameters  ( addr -- addr addrN lenN ... addr1 len1 N )
  981.   dup >r
  982.   r@ module.args .addr @ r@ module.args .len @
  983.   r@ module.loadname .len @ if
  984.     r@ module.loadname .addr @ r@ module.loadname .len @
  985.   else
  986.     r@ module.name .addr @ r@ module.name .len @
  987.   then
  988.   r@ module.type .len @ if
  989.     r@ module.type .addr @ r@ module.type .len @
  990.     s" -t "
  991.     4 ( -t type name flags )
  992.   else
  993.     2 ( name flags )
  994.   then
  995.   r> drop
  996. ;
  997.  
  998. : before_load  ( addr -- addr )
  999.   dup module.beforeload .len @ if
  1000.     dup module.beforeload .addr @ over module.beforeload .len @
  1001.     ['] evaluate catch if before_load_error throw then
  1002.   then
  1003. ;
  1004.  
  1005. : after_load  ( addr -- addr )
  1006.   dup module.afterload .len @ if
  1007.     dup module.afterload .addr @ over module.afterload .len @
  1008.     ['] evaluate catch if after_load_error throw then
  1009.   then
  1010. ;
  1011.  
  1012. : load_error  ( addr -- addr )
  1013.   dup module.loaderror .len @ if
  1014.     dup module.loaderror .addr @ over module.loaderror .len @
  1015.     evaluate  \ This we do not intercept so it can throw errors
  1016.   then
  1017. ;
  1018.  
  1019. : pre_load_message  ( addr -- addr )
  1020.   verbose? if
  1021.     dup module.name .addr @ over module.name .len @ type
  1022.     ." ..."
  1023.   then
  1024. ;
  1025.  
  1026. : load_error_message verbose? if ." failed!" cr then ;
  1027.  
  1028. : load_succesful_message verbose? if ." ok" cr then ;
  1029.  
  1030. : load_module
  1031.   load_parameters load
  1032. ;
  1033.  
  1034. : process_module  ( addr -- addr )
  1035.   pre_load_message
  1036.   before_load
  1037.   begin
  1038.     ['] load_module catch if
  1039.       dup module.loaderror .len @ if
  1040.         load_error            \ Command should return a flag!
  1041.       else 
  1042.         load_error_message true        \ Do not retry
  1043.       then
  1044.     else
  1045.       after_load
  1046.       load_succesful_message true    \ Succesful, do not retry
  1047.     then
  1048.   until
  1049. ;
  1050.  
  1051. : process_module_errors  ( addr ior -- )
  1052.   dup before_load_error = if
  1053.     drop
  1054.     ." Module "
  1055.     dup module.name .addr @ over module.name .len @ type
  1056.     dup module.loadname .len @ if
  1057.       ." (" dup module.loadname .addr @ over module.loadname .len @ type ." )"
  1058.     then
  1059.     cr
  1060.     ." Error executing "
  1061.     dup module.beforeload .addr @ over module.afterload .len @ type cr
  1062.     abort
  1063.   then
  1064.  
  1065.   dup after_load_error = if
  1066.     drop
  1067.     ." Module "
  1068.     dup module.name .addr @ over module.name .len @ type
  1069.     dup module.loadname .len @ if
  1070.       ." (" dup module.loadname .addr @ over module.loadname .len @ type ." )"
  1071.     then
  1072.     cr
  1073.     ." Error executing "
  1074.     dup module.afterload .addr @ over module.afterload .len @ type cr
  1075.     abort
  1076.   then
  1077.  
  1078.   throw  \ Don't know what it is all about -- pass ahead
  1079. ;
  1080.  
  1081. \ Module loading interface
  1082.  
  1083. : load_modules  ( -- ) ( throws: abort & user-defined )
  1084.   module_options @
  1085.   begin
  1086.     ?dup
  1087.   while
  1088.     dup load_module? if
  1089.       ['] process_module catch
  1090.       process_module_errors
  1091.     then
  1092.     module.next @
  1093.   repeat
  1094. ;
  1095.  
  1096. \ Additional functions used in "start"
  1097.  
  1098. : initialize  ( addr len -- )
  1099.   initialize_support
  1100.   strdup conf_files .len ! conf_files .addr !
  1101. ;
  1102.  
  1103. : load_kernel  ( -- ) ( throws: abort )
  1104.   s" load ${kernel} ${kernel_options}" ['] evaluate catch
  1105.   if s" echo Unable to load kernel: ${kernel_name}" evaluate abort then
  1106. ;
  1107.  
  1108. : read-password { size | buf len -- }
  1109.   size allocate if out_of_memory throw then
  1110.   to buf
  1111.   0 to len
  1112.   begin
  1113.     key
  1114.     dup backspace = if
  1115.       drop
  1116.       len if
  1117.         backspace emit bl emit backspace emit
  1118.         len 1 - to len
  1119.       else
  1120.         bell emit
  1121.       then
  1122.     else
  1123.       dup <cr> = if cr drop buf len exit then
  1124.       [char] * emit
  1125.       len size < if
  1126.         buf len chars + c!
  1127.       else
  1128.         drop
  1129.       then
  1130.       len 1+ to len
  1131.     then
  1132.   again
  1133. ;
  1134.  
  1135. \ Go back to straight forth vocabulary
  1136.  
  1137. only forth also definitions
  1138.  
  1139.