PageRenderTime 30ms CodeModel.GetById 23ms RepoModel.GetById 0ms app.codeStats 0ms

/usr/src/boot/forth/support.4th

https://github.com/illumos/illumos-gate
Forth | 2056 lines | 1776 code | 275 blank | 5 comment | 167 complexity | 644e27d6e045d458c5088a4f2071bb75 MD5 | raw file
  1. \ Copyright (c) 1999 Daniel C. Sobral <dcs@FreeBSD.org>
  2. \ Copyright 2019 OmniOS Community Edition (OmniOSce) Association.
  3. \ All rights reserved.
  4. \
  5. \ Redistribution and use in source and binary forms, with or without
  6. \ modification, are permitted provided that the following conditions
  7. \ are met:
  8. \ 1. Redistributions of source code must retain the above copyright
  9. \ notice, this list of conditions and the following disclaimer.
  10. \ 2. Redistributions in binary form must reproduce the above copyright
  11. \ notice, this list of conditions and the following disclaimer in the
  12. \ documentation and/or other materials provided with the distribution.
  13. \
  14. \ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  15. \ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  16. \ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  17. \ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  18. \ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  19. \ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  20. \ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  21. \ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  22. \ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  23. \ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  24. \ SUCH DAMAGE.
  25. \ Loader.rc support functions:
  26. \
  27. \ initialize ( addr len -- ) as above, plus load_conf_files
  28. \ load_conf ( addr len -- ) load conf file given
  29. \ include_bootenv ( -- ) load bootenv.rc
  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 (file | hash | rootfs)
  47. \ string module.hash module's sha1 hash
  48. \ string module.args flags to be passed during load
  49. \ string module.largs internal argument list
  50. \ string module.beforeload command to be executed before load
  51. \ string module.afterload command to be executed after load
  52. \ string module.loaderror command to be executed if load fails
  53. \ cell module.next list chain
  54. \
  55. \ Exported global variables;
  56. \
  57. \ string conf_files configuration files to be loaded
  58. \ cell modules_options pointer to first module information
  59. \ value verbose? indicates if user wants a verbose loading
  60. \ value any_conf_read? indicates if a conf file was successfully read
  61. \
  62. \ Other exported words:
  63. \ note, strlen is internal
  64. \ strdup ( addr len -- addr' len) similar to strdup(3)
  65. \ strcat ( addr len addr' len' -- addr len+len' ) similar to strcat(3)
  66. \ s' ( | string' -- addr len | ) similar to s"
  67. \ rudimentary structure support
  68. \ Exception values
  69. 1 constant ESYNTAX
  70. 2 constant ENOMEM
  71. 3 constant EFREE
  72. 4 constant ESETERROR \ error setting environment variable
  73. 5 constant EREAD \ error reading
  74. 6 constant EOPEN
  75. 7 constant EEXEC \ XXX never catched
  76. 8 constant EBEFORELOAD
  77. 9 constant EAFTERLOAD
  78. \ I/O constants
  79. 0 constant SEEK_SET
  80. 1 constant SEEK_CUR
  81. 2 constant SEEK_END
  82. 0 constant O_RDONLY
  83. 1 constant O_WRONLY
  84. 2 constant O_RDWR
  85. \ Crude structure support
  86. : structure:
  87. create here 0 , ['] drop , 0
  88. does> create here swap dup @ allot cell+ @ execute
  89. ;
  90. : member: create dup , over , + does> cell+ @ + ;
  91. : ;structure swap ! ;
  92. : constructor! >body cell+ ! ;
  93. : constructor: over :noname ;
  94. : ;constructor postpone ; swap cell+ ! ; immediate
  95. : sizeof ' >body @ state @ if postpone literal then ; immediate
  96. : offsetof ' >body cell+ @ state @ if postpone literal then ; immediate
  97. : ptr 1 cells member: ;
  98. : int 1 cells member: ;
  99. \ String structure
  100. structure: string
  101. ptr .addr
  102. int .len
  103. constructor:
  104. 0 over .addr !
  105. 0 swap .len !
  106. ;constructor
  107. ;structure
  108. \ Module options linked list
  109. structure: module
  110. int module.flag
  111. sizeof string member: module.name
  112. sizeof string member: module.loadname
  113. sizeof string member: module.type
  114. sizeof string member: module.hash
  115. sizeof string member: module.args
  116. sizeof string member: module.largs
  117. sizeof string member: module.beforeload
  118. sizeof string member: module.afterload
  119. sizeof string member: module.loaderror
  120. ptr module.next
  121. ;structure
  122. \ Internal loader structures (preloaded_file, kernel_module, file_metadata)
  123. \ must be in sync with the C struct in sys/boot/common/bootstrap.h
  124. structure: preloaded_file
  125. ptr pf.name
  126. ptr pf.type
  127. ptr pf.args
  128. ptr pf.metadata \ file_metadata
  129. int pf.loader
  130. int pf.addr
  131. int pf.size
  132. ptr pf.modules \ kernel_module
  133. ptr pf.next \ preloaded_file
  134. ;structure
  135. structure: kernel_module
  136. ptr km.name
  137. ptr km.args
  138. ptr km.fp \ preloaded_file
  139. ptr km.next \ kernel_module
  140. ;structure
  141. structure: file_metadata
  142. int md.size
  143. 2 member: md.type \ this is not ANS Forth compatible (XXX)
  144. ptr md.next \ file_metadata
  145. 0 member: md.data \ variable size
  146. ;structure
  147. \ end of structures
  148. \ Global variables
  149. string conf_files
  150. create module_options sizeof module.next allot 0 module_options !
  151. create last_module_option sizeof module.next allot 0 last_module_option !
  152. 0 value verbose?
  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. : strspn { addr len addr1 len1 | paddr plen -- addr' len' }
  173. begin
  174. len
  175. while
  176. addr1 to paddr
  177. len1 to plen
  178. begin
  179. plen
  180. while
  181. addr c@ paddr c@ = if addr len exit then
  182. paddr 1+ to paddr
  183. plen 1- to plen
  184. repeat
  185. addr 1 + to addr
  186. len 1 - to len
  187. repeat
  188. 0 0
  189. ;
  190. : s' \ same as s", allows " in the string
  191. [char] ' parse
  192. state @ if postpone sliteral then
  193. ; immediate
  194. : 2>r postpone >r postpone >r ; immediate
  195. : 2r> postpone r> postpone r> ; immediate
  196. : 2r@ postpone 2r> postpone 2dup postpone 2>r ; immediate
  197. \ Number to string
  198. : n2s ( n -- c-addr/u ) s>d <# #s #> ;
  199. \ String to number
  200. : s2n ( c-addr/u1 -- u2 | -1 ) ?number 0= if -1 then ;
  201. \ Test if an environment variable is set
  202. : getenv? getenv -1 = if false else drop true then ;
  203. \ Fetch a number from an environment variable, or a default if not set or does
  204. \ not parse (s2n returns -1).
  205. : getenvn ( n1 c-addr/u -- n1 | n2 )
  206. getenv dup -1 = if
  207. \ environment variable not set
  208. drop ( n1 -1 -- n1 )
  209. else
  210. s2n ( n1 c-addr/u1 -- n1 n2 )
  211. dup -1 = if
  212. \ parse failed
  213. drop ( n1 n2 -- n1 )
  214. else
  215. nip ( n1 n2 -- n2 )
  216. then
  217. then
  218. ;
  219. \ execute xt for each device listed in console variable.
  220. \ this allows us to have device specific output for logos, menu frames etc
  221. : console-iterate { xt | caddr clen taddr tlen -- }
  222. \ get current console and save it
  223. s" console" getenv
  224. ['] strdup catch if 2drop exit then
  225. to clen to caddr
  226. clen to tlen
  227. caddr to taddr
  228. begin
  229. tlen
  230. while
  231. taddr tlen s" , " strspn
  232. \ we need to handle 3 cases for addr len pairs on stack:
  233. \ addr len are 0 0 - there was no comma nor space
  234. \ addr len are x 0 - the first char is either comma or space
  235. \ addr len are x y.
  236. 2dup + 0= if
  237. \ there was no comma nor space.
  238. 2drop
  239. taddr tlen s" console" setenv
  240. xt execute
  241. 0 to tlen
  242. else dup 0= if
  243. 2drop
  244. else
  245. dup ( taddr' tlen' tlen' )
  246. tlen swap - dup
  247. 0= if \ sequence of comma and space?
  248. drop
  249. else
  250. taddr swap s" console" setenv
  251. xt execute
  252. then
  253. to tlen
  254. to taddr
  255. then then
  256. tlen 0> if \ step over separator
  257. tlen 1- to tlen
  258. taddr 1+ to taddr
  259. then
  260. repeat
  261. caddr clen s" console" setenv \ restore console setup
  262. caddr free drop
  263. ;
  264. \ Test if booted in an EFI environment
  265. : efi? ( -- flag )
  266. s" efi-version" getenv?
  267. ;
  268. \ determine if a word appears in a string, case-insensitive
  269. : contains? ( addr1 len1 addr2 len2 -- 0 | -1 )
  270. 2 pick 0= if 2drop 2drop true exit then
  271. dup 0= if 2drop 2drop false exit then
  272. begin
  273. begin
  274. swap dup c@ dup 32 = over 9 = or over 10 = or
  275. over 13 = or over 44 = or swap drop
  276. while 1+ swap 1- repeat
  277. swap 2 pick 1- over <
  278. while
  279. 2over 2over drop over compare-insensitive 0= if
  280. 2 pick over = if 2drop 2drop true exit then
  281. 2 pick tuck - -rot + swap over c@ dup 32 =
  282. over 9 = or over 10 = or over 13 = or over 44 = or
  283. swap drop if 2drop 2drop true exit then
  284. then begin
  285. swap dup c@ dup 32 = over 9 = or over 10 = or
  286. over 13 = or over 44 = or swap drop
  287. if false else true then 2 pick 0> and
  288. while 1+ swap 1- repeat
  289. swap
  290. repeat
  291. 2drop 2drop false
  292. ;
  293. : boot_serial? ( -- 0 | -1 )
  294. s" console" getenv dup -1 <> if
  295. 2dup
  296. s" ttya" 2swap contains? ( addr len f )
  297. -rot 2dup ( f addr len addr len )
  298. s" ttyb" 2swap contains? ( f addr len f )
  299. -rot 2dup ( f f addr len addr len )
  300. s" ttyc" 2swap contains? ( f f addr len f )
  301. -rot ( f f f addr len )
  302. s" ttyd" 2swap contains? ( f f addr len f )
  303. or or or
  304. else drop false then
  305. s" boot_serial" getenv dup -1 <> if
  306. swap drop 0>
  307. else drop false then
  308. or \ console contains tty ( or ) boot_serial
  309. s" boot_multicons" getenv dup -1 <> if
  310. swap drop 0>
  311. else drop false then
  312. or \ previous boolean ( or ) boot_multicons
  313. ;
  314. : framebuffer? ( -- t )
  315. s" console" getenv
  316. s" text" compare 0<> if
  317. FALSE exit
  318. then
  319. s" screen-width" getenv?
  320. ;
  321. \ Private definitions
  322. vocabulary support-functions
  323. only forth also support-functions definitions
  324. \ Some control characters constants
  325. 7 constant bell
  326. 8 constant backspace
  327. 9 constant tab
  328. 10 constant lf
  329. 13 constant <cr>
  330. \ Read buffer size
  331. 80 constant read_buffer_size
  332. \ Standard suffixes
  333. : load_module_suffix s" _load" ;
  334. : module_loadname_suffix s" _name" ;
  335. : module_type_suffix s" _type" ;
  336. : module_hash_suffix s" _hash" ;
  337. : module_args_suffix s" _flags" ;
  338. : module_beforeload_suffix s" _before" ;
  339. : module_afterload_suffix s" _after" ;
  340. : module_loaderror_suffix s" _error" ;
  341. \ Support operators
  342. : >= < 0= ;
  343. : <= > 0= ;
  344. \ Assorted support functions
  345. : free-memory free if EFREE throw then ;
  346. : strget { var -- addr len } var .addr @ var .len @ ;
  347. \ assign addr len to variable.
  348. : strset { addr len var -- } addr var .addr ! len var .len ! ;
  349. \ free memory and reset fields
  350. : strfree { var -- } var .addr @ ?dup if free-memory 0 0 var strset then ;
  351. \ free old content, make a copy of the string and assign to variable
  352. : string= { addr len var -- } var strfree addr len strdup var strset ;
  353. : strtype ( str -- ) strget type ;
  354. \ assign a reference to what is on the stack
  355. : strref { addr len var -- addr len }
  356. addr var .addr ! len var .len ! addr len
  357. ;
  358. \ unquote a string
  359. : unquote ( addr len -- addr len )
  360. over c@ [char] " = if 2 chars - swap char+ swap then
  361. ;
  362. \ Assignment data temporary storage
  363. string name_buffer
  364. string value_buffer
  365. \ Line by line file reading functions
  366. \
  367. \ exported:
  368. \ line_buffer
  369. \ end_of_file?
  370. \ fd
  371. \ read_line
  372. \ reset_line_reading
  373. vocabulary line-reading
  374. also line-reading definitions
  375. \ File data temporary storage
  376. string read_buffer
  377. 0 value read_buffer_ptr
  378. \ File's line reading function
  379. get-current ( -- wid ) previous definitions
  380. string line_buffer
  381. 0 value end_of_file?
  382. variable fd
  383. >search ( wid -- ) definitions
  384. : skip_newlines
  385. begin
  386. read_buffer .len @ read_buffer_ptr >
  387. while
  388. read_buffer .addr @ read_buffer_ptr + c@ lf = if
  389. read_buffer_ptr char+ to read_buffer_ptr
  390. else
  391. exit
  392. then
  393. repeat
  394. ;
  395. : scan_buffer ( -- addr len )
  396. read_buffer_ptr >r
  397. begin
  398. read_buffer .len @ r@ >
  399. while
  400. read_buffer .addr @ r@ + c@ lf = if
  401. read_buffer .addr @ read_buffer_ptr + ( -- addr )
  402. r@ read_buffer_ptr - ( -- len )
  403. r> to read_buffer_ptr
  404. exit
  405. then
  406. r> char+ >r
  407. repeat
  408. read_buffer .addr @ read_buffer_ptr + ( -- addr )
  409. r@ read_buffer_ptr - ( -- len )
  410. r> to read_buffer_ptr
  411. ;
  412. : line_buffer_resize ( len -- len )
  413. dup 0= if exit then
  414. >r
  415. line_buffer .len @ if
  416. line_buffer .addr @
  417. line_buffer .len @ r@ +
  418. resize if ENOMEM throw then
  419. else
  420. r@ allocate if ENOMEM throw then
  421. then
  422. line_buffer .addr !
  423. r>
  424. ;
  425. : append_to_line_buffer ( addr len -- )
  426. dup 0= if 2drop exit then
  427. line_buffer strget
  428. 2swap strcat
  429. line_buffer .len !
  430. drop
  431. ;
  432. : read_from_buffer
  433. scan_buffer ( -- addr len )
  434. line_buffer_resize ( len -- len )
  435. append_to_line_buffer ( addr len -- )
  436. ;
  437. : refill_required?
  438. read_buffer .len @ read_buffer_ptr =
  439. end_of_file? 0= and
  440. ;
  441. : refill_buffer
  442. 0 to read_buffer_ptr
  443. read_buffer .addr @ 0= if
  444. read_buffer_size allocate if ENOMEM throw then
  445. read_buffer .addr !
  446. then
  447. fd @ read_buffer .addr @ read_buffer_size fread
  448. dup -1 = if EREAD throw then
  449. dup 0= if true to end_of_file? then
  450. read_buffer .len !
  451. ;
  452. get-current ( -- wid ) previous definitions >search ( wid -- )
  453. : reset_line_reading
  454. 0 to read_buffer_ptr
  455. ;
  456. : read_line
  457. line_buffer strfree
  458. skip_newlines
  459. begin
  460. read_from_buffer
  461. refill_required?
  462. while
  463. refill_buffer
  464. repeat
  465. ;
  466. only forth also support-functions definitions
  467. \ Conf file line parser:
  468. \ <line> ::= <spaces><name><spaces>'='<spaces><value><spaces>[<comment>] |
  469. \ <spaces>[<comment>]
  470. \ <name> ::= <letter>{<letter>|<digit>|'_'|'-'}
  471. \ <vname> ::= <letter>{<letter>|<digit>|'_'|'-'|','}
  472. \ <value> ::= '"'{<character_set>|'\'<anything>}'"' | <vname>
  473. \ <character_set> ::= ASCII 32 to 126, except '\' and '"'
  474. \ <comment> ::= '#'{<anything>}
  475. \
  476. \ bootenv line parser:
  477. \ <line> ::= <spaces>setprop<spaces><name><spaces><value><spaces>[<comment>] |
  478. \ <spaces>[<comment>]
  479. \
  480. \ exported:
  481. \ line_pointer
  482. \ process_conf
  483. \ process_conf
  484. 0 value line_pointer
  485. vocabulary file-processing
  486. also file-processing definitions
  487. \ parser functions
  488. \
  489. \ exported:
  490. \ get_assignment
  491. \ get_prop
  492. vocabulary parser
  493. also parser definitions
  494. 0 value parsing_function
  495. 0 value end_of_line
  496. : end_of_line? line_pointer end_of_line = ;
  497. \ classifiers for various character classes in the input line
  498. : letter?
  499. line_pointer c@ >r
  500. r@ [char] A >=
  501. r@ [char] Z <= and
  502. r@ [char] a >=
  503. r> [char] z <= and
  504. or
  505. ;
  506. : digit?
  507. line_pointer c@ >r
  508. r@ [char] - =
  509. r@ [char] 0 >=
  510. r> [char] 9 <= and
  511. or
  512. ;
  513. : "quote? line_pointer c@ [char] " = ;
  514. : 'quote? line_pointer c@ [char] ' = ;
  515. : assignment_sign? line_pointer c@ [char] = = ;
  516. : comment? line_pointer c@ [char] # = ;
  517. : space? line_pointer c@ bl = line_pointer c@ tab = or ;
  518. : backslash? line_pointer c@ [char] \ = ;
  519. : underscore? line_pointer c@ [char] _ = ;
  520. : dot? line_pointer c@ [char] . = ;
  521. : dash? line_pointer c@ [char] - = ;
  522. : comma? line_pointer c@ [char] , = ;
  523. : at? line_pointer c@ [char] @ = ;
  524. : slash? line_pointer c@ [char] / = ;
  525. : colon? line_pointer c@ [char] : = ;
  526. \ manipulation of input line
  527. : skip_character line_pointer char+ to line_pointer ;
  528. : skip_to_end_of_line end_of_line to line_pointer ;
  529. : eat_space
  530. begin
  531. end_of_line? if 0 else space? then
  532. while
  533. skip_character
  534. repeat
  535. ;
  536. : parse_name ( -- addr len )
  537. line_pointer
  538. begin
  539. end_of_line? if 0 else
  540. letter? digit? underscore? dot? dash? comma?
  541. or or or or or
  542. then
  543. while
  544. skip_character
  545. repeat
  546. line_pointer over -
  547. strdup
  548. ;
  549. : parse_value ( -- addr len )
  550. line_pointer
  551. begin
  552. end_of_line? if 0 else
  553. letter? digit? underscore? dot? comma? dash? at? slash? colon?
  554. or or or or or or or or
  555. then
  556. while
  557. skip_character
  558. repeat
  559. line_pointer over -
  560. strdup
  561. ;
  562. : remove_backslashes { addr len | addr' len' -- addr' len' }
  563. len allocate if ENOMEM throw then
  564. to addr'
  565. addr >r
  566. begin
  567. addr c@ [char] \ <> if
  568. addr c@ addr' len' + c!
  569. len' char+ to len'
  570. then
  571. addr char+ to addr
  572. r@ len + addr =
  573. until
  574. r> drop
  575. addr' len'
  576. ;
  577. : parse_quote ( xt -- addr len )
  578. >r ( R: xt )
  579. line_pointer
  580. skip_character
  581. end_of_line? if ESYNTAX throw then
  582. begin
  583. r@ execute 0=
  584. while
  585. backslash? if
  586. skip_character
  587. end_of_line? if ESYNTAX throw then
  588. then
  589. skip_character
  590. end_of_line? if ESYNTAX throw then
  591. repeat
  592. r> drop
  593. skip_character
  594. line_pointer over -
  595. remove_backslashes
  596. ;
  597. : read_name
  598. parse_name ( -- addr len )
  599. name_buffer strset
  600. ;
  601. : read_value
  602. "quote? if
  603. ['] "quote? parse_quote ( -- addr len )
  604. else
  605. 'quote? if
  606. ['] 'quote? parse_quote ( -- addr len )
  607. else
  608. parse_value ( -- addr len )
  609. then
  610. then
  611. value_buffer strset
  612. ;
  613. : comment
  614. skip_to_end_of_line
  615. ;
  616. : white_space_4
  617. eat_space
  618. comment? if ['] comment to parsing_function exit then
  619. end_of_line? 0= if ESYNTAX throw then
  620. ;
  621. : variable_value
  622. read_value
  623. ['] white_space_4 to parsing_function
  624. ;
  625. : white_space_3
  626. eat_space
  627. slash? letter? digit? "quote? 'quote? or or or or if
  628. ['] variable_value to parsing_function exit
  629. then
  630. ESYNTAX throw
  631. ;
  632. : assignment_sign
  633. skip_character
  634. ['] white_space_3 to parsing_function
  635. ;
  636. : white_space_2
  637. eat_space
  638. assignment_sign? if ['] assignment_sign to parsing_function exit then
  639. ESYNTAX throw
  640. ;
  641. : variable_name
  642. read_name
  643. ['] white_space_2 to parsing_function
  644. ;
  645. : white_space_1
  646. eat_space
  647. letter? if ['] variable_name to parsing_function exit then
  648. comment? if ['] comment to parsing_function exit then
  649. end_of_line? 0= if ESYNTAX throw then
  650. ;
  651. : prop_name
  652. eat_space
  653. read_name
  654. ['] white_space_3 to parsing_function
  655. ;
  656. : get_prop_cmd
  657. eat_space
  658. s" setprop" line_pointer over compare 0=
  659. if line_pointer 7 + to line_pointer
  660. ['] prop_name to parsing_function exit
  661. then
  662. comment? if ['] comment to parsing_function exit then
  663. end_of_line? 0= if ESYNTAX throw then
  664. ;
  665. get-current ( -- wid ) previous definitions >search ( wid -- )
  666. : get_assignment
  667. line_buffer strget + to end_of_line
  668. line_buffer .addr @ to line_pointer
  669. ['] white_space_1 to parsing_function
  670. begin
  671. end_of_line? 0=
  672. while
  673. parsing_function execute
  674. repeat
  675. parsing_function ['] comment =
  676. parsing_function ['] white_space_1 =
  677. parsing_function ['] white_space_4 =
  678. or or 0= if ESYNTAX throw then
  679. ;
  680. : get_prop
  681. line_buffer strget + to end_of_line
  682. line_buffer .addr @ to line_pointer
  683. ['] get_prop_cmd to parsing_function
  684. begin
  685. end_of_line? 0=
  686. while
  687. parsing_function execute
  688. repeat
  689. parsing_function ['] comment =
  690. parsing_function ['] get_prop_cmd =
  691. parsing_function ['] white_space_4 =
  692. or or 0= if ESYNTAX throw then
  693. ;
  694. only forth also support-functions also file-processing definitions
  695. \ Process line
  696. : assignment_type? ( addr len -- flag )
  697. name_buffer strget
  698. compare 0=
  699. ;
  700. : suffix_type? ( addr len -- flag )
  701. name_buffer .len @ over <= if 2drop false exit then
  702. name_buffer .len @ over - name_buffer .addr @ +
  703. over compare 0=
  704. ;
  705. : loader_conf_files? s" loader_conf_files" assignment_type? ;
  706. : verbose_flag? s" verbose_loading" assignment_type? ;
  707. : execute? s" exec" assignment_type? ;
  708. : module_load? load_module_suffix suffix_type? ;
  709. : module_loadname? module_loadname_suffix suffix_type? ;
  710. : module_type? module_type_suffix suffix_type? ;
  711. : module_hash? module_hash_suffix suffix_type? ;
  712. : module_args? module_args_suffix suffix_type? ;
  713. : module_beforeload? module_beforeload_suffix suffix_type? ;
  714. : module_afterload? module_afterload_suffix suffix_type? ;
  715. : module_loaderror? module_loaderror_suffix suffix_type? ;
  716. \ build a 'set' statement and execute it
  717. : set_environment_variable
  718. name_buffer .len @ value_buffer .len @ + 5 chars + \ size of result string
  719. allocate if ENOMEM throw then
  720. dup 0 \ start with an empty string and append the pieces
  721. s" set " strcat
  722. name_buffer strget strcat
  723. s" =" strcat
  724. value_buffer strget strcat
  725. ['] evaluate catch if
  726. 2drop free drop
  727. ESETERROR throw
  728. else
  729. free-memory
  730. then
  731. ;
  732. : set_conf_files
  733. set_environment_variable
  734. s" loader_conf_files" getenv conf_files string=
  735. ;
  736. : append_to_module_options_list ( addr -- )
  737. module_options @ 0= if
  738. dup module_options !
  739. last_module_option !
  740. else
  741. dup last_module_option @ module.next !
  742. last_module_option !
  743. then
  744. ;
  745. : set_module_name { addr -- } \ check leaks
  746. name_buffer strget addr module.name string=
  747. ;
  748. : yes_value?
  749. value_buffer strget unquote
  750. s" yes" compare-insensitive 0=
  751. ;
  752. : find_module_option ( -- addr | 0 ) \ return ptr to entry matching name_buffer
  753. module_options @
  754. begin
  755. dup
  756. while
  757. dup module.name strget
  758. name_buffer strget
  759. compare 0= if exit then
  760. module.next @
  761. repeat
  762. ;
  763. : new_module_option ( -- addr )
  764. sizeof module allocate if ENOMEM throw then
  765. dup sizeof module erase
  766. dup append_to_module_options_list
  767. dup set_module_name
  768. ;
  769. : get_module_option ( -- addr )
  770. find_module_option
  771. ?dup 0= if new_module_option then
  772. ;
  773. : set_module_flag
  774. name_buffer .len @ load_module_suffix nip - name_buffer .len !
  775. yes_value? get_module_option module.flag !
  776. ;
  777. : set_module_args
  778. name_buffer .len @ module_args_suffix nip - name_buffer .len !
  779. value_buffer strget unquote
  780. get_module_option module.args string=
  781. ;
  782. : set_module_loadname
  783. name_buffer .len @ module_loadname_suffix nip - name_buffer .len !
  784. value_buffer strget unquote
  785. get_module_option module.loadname string=
  786. ;
  787. : set_module_type
  788. name_buffer .len @ module_type_suffix nip - name_buffer .len !
  789. value_buffer strget unquote
  790. get_module_option module.type string=
  791. ;
  792. : set_module_hash
  793. name_buffer .len @ module_hash_suffix nip - name_buffer .len !
  794. value_buffer strget unquote
  795. get_module_option module.hash string=
  796. ;
  797. : set_module_beforeload
  798. name_buffer .len @ module_beforeload_suffix nip - name_buffer .len !
  799. value_buffer strget unquote
  800. get_module_option module.beforeload string=
  801. ;
  802. : set_module_afterload
  803. name_buffer .len @ module_afterload_suffix nip - name_buffer .len !
  804. value_buffer strget unquote
  805. get_module_option module.afterload string=
  806. ;
  807. : set_module_loaderror
  808. name_buffer .len @ module_loaderror_suffix nip - name_buffer .len !
  809. value_buffer strget unquote
  810. get_module_option module.loaderror string=
  811. ;
  812. : set_verbose
  813. yes_value? to verbose?
  814. ;
  815. : execute_command
  816. value_buffer strget unquote
  817. ['] evaluate catch if EEXEC throw then
  818. ;
  819. : process_assignment
  820. name_buffer .len @ 0= if exit then
  821. loader_conf_files? if set_conf_files exit then
  822. verbose_flag? if set_verbose exit then
  823. execute? if execute_command exit then
  824. module_load? if set_module_flag exit then
  825. module_loadname? if set_module_loadname exit then
  826. module_type? if set_module_type exit then
  827. module_hash? if set_module_hash exit then
  828. module_args? if set_module_args exit then
  829. module_beforeload? if set_module_beforeload exit then
  830. module_afterload? if set_module_afterload exit then
  831. module_loaderror? if set_module_loaderror exit then
  832. set_environment_variable
  833. ;
  834. \ free_buffer ( -- )
  835. \
  836. \ Free some pointers if needed. The code then tests for errors
  837. \ in freeing, and throws an exception if needed. If a pointer is
  838. \ not allocated, it's value (0) is used as flag.
  839. : free_buffers
  840. name_buffer strfree
  841. value_buffer strfree
  842. ;
  843. \ Higher level file processing
  844. get-current ( -- wid ) previous definitions >search ( wid -- )
  845. : process_bootenv
  846. begin
  847. end_of_file? 0=
  848. while
  849. free_buffers
  850. read_line
  851. get_prop
  852. ['] process_assignment catch
  853. ['] free_buffers catch
  854. swap throw throw
  855. repeat
  856. ;
  857. : process_conf
  858. begin
  859. end_of_file? 0=
  860. while
  861. free_buffers
  862. read_line
  863. get_assignment
  864. ['] process_assignment catch
  865. ['] free_buffers catch
  866. swap throw throw
  867. repeat
  868. ;
  869. : peek_file ( addr len -- )
  870. 0 to end_of_file?
  871. reset_line_reading
  872. O_RDONLY fopen fd !
  873. fd @ -1 = if EOPEN throw then
  874. free_buffers
  875. read_line
  876. get_assignment
  877. ['] process_assignment catch
  878. ['] free_buffers catch
  879. fd @ fclose
  880. swap throw throw
  881. ;
  882. only forth also support-functions definitions
  883. \ Interface to loading conf files
  884. : load_conf ( addr len -- )
  885. 0 to end_of_file?
  886. reset_line_reading
  887. O_RDONLY fopen fd !
  888. fd @ -1 = if EOPEN throw then
  889. ['] process_conf catch
  890. fd @ fclose
  891. throw
  892. ;
  893. : print_line line_buffer strtype cr ;
  894. : print_syntax_error
  895. line_buffer strtype cr
  896. line_buffer .addr @
  897. begin
  898. line_pointer over <>
  899. while
  900. bl emit char+
  901. repeat
  902. drop
  903. ." ^" cr
  904. ;
  905. : load_bootenv ( addr len -- )
  906. 0 to end_of_file?
  907. reset_line_reading
  908. O_RDONLY fopen fd !
  909. fd @ -1 = if EOPEN throw then
  910. ['] process_bootenv catch
  911. fd @ fclose
  912. throw
  913. ;
  914. \ Debugging support functions
  915. only forth definitions also support-functions
  916. : test-file
  917. ['] load_conf catch dup .
  918. ESYNTAX = if cr print_syntax_error then
  919. ;
  920. \ find a module name, leave addr on the stack (0 if not found)
  921. : find-module ( <module> -- ptr | 0 )
  922. bl parse ( addr len )
  923. dup 0= if 2drop then ( parse did not find argument, try stack )
  924. depth 2 < if 0 exit then
  925. module_options @ >r ( store current pointer )
  926. begin
  927. r@
  928. while
  929. 2dup ( addr len addr len )
  930. r@ module.name strget
  931. compare 0= if drop drop r> exit then ( found it )
  932. r> module.next @ >r
  933. repeat
  934. type ." was not found" cr r>
  935. ;
  936. : show-nonempty ( addr len mod -- )
  937. strget dup verbose? or if
  938. 2swap type type cr
  939. else
  940. drop drop drop drop
  941. then ;
  942. : show-one-module { addr -- addr }
  943. ." Name: " addr module.name strtype cr
  944. s" Path: " addr module.loadname show-nonempty
  945. s" Type: " addr module.type show-nonempty
  946. s" Hash: " addr module.hash show-nonempty
  947. s" Flags: " addr module.args show-nonempty
  948. s" Before load: " addr module.beforeload show-nonempty
  949. s" After load: " addr module.afterload show-nonempty
  950. s" Error: " addr module.loaderror show-nonempty
  951. ." Status: " addr module.flag @ if ." Load" else ." Don't load" then cr
  952. cr
  953. addr
  954. ;
  955. : show-module-options
  956. module_options @
  957. begin
  958. ?dup
  959. while
  960. show-one-module
  961. module.next @
  962. repeat
  963. ;
  964. : free-one-module { addr -- addr }
  965. addr module.name strfree
  966. addr module.loadname strfree
  967. addr module.type strfree
  968. addr module.hash strfree
  969. addr module.args strfree
  970. addr module.largs strfree
  971. addr module.beforeload strfree
  972. addr module.afterload strfree
  973. addr module.loaderror strfree
  974. addr
  975. ;
  976. : free-module-options
  977. module_options @
  978. begin
  979. ?dup
  980. while
  981. free-one-module
  982. dup module.next @
  983. swap free-memory
  984. repeat
  985. 0 module_options !
  986. 0 last_module_option !
  987. ;
  988. only forth also support-functions definitions
  989. \ Variables used for processing multiple conf files
  990. string current_file_name_ref \ used to print the file name
  991. \ Indicates if any conf file was successfully read
  992. 0 value any_conf_read?
  993. \ loader_conf_files processing support functions
  994. \ true if string in addr1 is smaller than in addr2
  995. : compar ( addr1 addr2 -- flag )
  996. swap ( addr2 addr1 )
  997. dup cell+ ( addr2 addr1 addr )
  998. swap @ ( addr2 addr len )
  999. rot ( addr len addr2 )
  1000. dup cell+ ( addr len addr2 addr' )
  1001. swap @ ( addr len addr' len' )
  1002. compare -1 =
  1003. ;
  1004. \ insertion sort algorithm. we dont expect large amounts of data to be
  1005. \ sorted, so insert should be ok. compar needs to implement < operator.
  1006. : insert ( start end -- start )
  1007. dup @ >r ( r: v ) \ v = a[i]
  1008. begin
  1009. 2dup < \ j>0
  1010. while
  1011. r@ over cell- @ compar \ a[j-1] > v
  1012. while
  1013. cell- \ j--
  1014. dup @ over cell+ ! \ a[j] = a[j-1]
  1015. repeat then
  1016. r> swap ! \ a[j] = v
  1017. ;
  1018. : sort ( array len -- )
  1019. 1 ?do dup i cells + insert loop drop
  1020. ;
  1021. : opendir
  1022. s" /boot/conf.d" fopendir if fd ! else
  1023. EOPEN throw
  1024. then
  1025. ;
  1026. : readdir ( addr len flag | flag )
  1027. fd @ freaddir
  1028. ;
  1029. : closedir
  1030. fd @ fclosedir
  1031. ;
  1032. : entries ( -- n ) \ count directory entries
  1033. ['] opendir catch ( n array )
  1034. throw
  1035. 0 ( i )
  1036. begin \ count the entries
  1037. readdir ( i addr len flag | i flag )
  1038. dup -1 = if
  1039. -ROT 2drop
  1040. swap 1+ swap
  1041. then
  1042. 0=
  1043. until
  1044. closedir
  1045. ;
  1046. \ built-in prefix directory name; it must end with /, so we don't
  1047. \ need to check and insert it.
  1048. : make_cstring ( addr len -- addr' )
  1049. dup ( addr len len )
  1050. s" /boot/conf.d/" ( addr len len addr' len' )
  1051. rot ( addr len addr' len' len )
  1052. over + ( addr len addr' len' total ) \ space for prefix+str
  1053. dup cell+ 1+ \ 1+ for '\0'
  1054. allocate if
  1055. -1 abort" malloc failed"
  1056. then
  1057. ( addr len addr' len' total taddr )
  1058. dup rot ( addr len addr' len' taddr taddr total )
  1059. swap ! ( addr len addr' len' taddr ) \ store length
  1060. dup >r \ save reference
  1061. cell+ \ point to string area
  1062. 2dup 2>r ( addr len addr' len' taddr' ) ( R: taddr len' taddr' )
  1063. swap move ( addr len )
  1064. 2r> + ( addr len taddr' ) ( R: taddr )
  1065. swap 1+ move \ 1+ for '\0'
  1066. r> ( taddr )
  1067. ;
  1068. : scan_conf_dir ( -- addr len -1 | 0 )
  1069. s" currdev" getenv -1 <> if
  1070. 3 \ we only need first 3 chars
  1071. s" net" compare 0= if
  1072. s" boot.tftproot.server" getenv? if
  1073. 0 exit \ readdir does not work on tftp
  1074. then
  1075. then
  1076. then
  1077. ['] entries catch if
  1078. 0 exit
  1079. then
  1080. dup 0= if exit then \ nothing to do
  1081. dup cells allocate ( n array flag ) \ allocate array
  1082. if 0 exit then
  1083. ['] opendir catch if ( n array )
  1084. free drop drop
  1085. 0 exit
  1086. then
  1087. over 0 do
  1088. readdir ( n array addr len flag | n array flag )
  1089. 0= if -1 abort" unexpected readdir error" then \ shouldnt happen
  1090. ( n array addr len )
  1091. \ we have relative name, make it absolute and convert to counted string
  1092. make_cstring ( n array addr )
  1093. over I cells + ! ( n array )
  1094. loop
  1095. closedir
  1096. 2dup swap sort
  1097. \ we have now array of strings with directory entry names.
  1098. \ calculate size of concatenated string
  1099. over 0 swap 0 do ( n array 0 )
  1100. over I cells + @ ( n array total array[I] )
  1101. @ + 1+ ( n array total' )
  1102. loop
  1103. dup allocate if drop free 2drop 0 exit then
  1104. ( n array len addr )
  1105. \ now concatenate all entries.
  1106. 2swap ( len addr n array )
  1107. over 0 swap 0 do ( len addr n array 0 )
  1108. over I cells + @ ( len addr n array total array[I] )
  1109. dup @ swap cell+ ( len addr n array total len addr' )
  1110. over ( len addr n array total len addr' len )
  1111. 6 pick ( len addr n array total len addr' len addr )
  1112. 4 pick + ( len addr n array total len addr' len addr+total )
  1113. swap move + ( len addr n array total+len )
  1114. 3 pick ( len addr n array total addr )
  1115. over + bl swap c! 1+ ( len addr n array total )
  1116. over I cells + @ free drop \ free array[I]
  1117. loop
  1118. drop free drop drop ( len addr )
  1119. swap ( addr len )
  1120. -1
  1121. ;
  1122. : get_conf_files ( -- addr len ) \ put addr/len on stack, reset var
  1123. \ ." -- starting on <" conf_files strtype ." >" cr \ debugging
  1124. scan_conf_dir if \ concatenate with conf_files
  1125. ( addr len )
  1126. dup conf_files .len @ + 2 + allocate abort" out of memory" ( addr len addr' )
  1127. dup conf_files strget ( addr len addr' caddr clen )
  1128. rot swap move ( addr len addr' )
  1129. \ add space
  1130. dup conf_files .len @ + ( addr len addr' addr'+clen )
  1131. dup bl swap c! 1+ ( addr len addr' addr'' )
  1132. 3 pick swap ( addr len addr' addr addr'' )
  1133. 3 pick move ( addr len addr' )
  1134. rot ( len addr' addr )
  1135. free drop swap ( addr' len )
  1136. conf_files .len @ + 1+ ( addr len )
  1137. conf_files strfree
  1138. else
  1139. conf_files strget 0 0 conf_files strset
  1140. then
  1141. ;
  1142. : skip_leading_spaces { addr len pos -- addr len pos' }
  1143. begin
  1144. pos len = if 0 else addr pos + c@ bl = then
  1145. while
  1146. pos char+ to pos
  1147. repeat
  1148. addr len pos
  1149. ;
  1150. \ return the file name at pos, or free the string if nothing left
  1151. : get_file_name { addr len pos -- addr len pos' addr' len' || 0 }
  1152. pos len = if
  1153. addr free abort" Fatal error freeing memory"
  1154. 0 exit
  1155. then
  1156. pos >r
  1157. begin
  1158. \ stay in the loop until have chars and they are not blank
  1159. pos len = if 0 else addr pos + c@ bl <> then
  1160. while
  1161. pos char+ to pos
  1162. repeat
  1163. addr len pos addr r@ + pos r> -
  1164. ;
  1165. : get_next_file ( addr len ptr -- addr len ptr' addr' len' | 0 )
  1166. skip_leading_spaces
  1167. get_file_name
  1168. ;
  1169. : print_current_file
  1170. current_file_name_ref strtype
  1171. ;
  1172. : process_conf_errors
  1173. dup 0= if true to any_conf_read? drop exit then
  1174. >r 2drop r>
  1175. dup ESYNTAX = if
  1176. ." Warning: syntax error on file " print_current_file cr
  1177. print_syntax_error drop exit
  1178. then
  1179. dup ESETERROR = if
  1180. ." Warning: bad definition on file " print_current_file cr
  1181. print_line drop exit
  1182. then
  1183. dup EREAD = if
  1184. ." Warning: error reading file " print_current_file cr drop exit
  1185. then
  1186. dup EOPEN = if
  1187. verbose? if ." Warning: unable to open file " print_current_file cr then
  1188. drop exit
  1189. then
  1190. dup EFREE = abort" Fatal error freeing memory"
  1191. dup ENOMEM = abort" Out of memory"
  1192. throw \ Unknown error -- pass ahead
  1193. ;
  1194. \ Process loader_conf_files recursively
  1195. \ Interface to loader_conf_files processing
  1196. : include_bootenv
  1197. s" /boot/solaris/bootenv.rc"
  1198. ['] load_bootenv catch
  1199. dup 0= if drop exit then
  1200. >r 2drop r>
  1201. dup ESYNTAX = if
  1202. ." Warning: syntax error on /boot/solaris/bootenv.rc" cr drop exit
  1203. then
  1204. dup EREAD = if
  1205. ." Warning: error reading /boot/solaris/bootenv.rc" cr drop exit
  1206. then
  1207. dup EOPEN = if
  1208. verbose? if ." Warning: unable to open /boot/solaris/bootenv.rc" cr then
  1209. drop exit
  1210. then
  1211. dup EFREE = abort" Fatal error freeing memory"
  1212. dup ENOMEM = abort" Out of memory"
  1213. throw \ Unknown error -- pass ahead
  1214. ;
  1215. : include_transient
  1216. s" /boot/transient.conf" ['] load_conf catch
  1217. dup 0= if drop exit then \ no error
  1218. >r 2drop r>
  1219. dup ESYNTAX = if
  1220. ." Warning: syntax error on file /boot/transient.conf" cr
  1221. drop exit
  1222. then
  1223. dup ESETERROR = if
  1224. ." Warning: bad definition on file /boot/transient.conf" cr
  1225. drop exit
  1226. then
  1227. dup EREAD = if
  1228. ." Warning: error reading file /boot/transient.conf" cr drop exit
  1229. then
  1230. dup EOPEN = if
  1231. verbose? if ." Warning: unable to open file /boot/transient.conf" cr then
  1232. drop exit
  1233. then
  1234. dup EFREE = abort" Fatal error freeing memory"
  1235. dup ENOMEM = abort" Out of memory"
  1236. throw \ Unknown error -- pass ahead
  1237. ;
  1238. : include_conf_files
  1239. get_conf_files 0 ( addr len offset )
  1240. begin
  1241. get_next_file ?dup ( addr len 1 | 0 )
  1242. while
  1243. current_file_name_ref strref
  1244. ['] load_conf catch
  1245. process_conf_errors
  1246. conf_files .addr @ if recurse then
  1247. repeat
  1248. ;
  1249. \ Module loading functions
  1250. \ concat two strings by allocating space
  1251. : concat { a1 l1 a2 l2 -- a' l' }
  1252. l1 l2 + allocate if ENOMEM throw then
  1253. 0 a1 l1 strcat
  1254. a2 l2 strcat
  1255. ;
  1256. \ build module argument list as: "hash= name= module.args"
  1257. \ if type is hash, name= will have module name without .hash suffix
  1258. \ will free old largs and set new.
  1259. : build_largs { addr -- addr }
  1260. addr module.largs strfree
  1261. addr module.hash .len @
  1262. if ( set hash= )
  1263. s" hash=" addr module.hash strget concat
  1264. addr module.largs strset \ largs = "hash=" + module.hash
  1265. then
  1266. addr module.type strget s" hash" compare 0=
  1267. if ( module.type == "hash" )
  1268. addr module.largs strget s" name=" concat
  1269. addr module.loadname .len @
  1270. if ( module.loadname != NULL )
  1271. addr module.loadname strget concat
  1272. else
  1273. addr module.name strget concat
  1274. then
  1275. addr module.largs strfree
  1276. addr module.largs strset \ largs = largs + name
  1277. \ last thing to do is to strip off ".hash" suffix
  1278. addr module.largs strget [char] . strchr
  1279. dup if ( strchr module.largs '.' )
  1280. s" .hash" compare 0=
  1281. if ( it is ".hash" )
  1282. addr module.largs .len @ 5 -
  1283. addr module.largs .len !
  1284. then
  1285. else
  1286. 2drop
  1287. then
  1288. then
  1289. \ and now add up the module.args
  1290. addr module.largs strget s" " concat
  1291. addr module.args strget concat
  1292. addr module.largs strfree
  1293. addr module.largs strset
  1294. addr
  1295. ;
  1296. : load_parameters { addr -- addr addrN lenN ... addr1 len1 N }
  1297. addr build_largs
  1298. addr module.largs strget
  1299. addr module.loadname .len @ if
  1300. addr module.loadname strget
  1301. else
  1302. addr module.name strget
  1303. then
  1304. addr module.type .len @ if
  1305. addr module.type strget
  1306. s" -t "
  1307. 4 ( -t type name flags )
  1308. else
  1309. 2 ( name flags )
  1310. then
  1311. ;
  1312. : before_load ( addr -- addr )
  1313. dup module.beforeload .len @ if
  1314. dup module.beforeload strget
  1315. ['] evaluate catch if EBEFORELOAD throw then
  1316. then
  1317. ;
  1318. : after_load ( addr -- addr )
  1319. dup module.afterload .len @ if
  1320. dup module.afterload strget
  1321. ['] evaluate catch if EAFTERLOAD throw then
  1322. then
  1323. ;
  1324. : load_error ( addr -- addr )
  1325. dup module.loaderror .len @ if
  1326. dup module.loaderror strget
  1327. evaluate \ This we do not intercept so it can throw errors
  1328. then
  1329. ;
  1330. : pre_load_message ( addr -- addr )
  1331. verbose? if
  1332. dup module.name strtype
  1333. ." ..."
  1334. then
  1335. ;
  1336. : load_error_message verbose? if ." failed!" cr then ;
  1337. : load_successful_message verbose? if ." ok" cr then ;
  1338. : load_module
  1339. load_parameters load
  1340. ;
  1341. : process_module ( addr -- addr )
  1342. pre_load_message
  1343. before_load
  1344. begin
  1345. ['] load_module catch if
  1346. dup module.loaderror .len @ if
  1347. load_error \ Command should return a flag!
  1348. else
  1349. load_error_message true \ Do not retry
  1350. then
  1351. else
  1352. after_load
  1353. load_successful_message true \ Successful, do not retry
  1354. then
  1355. until
  1356. ;
  1357. : process_module_errors ( addr ior -- )
  1358. dup EBEFORELOAD = if
  1359. drop
  1360. ." Module "
  1361. dup module.name strtype
  1362. dup module.loadname .len @ if
  1363. ." (" dup module.loadname strtype ." )"
  1364. then
  1365. cr
  1366. ." Error executing "
  1367. dup module.beforeload strtype cr \ XXX there was a typo here
  1368. abort
  1369. then
  1370. dup EAFTERLOAD = if
  1371. drop
  1372. ." Module "
  1373. dup module.name .addr @ over module.name .len @ type
  1374. dup module.loadname .len @ if
  1375. ." (" dup module.loadname strtype ." )"
  1376. then
  1377. cr
  1378. ." Error executing "
  1379. dup module.afterload strtype cr
  1380. abort
  1381. then
  1382. throw \ Don't know what it is all about -- pass ahead
  1383. ;
  1384. \ Module loading interface
  1385. \ scan the list of modules, load enabled ones.
  1386. : load_modules ( -- ) ( throws: abort & user-defined )
  1387. module_options @ ( list_head )
  1388. begin
  1389. ?dup
  1390. while
  1391. dup module.flag @ if
  1392. ['] process_module catch
  1393. process_module_errors
  1394. then
  1395. module.next @
  1396. repeat
  1397. ;
  1398. \ h00h00 magic used to try loading either a kernel with a given name,
  1399. \ or a kernel with the default name in a directory of a given name
  1400. \ (the pain!)
  1401. : bootpath s" /platform/" ;
  1402. : modulepath s" module_path" ;
  1403. \ Functions used to save and restore module_path's value.
  1404. : saveenv ( addr len | -1 -- addr' len | 0 -1 )
  1405. dup -1 = if 0 swap exit then
  1406. strdup
  1407. ;
  1408. : freeenv ( addr len | 0 -1 )
  1409. -1 = if drop else free abort" Freeing error" then
  1410. ;
  1411. : restoreenv ( addr len | 0 -1 -- )
  1412. dup -1 = if ( it wasn't set )
  1413. 2drop
  1414. modulepath unsetenv
  1415. else
  1416. over >r
  1417. modulepath setenv
  1418. r> free abort" Freeing error"
  1419. then
  1420. ;
  1421. : clip_args \ Drop second string if only one argument is passed
  1422. 1 = if
  1423. 2swap 2drop
  1424. 1
  1425. else
  1426. 2
  1427. then
  1428. ;
  1429. also builtins
  1430. \ Parse filename from a semicolon-separated list
  1431. : parse-; ( addr len -- addr' len-x addr x )
  1432. over 0 2swap ( addr 0 addr len )
  1433. begin
  1434. dup 0 <> ( addr 0 addr len )
  1435. while
  1436. over c@ [char] ; <> ( addr 0 addr len flag )
  1437. while
  1438. 1- swap 1+ swap
  1439. 2swap 1+ 2swap
  1440. repeat then
  1441. dup 0 <> if
  1442. 1- swap 1+ swap
  1443. then
  1444. 2swap
  1445. ;
  1446. \ Try loading one of multiple kernels specified
  1447. : try_multiple_kernels ( addr len addr' len' args -- flag )
  1448. >r
  1449. begin
  1450. parse-; 2>r
  1451. 2over 2r>
  1452. r@ clip_args
  1453. s" DEBUG" getenv? if
  1454. s" echo Module_path: ${module_path}" evaluate
  1455. ." Kernel : " >r 2dup type r> cr
  1456. dup 2 = if ." Flags : " >r 2over type r> cr then
  1457. then
  1458. \ if it's xen, the xen kernel is loaded, unix needs to be loaded as module
  1459. s" xen_kernel" getenv -1 <> if
  1460. drop \ drop address from getenv
  1461. >r \ argument count to R
  1462. s" kernel" s" -t " \ push 2 strings into the stack
  1463. r> 2 + \ increment argument count
  1464. then
  1465. 1 ['] load catch dup if
  1466. ( addr0 len0 addr1 len1 ... args 1 error )
  1467. >r \ error code to R
  1468. drop \ drop 1
  1469. 0 do 2drop loop \ drop addr len pairs
  1470. r> \ set flag for while
  1471. then
  1472. while
  1473. dup 0=
  1474. until
  1475. 1 >r \ Failure
  1476. else
  1477. 0 >r \ Success
  1478. then
  1479. 2drop 2drop
  1480. r>
  1481. r> drop
  1482. ;
  1483. \ Try to load a kernel; the kernel name is taken from one of
  1484. \ the following lists, as ordered:
  1485. \
  1486. \ 1. The "bootfile" environment variable
  1487. \ 2. The "kernel" environment variable
  1488. \
  1489. \ Flags are passed, if available. If not, dummy values must be given.
  1490. \
  1491. \ The kernel gets loaded from the current module_path.
  1492. : load_a_kernel ( flags len 1 | x x 0 -- flag )
  1493. local args
  1494. 2local flags
  1495. 0 0 2local kernel
  1496. end-locals
  1497. \ Check if a default kernel name exists at all, exits if not
  1498. s" bootfile" getenv dup -1 <> if
  1499. to kernel
  1500. flags kernel args 1+ try_multiple_kernels
  1501. dup 0= if exit then
  1502. then
  1503. drop
  1504. s" kernel" getenv dup -1 <> if
  1505. to kernel
  1506. else
  1507. drop
  1508. 1 exit \ Failure
  1509. then
  1510. \ Try all default kernel names
  1511. flags kernel args 1+ try_multiple_kernels
  1512. ;
  1513. \ Try to load a kernel; the kernel name is taken from one of
  1514. \ the following lists, as ordered:
  1515. \
  1516. \ 1. The "bootfile" environment variable
  1517. \ 2. The "kernel" environment variable
  1518. \
  1519. \ Flags are passed, if provided.
  1520. \
  1521. \ The kernel will be loaded from a directory computed from the
  1522. \ path given. Two directories will be tried in the following order:
  1523. \
  1524. \ 1. /boot/path
  1525. \ 2. path
  1526. \
  1527. \ The module_path variable is overridden if load is successful, by
  1528. \ prepending the successful path.
  1529. : load_from_directory ( path len 1 | flags len' path len 2 -- flag )
  1530. local args
  1531. 2local path
  1532. args 1 = if 0 0 then
  1533. 2local flags
  1534. 0 0 2local oldmodulepath \ like a string
  1535. 0 0 2local newmodulepath \ like a string
  1536. end-locals
  1537. \ Set the environment variable module_path, and try loading
  1538. \ the kernel again.
  1539. modulepath getenv saveenv to oldmodulepath
  1540. \ Try prepending /boot/ first
  1541. bootpath nip path nip + \ total length
  1542. oldmodulepath nip dup -1 = if
  1543. drop
  1544. else
  1545. 1+ + \ add oldpath -- XXX why the 1+ ?
  1546. then
  1547. allocate if ( out of memory ) 1 exit then \ XXX throw ?
  1548. 0
  1549. bootpath strcat
  1550. path strcat
  1551. 2dup to newmodulepath
  1552. modulepath setenv
  1553. \ Try all default kernel names
  1554. flags args 1- load_a_kernel
  1555. 0= if ( success )
  1556. oldmodulepath nip -1 <> if
  1557. newmodulepath s" ;" strcat
  1558. oldmodulepath strcat
  1559. modulepath setenv
  1560. newmodulepath drop free-memory
  1561. oldmodulepath drop free-memory
  1562. then
  1563. 0 exit
  1564. then
  1565. \ Well, try without the prepended /boot/
  1566. path newmodulepath drop swap move
  1567. newmodulepath drop path nip
  1568. 2dup to newmodulepath
  1569. modulepath setenv
  1570. \ Try all default kernel names
  1571. flags args 1- load_a_kernel
  1572. if ( failed once more )
  1573. oldmodulepath restoreenv
  1574. newmodulepath drop free-memory
  1575. 1
  1576. else
  1577. oldmodulepath nip -1 <> if
  1578. newmodulepath s" ;" strcat
  1579. oldmodulepath strcat
  1580. modulepath setenv
  1581. newmodulepath drop free-memory
  1582. oldmodulepath drop free-memory
  1583. then
  1584. 0
  1585. then
  1586. ;
  1587. \ Try to load a kernel; the kernel name is taken from one of
  1588. \ the following lists, as ordered:
  1589. \
  1590. \ 1. The "bootfile" environment variable
  1591. \ 2. The "kernel" environment variable
  1592. \ 3. The "path" argument
  1593. \
  1594. \ Flags are passed, if provided.
  1595. \
  1596. \ The kernel will be loaded from a directory computed from the
  1597. \ path given. Two directories will be tried in the following order:
  1598. \
  1599. \ 1. /boot/path
  1600. \ 2. path
  1601. \
  1602. \ Unless "path" is meant to be kernel name itself. In that case, it
  1603. \ will first be tried as a full path, and, next, search on the
  1604. \ directories pointed by module_path.
  1605. \
  1606. \ The module_path variable is overridden if load is successful, by
  1607. \ prepending the successful path.
  1608. : load_directory_or_file ( path len 1 | flags len' path len 2 -- flag )
  1609. local args
  1610. 2local path
  1611. args 1 = if 0 0 then
  1612. 2local flags
  1613. end-locals
  1614. \ First, assume path is an absolute path to a directory
  1615. flags path args clip_args load_from_directory
  1616. dup 0= if exit else drop then
  1617. \ Next, assume path points to the kernel
  1618. flags path args try_multiple_kernels
  1619. ;
  1620. : initialize ( addr len -- )
  1621. strdup conf_files strset
  1622. ;
  1623. : boot-args ( -- addr len 1 | 0 )
  1624. s" boot-args" getenv
  1625. dup -1 = if drop 0 else 1 then
  1626. ;
  1627. : standard_kernel_search ( flags 1 | 0 -- flag )
  1628. local args
  1629. args 0= if 0 0 then
  1630. 2local flags
  1631. s" kernel" getenv
  1632. dup -1 = if 0 swap then
  1633. 2local path
  1634. end-locals
  1635. path nip -1 = if ( there isn't a "kernel" environment variable )
  1636. flags args load_a_kernel
  1637. else
  1638. flags path args 1+ clip_args load_directory_or_file
  1639. then
  1640. ;
  1641. : load_kernel ( -- ) ( throws: abort )
  1642. s" xen_kernel" getenv -1 = if
  1643. boot-args standard_kernel_search
  1644. abort" Unable to load a kernel!"
  1645. exit
  1646. then
  1647. drop
  1648. \ we have loaded the xen kernel, load unix as module
  1649. s" bootfile" getenv dup -1 <> if
  1650. s" kernel" s" -t " 3 1 load
  1651. then
  1652. abort" Unable to load a kernel!"
  1653. ;
  1654. : load_xen ( -- )
  1655. s" xen_kernel" getenv dup -1 <> if
  1656. 1 1 load ( c-addr/u flag N -- flag )
  1657. else
  1658. drop
  1659. 0 ( -1 -- flag )
  1660. then
  1661. ;
  1662. : load_xen_throw ( -- ) ( throws: abort )
  1663. load_xen
  1664. abort" Unable to load Xen!"
  1665. ;
  1666. : set_defaultoptions ( -- )
  1667. s" boot-args" getenv dup -1 = if
  1668. drop
  1669. else
  1670. s" temp_options" setenv
  1671. then
  1672. ;
  1673. \ pick the i-th argument, i starts at 0
  1674. : argv[] ( aN uN ... a1 u1 N i -- aN uN ... a1 u1 N ai+1 ui+1 )
  1675. 2dup = if 0 0 exit then \ out of range
  1676. dup >r
  1677. 1+ 2* ( skip N and ui )
  1678. pick
  1679. r>
  1680. 1+ 2* ( skip N and ai )
  1681. pick
  1682. ;
  1683. : drop_args ( aN uN ... a1 u1 N -- )
  1684. 0 ?do 2drop loop
  1685. ;
  1686. : argc
  1687. dup
  1688. ;
  1689. : queue_argv ( aN uN ... a1 u1 N a u -- a u aN uN ... a1 u1 N+1 )
  1690. >r
  1691. over 2* 1+ -roll
  1692. r>
  1693. over 2* 1+ -roll
  1694. 1+
  1695. ;
  1696. : unqueue_argv ( aN uN ... a1 u1 N -- aN uN ... a2 u2 N-1 a1 u1 )
  1697. 1- -rot
  1698. ;
  1699. \ compute the length of the buffer including the spaces between words
  1700. : strlen(argv) ( aN uN .. a1 u1 N -- aN uN .. a1 u1 N len )
  1701. dup 0= if 0 exit then
  1702. 0 >r \ Size
  1703. 0 >r \ Index
  1704. begin
  1705. argc r@ <>
  1706. while
  1707. r@ argv[]
  1708. nip
  1709. r> r> rot + 1+
  1710. >r 1+ >r
  1711. repeat
  1712. r> drop
  1713. r>
  1714. ;
  1715. : concat_argv ( aN uN ... a1 u1 N -- a u )
  1716. strlen(argv) allocate if ENOMEM throw then
  1717. 0 2>r ( save addr 0 on return stack )
  1718. begin
  1719. dup
  1720. while
  1721. unqueue_argv ( ... N a1 u1 )
  1722. 2r> 2swap ( old a1 u1 )
  1723. strcat
  1724. s" " strcat ( append one space ) \ XXX this gives a trailing space
  1725. 2>r ( store string on the result stack )
  1726. repeat
  1727. drop_args
  1728. 2r>
  1729. ;
  1730. : set_tempoptions ( addrN lenN ... addr1 len1 N -- addr len 1 | 0 )
  1731. \ Save the first argument, if it exists and is not a flag
  1732. argc if
  1733. 0 argv[] drop c@ [char] - <> if
  1734. unqueue_argv 2>r \ Filename
  1735. 1 >r \ Filename present
  1736. else
  1737. 0 >r \ Filename not present
  1738. then
  1739. else
  1740. 0 >r \ Filename not present
  1741. then
  1742. \ If there are other arguments, assume they are flags
  1743. ?dup if
  1744. concat_argv
  1745. 2dup s" temp_options" setenv
  1746. drop free if EFREE throw then
  1747. else
  1748. set_defaultoptions
  1749. then
  1750. \ Bring back the filename, if one was provided
  1751. r> if 2r> 1 else 0 then
  1752. ;
  1753. : get_arguments ( -- addrN lenN ... addr1 len1 N )
  1754. 0
  1755. begin
  1756. \ Get next word on the command line
  1757. parse-word
  1758. ?dup while
  1759. queue_argv
  1760. repeat
  1761. drop ( empty string )
  1762. ;
  1763. : load_kernel_and_modules ( args -- flag )
  1764. set_tempoptions
  1765. argc >r
  1766. s" temp_options" getenv dup -1 <> if
  1767. queue_argv
  1768. else
  1769. drop
  1770. then
  1771. load_xen
  1772. ?dup 0= if ( success )
  1773. r> if ( a path was passed )
  1774. load_directory_or_file
  1775. else
  1776. standard_kernel_search
  1777. then
  1778. ?dup 0= if ['] load_modules catch then
  1779. then
  1780. ;
  1781. only forth definitions