PageRenderTime 63ms CodeModel.GetById 26ms RepoModel.GetById 0ms app.codeStats 1ms

/SBUNIX-C-H/rootfs/boot/support.4th

https://github.com/Dexhub/Course-Project---OS-Integration
Forth | 1529 lines | 1293 code | 236 blank | 0 comment | 117 complexity | 174a0670659c4a79a459d15d280c740a MD5 | raw file
Possible License(s): BSD-3-Clause
  1. \ Copyright (c) 1999 Daniel C. Sobral <dcs@freebsd.org>
  2. \ All rights reserved.
  3. \
  4. \ Redistribution and use in source and binary forms, with or without
  5. \ modification, are permitted provided that the following conditions
  6. \ are met:
  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.
  12. \
  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
  23. \ SUCH DAMAGE.
  24. \
  25. \ $FreeBSD: release/9.1.0/sys/boot/forth/support.4th 222417 2011-05-28 08:50:38Z julian $
  26. \ Loader.rc support functions:
  27. \
  28. \ initialize ( addr len -- ) as above, plus load_conf_files
  29. \ load_conf ( addr len -- ) load conf file given
  30. \ include_conf_files ( -- ) load all conf files in load_conf_files
  31. \ print_syntax_error ( -- ) print line and marker of where a syntax
  32. \ error was detected
  33. \ print_line ( -- ) print last line processed
  34. \ load_kernel ( -- ) load kernel
  35. \ load_modules ( -- ) load modules flagged
  36. \
  37. \ Exported structures:
  38. \
  39. \ string counted string structure
  40. \ cell .addr string address
  41. \ cell .len string length
  42. \ module module loading information structure
  43. \ cell module.flag should we load it?
  44. \ string module.name module's name
  45. \ string module.loadname name to be used in loading the module
  46. \ string module.type module's type
  47. \ string module.args flags to be passed during load
  48. \ string module.beforeload command to be executed before load
  49. \ string module.afterload command to be executed after load
  50. \ string module.loaderror command to be executed if load fails
  51. \ cell module.next list chain
  52. \
  53. \ Exported global variables;
  54. \
  55. \ string conf_files configuration files to be loaded
  56. \ cell modules_options pointer to first module information
  57. \ value verbose? indicates if user wants a verbose loading
  58. \ value any_conf_read? indicates if a conf file was succesfully read
  59. \
  60. \ Other exported words:
  61. \ note, strlen is internal
  62. \ strdup ( addr len -- addr' len) similar to strdup(3)
  63. \ strcat ( addr len addr' len' -- addr len+len' ) similar to strcat(3)
  64. \ s' ( | string' -- addr len | ) similar to s"
  65. \ rudimentary structure support
  66. \ Exception values
  67. 1 constant ESYNTAX
  68. 2 constant ENOMEM
  69. 3 constant EFREE
  70. 4 constant ESETERROR \ error setting environment variable
  71. 5 constant EREAD \ error reading
  72. 6 constant EOPEN
  73. 7 constant EEXEC \ XXX never catched
  74. 8 constant EBEFORELOAD
  75. 9 constant EAFTERLOAD
  76. \ I/O constants
  77. 0 constant SEEK_SET
  78. 1 constant SEEK_CUR
  79. 2 constant SEEK_END
  80. 0 constant O_RDONLY
  81. 1 constant O_WRONLY
  82. 2 constant O_RDWR
  83. \ Crude structure support
  84. : structure:
  85. create here 0 , ['] drop , 0
  86. does> create here swap dup @ allot cell+ @ execute
  87. ;
  88. : member: create dup , over , + does> cell+ @ + ;
  89. : ;structure swap ! ;
  90. : constructor! >body cell+ ! ;
  91. : constructor: over :noname ;
  92. : ;constructor postpone ; swap cell+ ! ; immediate
  93. : sizeof ' >body @ state @ if postpone literal then ; immediate
  94. : offsetof ' >body cell+ @ state @ if postpone literal then ; immediate
  95. : ptr 1 cells member: ;
  96. : int 1 cells member: ;
  97. \ String structure
  98. structure: string
  99. ptr .addr
  100. int .len
  101. constructor:
  102. 0 over .addr !
  103. 0 swap .len !
  104. ;constructor
  105. ;structure
  106. \ Module options linked list
  107. structure: module
  108. int module.flag
  109. sizeof string member: module.name
  110. sizeof string member: module.loadname
  111. sizeof string member: module.type
  112. sizeof string member: module.args
  113. sizeof string member: module.beforeload
  114. sizeof string member: module.afterload
  115. sizeof string member: module.loaderror
  116. ptr module.next
  117. ;structure
  118. \ Internal loader structures (preloaded_file, kernel_module, file_metadata)
  119. \ must be in sync with the C struct in sys/boot/common/bootstrap.h
  120. structure: preloaded_file
  121. ptr pf.name
  122. ptr pf.type
  123. ptr pf.args
  124. ptr pf.metadata \ file_metadata
  125. int pf.loader
  126. int pf.addr
  127. int pf.size
  128. ptr pf.modules \ kernel_module
  129. ptr pf.next \ preloaded_file
  130. ;structure
  131. structure: kernel_module
  132. ptr km.name
  133. \ ptr km.args
  134. ptr km.fp \ preloaded_file
  135. ptr km.next \ kernel_module
  136. ;structure
  137. structure: file_metadata
  138. int md.size
  139. 2 member: md.type \ this is not ANS Forth compatible (XXX)
  140. ptr md.next \ file_metadata
  141. 0 member: md.data \ variable size
  142. ;structure
  143. \ end of structures
  144. \ Global variables
  145. string conf_files
  146. string nextboot_conf_file
  147. create module_options sizeof module.next allot 0 module_options !
  148. create last_module_option sizeof module.next allot 0 last_module_option !
  149. 0 value verbose?
  150. 0 value nextboot?
  151. \ Support string functions
  152. : strdup { addr len -- addr' len' }
  153. len allocate if ENOMEM throw then
  154. addr over len move len
  155. ;
  156. : strcat { addr len addr' len' -- addr len+len' }
  157. addr' addr len + len' move
  158. addr len len' +
  159. ;
  160. : strchr { addr len c -- addr' len' }
  161. begin
  162. len
  163. while
  164. addr c@ c = if addr len exit then
  165. addr 1 + to addr
  166. len 1 - to len
  167. repeat
  168. 0 0
  169. ;
  170. : s' \ same as s", allows " in the string
  171. [char] ' parse
  172. state @ if postpone sliteral then
  173. ; immediate
  174. : 2>r postpone >r postpone >r ; immediate
  175. : 2r> postpone r> postpone r> ; immediate
  176. : 2r@ postpone 2r> postpone 2dup postpone 2>r ; immediate
  177. : getenv? getenv -1 = if false else drop true then ;
  178. \ Private definitions
  179. vocabulary support-functions
  180. only forth also support-functions definitions
  181. \ Some control characters constants
  182. 7 constant bell
  183. 8 constant backspace
  184. 9 constant tab
  185. 10 constant lf
  186. 13 constant <cr>
  187. \ Read buffer size
  188. 80 constant read_buffer_size
  189. \ Standard suffixes
  190. : load_module_suffix s" _load" ;
  191. : module_loadname_suffix s" _name" ;
  192. : module_type_suffix s" _type" ;
  193. : module_args_suffix s" _flags" ;
  194. : module_beforeload_suffix s" _before" ;
  195. : module_afterload_suffix s" _after" ;
  196. : module_loaderror_suffix s" _error" ;
  197. \ Support operators
  198. : >= < 0= ;
  199. : <= > 0= ;
  200. \ Assorted support functions
  201. : free-memory free if EFREE throw then ;
  202. : strget { var -- addr len } var .addr @ var .len @ ;
  203. \ assign addr len to variable.
  204. : strset { addr len var -- } addr var .addr ! len var .len ! ;
  205. \ free memory and reset fields
  206. : strfree { var -- } var .addr @ ?dup if free-memory 0 0 var strset then ;
  207. \ free old content, make a copy of the string and assign to variable
  208. : string= { addr len var -- } var strfree addr len strdup var strset ;
  209. : strtype ( str -- ) strget type ;
  210. \ assign a reference to what is on the stack
  211. : strref { addr len var -- addr len }
  212. addr var .addr ! len var .len ! addr len
  213. ;
  214. \ unquote a string
  215. : unquote ( addr len -- addr len )
  216. over c@ [char] " = if 2 chars - swap char+ swap then
  217. ;
  218. \ Assignment data temporary storage
  219. string name_buffer
  220. string value_buffer
  221. \ Line by line file reading functions
  222. \
  223. \ exported:
  224. \ line_buffer
  225. \ end_of_file?
  226. \ fd
  227. \ read_line
  228. \ reset_line_reading
  229. vocabulary line-reading
  230. also line-reading definitions also
  231. \ File data temporary storage
  232. string read_buffer
  233. 0 value read_buffer_ptr
  234. \ File's line reading function
  235. support-functions definitions
  236. string line_buffer
  237. 0 value end_of_file?
  238. variable fd
  239. line-reading definitions
  240. : skip_newlines
  241. begin
  242. read_buffer .len @ read_buffer_ptr >
  243. while
  244. read_buffer .addr @ read_buffer_ptr + c@ lf = if
  245. read_buffer_ptr char+ to read_buffer_ptr
  246. else
  247. exit
  248. then
  249. repeat
  250. ;
  251. : scan_buffer ( -- addr len )
  252. read_buffer_ptr >r
  253. begin
  254. read_buffer .len @ r@ >
  255. while
  256. read_buffer .addr @ r@ + c@ lf = if
  257. read_buffer .addr @ read_buffer_ptr + ( -- addr )
  258. r@ read_buffer_ptr - ( -- len )
  259. r> to read_buffer_ptr
  260. exit
  261. then
  262. r> char+ >r
  263. repeat
  264. read_buffer .addr @ read_buffer_ptr + ( -- addr )
  265. r@ read_buffer_ptr - ( -- len )
  266. r> to read_buffer_ptr
  267. ;
  268. : line_buffer_resize ( len -- len )
  269. >r
  270. line_buffer .len @ if
  271. line_buffer .addr @
  272. line_buffer .len @ r@ +
  273. resize if ENOMEM throw then
  274. else
  275. r@ allocate if ENOMEM throw then
  276. then
  277. line_buffer .addr !
  278. r>
  279. ;
  280. : append_to_line_buffer ( addr len -- )
  281. line_buffer strget
  282. 2swap strcat
  283. line_buffer .len !
  284. drop
  285. ;
  286. : read_from_buffer
  287. scan_buffer ( -- addr len )
  288. line_buffer_resize ( len -- len )
  289. append_to_line_buffer ( addr len -- )
  290. ;
  291. : refill_required?
  292. read_buffer .len @ read_buffer_ptr =
  293. end_of_file? 0= and
  294. ;
  295. : refill_buffer
  296. 0 to read_buffer_ptr
  297. read_buffer .addr @ 0= if
  298. read_buffer_size allocate if ENOMEM throw then
  299. read_buffer .addr !
  300. then
  301. fd @ read_buffer .addr @ read_buffer_size fread
  302. dup -1 = if EREAD throw then
  303. dup 0= if true to end_of_file? then
  304. read_buffer .len !
  305. ;
  306. support-functions definitions
  307. : reset_line_reading
  308. 0 to read_buffer_ptr
  309. ;
  310. : read_line
  311. line_buffer strfree
  312. skip_newlines
  313. begin
  314. read_from_buffer
  315. refill_required?
  316. while
  317. refill_buffer
  318. repeat
  319. ;
  320. only forth also support-functions definitions
  321. \ Conf file line parser:
  322. \ <line> ::= <spaces><name><spaces>'='<spaces><value><spaces>[<comment>] |
  323. \ <spaces>[<comment>]
  324. \ <name> ::= <letter>{<letter>|<digit>|'_'}
  325. \ <value> ::= '"'{<character_set>|'\'<anything>}'"' | <name>
  326. \ <character_set> ::= ASCII 32 to 126, except '\' and '"'
  327. \ <comment> ::= '#'{<anything>}
  328. \
  329. \ exported:
  330. \ line_pointer
  331. \ process_conf
  332. 0 value line_pointer
  333. vocabulary file-processing
  334. also file-processing definitions
  335. \ parser functions
  336. \
  337. \ exported:
  338. \ get_assignment
  339. vocabulary parser
  340. also parser definitions also
  341. 0 value parsing_function
  342. 0 value end_of_line
  343. : end_of_line? line_pointer end_of_line = ;
  344. \ classifiers for various character classes in the input line
  345. : letter?
  346. line_pointer c@ >r
  347. r@ [char] A >=
  348. r@ [char] Z <= and
  349. r@ [char] a >=
  350. r> [char] z <= and
  351. or
  352. ;
  353. : digit?
  354. line_pointer c@ >r
  355. r@ [char] - =
  356. r@ [char] 0 >=
  357. r> [char] 9 <= and
  358. or
  359. ;
  360. : quote? line_pointer c@ [char] " = ;
  361. : assignment_sign? line_pointer c@ [char] = = ;
  362. : comment? line_pointer c@ [char] # = ;
  363. : space? line_pointer c@ bl = line_pointer c@ tab = or ;
  364. : backslash? line_pointer c@ [char] \ = ;
  365. : underscore? line_pointer c@ [char] _ = ;
  366. : dot? line_pointer c@ [char] . = ;
  367. \ manipulation of input line
  368. : skip_character line_pointer char+ to line_pointer ;
  369. : skip_to_end_of_line end_of_line to line_pointer ;
  370. : eat_space
  371. begin
  372. end_of_line? if 0 else space? then
  373. while
  374. skip_character
  375. repeat
  376. ;
  377. : parse_name ( -- addr len )
  378. line_pointer
  379. begin
  380. end_of_line? if 0 else letter? digit? underscore? dot? or or or then
  381. while
  382. skip_character
  383. repeat
  384. line_pointer over -
  385. strdup
  386. ;
  387. : remove_backslashes { addr len | addr' len' -- addr' len' }
  388. len allocate if ENOMEM 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. : parse_quote ( -- addr len )
  403. line_pointer
  404. skip_character
  405. end_of_line? if ESYNTAX throw then
  406. begin
  407. quote? 0=
  408. while
  409. backslash? if
  410. skip_character
  411. end_of_line? if ESYNTAX throw then
  412. then
  413. skip_character
  414. end_of_line? if ESYNTAX throw then
  415. repeat
  416. skip_character
  417. line_pointer over -
  418. remove_backslashes
  419. ;
  420. : read_name
  421. parse_name ( -- addr len )
  422. name_buffer strset
  423. ;
  424. : read_value
  425. quote? if
  426. parse_quote ( -- addr len )
  427. else
  428. parse_name ( -- addr len )
  429. then
  430. value_buffer strset
  431. ;
  432. : comment
  433. skip_to_end_of_line
  434. ;
  435. : white_space_4
  436. eat_space
  437. comment? if ['] comment to parsing_function exit then
  438. end_of_line? 0= if ESYNTAX throw then
  439. ;
  440. : variable_value
  441. read_value
  442. ['] white_space_4 to parsing_function
  443. ;
  444. : white_space_3
  445. eat_space
  446. letter? digit? quote? or or if
  447. ['] variable_value to parsing_function exit
  448. then
  449. ESYNTAX throw
  450. ;
  451. : assignment_sign
  452. skip_character
  453. ['] white_space_3 to parsing_function
  454. ;
  455. : white_space_2
  456. eat_space
  457. assignment_sign? if ['] assignment_sign to parsing_function exit then
  458. ESYNTAX throw
  459. ;
  460. : variable_name
  461. read_name
  462. ['] white_space_2 to parsing_function
  463. ;
  464. : white_space_1
  465. eat_space
  466. letter? if ['] variable_name to parsing_function exit then
  467. comment? if ['] comment to parsing_function exit then
  468. end_of_line? 0= if ESYNTAX throw then
  469. ;
  470. file-processing definitions
  471. : get_assignment
  472. line_buffer strget + to end_of_line
  473. line_buffer .addr @ to line_pointer
  474. ['] white_space_1 to parsing_function
  475. begin
  476. end_of_line? 0=
  477. while
  478. parsing_function execute
  479. repeat
  480. parsing_function ['] comment =
  481. parsing_function ['] white_space_1 =
  482. parsing_function ['] white_space_4 =
  483. or or 0= if ESYNTAX throw then
  484. ;
  485. only forth also support-functions also file-processing definitions also
  486. \ Process line
  487. : assignment_type? ( addr len -- flag )
  488. name_buffer strget
  489. compare 0=
  490. ;
  491. : suffix_type? ( addr len -- flag )
  492. name_buffer .len @ over <= if 2drop false exit then
  493. name_buffer .len @ over - name_buffer .addr @ +
  494. over compare 0=
  495. ;
  496. : loader_conf_files? s" loader_conf_files" assignment_type? ;
  497. : nextboot_flag? s" nextboot_enable" assignment_type? ;
  498. : nextboot_conf? s" nextboot_conf" assignment_type? ;
  499. : verbose_flag? s" verbose_loading" assignment_type? ;
  500. : execute? s" exec" assignment_type? ;
  501. : module_load? load_module_suffix suffix_type? ;
  502. : module_loadname? module_loadname_suffix suffix_type? ;
  503. : module_type? module_type_suffix suffix_type? ;
  504. : module_args? module_args_suffix suffix_type? ;
  505. : module_beforeload? module_beforeload_suffix suffix_type? ;
  506. : module_afterload? module_afterload_suffix suffix_type? ;
  507. : module_loaderror? module_loaderror_suffix suffix_type? ;
  508. \ build a 'set' statement and execute it
  509. : set_environment_variable
  510. name_buffer .len @ value_buffer .len @ + 5 chars + \ size of result string
  511. allocate if ENOMEM throw then
  512. dup 0 \ start with an empty string and append the pieces
  513. s" set " strcat
  514. name_buffer strget strcat
  515. s" =" strcat
  516. value_buffer strget strcat
  517. ['] evaluate catch if
  518. 2drop free drop
  519. ESETERROR throw
  520. else
  521. free-memory
  522. then
  523. ;
  524. : set_conf_files
  525. set_environment_variable
  526. s" loader_conf_files" getenv conf_files string=
  527. ;
  528. : set_nextboot_conf \ XXX maybe do as set_conf_files ?
  529. value_buffer strget unquote nextboot_conf_file string=
  530. ;
  531. : append_to_module_options_list ( addr -- )
  532. module_options @ 0= if
  533. dup module_options !
  534. last_module_option !
  535. else
  536. dup last_module_option @ module.next !
  537. last_module_option !
  538. then
  539. ;
  540. : set_module_name { addr -- } \ check leaks
  541. name_buffer strget addr module.name string=
  542. ;
  543. : yes_value?
  544. value_buffer strget \ XXX could use unquote
  545. 2dup s' "YES"' compare >r
  546. 2dup s' "yes"' compare >r
  547. 2dup s" YES" compare >r
  548. s" yes" compare r> r> r> and and and 0=
  549. ;
  550. : find_module_option ( -- addr | 0 ) \ return ptr to entry matching name_buffer
  551. module_options @
  552. begin
  553. dup
  554. while
  555. dup module.name strget
  556. name_buffer strget
  557. compare 0= if exit then
  558. module.next @
  559. repeat
  560. ;
  561. : new_module_option ( -- addr )
  562. sizeof module allocate if ENOMEM throw then
  563. dup sizeof module erase
  564. dup append_to_module_options_list
  565. dup set_module_name
  566. ;
  567. : get_module_option ( -- addr )
  568. find_module_option
  569. ?dup 0= if new_module_option then
  570. ;
  571. : set_module_flag
  572. name_buffer .len @ load_module_suffix nip - name_buffer .len !
  573. yes_value? get_module_option module.flag !
  574. ;
  575. : set_module_args
  576. name_buffer .len @ module_args_suffix nip - name_buffer .len !
  577. value_buffer strget unquote
  578. get_module_option module.args string=
  579. ;
  580. : set_module_loadname
  581. name_buffer .len @ module_loadname_suffix nip - name_buffer .len !
  582. value_buffer strget unquote
  583. get_module_option module.loadname string=
  584. ;
  585. : set_module_type
  586. name_buffer .len @ module_type_suffix nip - name_buffer .len !
  587. value_buffer strget unquote
  588. get_module_option module.type string=
  589. ;
  590. : set_module_beforeload
  591. name_buffer .len @ module_beforeload_suffix nip - name_buffer .len !
  592. value_buffer strget unquote
  593. get_module_option module.beforeload string=
  594. ;
  595. : set_module_afterload
  596. name_buffer .len @ module_afterload_suffix nip - name_buffer .len !
  597. value_buffer strget unquote
  598. get_module_option module.afterload string=
  599. ;
  600. : set_module_loaderror
  601. name_buffer .len @ module_loaderror_suffix nip - name_buffer .len !
  602. value_buffer strget unquote
  603. get_module_option module.loaderror string=
  604. ;
  605. : set_nextboot_flag
  606. yes_value? to nextboot?
  607. ;
  608. : set_verbose
  609. yes_value? to verbose?
  610. ;
  611. : execute_command
  612. value_buffer strget unquote
  613. ['] evaluate catch if EEXEC throw then
  614. ;
  615. : process_assignment
  616. name_buffer .len @ 0= if exit then
  617. loader_conf_files? if set_conf_files exit then
  618. nextboot_flag? if set_nextboot_flag exit then
  619. nextboot_conf? if set_nextboot_conf exit then
  620. verbose_flag? if set_verbose exit then
  621. execute? if execute_command exit then
  622. module_load? if set_module_flag exit then
  623. module_loadname? if set_module_loadname exit then
  624. module_type? if set_module_type exit then
  625. module_args? if set_module_args exit then
  626. module_beforeload? if set_module_beforeload exit then
  627. module_afterload? if set_module_afterload exit then
  628. module_loaderror? if set_module_loaderror exit then
  629. set_environment_variable
  630. ;
  631. \ free_buffer ( -- )
  632. \
  633. \ Free some pointers if needed. The code then tests for errors
  634. \ in freeing, and throws an exception if needed. If a pointer is
  635. \ not allocated, it's value (0) is used as flag.
  636. : free_buffers
  637. name_buffer strfree
  638. value_buffer strfree
  639. ;
  640. \ Higher level file processing
  641. support-functions definitions
  642. : process_conf
  643. begin
  644. end_of_file? 0=
  645. while
  646. free_buffers
  647. read_line
  648. get_assignment
  649. ['] process_assignment catch
  650. ['] free_buffers catch
  651. swap throw throw
  652. repeat
  653. ;
  654. : peek_file
  655. 0 to end_of_file?
  656. reset_line_reading
  657. O_RDONLY fopen fd !
  658. fd @ -1 = if EOPEN throw then
  659. free_buffers
  660. read_line
  661. get_assignment
  662. ['] process_assignment catch
  663. ['] free_buffers catch
  664. fd @ fclose
  665. ;
  666. only forth also support-functions definitions
  667. \ Interface to loading conf files
  668. : load_conf ( addr len -- )
  669. \ ." ----- Trying conf " 2dup type cr \ debugging
  670. 0 to end_of_file?
  671. reset_line_reading
  672. O_RDONLY fopen fd !
  673. fd @ -1 = if EOPEN throw then
  674. ['] process_conf catch
  675. fd @ fclose
  676. throw
  677. ;
  678. : print_line line_buffer strtype cr ;
  679. : print_syntax_error
  680. line_buffer strtype cr
  681. line_buffer .addr @
  682. begin
  683. line_pointer over <>
  684. while
  685. bl emit char+
  686. repeat
  687. drop
  688. ." ^" cr
  689. ;
  690. \ Debugging support functions
  691. only forth definitions also support-functions
  692. : test-file
  693. ['] load_conf catch dup .
  694. ESYNTAX = if cr print_syntax_error then
  695. ;
  696. \ find a module name, leave addr on the stack (0 if not found)
  697. : find-module ( <module> -- ptr | 0 )
  698. bl parse ( addr len )
  699. module_options @ >r ( store current pointer )
  700. begin
  701. r@
  702. while
  703. 2dup ( addr len addr len )
  704. r@ module.name strget
  705. compare 0= if drop drop r> exit then ( found it )
  706. r> module.next @ >r
  707. repeat
  708. type ." was not found" cr r>
  709. ;
  710. : show-nonempty ( addr len mod -- )
  711. strget dup verbose? or if
  712. 2swap type type cr
  713. else
  714. drop drop drop drop
  715. then ;
  716. : show-one-module { addr -- addr }
  717. ." Name: " addr module.name strtype cr
  718. s" Path: " addr module.loadname show-nonempty
  719. s" Type: " addr module.type show-nonempty
  720. s" Flags: " addr module.args show-nonempty
  721. s" Before load: " addr module.beforeload show-nonempty
  722. s" After load: " addr module.afterload show-nonempty
  723. s" Error: " addr module.loaderror show-nonempty
  724. ." Status: " addr module.flag @ if ." Load" else ." Don't load" then cr
  725. cr
  726. addr
  727. ;
  728. : show-module-options
  729. module_options @
  730. begin
  731. ?dup
  732. while
  733. show-one-module
  734. module.next @
  735. repeat
  736. ;
  737. only forth also support-functions definitions
  738. \ Variables used for processing multiple conf files
  739. string current_file_name_ref \ used to print the file name
  740. \ Indicates if any conf file was succesfully read
  741. 0 value any_conf_read?
  742. \ loader_conf_files processing support functions
  743. : get_conf_files ( -- addr len ) \ put addr/len on stack, reset var
  744. \ ." -- starting on <" conf_files strtype ." >" cr \ debugging
  745. conf_files strget 0 0 conf_files strset
  746. ;
  747. : skip_leading_spaces { addr len pos -- addr len pos' }
  748. begin
  749. pos len = if 0 else addr pos + c@ bl = then
  750. while
  751. pos char+ to pos
  752. repeat
  753. addr len pos
  754. ;
  755. \ return the file name at pos, or free the string if nothing left
  756. : get_file_name { addr len pos -- addr len pos' addr' len' || 0 }
  757. pos len = if
  758. addr free abort" Fatal error freeing memory"
  759. 0 exit
  760. then
  761. pos >r
  762. begin
  763. \ stay in the loop until have chars and they are not blank
  764. pos len = if 0 else addr pos + c@ bl <> then
  765. while
  766. pos char+ to pos
  767. repeat
  768. addr len pos addr r@ + pos r> -
  769. \ 2dup ." get_file_name has " type cr \ debugging
  770. ;
  771. : get_next_file ( addr len ptr -- addr len ptr' addr' len' | 0 )
  772. skip_leading_spaces
  773. get_file_name
  774. ;
  775. : print_current_file
  776. current_file_name_ref strtype
  777. ;
  778. : process_conf_errors
  779. dup 0= if true to any_conf_read? drop exit then
  780. >r 2drop r>
  781. dup ESYNTAX = if
  782. ." Warning: syntax error on file " print_current_file cr
  783. print_syntax_error drop exit
  784. then
  785. dup ESETERROR = if
  786. ." Warning: bad definition on file " print_current_file cr
  787. print_line drop exit
  788. then
  789. dup EREAD = if
  790. ." Warning: error reading file " print_current_file cr drop exit
  791. then
  792. dup EOPEN = if
  793. verbose? if ." Warning: unable to open file " print_current_file cr then
  794. drop exit
  795. then
  796. dup EFREE = abort" Fatal error freeing memory"
  797. dup ENOMEM = abort" Out of memory"
  798. throw \ Unknown error -- pass ahead
  799. ;
  800. \ Process loader_conf_files recursively
  801. \ Interface to loader_conf_files processing
  802. : include_conf_files
  803. get_conf_files 0 ( addr len offset )
  804. begin
  805. get_next_file ?dup ( addr len 1 | 0 )
  806. while
  807. current_file_name_ref strref
  808. ['] load_conf catch
  809. process_conf_errors
  810. conf_files .addr @ if recurse then
  811. repeat
  812. ;
  813. : get_nextboot_conf_file ( -- addr len )
  814. nextboot_conf_file strget strdup \ XXX is the strdup a leak ?
  815. ;
  816. : rewrite_nextboot_file ( -- )
  817. get_nextboot_conf_file
  818. O_WRONLY fopen fd !
  819. fd @ -1 = if EOPEN throw then
  820. fd @ s' nextboot_enable="NO" ' fwrite
  821. fd @ fclose
  822. ;
  823. : include_nextboot_file
  824. get_nextboot_conf_file
  825. ['] peek_file catch
  826. nextboot? if
  827. get_nextboot_conf_file
  828. ['] load_conf catch
  829. process_conf_errors
  830. ['] rewrite_nextboot_file catch
  831. then
  832. ;
  833. \ Module loading functions
  834. : load_parameters { addr -- addr addrN lenN ... addr1 len1 N }
  835. addr
  836. addr module.args strget
  837. addr module.loadname .len @ if
  838. addr module.loadname strget
  839. else
  840. addr module.name strget
  841. then
  842. addr module.type .len @ if
  843. addr module.type strget
  844. s" -t "
  845. 4 ( -t type name flags )
  846. else
  847. 2 ( name flags )
  848. then
  849. ;
  850. : before_load ( addr -- addr )
  851. dup module.beforeload .len @ if
  852. dup module.beforeload strget
  853. ['] evaluate catch if EBEFORELOAD throw then
  854. then
  855. ;
  856. : after_load ( addr -- addr )
  857. dup module.afterload .len @ if
  858. dup module.afterload strget
  859. ['] evaluate catch if EAFTERLOAD throw then
  860. then
  861. ;
  862. : load_error ( addr -- addr )
  863. dup module.loaderror .len @ if
  864. dup module.loaderror strget
  865. evaluate \ This we do not intercept so it can throw errors
  866. then
  867. ;
  868. : pre_load_message ( addr -- addr )
  869. verbose? if
  870. dup module.name strtype
  871. ." ..."
  872. then
  873. ;
  874. : load_error_message verbose? if ." failed!" cr then ;
  875. : load_succesful_message verbose? if ." ok" cr then ;
  876. : load_module
  877. load_parameters load
  878. ;
  879. : process_module ( addr -- addr )
  880. pre_load_message
  881. before_load
  882. begin
  883. ['] load_module catch if
  884. dup module.loaderror .len @ if
  885. load_error \ Command should return a flag!
  886. else
  887. load_error_message true \ Do not retry
  888. then
  889. else
  890. after_load
  891. load_succesful_message true \ Succesful, do not retry
  892. then
  893. until
  894. ;
  895. : process_module_errors ( addr ior -- )
  896. dup EBEFORELOAD = if
  897. drop
  898. ." Module "
  899. dup module.name strtype
  900. dup module.loadname .len @ if
  901. ." (" dup module.loadname strtype ." )"
  902. then
  903. cr
  904. ." Error executing "
  905. dup module.beforeload strtype cr \ XXX there was a typo here
  906. abort
  907. then
  908. dup EAFTERLOAD = if
  909. drop
  910. ." Module "
  911. dup module.name .addr @ over module.name .len @ type
  912. dup module.loadname .len @ if
  913. ." (" dup module.loadname strtype ." )"
  914. then
  915. cr
  916. ." Error executing "
  917. dup module.afterload strtype cr
  918. abort
  919. then
  920. throw \ Don't know what it is all about -- pass ahead
  921. ;
  922. \ Module loading interface
  923. \ scan the list of modules, load enabled ones.
  924. : load_modules ( -- ) ( throws: abort & user-defined )
  925. module_options @ ( list_head )
  926. begin
  927. ?dup
  928. while
  929. dup module.flag @ if
  930. ['] process_module catch
  931. process_module_errors
  932. then
  933. module.next @
  934. repeat
  935. ;
  936. \ h00h00 magic used to try loading either a kernel with a given name,
  937. \ or a kernel with the default name in a directory of a given name
  938. \ (the pain!)
  939. : bootpath s" /boot/" ;
  940. : modulepath s" module_path" ;
  941. \ Functions used to save and restore module_path's value.
  942. : saveenv ( addr len | -1 -- addr' len | 0 -1 )
  943. dup -1 = if 0 swap exit then
  944. strdup
  945. ;
  946. : freeenv ( addr len | 0 -1 )
  947. -1 = if drop else free abort" Freeing error" then
  948. ;
  949. : restoreenv ( addr len | 0 -1 -- )
  950. dup -1 = if ( it wasn't set )
  951. 2drop
  952. modulepath unsetenv
  953. else
  954. over >r
  955. modulepath setenv
  956. r> free abort" Freeing error"
  957. then
  958. ;
  959. : clip_args \ Drop second string if only one argument is passed
  960. 1 = if
  961. 2swap 2drop
  962. 1
  963. else
  964. 2
  965. then
  966. ;
  967. also builtins
  968. \ Parse filename from a semicolon-separated list
  969. \ replacement, not working yet
  970. : newparse-; { addr len | a1 -- a' len-x addr x }
  971. addr len [char] ; strchr dup if ( a1 len1 )
  972. swap to a1 ( store address )
  973. 1 - a1 @ 1 + swap ( remove match )
  974. addr a1 addr -
  975. else
  976. 0 0 addr len
  977. then
  978. ;
  979. : parse-; ( addr len -- addr' len-x addr x )
  980. over 0 2swap ( addr 0 addr len )
  981. begin
  982. dup 0 <> ( addr 0 addr len )
  983. while
  984. over c@ [char] ; <> ( addr 0 addr len flag )
  985. while
  986. 1- swap 1+ swap
  987. 2swap 1+ 2swap
  988. repeat then
  989. dup 0 <> if
  990. 1- swap 1+ swap
  991. then
  992. 2swap
  993. ;
  994. \ Try loading one of multiple kernels specified
  995. : try_multiple_kernels ( addr len addr' len' args -- flag )
  996. >r
  997. begin
  998. parse-; 2>r
  999. 2over 2r>
  1000. r@ clip_args
  1001. s" DEBUG" getenv? if
  1002. s" echo Module_path: ${module_path}" evaluate
  1003. ." Kernel : " >r 2dup type r> cr
  1004. dup 2 = if ." Flags : " >r 2over type r> cr then
  1005. then
  1006. 1 load
  1007. while
  1008. dup 0=
  1009. until
  1010. 1 >r \ Failure
  1011. else
  1012. 0 >r \ Success
  1013. then
  1014. 2drop 2drop
  1015. r>
  1016. r> drop
  1017. ;
  1018. \ Try to load a kernel; the kernel name is taken from one of
  1019. \ the following lists, as ordered:
  1020. \
  1021. \ 1. The "bootfile" environment variable
  1022. \ 2. The "kernel" environment variable
  1023. \
  1024. \ Flags are passed, if available. If not, dummy values must be given.
  1025. \
  1026. \ The kernel gets loaded from the current module_path.
  1027. : load_a_kernel ( flags len 1 | x x 0 -- flag )
  1028. local args
  1029. 2local flags
  1030. 0 0 2local kernel
  1031. end-locals
  1032. \ Check if a default kernel name exists at all, exits if not
  1033. s" bootfile" getenv dup -1 <> if
  1034. to kernel
  1035. flags kernel args 1+ try_multiple_kernels
  1036. dup 0= if exit then
  1037. then
  1038. drop
  1039. s" kernel" getenv dup -1 <> if
  1040. to kernel
  1041. else
  1042. drop
  1043. 1 exit \ Failure
  1044. then
  1045. \ Try all default kernel names
  1046. flags kernel args 1+ try_multiple_kernels
  1047. ;
  1048. \ Try to load a kernel; the kernel name is taken from one of
  1049. \ the following lists, as ordered:
  1050. \
  1051. \ 1. The "bootfile" environment variable
  1052. \ 2. The "kernel" environment variable
  1053. \
  1054. \ Flags are passed, if provided.
  1055. \
  1056. \ The kernel will be loaded from a directory computed from the
  1057. \ path given. Two directories will be tried in the following order:
  1058. \
  1059. \ 1. /boot/path
  1060. \ 2. path
  1061. \
  1062. \ The module_path variable is overridden if load is succesful, by
  1063. \ prepending the successful path.
  1064. : load_from_directory ( path len 1 | flags len' path len 2 -- flag )
  1065. local args
  1066. 2local path
  1067. args 1 = if 0 0 then
  1068. 2local flags
  1069. 0 0 2local oldmodulepath \ like a string
  1070. 0 0 2local newmodulepath \ like a string
  1071. end-locals
  1072. \ Set the environment variable module_path, and try loading
  1073. \ the kernel again.
  1074. modulepath getenv saveenv to oldmodulepath
  1075. \ Try prepending /boot/ first
  1076. bootpath nip path nip + \ total length
  1077. oldmodulepath nip dup -1 = if
  1078. drop
  1079. else
  1080. 1+ + \ add oldpath -- XXX why the 1+ ?
  1081. then
  1082. allocate if ( out of memory ) 1 exit then \ XXX throw ?
  1083. 0
  1084. bootpath strcat
  1085. path strcat
  1086. 2dup to newmodulepath
  1087. modulepath setenv
  1088. \ Try all default kernel names
  1089. flags args 1- load_a_kernel
  1090. 0= if ( success )
  1091. oldmodulepath nip -1 <> if
  1092. newmodulepath s" ;" strcat
  1093. oldmodulepath strcat
  1094. modulepath setenv
  1095. newmodulepath drop free-memory
  1096. oldmodulepath drop free-memory
  1097. then
  1098. 0 exit
  1099. then
  1100. \ Well, try without the prepended /boot/
  1101. path newmodulepath drop swap move
  1102. newmodulepath drop path nip
  1103. 2dup to newmodulepath
  1104. modulepath setenv
  1105. \ Try all default kernel names
  1106. flags args 1- load_a_kernel
  1107. if ( failed once more )
  1108. oldmodulepath restoreenv
  1109. newmodulepath drop free-memory
  1110. 1
  1111. else
  1112. oldmodulepath nip -1 <> if
  1113. newmodulepath s" ;" strcat
  1114. oldmodulepath strcat
  1115. modulepath setenv
  1116. newmodulepath drop free-memory
  1117. oldmodulepath drop free-memory
  1118. then
  1119. 0
  1120. then
  1121. ;
  1122. \ Try to load a kernel; the kernel name is taken from one of
  1123. \ the following lists, as ordered:
  1124. \
  1125. \ 1. The "bootfile" environment variable
  1126. \ 2. The "kernel" environment variable
  1127. \ 3. The "path" argument
  1128. \
  1129. \ Flags are passed, if provided.
  1130. \
  1131. \ The kernel will be loaded from a directory computed from the
  1132. \ path given. Two directories will be tried in the following order:
  1133. \
  1134. \ 1. /boot/path
  1135. \ 2. path
  1136. \
  1137. \ Unless "path" is meant to be kernel name itself. In that case, it
  1138. \ will first be tried as a full path, and, next, search on the
  1139. \ directories pointed by module_path.
  1140. \
  1141. \ The module_path variable is overridden if load is succesful, by
  1142. \ prepending the successful path.
  1143. : load_directory_or_file ( path len 1 | flags len' path len 2 -- flag )
  1144. local args
  1145. 2local path
  1146. args 1 = if 0 0 then
  1147. 2local flags
  1148. end-locals
  1149. \ First, assume path is an absolute path to a directory
  1150. flags path args clip_args load_from_directory
  1151. dup 0= if exit else drop then
  1152. \ Next, assume path points to the kernel
  1153. flags path args try_multiple_kernels
  1154. ;
  1155. : initialize ( addr len -- )
  1156. strdup conf_files strset
  1157. ;
  1158. : kernel_options ( -- addr len 1 | 0 )
  1159. s" kernel_options" getenv
  1160. dup -1 = if drop 0 else 1 then
  1161. ;
  1162. : standard_kernel_search ( flags 1 | 0 -- flag )
  1163. local args
  1164. args 0= if 0 0 then
  1165. 2local flags
  1166. s" kernel" getenv
  1167. dup -1 = if 0 swap then
  1168. 2local path
  1169. end-locals
  1170. path nip -1 = if ( there isn't a "kernel" environment variable )
  1171. flags args load_a_kernel
  1172. else
  1173. flags path args 1+ clip_args load_directory_or_file
  1174. then
  1175. ;
  1176. : load_kernel ( -- ) ( throws: abort )
  1177. kernel_options standard_kernel_search
  1178. abort" Unable to load a kernel!"
  1179. ;
  1180. : set_defaultoptions ( -- )
  1181. s" kernel_options" getenv dup -1 = if
  1182. drop
  1183. else
  1184. s" temp_options" setenv
  1185. then
  1186. ;
  1187. \ pick the i-th argument, i starts at 0
  1188. : argv[] ( aN uN ... a1 u1 N i -- aN uN ... a1 u1 N ai+1 ui+1 )
  1189. 2dup = if 0 0 exit then \ out of range
  1190. dup >r
  1191. 1+ 2* ( skip N and ui )
  1192. pick
  1193. r>
  1194. 1+ 2* ( skip N and ai )
  1195. pick
  1196. ;
  1197. : drop_args ( aN uN ... a1 u1 N -- )
  1198. 0 ?do 2drop loop
  1199. ;
  1200. : argc
  1201. dup
  1202. ;
  1203. : queue_argv ( aN uN ... a1 u1 N a u -- a u aN uN ... a1 u1 N+1 )
  1204. >r
  1205. over 2* 1+ -roll
  1206. r>
  1207. over 2* 1+ -roll
  1208. 1+
  1209. ;
  1210. : unqueue_argv ( aN uN ... a1 u1 N -- aN uN ... a2 u2 N-1 a1 u1 )
  1211. 1- -rot
  1212. ;
  1213. \ compute the length of the buffer including the spaces between words
  1214. : strlen(argv) ( aN uN .. a1 u1 N -- aN uN .. a1 u1 N len )
  1215. dup 0= if 0 exit then
  1216. 0 >r \ Size
  1217. 0 >r \ Index
  1218. begin
  1219. argc r@ <>
  1220. while
  1221. r@ argv[]
  1222. nip
  1223. r> r> rot + 1+
  1224. >r 1+ >r
  1225. repeat
  1226. r> drop
  1227. r>
  1228. ;
  1229. : concat_argv ( aN uN ... a1 u1 N -- a u )
  1230. strlen(argv) allocate if ENOMEM throw then
  1231. 0 2>r ( save addr 0 on return stack )
  1232. begin
  1233. dup
  1234. while
  1235. unqueue_argv ( ... N a1 u1 )
  1236. 2r> 2swap ( old a1 u1 )
  1237. strcat
  1238. s" " strcat ( append one space ) \ XXX this gives a trailing space
  1239. 2>r ( store string on the result stack )
  1240. repeat
  1241. drop_args
  1242. 2r>
  1243. ;
  1244. : set_tempoptions ( addrN lenN ... addr1 len1 N -- addr len 1 | 0 )
  1245. \ Save the first argument, if it exists and is not a flag
  1246. argc if
  1247. 0 argv[] drop c@ [char] - <> if
  1248. unqueue_argv 2>r \ Filename
  1249. 1 >r \ Filename present
  1250. else
  1251. 0 >r \ Filename not present
  1252. then
  1253. else
  1254. 0 >r \ Filename not present
  1255. then
  1256. \ If there are other arguments, assume they are flags
  1257. ?dup if
  1258. concat_argv
  1259. 2dup s" temp_options" setenv
  1260. drop free if EFREE throw then
  1261. else
  1262. set_defaultoptions
  1263. then
  1264. \ Bring back the filename, if one was provided
  1265. r> if 2r> 1 else 0 then
  1266. ;
  1267. : get_arguments ( -- addrN lenN ... addr1 len1 N )
  1268. 0
  1269. begin
  1270. \ Get next word on the command line
  1271. parse-word
  1272. ?dup while
  1273. queue_argv
  1274. repeat
  1275. drop ( empty string )
  1276. ;
  1277. : load_kernel_and_modules ( args -- flag )
  1278. set_tempoptions
  1279. argc >r
  1280. s" temp_options" getenv dup -1 <> if
  1281. queue_argv
  1282. else
  1283. drop
  1284. then
  1285. r> if ( a path was passed )
  1286. load_directory_or_file
  1287. else
  1288. standard_kernel_search
  1289. then
  1290. ?dup 0= if ['] load_modules catch then
  1291. ;
  1292. \ Go back to straight forth vocabulary
  1293. only forth also definitions