From b566ea5c3fca6d9e979094da6af6e4555e4a0801 Mon Sep 17 00:00:00 2001 From: Irmen de Jong Date: Thu, 22 Aug 2024 22:54:38 +0200 Subject: [PATCH] added string.rfind() --- compiler/res/prog8lib/cx16/gfx2.p8 | 1 + compiler/res/prog8lib/string.p8 | 35 ++++++++++++- compiler/res/prog8lib/virtual/string.p8 | 15 ++++++ docs/source/libraries.rst | 15 +++--- examples/test.p8 | 66 ++++++++++++------------- 5 files changed, 89 insertions(+), 43 deletions(-) diff --git a/compiler/res/prog8lib/cx16/gfx2.p8 b/compiler/res/prog8lib/cx16/gfx2.p8 index ae8e4f665..b39dc4f60 100644 --- a/compiler/res/prog8lib/cx16/gfx2.p8 +++ b/compiler/res/prog8lib/cx16/gfx2.p8 @@ -13,6 +13,7 @@ ; NOTE: For sake of speed, NO BOUNDS CHECKING is performed in most routines! ; You'll have to make sure yourself that you're not writing outside of bitmap boundaries! ; +; NOTE: the bitmap screen data is positioned in vram at $0:0000 ; ; SCREEN MODE LIST: ; mode 0 = reset back to default text mode diff --git a/compiler/res/prog8lib/string.p8 b/compiler/res/prog8lib/string.p8 index 4a6ab1367..3eead5127 100644 --- a/compiler/res/prog8lib/string.p8 +++ b/compiler/res/prog8lib/string.p8 @@ -134,11 +134,11 @@ _startloop dey ; need to copy the the cx16 virtual registers to zeropage to make this run on C64... sta P8ZP_SCRATCH_W1 sty P8ZP_SCRATCH_W1+1 - stx P8ZP_SCRATCH_B1 + stx _comparemod+1 ldy #0 - lda (P8ZP_SCRATCH_W1),y beq _notfound - cmp P8ZP_SCRATCH_B1 +_comparemod cmp #0 ; modified beq _found iny bne - @@ -151,6 +151,37 @@ _found tya }} } + asmsub rfind(uword string @AY, ubyte character @X) -> ubyte @A, bool @Pc { + ; 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). + %asm {{ + stx _comparemod+1 + sta _str + sty _str+1 + jsr string.length + dey + lda _str + sta P8ZP_SCRATCH_W1 + lda _str+1 + sta P8ZP_SCRATCH_W1+1 +- lda (P8ZP_SCRATCH_W1),y +_comparemod cmp #0 ; modified + beq _found + dey + cpy #255 + bne - +_notfound lda #255 + clc + rts +_found tya + sec + rts + +_str .word 0 + + }} + } + asmsub contains(uword string @AY, ubyte character @X) -> bool @Pc { ; Just return true/false if the character is in the given string or not. %asm {{ diff --git a/compiler/res/prog8lib/virtual/string.p8 b/compiler/res/prog8lib/virtual/string.p8 index 3079004ac..a1dbec3fe 100644 --- a/compiler/res/prog8lib/virtual/string.p8 +++ b/compiler/res/prog8lib/virtual/string.p8 @@ -68,6 +68,21 @@ string { return 255 } + 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 + for ix in string.length(stringptr)-1 downto 0 { + if stringptr[ix]==character { + sys.set_carry() + return ix + } + } + sys.clear_carry() + return 255 + } + sub contains(str st, ubyte character) -> bool { void find(st, character) if_cs diff --git a/docs/source/libraries.rst b/docs/source/libraries.rst index 6710b07b8..ef2010796 100644 --- a/docs/source/libraries.rst +++ b/docs/source/libraries.rst @@ -483,14 +483,15 @@ Provides string manipulation routines. 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). -``find (string, char) -> ubyte index + carry bit`` - Locates the first position of the given character in the string, returns carry bit set if found - and the index in the string. Or 0+carry bit clear if the character was not found. +``find (string, char) -> ubyte index, bool found`` + Locates the first index of the given character in the string, and a boolean (in Carry flag) + to say if it was found at all. If the character is not found, index 255 (and false) is returned. You can consider this a safer way of checking if a character occurs - in a string than using an `in` containment check - because the find routine - properly stops at the first 0-byte string terminator it encounters. - Simply call this and only act on the carry status with ``if_cc`` for example. - Much like the difference between len(str) and length(str). + in a string than using an `in` containment check - because this find routine + properly stops at the first 0-byte string terminator it encounters in case the string was modified. + +``rfind (string, char) -> ubyte index, bool found`` + Like ``find``, but now looking from the *right* of the string instead. ``contains (string, char) -> bool`` Just returns true if the character is in the given string, or false if it's not. diff --git a/examples/test.p8 b/examples/test.p8 index 05e08e345..93a0586a3 100644 --- a/examples/test.p8 +++ b/examples/test.p8 @@ -1,48 +1,46 @@ %import textio +%import string %option no_sysinit %zeropage basicsafe main { sub start() { - ubyte @shared v1,v2,v3 - v1 = %10011001 - v2 = %10101010 - v3 = %00111100 + str name = "zn.iff.jpg" - v1 &= %00011111 - v1++ - txt.print_ubbin(v1, true) - txt.nl() + ubyte index + bool found - v1 &= ~v2 - v1++ - txt.print_ubbin(v1, true) - txt.nl() + index, found = string.find(name, '.') + if found { + txt.print_ub(index) + txt.nl() + } else { + txt.print(". not found\n") + } - v1 |= 100 - v1++ - txt.print_ubbin(v1, true) - txt.nl() + index, found = string.find(name, '@') + if found { + txt.print_ub(index) + txt.nl() + } else { + txt.print("@ not found\n") + } - v1 |= v2 - v1++ - txt.print_ubbin(v1, true) - txt.nl() + index, found = string.rfind(name, '.') + if found { + txt.print_ub(index) + txt.nl() + } else { + txt.print(". not r found\n") + } - v1 |= v2 & v3 - v1++ - txt.print_ubbin(v1, true) - txt.nl() - - v1 &= v2|v3 - v1++ - txt.print_ubbin(v1, true) - txt.nl() - - v1 &= ~(v2|v3) - v1++ - txt.print_ubbin(v1, true) - txt.nl() + index, found = string.rfind(name, '@') + if found { + txt.print_ub(index) + txt.nl() + } else { + txt.print("@ not r found\n") + } } }