commit 7eb73f66648ba5261cbd809c131b47b332298cb4
parent d30142337aa8b5cd6a63ae45a41375d3f8f27a72
Author: Virgil Dupras <hsoft@hardcoded.net>
Date: Wed, 25 Jan 2023 21:20:15 -0500
lib/str: add "[str]?", remove unused "scontains", add docs
Diffstat:
3 files changed, 75 insertions(+), 36 deletions(-)
diff --git a/fs/doc/lib/str.txt b/fs/doc/lib/str.txt
@@ -0,0 +1,67 @@
+# String utilities
+
+This unit lives at /lib/str.fs and provides a few string-related words.
+
+Most strings in Dusk are regular strings as doc/usage describes. However, we
+sometimes have to deal with null-terminated strings and this unit also has words
+to deal with them. We refer to null-terminated strings as "zstr" (z for zero).
+
+This unit also defines the concept of "string lists". Those are simply strings
+following each other in memory, ending with a null string. To iterate a string
+list, all we need to do is "skip" the string using its size byte.
+
+## API
+
+Constants:
+
+STR_MAXSZ Maximum size of strings, including size byte
+NULLSTR An empty string
+
+Words:
+
+ws? ( c -- f )
+ Returns whether character "c" is a whitespace.
+
+s) ( str -- a )
+ Skip "str", that is, return the address following its last char.
+
+s, ( str -- )
+ Write "str" to here.
+
+s[]= ( str a u -- f )
+ Compares a string to a range.
+
+zstrlen ( ztr -- len )
+ Returns the length of "zstr".
+
+sfind ( str list -- idx )
+ Find "str" in "list" and return its index, -1 if not found.
+
+slistiter ( idx list -- str )
+ Given a string list "list", iterate to its "idx" element and return the str.
+
+rmatch ( c range -- f )
+ Given a list of character ranges, which is given in the form of a string of
+ character pairs, return whether the specified character is in one of the
+ ranges.
+
+0-9? ( c -- f )
+ Returns whether "c" is a digit.
+
+A-Za-z? ( c -- f )
+ Returns whether "c" is an ASCII letter.
+
+alnum? ( c -- f )
+ Returns whether "c" is a letter or digit.
+
+toword ( -- c )
+ Read stdin until next non WS and yield it.
+
+expectchar ( c -- )
+ Read stdin, discarding whitespaces and expect the next char to be "c"
+
+stringlist ( n "name" "..." -- )
+ Create a list of strings (same format as sfind above) with the specified
+ number of elements. Each element must be "quoted" with no space (unless you
+ want them in the string) in the quotes.
+\ Example: 3 stringlist mylist "foo" "bar" "hello world!"
diff --git a/fs/lib/str.fs b/fs/lib/str.fs
@@ -1,51 +1,31 @@
\ String/range utilities
-\\ maximum size of strings (including size byte)
$100 value STR_MAXSZ
create NULLSTR 0 c,
-\ is c a whitespace?
: ws? ( c -- f ) SPC <= ;
-\ "skip" str, that is, return the address following its last char
: s) ( str -- a ) c@+ + ;
-\ write "str" to here
: s, ( str -- ) dup c@ 1+ move, ;
-\ compare a string to a range
-: s[]= ( str a len -- f )
+: s[]= ( str a u -- f )
rot dup c@ rot = if ( a str ) c@+ []= else 2drop 0 then ;
-\ null-terminated strings (zstr) routines
: zstrlen ( zstr -- len )
0 swap $100 [c]? ( idx ) dup 0< if abort" string too long" then ;
-\\ append character to end of string
-: sappend ( c str -- ) tuck s) c! dup c@ 1+ swap c! ;
+: [str]? ( str a u -- idx ) rot> >r >r ( u ) \ V1=aref V2=str
+ V2 c@ - dup 0>= if 1+ >r V1 begin ( a )
+ dup V2 c@+ []= if ( a ) rdrop rdrop r> - exit then 1+ next ( a )
+ else drop then ( a )
+ drop rdrop rdrop -1 ;
-\\ checks if str1 contains all of str2 (is str2 a substring?)
-: scontains ( str1 str2 -- f )
- >r c@+ begin
- dup r@ c@ >= while
- over r@ c@+ []= if
- r> drop 2drop 1 exit
- then
- 1- swap 1+ swap
- repeat r> drop 2drop 0 ;
-
-\ find active string in "list" and return its index, -1 if not found.
-\ A list is a simple sequence of strings (length byte, then contents, then
-\ another one...) ended by a 0 length
: sfind ( str list -- idx ) -1 rot> begin ( idx s a )
rot 1+ rot> ( idx s a )
2dup s= if ( found ) 2drop exit then
s) dup c@ not until ( idx s a ) 2drop drop -1 ;
-\ Given a string list "list", iterate to its "idx" element and return the str.
: slistiter ( idx list -- str )
swap dup if >r begin s) next else drop then ;
-\ Given a list of character ranges, which is given in the form of a string of
-\ character pairs, return whether the specified character is in one of the
-\ ranges.
: rmatch ( c range -- f )
>r 8b to@+ V1 >> ( len/2 ) >r begin ( c )
dup 8b to@+ V1 8b to@+ V1 ( c c lo hi ) =><= if
@@ -59,15 +39,9 @@ create _ 4 c, ," AZaz"
create _ 6 c, ," AZaz09"
: alnum? ( c -- f ) _ rmatch ;
-\\ Read stdin until next non WS and yield it
: toword ( -- c ) begin stdin dup ws? while drop repeat ( c ) ;
-\\ Read stdin, discarding whitespaces and expect the next char to be "c"
: expectchar ( c -- )
toword over = not if emit abort" expected" else drop then ;
-\ Create a list of strings (same format as sfind above) with the specified
-\ number of elements. Each element must be "quoted" with no space (unless you
-\ want them in the string) in the quotes.
-\ Example: 3 stringlist mylist "foo" "bar" "hello world!"
: stringlist create >r begin '"' expectchar [compile] S" drop next 0 c, ;
diff --git a/fs/tests/lib/str.fs b/fs/tests/lib/str.fs
@@ -16,8 +16,6 @@ S" baz" list sfind -1 #eq
'z' alnum? #
'0' alnum? #
-S" foobar" S" foo" scontains #
-S" foobar" S" bar" scontains #
-S" foobar" S" oba" scontains #
-S" foobar" S" baz" scontains not #
+S" bar" S" foobar" c@+ [str]? 3 #eq
+S" baz" S" foobar" c@+ [str]? -1 #eq
testend