Make the len parameter optional in STRSUB(str, pos, len)

An unspecified length will continue to the end of the string.
This commit is contained in:
Rangi
2021-04-19 12:00:42 -04:00
committed by Eldred Habert
parent b1e6c73197
commit dc5b7802c8
5 changed files with 67 additions and 36 deletions

View File

@@ -105,25 +105,18 @@ static size_t strlenUTF8(char const *s)
return len;
}
static void strsubUTF8(char *dest, size_t destLen, char const *src, int32_t pos, uint32_t len)
static void strsubUTF8(char *dest, size_t destLen, char const *src, uint32_t pos, uint32_t len)
{
size_t srcIndex = 0;
size_t destIndex = 0;
uint32_t state = 0;
uint32_t codep = 0;
uint32_t curLen = 0;
if (pos < 1) {
pos += strlenUTF8(src);
if (pos < 1) {
warning(WARNING_BUILTIN_ARG, "STRSUB: Position starts at 1\n");
pos = 1;
}
}
uint32_t curPos = 1;
/* Advance to starting position in source string. */
for (uint32_t curPos = 1; src[srcIndex] && curPos < pos; srcIndex++) {
switch (decode(&state, &codep, src[srcIndex])) {
while (src[srcIndex] && curPos < pos) {
switch (decode(&state, &codep, src[srcIndex++])) {
case 1:
fatalerror("STRSUB: Invalid UTF-8 character\n");
break;
@@ -133,9 +126,13 @@ static void strsubUTF8(char *dest, size_t destLen, char const *src, int32_t pos,
}
}
if (!src[srcIndex] && len)
/*
* A position 1 past the end of the string is allowed, but will trigger the
* "Length too big" warning below if the length is nonzero.
*/
if (!src[srcIndex] && pos > curPos)
warning(WARNING_BUILTIN_ARG,
"STRSUB: Position %" PRId32 " is past the end of the string\n", pos);
"STRSUB: Position %" PRIu32 " is past the end of the string\n", pos);
/* Copy from source to destination. */
while (src[srcIndex] && destIndex < destLen - 1 && curLen < len) {
@@ -151,7 +148,7 @@ static void strsubUTF8(char *dest, size_t destLen, char const *src, int32_t pos,
}
if (curLen < len)
warning(WARNING_BUILTIN_ARG, "STRSUB: Length too big: %lu\n", (unsigned long)len);
warning(WARNING_BUILTIN_ARG, "STRSUB: Length too big: %" PRIu32 "\n", len);
/* Check for partial code point. */
if (state != 0)
@@ -170,18 +167,10 @@ static size_t charlenUTF8(char const *s)
return len;
}
static void charsubUTF8(char *dest, char const *src, int32_t pos)
static void charsubUTF8(char *dest, char const *src, uint32_t pos)
{
size_t charLen = 1;
if (pos < 1) {
pos += charlenUTF8(src);
if (pos < 1) {
warning(WARNING_BUILTIN_ARG, "CHARSUB: Position starts at 1\n");
pos = 1;
}
}
/* Advance to starting position in source string. */
for (uint32_t curPos = 1; charLen && curPos < pos; curPos++)
charLen = charmap_ConvertNext(&src, NULL);
@@ -190,7 +179,7 @@ static void charsubUTF8(char *dest, char const *src, int32_t pos)
if (!charmap_ConvertNext(&src, NULL))
warning(WARNING_BUILTIN_ARG,
"CHARSUB: Position %" PRId32 " is past the end of the string\n", pos);
"CHARSUB: Position %" PRIu32 " is past the end of the string\n", pos);
/* Copy from source to destination. */
memcpy(dest, start, src - start);
@@ -198,6 +187,22 @@ static void charsubUTF8(char *dest, char const *src, int32_t pos)
dest[src - start] = '\0';
}
static uint32_t adjustNegativePos(int32_t pos, size_t len, char const *functionName)
{
/*
* STRSUB and CHARSUB adjust negative `pos` arguments the same way,
* such that position 0 is the last character of a string.
*/
if (pos < 1) {
pos += len;
if (pos < 1) {
warning(WARNING_BUILTIN_ARG, "%s: Position starts at 1\n", functionName);
pos = 1;
}
}
return (uint32_t)pos;
}
static void strrpl(char *dest, size_t destLen, char const *src, char const *old, char const *new)
{
size_t oldLen = strlen(old);
@@ -1531,10 +1536,22 @@ const_no_str : relocexpr_no_str {
string : T_STRING
| T_OP_STRSUB T_LPAREN string T_COMMA const T_COMMA uconst T_RPAREN {
strsubUTF8($$, sizeof($$), $3, $5, $7);
size_t len = strlenUTF8($3);
uint32_t pos = adjustNegativePos($5, len, "STRSUB");
strsubUTF8($$, sizeof($$), $3, pos, $7);
}
| T_OP_STRSUB T_LPAREN string T_COMMA const T_RPAREN {
size_t len = strlenUTF8($3);
uint32_t pos = adjustNegativePos($5, len, "STRSUB");
strsubUTF8($$, sizeof($$), $3, pos, pos > len ? 0 : len + 1 - pos);
}
| T_OP_CHARSUB T_LPAREN string T_COMMA const T_RPAREN {
charsubUTF8($$, $3, $5);
size_t len = charlenUTF8($3);
uint32_t pos = adjustNegativePos($5, len, "CHARSUB");
charsubUTF8($$, $3, pos);
}
| T_OP_STRCAT T_LPAREN T_RPAREN {
$$[0] = '\0';