PageRenderTime 59ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 1ms

/sys/boot/forth/support.4th

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