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

/freebsd5/sys/boot/forth/support.4th

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