PageRenderTime 47ms CodeModel.GetById 15ms RepoModel.GetById 0ms app.codeStats 0ms

/stand/forth/support.4th

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