Skip to content

Commit

Permalink
Add strings.ncompare (and backing strncmp_mem) to compare up to n cha…
Browse files Browse the repository at this point in the history
…racters of a string. (#164)

* Add strings.ncompare (and backing strncmp_mem) to compare up to n characters of a string.

* Document strings.ncompare.
  • Loading branch information
gillham authored Mar 7, 2025
1 parent ef23d52 commit 81c255c
Show file tree
Hide file tree
Showing 6 changed files with 56 additions and 1 deletion.
28 changes: 28 additions & 0 deletions compiler/res/prog8lib/prog8_lib.asm
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,34 @@ _c1_zero lda (P8ZP_SCRATCH_W2),y
+ rts
.pend

strncmp_mem .proc
; -- compares strings in s1 (AY) and s2 (P8ZP_SCRATCH_W2).
; Compares up to maximum length specified in X.
; Returns -1,0,1 in A, depending on the ordering. Clobbers X & Y.
sta P8ZP_SCRATCH_W1
sty P8ZP_SCRATCH_W1+1
ldy #0
_loop lda (P8ZP_SCRATCH_W1),y
beq _c1_zero
cmp (P8ZP_SCRATCH_W2),y
beq _equal
bmi _less
lda #1
rts
_less lda #-1
rts
_equal dex
bne +
lda #0
rts
+ iny
bne _loop
_c1_zero lda (P8ZP_SCRATCH_W2),y
beq +
lda #-1
+ rts
.pend


strlen .proc
; -- returns the number of bytes in the string in AY, in Y. Clobbers A.
Expand Down
13 changes: 13 additions & 0 deletions compiler/res/prog8lib/strings.p8
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,19 @@ _str .word 0
}}
}

asmsub ncompare(uword string1 @R0, uword string2 @AY, ubyte length @X) clobbers(X, Y) -> byte @A {
; Compares two strings for sorting.
; Returns -1 (255), 0 or 1, meaning: string1 sorts before, equal or after string2.
; Only compares the strings from index 0 up to the length argument.
%asm {{
sta P8ZP_SCRATCH_W2
sty P8ZP_SCRATCH_W2+1
lda cx16.r0
ldy cx16.r0+1
jmp prog8_lib.strncmp_mem
}}
}

asmsub lower(uword st @AY) -> ubyte @Y {
; Lowercases the petscii string in-place. Returns length of the string.
; (for efficiency, non-letter characters > 128 will also not be left intact,
Expand Down
7 changes: 7 additions & 0 deletions compiler/test/comparisons/more_compares.p8
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,13 @@ main {
txt.print("name2 fail!\n")
}

if (strings.ncompare(name, "aaa", 3)==0) or (strings.compare(name, "johm", 3)==0) or (strings.compare(name, "bbb", 3)==0) {
txt.print("name1 ok\n")
}
if (strings.ncompare(name, "aaa", 2)==0) or (strings.ncompare(name, "zzz", 2)==0) or (strings.ncompare(name, "bbb", 2)==0) {
txt.print("name2 fail!\n")
}

if name=="aaa" or name=="john" or name=="bbb"
txt.print("name1b ok\n")
if name=="aaa" or name=="zzz" or name=="bbb"
Expand Down
6 changes: 6 additions & 0 deletions docs/source/libraries.rst
Original file line number Diff line number Diff line change
Expand Up @@ -900,6 +900,12 @@ Provides string manipulation routines.
using ``==``, ``<`` etcetera (it will use strings.compare for you under water automatically).
This even works when dealing with uword (pointer) variables when comparing them to a string type.

``ncompare (string1, string2, length) -> ubyte result``
Compares two strings up to the number of characters in the length parameter.
Returns -1, 0 or 1 depending on whether string1 sorts before, equal or after string2.
Note that lengths of 0 or 1 evaluate the same. The first character is always compared.
A length larger than either string will function identically to compare.

``copy (from, to) -> ubyte length``
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``
Expand Down
2 changes: 1 addition & 1 deletion syntax-files/SublimeText/Prog8.sublime-syntax
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ contexts:
- match: (\b(const)\b)
scope: storage.modifier.prog8
support:
- match: (\b(abs|atan|ceil|cos|cos8u|cos8|cos16u|cos16|deg|floor|ln|log2|rad|round|sin|sgn|sin8u|sin8|sin16u|sin16|sqrt16|sqrt|tan|any|all|len|max|min|reverse|sum|sort|memcopy|memset|memsetw|leftstr|rightstr|strlen|strcmp|substr|exit|lsb|msb|lsw|msw|mkword|rnd|rndw|rndf|rol|rol2|ror|ror2|rsave|rrestore|read_flags|sizeof|set_carry|clear_carry|set_irqd|clear_irqd|swap)\b)
- match: (\b(abs|atan|ceil|cos|cos8u|cos8|cos16u|cos16|deg|floor|ln|log2|rad|round|sin|sgn|sin8u|sin8|sin16u|sin16|sqrt16|sqrt|tan|any|all|len|max|min|reverse|sum|sort|memcopy|memset|memsetw|leftstr|rightstr|strlen|strcmp|strncmp|substr|exit|lsb|msb|lsw|msw|mkword|rnd|rndw|rndf|rol|rol2|ror|ror2|rsave|rrestore|read_flags|sizeof|set_carry|clear_carry|set_irqd|clear_irqd|swap)\b)
scope: support.function.prog8
variable:
- match: (\b\w+\b)
Expand Down
1 change: 1 addition & 0 deletions syntax-files/Vim/prog8_builtins.vim
Original file line number Diff line number Diff line change
Expand Up @@ -778,6 +778,7 @@ syn match prog8BuiltInFunc "\<strings\.contains\>"
syn match prog8BuiltInFunc "\<strings\.copy\>"
syn match prog8BuiltInFunc "\<strings\.append\>"
syn match prog8BuiltInFunc "\<strings\.compare\>"
syn match prog8BuiltInFunc "\<strings\.ncompare\>"
syn match prog8BuiltInFunc "\<strings\.lower\>"
syn match prog8BuiltInFunc "\<strings\.lowerchar\>"
syn match prog8BuiltInFunc "\<strings\.upper\>"
Expand Down

0 comments on commit 81c255c

Please sign in to comment.