diff --git a/src/asm/parser.y b/src/asm/parser.y index 3208e035..604d5dd2 100644 --- a/src/asm/parser.y +++ b/src/asm/parser.y @@ -191,14 +191,13 @@ static uint32_t adjustNegativePos(int32_t pos, size_t len, char const *functionN { /* * STRSUB and CHARSUB adjust negative `pos` arguments the same way, - * such that position 0 is the last character of a string. + * such that position -1 is the last character of a string. */ + if (pos < 0) + pos += len + 1; if (pos < 1) { - pos += len; - if (pos < 1) { - warning(WARNING_BUILTIN_ARG, "%s: Position starts at 1\n", functionName); - pos = 1; - } + warning(WARNING_BUILTIN_ARG, "%s: Position starts at 1\n", functionName); + pos = 1; } return (uint32_t)pos; } diff --git a/src/asm/rgbasm.5 b/src/asm/rgbasm.5 index 6cd68c40..171d87c0 100644 --- a/src/asm/rgbasm.5 +++ b/src/asm/rgbasm.5 @@ -394,13 +394,13 @@ Most of them return a string, however some of these functions actually return an .It Fn STRCMP str1 str2 Ta Returns -1 if Ar str1 No is alphabetically lower than Ar str2 No , zero if they match, 1 if Ar str1 No is greater than Ar str2 . .It Fn STRIN str1 str2 Ta Returns the first position of Ar str2 No in Ar str1 No or zero if it's not present Pq first character is position 1 . .It Fn STRRIN str1 str2 Ta Returns the last position of Ar str2 No in Ar str1 No or zero if it's not present Pq first character is position 1 . -.It Fn STRSUB str pos len Ta Returns a substring from Ar str No starting at Ar pos No (first character is position 1) and Ar len No characters long. Zero or negative Ar pos No counts from the end, as if Qo STRLEN(str) Qc were added to it. If Ar len No is not specified the substring continues to the end of Ar str . +.It Fn STRSUB str pos len Ta Returns a substring from Ar str No starting at Ar pos No (first character is position 1, last is position -1) and Ar len No characters long. If Ar len No is not specified the substring continues to the end of Ar str . .It Fn STRUPR str Ta Returns Ar str No with all letters in uppercase. .It Fn STRLWR str Ta Returns Ar str No with all letters in lowercase. .It Fn STRRPL str old new Ta Returns Ar str No with each non-overlapping occurrence of the substring Ar old No replaced with Ar new . .It Fn STRFMT fmt args... Ta Returns the string Ar fmt No with each .It Fn CHARLEN str Ta Returns the number of charmap entries in Ar str No with the current charmap. -.It Fn CHARSUB str pos Ta Returns the substring for the charmap entry at Ar pos No in Ar str No (first character is position 1) with the current charmap. Zero or negative Ar pos No counts from the end, as if Qo CHARLEN(str) Qc were added to it. +.It Fn CHARSUB str pos Ta Returns the substring for the charmap entry at Ar pos No in Ar str No (first character is position 1, last is position -1) with the current charmap. .Ql %spec pattern replaced by interpolating the format .Ar spec diff --git a/test/asm/charlen-charsub.asm b/test/asm/charlen-charsub.asm index dcab1fb0..c2ae8bbb 100644 --- a/test/asm/charlen-charsub.asm +++ b/test/asm/charlen-charsub.asm @@ -11,7 +11,7 @@ S EQUS "XBoldABC" assert CHARLEN("{S}") == 6 println CHARSUB("{S}", 2) assert !STRCMP(CHARSUB("{S}", 2), "Bold") - assert CHARSUB("{S}", -4) == CHARSUB("{S}", CHARLEN("{S}") - 4) + assert CHARSUB("{S}", -5) == CHARSUB("{S}", CHARLEN("{S}") + 1 - 5) assert CHARSUB("{S}", 2) == "Bold" && "Bold" == $88 assert CHARSUB("{S}", 1) == $58 ; ASCII "X" db "{S}" @@ -21,7 +21,7 @@ S EQUS "XBoldABC" assert CHARLEN("{S}") == 14 println CHARSUB("{S}", 2) assert !STRCMP(CHARSUB("{S}", 2), "B") - assert CHARSUB("{S}", -4) == CHARSUB("{S}", CHARLEN("{S}") - 4) + assert CHARSUB("{S}", -5) == CHARSUB("{S}", CHARLEN("{S}") + 1 - 5) assert CHARSUB("{S}", 2) == "B" && "B" == $42 ; ASCII "B" assert CHARSUB("{S}", 1) == $58 ; ASCII "X" db "{S}" diff --git a/test/asm/strsub.asm b/test/asm/strsub.asm index 120d2d8f..4b5f23e2 100644 --- a/test/asm/strsub.asm +++ b/test/asm/strsub.asm @@ -7,18 +7,19 @@ ENDM xstrsub "ABC", 1, 1 xstrsub "ABC", 2, 1 xstrsub "ABC", 3, 1 + xstrsub "ABC", -3, 1 xstrsub "ABC", -2, 1 xstrsub "ABC", -1, 1 - xstrsub "ABC", 0, 1 xstrsub "ABC", 2 - xstrsub "ABC", -1 + xstrsub "ABC", 0 + xstrsub "ABC", -2 xstrsub "ABC", 5 xstrsub "ABC", -5 xstrsub "ABC", 1, 2 xstrsub "ABC", 2, 2 xstrsub "ABC", 2, 32 xstrsub "ABC", 2, 300 - xstrsub "ABC", -3, 300 + xstrsub "ABC", -4, 300 xstrsub "ABC", 4, 0 xstrsub "ABC", 5, 0 xstrsub "ABC", 4, 1 diff --git a/test/asm/strsub.err b/test/asm/strsub.err index 7a81bc64..a40b28ec 100644 --- a/test/asm/strsub.err +++ b/test/asm/strsub.err @@ -1,18 +1,20 @@ -warning: strsub.asm(15) -> strsub.asm::xstrsub(4): [-Wbuiltin-args] - STRSUB: Position 5 is past the end of the string +warning: strsub.asm(14) -> strsub.asm::xstrsub(4): [-Wbuiltin-args] + STRSUB: Position starts at 1 warning: strsub.asm(16) -> strsub.asm::xstrsub(4): [-Wbuiltin-args] - STRSUB: Position starts at 1 -warning: strsub.asm(19) -> strsub.asm::xstrsub(4): [-Wbuiltin-args] - STRSUB: Length too big: 32 -warning: strsub.asm(20) -> strsub.asm::xstrsub(4): [-Wbuiltin-args] - STRSUB: Length too big: 300 -warning: strsub.asm(21) -> strsub.asm::xstrsub(4): [-Wbuiltin-args] - STRSUB: Position starts at 1 -warning: strsub.asm(21) -> strsub.asm::xstrsub(4): [-Wbuiltin-args] - STRSUB: Length too big: 300 -warning: strsub.asm(23) -> strsub.asm::xstrsub(4): [-Wbuiltin-args] STRSUB: Position 5 is past the end of the string +warning: strsub.asm(17) -> strsub.asm::xstrsub(4): [-Wbuiltin-args] + STRSUB: Position starts at 1 +warning: strsub.asm(20) -> strsub.asm::xstrsub(4): [-Wbuiltin-args] + STRSUB: Length too big: 32 +warning: strsub.asm(21) -> strsub.asm::xstrsub(4): [-Wbuiltin-args] + STRSUB: Length too big: 300 +warning: strsub.asm(22) -> strsub.asm::xstrsub(4): [-Wbuiltin-args] + STRSUB: Position starts at 1 +warning: strsub.asm(22) -> strsub.asm::xstrsub(4): [-Wbuiltin-args] + STRSUB: Length too big: 300 warning: strsub.asm(24) -> strsub.asm::xstrsub(4): [-Wbuiltin-args] + STRSUB: Position 5 is past the end of the string +warning: strsub.asm(25) -> strsub.asm::xstrsub(4): [-Wbuiltin-args] STRSUB: Length too big: 1 -warning: strsub.asm(27) -> strsub.asm::xstrsub(4): [-Wbuiltin-args] +warning: strsub.asm(28) -> strsub.asm::xstrsub(4): [-Wbuiltin-args] STRSUB: Length too big: 10 diff --git a/test/asm/strsub.out b/test/asm/strsub.out index 7279a74d..7270b3f8 100644 --- a/test/asm/strsub.out +++ b/test/asm/strsub.out @@ -5,6 +5,7 @@ A B C BC +ABC BC ABC