\ vandys \ tools.f \ Less often used tools, under the "extensions" vocabulary only extensions definitions \ ****************************************************************** \ The following block-oriented operations are deprecated now that we \ have the Forth block filesystem instead. \ ****************************************************************** \ This is defined as \ a block with an initial '\', and with all other lines containing \ only spaces. \ : (empty) ( a -- bool ) \ dup c@ [char] \ <> if drop false exit then \ BLKCOLS + \ SCRSIZ BLKCOLS - 0 do \ dup c@ ( space ) 32 <> if \ unloop drop false exit then \ 1+ loop \ drop true \ ; \ vandys \ Find first free block \ Scans forward until an empty one is found. "block" is expected \ to throw an error if no free blocks are available. \ : (1stfree) ( u -- u' ) \ begin dup block (empty) not while 1+ repeat ; \ Insert a block \ Scans forward to find first unused block, then copies screens \ to shift them forward. \ : insblock ( u -- ) \ \ Copy from highest screen down to lowest \ dup 1+ (1stfree) begin 2dup <> while \ dup . dup dup 1- swap copy \ 1- repeat drop \ block BLKSIZ blank update cr sync ; \ String functions, supports max 256 char length vandys : $null ( a -- ) 0 swap c! ; : $count ( a -- a+1 n ) count ; : $strlen ( a -- n ) c@ ; : $eos ( a -- a' ) count + ; : +c! ( n a -- ) tuck c@ + swap c! ; : $strcat ( a1 a2 -- ) over $eos over $count >r swap r> move c@ swap +c! ; : $ccat ( a c -- ) over $eos c! 1 swap +c! ; : $strcmp ( s1 s2 -- n ) 2dup c@ swap c@ 2dup >r >r min 1+ 1 do 2dup i + c@ swap i + c@ - ?dup if -rot 2drop r> r> 2drop unloop exit then loop 2drop r> r> - ; \ vandys : allEnts ( 'fn -- ) >r current begin cell+ @ ?dup while dup begin @ ?dup while cell- cell- dup r@ execute cell+ repeat repeat r> drop ; \ vandys \ Show stack backtrace \ There's no formal stack framing, so we just interpret the values we \ find on the return stack as best we can. \ Note: not reentrant \ The best entry, and the closest we got to its exact address variable (bestEnt) variable (bestDelta) \ The value we're searching for variable (val) \ If the indicated entry is closer to the sought value, record it : (checkEnt) ( ent -- ) dup @ (val) @ 2dup u<= if swap - dup (bestDelta) @ u< if (bestDelta) ! (bestEnt) ! else 2drop then else 2drop drop then ; \ vandys \ Return most closely matching entry : (bestent) ( a -- 0 | u a ) (val) ! 0 (bestEnt) ! $10000 (bestDelta) ! ['] (checkEnt) allEnts (bestEnt) @ dup if (bestDelta) @ swap then ; \ Print an entry in name[+offset] format : (prval2) ( u a -- ) cell+ cell+ .id ?dup if ." +" 1 u.r then ; \ Dump a value as a raw integer, also name+ if possible : (showval) ( u -- ) dup 1 u.r (bestent) ?dup if ." : " (prval2) then ; \ Print a value, in hex if no conversion was possible : (prval) ( u -- ) dup (bestent) ?dup if (prval2) drop else 1 u.r then ; \ vandys \ Walk back cells of calling stack, displaying each \ Note: the debugger uses its own routine, which knows about local \ variable frames : where ( -- ) cr rp@ begin dup rp0 @ < while dup @ (showval) cr cell+ repeat drop ; \ Random number generator create randstate 0 , : random ( -- u ) randstate dup @ 1103515245 * 12345 + $7FFFFFFF and dup rot ! ; \ vandys \ Intern a counted string to a unique counted string pointer which is \ always the same for that particular string. Implemented by a tree \ indexed by successive bytes, with the 257th pointer being a pointer \ to the unique version of the counted string. \ create (syms) 0 , \ 256 constant (#chars) : zallot ( u -- ) here over erase allot ; : $strdup ( ptr -- ptr' ) here swap 2dup c@ 1+ dup allot move align ; : $strdup+ ( ptr u -- ptr' ) here -rot over c@ 1+ + allot ( ptr' ptr ) 2dup c@ 1+ move ; \ : (allocSym) ( ptr a -- ) swap $strdup tuck swap ! ; \ : >symbol ( a -- ptr ) (syms) over count over + swap do \ dup @ 0= if here over ! 257 cells zallot then \ @ i c@ cells + loop \ dup @ 0= if (allocSym) else nip @ then ; only