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

/sys/boot/forth/support.4th

https://repo.or.cz/dragonfly/vkernel-mp.git
Forth | 1714 lines | 1475 code | 239 blank | 0 comment | 119 complexity | db0543a232dfa732b977dab308b5452a MD5 | raw file
Possible License(s): CC-BY-SA-3.0, Unlicense, BSD-3-Clause, ISC, GPL-2.0, AGPL-1.0
  1. \ Copyright (c) 1999 Daniel C. Sobral <dcs@freebsd.org>
  2. \ All rights reserved.
  3. \
  4. \ Redistribution and use in source and binary forms, with or without
  5. \ modification, are permitted provided that the following conditions
  6. \ are met:
  7. \ 1. Redistributions of source code must retain the above copyright
  8. \ notice, this list of conditions and the following disclaimer.
  9. \ 2. Redistributions in binary form must reproduce the above copyright
  10. \ notice, this list of conditions and the following disclaimer in the
  11. \ documentation and/or other materials provided with the distribution.
  12. \
  13. \ THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
  14. \ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  15. \ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  16. \ ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
  17. \ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  18. \ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  19. \ OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  20. \ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  21. \ LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  22. \ OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  23. \ SUCH DAMAGE.
  24. \
  25. \ $FreeBSD: src/sys/boot/forth/support.4th,v 1.15 2002/05/24 02:28:58 gordon Exp $
  26. \ $DragonFly: src/sys/boot/forth/support.4th,v 1.3 2003/11/10 07:08:34 dillon Exp $
  27. \ Loader.rc support functions:
  28. \
  29. \ initialize_support ( -- ) initialize global variables
  30. \ initialize ( addr len -- ) as above, plus load_conf_files
  31. \ load_conf ( addr len -- ) load conf file given
  32. \ include_conf_files ( -- ) load all conf files in load_conf_files
  33. \ print_syntax_error ( -- ) print line and marker of where a syntax
  34. \ error was detected
  35. \ print_line ( -- ) print last line processed
  36. \ load_kernel ( -- ) load kernel
  37. \ load_modules ( -- ) load modules flagged
  38. \
  39. \ Exported structures:
  40. \
  41. \ string counted string structure
  42. \ cell .addr string address
  43. \ cell .len string length
  44. \ module module loading information structure
  45. \ cell module.flag should we load it?
  46. \ string module.name module's name
  47. \ string module.loadname name to be used in loading the module
  48. \ string module.type module's type
  49. \ string module.args flags to be passed during load
  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. \ string password password
  59. \ cell modules_options pointer to first module information
  60. \ value verbose? indicates if user wants a verbose loading
  61. \ value any_conf_read? indicates if a conf file was succesfully read
  62. \
  63. \ Other exported words:
  64. \
  65. \ strdup ( addr len -- addr' len) similar to strdup(3)
  66. \ strcat ( addr len addr' len' -- addr len+len' ) similar to strcat(3)
  67. \ strlen ( addr -- len ) similar to strlen(3)
  68. \ s' ( | string' -- addr len | ) similar to s"
  69. \ rudimentary structure support
  70. \ Exception values
  71. 1 constant syntax_error
  72. 2 constant out_of_memory
  73. 3 constant free_error
  74. 4 constant set_error
  75. 5 constant read_error
  76. 6 constant open_error
  77. 7 constant exec_error
  78. 8 constant before_load_error
  79. 9 constant after_load_error
  80. \ I/O constants
  81. 0 constant SEEK_SET
  82. 1 constant SEEK_CUR
  83. 2 constant SEEK_END
  84. 0 constant O_RDONLY
  85. 1 constant O_WRONLY
  86. 2 constant O_RDWR
  87. \ Crude structure support
  88. : structure:
  89. create here 0 , ['] drop , 0
  90. does> create here swap dup @ allot cell+ @ execute
  91. ;
  92. : member: create dup , over , + does> cell+ @ + ;
  93. : ;structure swap ! ;
  94. : constructor! >body cell+ ! ;
  95. : constructor: over :noname ;
  96. : ;constructor postpone ; swap cell+ ! ; immediate
  97. : sizeof ' >body @ state @ if postpone literal then ; immediate
  98. : offsetof ' >body cell+ @ state @ if postpone literal then ; immediate
  99. : ptr 1 cells member: ;
  100. : int 1 cells member: ;
  101. \ String structure
  102. structure: string
  103. ptr .addr
  104. int .len
  105. constructor:
  106. 0 over .addr !
  107. 0 swap .len !
  108. ;constructor
  109. ;structure
  110. \ Module options linked list
  111. structure: module
  112. int module.flag
  113. sizeof string member: module.name
  114. sizeof string member: module.loadname
  115. sizeof string member: module.type
  116. sizeof string member: module.args
  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
  123. structure: preloaded_file
  124. ptr pf.name
  125. ptr pf.type
  126. ptr pf.args
  127. ptr pf.metadata \ file_metadata
  128. int pf.loader
  129. int pf.addr
  130. int pf.size
  131. ptr pf.modules \ kernel_module
  132. ptr pf.next \ preloaded_file
  133. ;structure
  134. structure: kernel_module
  135. ptr km.name
  136. \ ptr km.args
  137. ptr km.fp \ preloaded_file
  138. ptr km.next \ kernel_module
  139. ;structure
  140. structure: file_metadata
  141. int md.size
  142. 2 member: md.type \ this is not ANS Forth compatible (XXX)
  143. ptr md.next \ file_metadata
  144. 0 member: md.data \ variable size
  145. ;structure
  146. structure: config_resource
  147. ptr cf.name
  148. int cf.type
  149. 0 constant RES_INT
  150. 1 constant RES_STRING
  151. 2 constant RES_LONG
  152. 2 cells member: u
  153. ;structure
  154. structure: config_device
  155. ptr cd.name
  156. int cd.unit
  157. int cd.resource_count
  158. ptr cd.resources \ config_resource
  159. ;structure
  160. structure: STAILQ_HEAD
  161. ptr stqh_first \ type*
  162. ptr stqh_last \ type**
  163. ;structure
  164. structure: STAILQ_ENTRY
  165. ptr stqe_next \ type*
  166. ;structure
  167. structure: pnphandler
  168. ptr pnph.name
  169. ptr pnph.enumerate
  170. ;structure
  171. structure: pnpident
  172. ptr pnpid.ident \ char*
  173. sizeof STAILQ_ENTRY cells member: pnpid.link \ pnpident
  174. ;structure
  175. structure: pnpinfo
  176. ptr pnpi.desc
  177. int pnpi.revision
  178. ptr pnpi.module \ (char*) module args
  179. int pnpi.argc
  180. ptr pnpi.argv
  181. ptr pnpi.handler \ pnphandler
  182. sizeof STAILQ_HEAD member: pnpi.ident \ pnpident
  183. sizeof STAILQ_ENTRY member: pnpi.link \ pnpinfo
  184. ;structure
  185. \ Global variables
  186. string conf_files
  187. string nextboot_conf_file
  188. string password
  189. create module_options sizeof module.next allot 0 module_options !
  190. create last_module_option sizeof module.next allot 0 last_module_option !
  191. 0 value verbose?
  192. 0 value nextboot?
  193. \ Support string functions
  194. : strdup ( addr len -- addr' len )
  195. >r r@ allocate if out_of_memory throw then
  196. tuck r@ move
  197. r>
  198. ;
  199. : strcat { addr len addr' len' -- addr len+len' }
  200. addr' addr len + len' move
  201. addr len len' +
  202. ;
  203. : strlen ( addr -- len )
  204. 0 >r
  205. begin
  206. dup c@ while
  207. 1+ r> 1+ >r repeat
  208. drop r>
  209. ;
  210. : s'
  211. [char] ' parse
  212. state @ if
  213. postpone sliteral
  214. then
  215. ; immediate
  216. : 2>r postpone >r postpone >r ; immediate
  217. : 2r> postpone r> postpone r> ; immediate
  218. : 2r@ postpone 2r> postpone 2dup postpone 2>r ; immediate
  219. : getenv?
  220. getenv
  221. -1 = if false else drop true then
  222. ;
  223. \ Private definitions
  224. vocabulary support-functions
  225. only forth also support-functions definitions
  226. \ Some control characters constants
  227. 7 constant bell
  228. 8 constant backspace
  229. 9 constant tab
  230. 10 constant lf
  231. 13 constant <cr>
  232. \ Read buffer size
  233. 80 constant read_buffer_size
  234. \ Standard suffixes
  235. : load_module_suffix s" _load" ;
  236. : module_loadname_suffix s" _name" ;
  237. : module_type_suffix s" _type" ;
  238. : module_args_suffix s" _flags" ;
  239. : module_beforeload_suffix s" _before" ;
  240. : module_afterload_suffix s" _after" ;
  241. : module_loaderror_suffix s" _error" ;
  242. \ Support operators
  243. : >= < 0= ;
  244. : <= > 0= ;
  245. \ Assorted support funcitons
  246. : free-memory free if free_error throw then ;
  247. \ Assignment data temporary storage
  248. string name_buffer
  249. string value_buffer
  250. \ Line by line file reading functions
  251. \
  252. \ exported:
  253. \ line_buffer
  254. \ end_of_file?
  255. \ fd
  256. \ read_line
  257. \ reset_line_reading
  258. vocabulary line-reading
  259. also line-reading definitions also
  260. \ File data temporary storage
  261. string read_buffer
  262. 0 value read_buffer_ptr
  263. \ File's line reading function
  264. support-functions definitions
  265. string line_buffer
  266. 0 value end_of_file?
  267. variable fd
  268. line-reading definitions
  269. : skip_newlines
  270. begin
  271. read_buffer .len @ read_buffer_ptr >
  272. while
  273. read_buffer .addr @ read_buffer_ptr + c@ lf = if
  274. read_buffer_ptr char+ to read_buffer_ptr
  275. else
  276. exit
  277. then
  278. repeat
  279. ;
  280. : scan_buffer ( -- addr len )
  281. read_buffer_ptr >r
  282. begin
  283. read_buffer .len @ r@ >
  284. while
  285. read_buffer .addr @ r@ + c@ lf = if
  286. read_buffer .addr @ read_buffer_ptr + ( -- addr )
  287. r@ read_buffer_ptr - ( -- len )
  288. r> to read_buffer_ptr
  289. exit
  290. then
  291. r> char+ >r
  292. repeat
  293. read_buffer .addr @ read_buffer_ptr + ( -- addr )
  294. r@ read_buffer_ptr - ( -- len )
  295. r> to read_buffer_ptr
  296. ;
  297. : line_buffer_resize ( len -- len )
  298. >r
  299. line_buffer .len @ if
  300. line_buffer .addr @
  301. line_buffer .len @ r@ +
  302. resize if out_of_memory throw then
  303. else
  304. r@ allocate if out_of_memory throw then
  305. then
  306. line_buffer .addr !
  307. r>
  308. ;
  309. : append_to_line_buffer ( addr len -- )
  310. line_buffer .addr @ line_buffer .len @
  311. 2swap strcat
  312. line_buffer .len !
  313. drop
  314. ;
  315. : read_from_buffer
  316. scan_buffer ( -- addr len )
  317. line_buffer_resize ( len -- len )
  318. append_to_line_buffer ( addr len -- )
  319. ;
  320. : refill_required?
  321. read_buffer .len @ read_buffer_ptr =
  322. end_of_file? 0= and
  323. ;
  324. : refill_buffer
  325. 0 to read_buffer_ptr
  326. read_buffer .addr @ 0= if
  327. read_buffer_size allocate if out_of_memory throw then
  328. read_buffer .addr !
  329. then
  330. fd @ read_buffer .addr @ read_buffer_size fread
  331. dup -1 = if read_error throw then
  332. dup 0= if true to end_of_file? then
  333. read_buffer .len !
  334. ;
  335. : reset_line_buffer
  336. line_buffer .addr @ ?dup if
  337. free-memory
  338. then
  339. 0 line_buffer .addr !
  340. 0 line_buffer .len !
  341. ;
  342. support-functions definitions
  343. : reset_line_reading
  344. 0 to read_buffer_ptr
  345. ;
  346. : read_line
  347. reset_line_buffer
  348. skip_newlines
  349. begin
  350. read_from_buffer
  351. refill_required?
  352. while
  353. refill_buffer
  354. repeat
  355. ;
  356. only forth also support-functions definitions
  357. \ Conf file line parser:
  358. \ <line> ::= <spaces><name><spaces>'='<spaces><value><spaces>[<comment>] |
  359. \ <spaces>[<comment>]
  360. \ <name> ::= <letter>{<letter>|<digit>|'_'}
  361. \ <value> ::= '"'{<character_set>|'\'<anything>}'"' | <name>
  362. \ <character_set> ::= ASCII 32 to 126, except '\' and '"'
  363. \ <comment> ::= '#'{<anything>}
  364. \
  365. \ exported:
  366. \ line_pointer
  367. \ process_conf
  368. 0 value line_pointer
  369. vocabulary file-processing
  370. also file-processing definitions
  371. \ parser functions
  372. \
  373. \ exported:
  374. \ get_assignment
  375. vocabulary parser
  376. also parser definitions also
  377. 0 value parsing_function
  378. 0 value end_of_line
  379. : end_of_line?
  380. line_pointer end_of_line =
  381. ;
  382. : letter?
  383. line_pointer c@ >r
  384. r@ [char] A >=
  385. r@ [char] Z <= and
  386. r@ [char] a >=
  387. r> [char] z <= and
  388. or
  389. ;
  390. : digit?
  391. line_pointer c@ >r
  392. r@ [char] 0 >=
  393. r> [char] 9 <= and
  394. ;
  395. : quote?
  396. line_pointer c@ [char] " =
  397. ;
  398. : assignment_sign?
  399. line_pointer c@ [char] = =
  400. ;
  401. : comment?
  402. line_pointer c@ [char] # =
  403. ;
  404. : space?
  405. line_pointer c@ bl =
  406. line_pointer c@ tab = or
  407. ;
  408. : backslash?
  409. line_pointer c@ [char] \ =
  410. ;
  411. : underscore?
  412. line_pointer c@ [char] _ =
  413. ;
  414. : dot?
  415. line_pointer c@ [char] . =
  416. ;
  417. : skip_character
  418. line_pointer char+ to line_pointer
  419. ;
  420. : skip_to_end_of_line
  421. end_of_line to line_pointer
  422. ;
  423. : eat_space
  424. begin
  425. space?
  426. while
  427. skip_character
  428. end_of_line? if exit then
  429. repeat
  430. ;
  431. : parse_name ( -- addr len )
  432. line_pointer
  433. begin
  434. letter? digit? underscore? dot? or or or
  435. while
  436. skip_character
  437. end_of_line? if
  438. line_pointer over -
  439. strdup
  440. exit
  441. then
  442. repeat
  443. line_pointer over -
  444. strdup
  445. ;
  446. : remove_backslashes { addr len | addr' len' -- addr' len' }
  447. len allocate if out_of_memory throw then
  448. to addr'
  449. addr >r
  450. begin
  451. addr c@ [char] \ <> if
  452. addr c@ addr' len' + c!
  453. len' char+ to len'
  454. then
  455. addr char+ to addr
  456. r@ len + addr =
  457. until
  458. r> drop
  459. addr' len'
  460. ;
  461. : parse_quote ( -- addr len )
  462. line_pointer
  463. skip_character
  464. end_of_line? if syntax_error throw then
  465. begin
  466. quote? 0=
  467. while
  468. backslash? if
  469. skip_character
  470. end_of_line? if syntax_error throw then
  471. then
  472. skip_character
  473. end_of_line? if syntax_error throw then
  474. repeat
  475. skip_character
  476. line_pointer over -
  477. remove_backslashes
  478. ;
  479. : read_name
  480. parse_name ( -- addr len )
  481. name_buffer .len !
  482. name_buffer .addr !
  483. ;
  484. : read_value
  485. quote? if
  486. parse_quote ( -- addr len )
  487. else
  488. parse_name ( -- addr len )
  489. then
  490. value_buffer .len !
  491. value_buffer .addr !
  492. ;
  493. : comment
  494. skip_to_end_of_line
  495. ;
  496. : white_space_4
  497. eat_space
  498. comment? if ['] comment to parsing_function exit then
  499. end_of_line? 0= if syntax_error throw then
  500. ;
  501. : variable_value
  502. read_value
  503. ['] white_space_4 to parsing_function
  504. ;
  505. : white_space_3
  506. eat_space
  507. letter? digit? quote? or or if
  508. ['] variable_value to parsing_function exit
  509. then
  510. syntax_error throw
  511. ;
  512. : assignment_sign
  513. skip_character
  514. ['] white_space_3 to parsing_function
  515. ;
  516. : white_space_2
  517. eat_space
  518. assignment_sign? if ['] assignment_sign to parsing_function exit then
  519. syntax_error throw
  520. ;
  521. : variable_name
  522. read_name
  523. ['] white_space_2 to parsing_function
  524. ;
  525. : white_space_1
  526. eat_space
  527. letter? if ['] variable_name to parsing_function exit then
  528. comment? if ['] comment to parsing_function exit then
  529. end_of_line? 0= if syntax_error throw then
  530. ;
  531. file-processing definitions
  532. : get_assignment
  533. line_buffer .addr @ line_buffer .len @ + to end_of_line
  534. line_buffer .addr @ to line_pointer
  535. ['] white_space_1 to parsing_function
  536. begin
  537. end_of_line? 0=
  538. while
  539. parsing_function execute
  540. repeat
  541. parsing_function ['] comment =
  542. parsing_function ['] white_space_1 =
  543. parsing_function ['] white_space_4 =
  544. or or 0= if syntax_error throw then
  545. ;
  546. only forth also support-functions also file-processing definitions also
  547. \ Process line
  548. : assignment_type? ( addr len -- flag )
  549. name_buffer .addr @ name_buffer .len @
  550. compare 0=
  551. ;
  552. : suffix_type? ( addr len -- flag )
  553. name_buffer .len @ over <= if 2drop false exit then
  554. name_buffer .len @ over - name_buffer .addr @ +
  555. over compare 0=
  556. ;
  557. : loader_conf_files?
  558. s" loader_conf_files" assignment_type?
  559. ;
  560. : nextboot_flag?
  561. s" nextboot_enable" assignment_type?
  562. ;
  563. : nextboot_conf?
  564. s" nextboot_conf" assignment_type?
  565. ;
  566. : verbose_flag?
  567. s" verbose_loading" assignment_type?
  568. ;
  569. : execute?
  570. s" exec" assignment_type?
  571. ;
  572. : password?
  573. s" password" assignment_type?
  574. ;
  575. : module_load?
  576. load_module_suffix suffix_type?
  577. ;
  578. : module_loadname?
  579. module_loadname_suffix suffix_type?
  580. ;
  581. : module_type?
  582. module_type_suffix suffix_type?
  583. ;
  584. : module_args?
  585. module_args_suffix suffix_type?
  586. ;
  587. : module_beforeload?
  588. module_beforeload_suffix suffix_type?
  589. ;
  590. : module_afterload?
  591. module_afterload_suffix suffix_type?
  592. ;
  593. : module_loaderror?
  594. module_loaderror_suffix suffix_type?
  595. ;
  596. : set_conf_files
  597. conf_files .addr @ ?dup if
  598. free-memory
  599. then
  600. value_buffer .addr @ c@ [char] " = if
  601. value_buffer .addr @ char+ value_buffer .len @ 2 chars -
  602. else
  603. value_buffer .addr @ value_buffer .len @
  604. then
  605. strdup
  606. conf_files .len ! conf_files .addr !
  607. ;
  608. : set_nextboot_conf
  609. nextboot_conf_file .addr @ ?dup if
  610. free-memory
  611. then
  612. value_buffer .addr @ c@ [char] " = if
  613. value_buffer .addr @ char+ value_buffer .len @ 2 chars -
  614. else
  615. value_buffer .addr @ value_buffer .len @
  616. then
  617. strdup
  618. nextboot_conf_file .len ! nextboot_conf_file .addr !
  619. ;
  620. : append_to_module_options_list ( addr -- )
  621. module_options @ 0= if
  622. dup module_options !
  623. last_module_option !
  624. else
  625. dup last_module_option @ module.next !
  626. last_module_option !
  627. then
  628. ;
  629. : set_module_name ( addr -- )
  630. name_buffer .addr @ name_buffer .len @
  631. strdup
  632. >r over module.name .addr !
  633. r> swap module.name .len !
  634. ;
  635. : yes_value?
  636. value_buffer .addr @ value_buffer .len @
  637. 2dup s' "YES"' compare >r
  638. 2dup s' "yes"' compare >r
  639. 2dup s" YES" compare >r
  640. s" yes" compare r> r> r> and and and 0=
  641. ;
  642. : find_module_option ( -- addr | 0 )
  643. module_options @
  644. begin
  645. dup
  646. while
  647. dup module.name dup .addr @ swap .len @
  648. name_buffer .addr @ name_buffer .len @
  649. compare 0= if exit then
  650. module.next @
  651. repeat
  652. ;
  653. : new_module_option ( -- addr )
  654. sizeof module allocate if out_of_memory throw then
  655. dup sizeof module erase
  656. dup append_to_module_options_list
  657. dup set_module_name
  658. ;
  659. : get_module_option ( -- addr )
  660. find_module_option
  661. ?dup 0= if new_module_option then
  662. ;
  663. : set_module_flag
  664. name_buffer .len @ load_module_suffix nip - name_buffer .len !
  665. yes_value? get_module_option module.flag !
  666. ;
  667. : set_module_args
  668. name_buffer .len @ module_args_suffix nip - name_buffer .len !
  669. get_module_option module.args
  670. dup .addr @ ?dup if free-memory then
  671. value_buffer .addr @ value_buffer .len @
  672. over c@ [char] " = if
  673. 2 chars - swap char+ swap
  674. then
  675. strdup
  676. >r over .addr !
  677. r> swap .len !
  678. ;
  679. : set_module_loadname
  680. name_buffer .len @ module_loadname_suffix nip - name_buffer .len !
  681. get_module_option module.loadname
  682. dup .addr @ ?dup if free-memory then
  683. value_buffer .addr @ value_buffer .len @
  684. over c@ [char] " = if
  685. 2 chars - swap char+ swap
  686. then
  687. strdup
  688. >r over .addr !
  689. r> swap .len !
  690. ;
  691. : set_module_type
  692. name_buffer .len @ module_type_suffix nip - name_buffer .len !
  693. get_module_option module.type
  694. dup .addr @ ?dup if free-memory then
  695. value_buffer .addr @ value_buffer .len @
  696. over c@ [char] " = if
  697. 2 chars - swap char+ swap
  698. then
  699. strdup
  700. >r over .addr !
  701. r> swap .len !
  702. ;
  703. : set_module_beforeload
  704. name_buffer .len @ module_beforeload_suffix nip - name_buffer .len !
  705. get_module_option module.beforeload
  706. dup .addr @ ?dup if free-memory then
  707. value_buffer .addr @ value_buffer .len @
  708. over c@ [char] " = if
  709. 2 chars - swap char+ swap
  710. then
  711. strdup
  712. >r over .addr !
  713. r> swap .len !
  714. ;
  715. : set_module_afterload
  716. name_buffer .len @ module_afterload_suffix nip - name_buffer .len !
  717. get_module_option module.afterload
  718. dup .addr @ ?dup if free-memory then
  719. value_buffer .addr @ value_buffer .len @
  720. over c@ [char] " = if
  721. 2 chars - swap char+ swap
  722. then
  723. strdup
  724. >r over .addr !
  725. r> swap .len !
  726. ;
  727. : set_module_loaderror
  728. name_buffer .len @ module_loaderror_suffix nip - name_buffer .len !
  729. get_module_option module.loaderror
  730. dup .addr @ ?dup if free-memory then
  731. value_buffer .addr @ value_buffer .len @
  732. over c@ [char] " = if
  733. 2 chars - swap char+ swap
  734. then
  735. strdup
  736. >r over .addr !
  737. r> swap .len !
  738. ;
  739. : set_environment_variable
  740. name_buffer .len @
  741. value_buffer .len @ +
  742. 5 chars +
  743. allocate if out_of_memory throw then
  744. dup 0 ( addr -- addr addr len )
  745. s" set " strcat
  746. name_buffer .addr @ name_buffer .len @ strcat
  747. s" =" strcat
  748. value_buffer .addr @ value_buffer .len @ strcat
  749. ['] evaluate catch if
  750. 2drop free drop
  751. set_error throw
  752. else
  753. free-memory
  754. then
  755. ;
  756. : set_nextboot_flag
  757. yes_value? to nextboot?
  758. ;
  759. : set_verbose
  760. yes_value? to verbose?
  761. ;
  762. : execute_command
  763. value_buffer .addr @ value_buffer .len @
  764. over c@ [char] " = if
  765. 2 - swap char+ swap
  766. then
  767. ['] evaluate catch if exec_error throw then
  768. ;
  769. : set_password
  770. password .addr @ ?dup if free if free_error throw then then
  771. value_buffer .addr @ c@ [char] " = if
  772. value_buffer .addr @ char+ value_buffer .len @ 2 - strdup
  773. value_buffer .addr @ free if free_error throw then
  774. else
  775. value_buffer .addr @ value_buffer .len @
  776. then
  777. password .len ! password .addr !
  778. 0 value_buffer .addr !
  779. ;
  780. : process_assignment
  781. name_buffer .len @ 0= if exit then
  782. loader_conf_files? if set_conf_files exit then
  783. nextboot_flag? if set_nextboot_flag exit then
  784. nextboot_conf? if set_nextboot_conf exit then
  785. verbose_flag? if set_verbose exit then
  786. execute? if execute_command exit then
  787. password? if set_password exit then
  788. module_load? if set_module_flag exit then
  789. module_loadname? if set_module_loadname exit then
  790. module_type? if set_module_type exit then
  791. module_args? if set_module_args exit then
  792. module_beforeload? if set_module_beforeload exit then
  793. module_afterload? if set_module_afterload exit then
  794. module_loaderror? if set_module_loaderror exit then
  795. set_environment_variable
  796. ;
  797. \ free_buffer ( -- )
  798. \
  799. \ Free some pointers if needed. The code then tests for errors
  800. \ in freeing, and throws an exception if needed. If a pointer is
  801. \ not allocated, it's value (0) is used as flag.
  802. : free_buffers
  803. name_buffer .addr @ dup if free then
  804. value_buffer .addr @ dup if free then
  805. or if free_error throw then
  806. ;
  807. : reset_assignment_buffers
  808. 0 name_buffer .addr !
  809. 0 name_buffer .len !
  810. 0 value_buffer .addr !
  811. 0 value_buffer .len !
  812. ;
  813. \ Higher level file processing
  814. support-functions definitions
  815. : process_conf
  816. begin
  817. end_of_file? 0=
  818. while
  819. reset_assignment_buffers
  820. read_line
  821. get_assignment
  822. ['] process_assignment catch
  823. ['] free_buffers catch
  824. swap throw throw
  825. repeat
  826. ;
  827. : peek_file
  828. 0 to end_of_file?
  829. reset_line_reading
  830. O_RDONLY fopen fd !
  831. fd @ -1 = if open_error throw then
  832. reset_assignment_buffers
  833. read_line
  834. get_assignment
  835. ['] process_assignment catch
  836. ['] free_buffers catch
  837. fd @ fclose
  838. ;
  839. only forth also support-functions definitions
  840. \ Interface to loading conf files
  841. : load_conf ( addr len -- )
  842. 0 to end_of_file?
  843. reset_line_reading
  844. O_RDONLY fopen fd !
  845. fd @ -1 = if open_error throw then
  846. ['] process_conf catch
  847. fd @ fclose
  848. throw
  849. ;
  850. : print_line
  851. line_buffer .addr @ line_buffer .len @ type cr
  852. ;
  853. : print_syntax_error
  854. line_buffer .addr @ line_buffer .len @ type cr
  855. line_buffer .addr @
  856. begin
  857. line_pointer over <>
  858. while
  859. bl emit
  860. char+
  861. repeat
  862. drop
  863. ." ^" cr
  864. ;
  865. \ Depuration support functions
  866. only forth definitions also support-functions
  867. : test-file
  868. ['] load_conf catch dup .
  869. syntax_error = if cr print_syntax_error then
  870. ;
  871. : show-module-options
  872. module_options @
  873. begin
  874. ?dup
  875. while
  876. ." Name: " dup module.name dup .addr @ swap .len @ type cr
  877. ." Path: " dup module.loadname dup .addr @ swap .len @ type cr
  878. ." Type: " dup module.type dup .addr @ swap .len @ type cr
  879. ." Flags: " dup module.args dup .addr @ swap .len @ type cr
  880. ." Before load: " dup module.beforeload dup .addr @ swap .len @ type cr
  881. ." After load: " dup module.afterload dup .addr @ swap .len @ type cr
  882. ." Error: " dup module.loaderror dup .addr @ swap .len @ type cr
  883. ." Status: " dup module.flag @ if ." Load" else ." Don't load" then cr
  884. module.next @
  885. repeat
  886. ;
  887. only forth also support-functions definitions
  888. \ Variables used for processing multiple conf files
  889. string current_file_name
  890. variable current_conf_files
  891. \ Indicates if any conf file was succesfully read
  892. 0 value any_conf_read?
  893. \ loader_conf_files processing support functions
  894. : set_current_conf_files
  895. conf_files .addr @ current_conf_files !
  896. ;
  897. : get_conf_files
  898. conf_files .addr @ conf_files .len @ strdup
  899. ;
  900. : recurse_on_conf_files?
  901. current_conf_files @ conf_files .addr @ <>
  902. ;
  903. : skip_leading_spaces { addr len pos -- addr len pos' }
  904. begin
  905. pos len = if addr len pos exit then
  906. addr pos + c@ bl =
  907. while
  908. pos char+ to pos
  909. repeat
  910. addr len pos
  911. ;
  912. : get_file_name { addr len pos -- addr len pos' addr' len' || 0 }
  913. pos len = if
  914. addr free abort" Fatal error freeing memory"
  915. 0 exit
  916. then
  917. pos >r
  918. begin
  919. addr pos + c@ bl <>
  920. while
  921. pos char+ to pos
  922. pos len = if
  923. addr len pos addr r@ + pos r> - exit
  924. then
  925. repeat
  926. addr len pos addr r@ + pos r> -
  927. ;
  928. : get_next_file ( addr len ptr -- addr len ptr' addr' len' | 0 )
  929. skip_leading_spaces
  930. get_file_name
  931. ;
  932. : set_current_file_name
  933. over current_file_name .addr !
  934. dup current_file_name .len !
  935. ;
  936. : print_current_file
  937. current_file_name .addr @ current_file_name .len @ type
  938. ;
  939. : process_conf_errors
  940. dup 0= if true to any_conf_read? drop exit then
  941. >r 2drop r>
  942. dup syntax_error = if
  943. ." Warning: syntax error on file " print_current_file cr
  944. print_syntax_error drop exit
  945. then
  946. dup set_error = if
  947. ." Warning: bad definition on file " print_current_file cr
  948. print_line drop exit
  949. then
  950. dup read_error = if
  951. ." Warning: error reading file " print_current_file cr drop exit
  952. then
  953. dup open_error = if
  954. verbose? if ." Warning: unable to open file " print_current_file cr then
  955. drop exit
  956. then
  957. dup free_error = abort" Fatal error freeing memory"
  958. dup out_of_memory = abort" Out of memory"
  959. throw \ Unknown error -- pass ahead
  960. ;
  961. \ Process loader_conf_files recursively
  962. \ Interface to loader_conf_files processing
  963. : include_conf_files
  964. set_current_conf_files
  965. get_conf_files 0
  966. begin
  967. get_next_file ?dup
  968. while
  969. set_current_file_name
  970. ['] load_conf catch
  971. process_conf_errors
  972. recurse_on_conf_files? if recurse then
  973. repeat
  974. ;
  975. : get_nextboot_conf_file ( -- addr len )
  976. nextboot_conf_file .addr @ nextboot_conf_file .len @ strdup
  977. ;
  978. : rewrite_nextboot_file ( -- )
  979. get_nextboot_conf_file
  980. O_WRONLY fopen fd !
  981. fd @ -1 = if open_error throw then
  982. fd @ s' nextboot_enable="NO" ' fwrite
  983. fd @ fclose
  984. ;
  985. : include_nextboot_file
  986. get_nextboot_conf_file
  987. ['] peek_file catch
  988. nextboot? if
  989. get_nextboot_conf_file
  990. ['] load_conf catch
  991. process_conf_errors
  992. ['] rewrite_nextboot_file catch
  993. then
  994. ;
  995. \ Module loading functions
  996. : load_module?
  997. module.flag @
  998. ;
  999. : load_parameters ( addr -- addr addrN lenN ... addr1 len1 N )
  1000. dup >r
  1001. r@ module.args .addr @ r@ module.args .len @
  1002. r@ module.loadname .len @ if
  1003. r@ module.loadname .addr @ r@ module.loadname .len @
  1004. else
  1005. r@ module.name .addr @ r@ module.name .len @
  1006. then
  1007. r@ module.type .len @ if
  1008. r@ module.type .addr @ r@ module.type .len @
  1009. s" -t "
  1010. 4 ( -t type name flags )
  1011. else
  1012. 2 ( name flags )
  1013. then
  1014. r> drop
  1015. ;
  1016. : before_load ( addr -- addr )
  1017. dup module.beforeload .len @ if
  1018. dup module.beforeload .addr @ over module.beforeload .len @
  1019. ['] evaluate catch if before_load_error throw then
  1020. then
  1021. ;
  1022. : after_load ( addr -- addr )
  1023. dup module.afterload .len @ if
  1024. dup module.afterload .addr @ over module.afterload .len @
  1025. ['] evaluate catch if after_load_error throw then
  1026. then
  1027. ;
  1028. : load_error ( addr -- addr )
  1029. dup module.loaderror .len @ if
  1030. dup module.loaderror .addr @ over module.loaderror .len @
  1031. evaluate \ This we do not intercept so it can throw errors
  1032. then
  1033. ;
  1034. : pre_load_message ( addr -- addr )
  1035. verbose? if
  1036. dup module.name .addr @ over module.name .len @ type
  1037. ." ..."
  1038. then
  1039. ;
  1040. : load_error_message verbose? if ." failed!" cr then ;
  1041. : load_succesful_message verbose? if ." ok" cr then ;
  1042. : load_module
  1043. load_parameters load
  1044. ;
  1045. : process_module ( addr -- addr )
  1046. pre_load_message
  1047. before_load
  1048. begin
  1049. ['] load_module catch if
  1050. dup module.loaderror .len @ if
  1051. load_error \ Command should return a flag!
  1052. else
  1053. load_error_message true \ Do not retry
  1054. then
  1055. else
  1056. after_load
  1057. load_succesful_message true \ Succesful, do not retry
  1058. then
  1059. until
  1060. ;
  1061. : process_module_errors ( addr ior -- )
  1062. dup before_load_error = if
  1063. drop
  1064. ." Module "
  1065. dup module.name .addr @ over module.name .len @ type
  1066. dup module.loadname .len @ if
  1067. ." (" dup module.loadname .addr @ over module.loadname .len @ type ." )"
  1068. then
  1069. cr
  1070. ." Error executing "
  1071. dup module.beforeload .addr @ over module.afterload .len @ type cr
  1072. abort
  1073. then
  1074. dup after_load_error = if
  1075. drop
  1076. ." Module "
  1077. dup module.name .addr @ over module.name .len @ type
  1078. dup module.loadname .len @ if
  1079. ." (" dup module.loadname .addr @ over module.loadname .len @ type ." )"
  1080. then
  1081. cr
  1082. ." Error executing "
  1083. dup module.afterload .addr @ over module.afterload .len @ type cr
  1084. abort
  1085. then
  1086. throw \ Don't know what it is all about -- pass ahead
  1087. ;
  1088. \ Module loading interface
  1089. : load_modules ( -- ) ( throws: abort & user-defined )
  1090. module_options @
  1091. begin
  1092. ?dup
  1093. while
  1094. dup load_module? if
  1095. ['] process_module catch
  1096. process_module_errors
  1097. then
  1098. module.next @
  1099. repeat
  1100. ;
  1101. \ h00h00 magic used to try loading either a kernel with a given name,
  1102. \ or a kernel with the default name in a directory of a given name
  1103. \ (the pain!)
  1104. : bootpath s" /boot/" ;
  1105. : modulepath s" module_path" ;
  1106. \ Functions used to save and restore module_path's value.
  1107. : saveenv ( addr len | -1 -- addr' len | 0 -1 )
  1108. dup -1 = if 0 swap exit then
  1109. strdup
  1110. ;
  1111. : freeenv ( addr len | 0 -1 )
  1112. -1 = if drop else free abort" Freeing error" then
  1113. ;
  1114. : restoreenv ( addr len | 0 -1 -- )
  1115. dup -1 = if ( it wasn't set )
  1116. 2drop
  1117. modulepath unsetenv
  1118. else
  1119. over >r
  1120. modulepath setenv
  1121. r> free abort" Freeing error"
  1122. then
  1123. ;
  1124. : clip_args \ Drop second string if only one argument is passed
  1125. 1 = if
  1126. 2swap 2drop
  1127. 1
  1128. else
  1129. 2
  1130. then
  1131. ;
  1132. also builtins
  1133. \ Parse filename from a comma-separated list
  1134. : parse-; ( addr len -- addr' len-x addr x )
  1135. over 0 2swap
  1136. begin
  1137. dup 0 <>
  1138. while
  1139. over c@ [char] ; <>
  1140. while
  1141. 1- swap 1+ swap
  1142. 2swap 1+ 2swap
  1143. repeat then
  1144. dup 0 <> if
  1145. 1- swap 1+ swap
  1146. then
  1147. 2swap
  1148. ;
  1149. \ Try loading one of multiple kernels specified
  1150. : try_multiple_kernels ( addr len addr' len' args -- flag )
  1151. >r
  1152. begin
  1153. parse-; 2>r
  1154. 2over 2r>
  1155. r@ clip_args
  1156. s" DEBUG" getenv? if
  1157. s" echo Module_path: ${module_path}" evaluate
  1158. ." Kernel : " >r 2dup type r> cr
  1159. dup 2 = if ." Flags : " >r 2over type r> cr then
  1160. then
  1161. 1 load
  1162. while
  1163. dup 0=
  1164. until
  1165. 1 >r \ Failure
  1166. else
  1167. 0 >r \ Success
  1168. then
  1169. 2drop 2drop
  1170. r>
  1171. r> drop
  1172. ;
  1173. \ Try to load a kernel; the kernel name is taken from one of
  1174. \ the following lists, as ordered:
  1175. \
  1176. \ 1. The "bootfile" environment variable
  1177. \ 2. The "kernel" environment variable
  1178. \
  1179. \ Flags are passed, if available. If not, dummy values must be given.
  1180. \
  1181. \ The kernel gets loaded from the current module_path.
  1182. : load_a_kernel ( flags len 1 | x x 0 -- flag )
  1183. local args
  1184. 2local flags
  1185. 0 0 2local kernel
  1186. end-locals
  1187. \ Check if a default kernel name exists at all, exits if not
  1188. s" bootfile" getenv dup -1 <> if
  1189. to kernel
  1190. flags kernel args 1+ try_multiple_kernels
  1191. dup 0= if exit then
  1192. then
  1193. drop
  1194. s" kernel" getenv dup -1 <> if
  1195. to kernel
  1196. else
  1197. drop
  1198. 1 exit \ Failure
  1199. then
  1200. \ Try all default kernel names
  1201. flags kernel args 1+ try_multiple_kernels
  1202. ;
  1203. \ Try to load a kernel; the kernel name is taken from one of
  1204. \ the following lists, as ordered:
  1205. \
  1206. \ 1. The "bootfile" environment variable
  1207. \ 2. The "kernel" environment variable
  1208. \
  1209. \ Flags are passed, if provided.
  1210. \
  1211. \ The kernel will be loaded from a directory computed from the
  1212. \ path given. Two directories will be tried in the following order:
  1213. \
  1214. \ 1. /boot/path
  1215. \ 2. path
  1216. \
  1217. \ The module_path variable is overridden if load is succesful, by
  1218. \ prepending the successful path.
  1219. : load_from_directory ( path len 1 | flags len' path len 2 -- flag )
  1220. local args
  1221. 2local path
  1222. args 1 = if 0 0 then
  1223. 2local flags
  1224. 0 0 2local oldmodulepath
  1225. 0 0 2local newmodulepath
  1226. end-locals
  1227. \ Set the environment variable module_path, and try loading
  1228. \ the kernel again.
  1229. modulepath getenv saveenv to oldmodulepath
  1230. \ Try prepending /boot/ first
  1231. bootpath nip path nip +
  1232. oldmodulepath nip dup -1 = if
  1233. drop
  1234. else
  1235. 1+ +
  1236. then
  1237. allocate
  1238. if ( out of memory )
  1239. 1 exit
  1240. then
  1241. 0
  1242. bootpath strcat
  1243. path strcat
  1244. 2dup to newmodulepath
  1245. modulepath setenv
  1246. \ Try all default kernel names
  1247. flags args 1- load_a_kernel
  1248. 0= if ( success )
  1249. oldmodulepath nip -1 <> if
  1250. newmodulepath s" ;" strcat
  1251. oldmodulepath strcat
  1252. modulepath setenv
  1253. newmodulepath drop free-memory
  1254. oldmodulepath drop free-memory
  1255. then
  1256. 0 exit
  1257. then
  1258. \ Well, try without the prepended /boot/
  1259. path newmodulepath drop swap move
  1260. newmodulepath drop path nip
  1261. 2dup to newmodulepath
  1262. modulepath setenv
  1263. \ Try all default kernel names
  1264. flags args 1- load_a_kernel
  1265. if ( failed once more )
  1266. oldmodulepath restoreenv
  1267. newmodulepath drop free-memory
  1268. 1
  1269. else
  1270. oldmodulepath nip -1 <> if
  1271. newmodulepath s" ;" strcat
  1272. oldmodulepath strcat
  1273. modulepath setenv
  1274. newmodulepath drop free-memory
  1275. oldmodulepath drop free-memory
  1276. then
  1277. 0
  1278. then
  1279. ;
  1280. \ Try to load a kernel; the kernel name is taken from one of
  1281. \ the following lists, as ordered:
  1282. \
  1283. \ 1. The "bootfile" environment variable
  1284. \ 2. The "kernel" environment variable
  1285. \ 3. The "path" argument
  1286. \
  1287. \ Flags are passed, if provided.
  1288. \
  1289. \ The kernel will be loaded from a directory computed from the
  1290. \ path given. Two directories will be tried in the following order:
  1291. \
  1292. \ 1. /boot/path
  1293. \ 2. path
  1294. \
  1295. \ Unless "path" is meant to be kernel name itself. In that case, it
  1296. \ will first be tried as a full path, and, next, search on the
  1297. \ directories pointed by module_path.
  1298. \
  1299. \ The module_path variable is overridden if load is succesful, by
  1300. \ prepending the successful path.
  1301. : load_directory_or_file ( path len 1 | flags len' path len 2 -- flag )
  1302. local args
  1303. 2local path
  1304. args 1 = if 0 0 then
  1305. 2local flags
  1306. end-locals
  1307. \ First, assume path is an absolute path to a directory
  1308. flags path args clip_args load_from_directory
  1309. dup 0= if exit else drop then
  1310. \ Next, assume path points to the kernel
  1311. flags path args try_multiple_kernels
  1312. ;
  1313. : initialize ( addr len -- )
  1314. strdup conf_files .len ! conf_files .addr !
  1315. ;
  1316. : kernel_options ( -- addr len 1 | 0 )
  1317. s" kernel_options" getenv
  1318. dup -1 = if drop 0 else 1 then
  1319. ;
  1320. : standard_kernel_search ( flags 1 | 0 -- flag )
  1321. local args
  1322. args 0= if 0 0 then
  1323. 2local flags
  1324. s" kernel" getenv
  1325. dup -1 = if 0 swap then
  1326. 2local path
  1327. end-locals
  1328. path nip -1 = if ( there isn't a "kernel" environment variable )
  1329. flags args load_a_kernel
  1330. else
  1331. flags path args 1+ clip_args load_directory_or_file
  1332. then
  1333. ;
  1334. : load_kernel ( -- ) ( throws: abort )
  1335. kernel_options standard_kernel_search
  1336. abort" Unable to load a kernel!"
  1337. ;
  1338. : set_defaultoptions ( -- )
  1339. s" kernel_options" getenv dup -1 = if
  1340. drop
  1341. else
  1342. s" temp_options" setenv
  1343. then
  1344. ;
  1345. : argv[] ( aN uN ... a1 u1 N i -- aN uN ... a1 u1 N ai+1 ui+1 )
  1346. 2dup = if 0 0 exit then
  1347. dup >r
  1348. 1+ 2* ( skip N and ui )
  1349. pick
  1350. r>
  1351. 1+ 2* ( skip N and ai )
  1352. pick
  1353. ;
  1354. : drop_args ( aN uN ... a1 u1 N -- )
  1355. 0 ?do 2drop loop
  1356. ;
  1357. : argc
  1358. dup
  1359. ;
  1360. : queue_argv ( aN uN ... a1 u1 N a u -- a u aN uN ... a1 u1 N+1 )
  1361. >r
  1362. over 2* 1+ -roll
  1363. r>
  1364. over 2* 1+ -roll
  1365. 1+
  1366. ;
  1367. : unqueue_argv ( aN uN ... a1 u1 N -- aN uN ... a2 u2 N-1 a1 u1 )
  1368. 1- -rot
  1369. ;
  1370. : strlen(argv)
  1371. dup 0= if 0 exit then
  1372. 0 >r \ Size
  1373. 0 >r \ Index
  1374. begin
  1375. argc r@ <>
  1376. while
  1377. r@ argv[]
  1378. nip
  1379. r> r> rot + 1+
  1380. >r 1+ >r
  1381. repeat
  1382. r> drop
  1383. r>
  1384. ;
  1385. : concat_argv ( aN uN ... a1 u1 N -- a u )
  1386. strlen(argv) allocate if out_of_memory throw then
  1387. 0 2>r
  1388. begin
  1389. argc
  1390. while
  1391. unqueue_argv
  1392. 2r> 2swap
  1393. strcat
  1394. s" " strcat
  1395. 2>r
  1396. repeat
  1397. drop_args
  1398. 2r>
  1399. ;
  1400. : set_tempoptions ( addrN lenN ... addr1 len1 N -- addr len 1 | 0 )
  1401. \ Save the first argument, if it exists and is not a flag
  1402. argc if
  1403. 0 argv[] drop c@ [char] - <> if
  1404. unqueue_argv 2>r \ Filename
  1405. 1 >r \ Filename present
  1406. else
  1407. 0 >r \ Filename not present
  1408. then
  1409. else
  1410. 0 >r \ Filename not present
  1411. then
  1412. \ If there are other arguments, assume they are flags
  1413. ?dup if
  1414. concat_argv
  1415. 2dup s" temp_options" setenv
  1416. drop free if free_error throw then
  1417. else
  1418. set_defaultoptions
  1419. then
  1420. \ Bring back the filename, if one was provided
  1421. r> if 2r> 1 else 0 then
  1422. ;
  1423. : get_arguments ( -- addrN lenN ... addr1 len1 N )
  1424. 0
  1425. begin
  1426. \ Get next word on the command line
  1427. parse-word
  1428. ?dup while
  1429. queue_argv
  1430. repeat
  1431. drop ( empty string )
  1432. ;
  1433. : load_kernel_and_modules ( args -- flag )
  1434. set_tempoptions
  1435. argc >r
  1436. s" temp_options" getenv dup -1 <> if
  1437. queue_argv
  1438. else
  1439. drop
  1440. then
  1441. r> if ( a path was passed )
  1442. load_directory_or_file
  1443. else
  1444. standard_kernel_search
  1445. then
  1446. ?dup 0= if ['] load_modules catch then
  1447. ;
  1448. : read-password { size | buf len -- }
  1449. size allocate if out_of_memory throw then
  1450. to buf
  1451. 0 to len
  1452. begin
  1453. key
  1454. dup backspace = if
  1455. drop
  1456. len if
  1457. backspace emit bl emit backspace emit
  1458. len 1 - to len
  1459. else
  1460. bell emit
  1461. then
  1462. else
  1463. dup <cr> = if cr drop buf len exit then
  1464. [char] * emit
  1465. len size < if
  1466. buf len chars + c!
  1467. else
  1468. drop
  1469. then
  1470. len 1+ to len
  1471. then
  1472. again
  1473. ;
  1474. \ Go back to straight forth vocabulary
  1475. only forth also definitions