2022-05-13 21:10:13 +00:00
|
|
|
|
; 0-terminated string manipulation routines. For the Virtual Machine target.
|
|
|
|
|
|
2024-02-07 22:06:01 +00:00
|
|
|
|
%import shared_string_functions
|
|
|
|
|
|
2024-11-23 14:51:38 +00:00
|
|
|
|
strings {
|
2023-12-26 22:37:59 +00:00
|
|
|
|
%option ignore_unused
|
|
|
|
|
|
2022-05-13 21:10:13 +00:00
|
|
|
|
sub length(str st) -> ubyte {
|
|
|
|
|
; Returns the number of bytes in the string.
|
|
|
|
|
; This value is determined during runtime and counts upto the first terminating 0 byte in the string,
|
|
|
|
|
; regardless of the size of the string during compilation time. Don’t confuse this with len and sizeof!
|
|
|
|
|
ubyte count = 0
|
2024-02-04 22:22:43 +00:00
|
|
|
|
while st[count]!=0
|
2022-05-13 21:10:13 +00:00
|
|
|
|
count++
|
|
|
|
|
return count
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub left(str source, ubyte slen, str target) {
|
|
|
|
|
; Copies the left side of the source string of the given length to target string.
|
|
|
|
|
; It is assumed the target string buffer is large enough to contain the result.
|
|
|
|
|
; Also, you have to make sure yourself that length is smaller or equal to the length of the source string.
|
|
|
|
|
; Modifies in-place, doesn’t return a value (so can’t be used in an expression).
|
|
|
|
|
target[slen] = 0
|
|
|
|
|
ubyte ix
|
|
|
|
|
for ix in 0 to slen-1 {
|
|
|
|
|
target[ix] = source[ix]
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub right(str source, ubyte slen, str target) {
|
|
|
|
|
; Copies the right side of the source string of the given length to target string.
|
|
|
|
|
; It is assumed the target string buffer is large enough to contain the result.
|
|
|
|
|
; Also, you have to make sure yourself that length is smaller or equal to the length of the source string.
|
|
|
|
|
; Modifies in-place, doesn’t return a value (so can’t be used in an expression).
|
|
|
|
|
ubyte offset = length(source)-slen
|
|
|
|
|
ubyte ix
|
|
|
|
|
for ix in 0 to slen-1 {
|
|
|
|
|
target[ix] = source[ix+offset]
|
|
|
|
|
}
|
|
|
|
|
target[ix]=0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub slice(str source, ubyte start, ubyte slen, str target) {
|
|
|
|
|
; Copies a segment from the source string, starting at the given index,
|
|
|
|
|
; and of the given length to target string.
|
|
|
|
|
; It is assumed the target string buffer is large enough to contain the result.
|
|
|
|
|
; Also, you have to make sure yourself that start and length are within bounds of the strings.
|
|
|
|
|
; Modifies in-place, doesn’t return a value (so can’t be used in an expression).
|
|
|
|
|
ubyte ix
|
|
|
|
|
for ix in 0 to slen-1 {
|
|
|
|
|
target[ix] = source[ix+start]
|
|
|
|
|
}
|
|
|
|
|
target[ix]=0
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub find(str st, ubyte character) -> ubyte {
|
|
|
|
|
; Locates the first position of the given character in the string,
|
2024-03-17 22:18:33 +00:00
|
|
|
|
; returns Carry set if found + index in A, or Carry clear if not found (and A will be 255, an invalid index).
|
2024-05-18 13:20:10 +00:00
|
|
|
|
; NOTE: because this isn't an asmsub, there's only a SINGLE return value here. On the c64/cx16 targets etc there are 2 return values.
|
2022-05-13 21:10:13 +00:00
|
|
|
|
ubyte ix
|
|
|
|
|
for ix in 0 to length(st)-1 {
|
|
|
|
|
if st[ix]==character {
|
|
|
|
|
sys.set_carry()
|
|
|
|
|
return ix
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
sys.clear_carry()
|
2024-03-17 22:18:33 +00:00
|
|
|
|
return 255
|
2022-05-13 21:10:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
2024-08-22 20:54:38 +00:00
|
|
|
|
sub rfind(uword stringptr, ubyte character) -> ubyte {
|
|
|
|
|
; Locates the first position of the given character in the string, starting from the right.
|
|
|
|
|
; returns Carry set if found + index in A, or Carry clear if not found (and A will be 255, an invalid index).
|
|
|
|
|
; NOTE: because this isn't an asmsub, there's only a SINGLE return value here. On the c64/cx16 targets etc there are 2 return values.
|
|
|
|
|
ubyte ix
|
2024-11-23 14:51:38 +00:00
|
|
|
|
for ix in length(stringptr)-1 downto 0 {
|
2024-08-22 20:54:38 +00:00
|
|
|
|
if stringptr[ix]==character {
|
|
|
|
|
sys.set_carry()
|
|
|
|
|
return ix
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
sys.clear_carry()
|
|
|
|
|
return 255
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-05 19:46:26 +00:00
|
|
|
|
sub contains(str st, ubyte character) -> bool {
|
|
|
|
|
void find(st, character)
|
|
|
|
|
if_cs
|
|
|
|
|
return true
|
|
|
|
|
return false
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-13 21:10:13 +00:00
|
|
|
|
sub copy(str source, str target) -> ubyte {
|
|
|
|
|
; Copy a string to another, overwriting that one.
|
|
|
|
|
; Returns the length of the string that was copied.
|
|
|
|
|
; Often you don’t have to call this explicitly and can just write string1 = string2
|
|
|
|
|
; but this function is useful if you’re dealing with addresses for instance.
|
2024-02-09 22:55:55 +00:00
|
|
|
|
%ir {{
|
2024-11-23 14:51:38 +00:00
|
|
|
|
loadm.w r65534,strings.copy.source
|
|
|
|
|
loadm.w r65535,strings.copy.target
|
2024-07-06 16:49:03 +00:00
|
|
|
|
syscall 39 (r65534.w, r65535.w): r0.b
|
2024-02-09 22:55:55 +00:00
|
|
|
|
returnr.b r0
|
|
|
|
|
}}
|
2022-05-13 21:10:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
2023-11-10 21:27:07 +00:00
|
|
|
|
sub append(str target, str suffix) -> ubyte {
|
|
|
|
|
; Append the suffix string to the target. (make sure the buffer is large enough!)
|
|
|
|
|
; Returns the length of the resulting string.
|
|
|
|
|
cx16.r0L = length(target)
|
|
|
|
|
return copy(suffix, target+cx16.r0L) + cx16.r0L
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-13 21:10:13 +00:00
|
|
|
|
sub compare(str st1, str st2) -> byte {
|
|
|
|
|
; Compares two strings for sorting.
|
2024-08-24 12:34:23 +00:00
|
|
|
|
; Returns -1 (255), 0 or 1, meaning: string1 sorts before, equal or after string2.
|
2022-05-13 21:10:13 +00:00
|
|
|
|
; Note that you can also directly compare strings and string values with eachother using
|
2024-08-24 12:34:23 +00:00
|
|
|
|
; comparison operators ==, < etcetera (this will use strcmp automatically).
|
2022-11-04 21:37:42 +00:00
|
|
|
|
%ir {{
|
2024-11-23 14:51:38 +00:00
|
|
|
|
loadm.w r65534,strings.compare.st1
|
|
|
|
|
loadm.w r65535,strings.compare.st2
|
2024-07-06 16:49:03 +00:00
|
|
|
|
syscall 16 (r65534.w, r65535.w) : r0.b
|
2023-04-11 20:28:19 +00:00
|
|
|
|
returnr.b r0
|
2022-11-04 21:37:42 +00:00
|
|
|
|
}}
|
2022-05-13 21:10:13 +00:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub lower(str st) -> ubyte {
|
|
|
|
|
; Lowercases the petscii string in-place. Returns length of the string.
|
|
|
|
|
; (for efficiency, non-letter characters > 128 will also not be left intact,
|
|
|
|
|
; but regular text doesn't usually contain those characters anyway.)
|
|
|
|
|
ubyte ix
|
|
|
|
|
repeat {
|
|
|
|
|
ubyte char=st[ix]
|
2024-02-04 22:22:43 +00:00
|
|
|
|
if char==0
|
2022-05-13 21:10:13 +00:00
|
|
|
|
return ix
|
|
|
|
|
if char >= 'A' and char <= 'Z'
|
|
|
|
|
st[ix] = char | %00100000
|
|
|
|
|
ix++
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub upper(str st) -> ubyte {
|
|
|
|
|
; Uppercases the petscii string in-place. Returns length of the string.
|
|
|
|
|
ubyte ix
|
|
|
|
|
repeat {
|
|
|
|
|
ubyte char=st[ix]
|
2024-02-04 22:22:43 +00:00
|
|
|
|
if char==0
|
2022-05-13 21:10:13 +00:00
|
|
|
|
return ix
|
|
|
|
|
if char >= 97 and char <= 122
|
|
|
|
|
st[ix] = char & %11011111
|
|
|
|
|
ix++
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-07-20 22:38:30 +00:00
|
|
|
|
|
2022-09-25 18:20:38 +00:00
|
|
|
|
sub lowerchar(ubyte char) -> ubyte {
|
|
|
|
|
if char >= 'A' and char <= 'Z'
|
|
|
|
|
char |= %00100000
|
|
|
|
|
return char
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub upperchar(ubyte char) -> ubyte {
|
|
|
|
|
if char >= 'a' and char <= 'z'
|
|
|
|
|
char &= %11011111
|
|
|
|
|
return char
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-26 21:07:05 +00:00
|
|
|
|
sub hash(str st) -> ubyte {
|
|
|
|
|
; experimental 8 bit hashing function.
|
|
|
|
|
; hash(-1)=179; hash(i) = ROL hash(i-1) XOR string[i]
|
|
|
|
|
; (experimental because the quality of the resulting hash value still has to be determined)
|
|
|
|
|
ubyte hashcode = 179
|
|
|
|
|
ubyte ix
|
2023-11-27 00:09:42 +00:00
|
|
|
|
sys.clear_carry()
|
2023-11-26 21:07:05 +00:00
|
|
|
|
repeat {
|
2024-02-04 22:22:43 +00:00
|
|
|
|
if st[ix]!=0 {
|
2023-11-26 21:07:05 +00:00
|
|
|
|
rol(hashcode)
|
|
|
|
|
hashcode ^= st[ix]
|
|
|
|
|
ix++
|
|
|
|
|
} else
|
|
|
|
|
return hashcode
|
|
|
|
|
}
|
|
|
|
|
}
|
2023-12-05 21:50:20 +00:00
|
|
|
|
|
|
|
|
|
sub isdigit(ubyte character) -> bool {
|
|
|
|
|
return character>='0' and character<='9'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub isupper(ubyte character) -> bool {
|
|
|
|
|
return character>='A' and character<='Z'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub islower(ubyte character) -> bool {
|
|
|
|
|
return character>='a' and character<='z'
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub isletter(ubyte character) -> bool {
|
|
|
|
|
return islower(character) or isupper(character)
|
|
|
|
|
}
|
2023-12-12 23:28:34 +00:00
|
|
|
|
|
|
|
|
|
sub isspace(ubyte character) -> bool {
|
|
|
|
|
return character in [32, 13, 9, 10, 141, 160]
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
sub isprint(ubyte character) -> bool {
|
|
|
|
|
return character>=32 and character<=127 or character>=160
|
|
|
|
|
}
|
|
|
|
|
}
|