returns a substring of the original string, beginning with a 0-based index start and length.
| 149 | |
| 150 | // returns a substring of the original string, beginning with a 0-based index start and length. |
| 151 | SIValue AR_SUBSTRING(SIValue *argv, int argc, void *private_data) { |
| 152 | /* |
| 153 | argv[0] - original string |
| 154 | argv[1] - start position |
| 155 | argv[2] - length |
| 156 | If length is omitted, the function returns the substring starting at the position given by start and extending to the end of original. |
| 157 | If either start or length is null or a negative integer, an error is raised. |
| 158 | If start is 0, the substring will start at the beginning of original. |
| 159 | If length is 0, the empty string will be returned. |
| 160 | */ |
| 161 | if(SIValue_IsNull(argv[0])) return SI_NullVal(); |
| 162 | |
| 163 | int64_t length; |
| 164 | const char *original = argv[0].stringval; |
| 165 | const int64_t original_len = strlen(original); |
| 166 | const int64_t start = argv[1].longval; |
| 167 | |
| 168 | /* Make sure start doesn't overreach. */ |
| 169 | if(start < 0) { |
| 170 | ErrorCtx_SetError("start must be a non-negative integer"); |
| 171 | return SI_NullVal(); |
| 172 | } |
| 173 | |
| 174 | if(start >= original_len) { |
| 175 | return SI_ConstStringVal(""); |
| 176 | } |
| 177 | |
| 178 | const int64_t suffix_len = original_len - start; |
| 179 | if(argc == 2) { |
| 180 | length = suffix_len; |
| 181 | } else { |
| 182 | length = argv[2].longval; |
| 183 | if(length < 0) { |
| 184 | ErrorCtx_SetError("length must be a non-negative integer"); |
| 185 | return SI_ConstStringVal(""); |
| 186 | } |
| 187 | |
| 188 | /* Make sure length does not overreach. */ |
| 189 | length = MIN(length, suffix_len); |
| 190 | } |
| 191 | |
| 192 | utf8proc_int32_t c; |
| 193 | // find the start position to copy from |
| 194 | const char *start_p = original; |
| 195 | for (int i = 0; i < start; i++) { |
| 196 | start_p += utf8proc_iterate((const utf8proc_uint8_t *)start_p, -1, &c); |
| 197 | } |
| 198 | |
| 199 | // find the end position |
| 200 | const char *end_p = start_p; |
| 201 | for (int i = 0; i < length; i++) { |
| 202 | end_p += utf8proc_iterate((const utf8proc_uint8_t *)end_p, -1, &c); |
| 203 | } |
| 204 | |
| 205 | int len = end_p - start_p; |
| 206 | char *substring = rm_malloc((len + 1) * sizeof(char)); |
| 207 | strncpy(substring, start_p, len); |
| 208 | substring[len] = '\0'; |
nothing calls this directly
no test coverage detected