Carp/core/carp_string.h

392 lines
9.3 KiB
C
Raw Normal View History

2020-05-12 02:14:02 +03:00
#include "carp_utf8.h"
String String_allocate(int len, char byte) {
/* Allocate a string of length 'len + 1'
* setting the first len bytes to byte
* and adding a null terminator
*
* String_alloc(10, "a") == "aaaaaaaaaa"
*/
String ptr = CARP_MALLOC(len + 1);
if (ptr != NULL) {
2021-06-08 22:05:51 +03:00
// calling memset(NULL,...) would exercise undefined behaviour...
memset(ptr, byte, len);
ptr[len] = '\0';
}
return ptr;
}
void String_delete(String s) {
CARP_FREE(s);
}
2018-02-27 16:14:14 +03:00
2018-05-19 09:49:48 +03:00
void String_string_MINUS_set_BANG_(String *s, int i, char ch) {
2019-06-20 23:13:18 +03:00
CHK_INDEX(i, strlen(*s));
2018-05-19 09:49:48 +03:00
(*s)[i] = ch;
}
void String_string_MINUS_set_MINUS_at_BANG_(String *into, int i,
const String *src) {
2018-05-20 06:53:30 +03:00
char *dest = (*into) + i;
2020-05-09 13:21:14 +03:00
size_t lsrc = strlen(*src);
2019-09-11 09:21:42 +03:00
/* given a string and indices
2018-05-20 06:53:30 +03:00
*
* 0 1 2 3 4 5 6 7 8 9
* "a b c d e f g h i j"
* linto = strlen(...) = 10
*
* if we want to insert at '6' a string of length '4'
*
* 0 1 2 3
* "w x y z"
* lsrc = strlen(...) = 4
2018-05-20 06:53:30 +03:00
*
* we need to make sure that the new string will not grow the first
*
* 0 1 2 3 4 5 6 7 8 9
* "a b c d e f g h i j"
* ^
* |
* 0 1 2 3
* "w x y z"
*
* we check this by
* (i + lsrc) < (linto + 1)
* (6 + 4) < (10 + 1)
* 10 < 11
2018-05-20 06:53:30 +03:00
* true
*
* so this write is safe
*/
CHK_INDEX(i + lsrc, strlen(*into) + 1);
2019-09-11 09:33:38 +03:00
memcpy(dest, *src, lsrc);
2018-05-20 06:53:30 +03:00
}
String String_copy(const String *s) {
2018-02-27 16:14:14 +03:00
size_t len = strlen(*s) + 1;
2018-03-18 16:53:03 +03:00
String ptr = CARP_MALLOC(len);
return (String)memcpy(ptr, *s, len);
2018-02-27 16:14:14 +03:00
}
bool String__EQ_(const String *a, const String *b) {
2018-02-27 16:14:14 +03:00
return strcmp(*a, *b) == 0;
}
bool String__GT_(const String *a, const String *b) {
2018-06-26 09:00:33 +03:00
return strcmp(*a, *b) > 0;
}
bool String__LT_(const String *a, const String *b) {
2018-06-26 09:00:33 +03:00
return strcmp(*a, *b) < 0;
}
String String_append(const String *a, const String *b) {
int la = strlen(*a);
int lb = strlen(*b);
2018-02-27 16:14:14 +03:00
int total = la + lb + 1;
2018-03-18 16:53:03 +03:00
String buffer = CARP_MALLOC(total);
2020-01-28 01:11:45 +03:00
memcpy(buffer, *a, la);
2020-02-11 11:09:30 +03:00
memcpy(buffer + la, *b, lb);
buffer[la + lb] = '\0';
return buffer;
}
int String_length(const String *s) {
return strlen(*s);
}
2018-02-27 16:14:14 +03:00
char *String_cstr(const String *s) {
return *s;
}
2018-02-27 16:14:14 +03:00
2020-01-14 00:47:09 +03:00
String String_from_MINUS_cstr(char *s) {
2020-01-14 12:08:29 +03:00
return String_copy(&s);
2020-01-14 00:47:09 +03:00
}
String String_str(const String *s) {
return String_copy(s);
}
2018-02-27 17:30:22 +03:00
int count_occurrences(String s, char c) {
int res = 0;
while (*s != '\0') {
if (*s == c) res++;
s++;
}
return res;
}
String String_prn(const String *s) {
int n = strlen(*s) + 4 + count_occurrences(*s, '"');
2018-03-18 16:53:03 +03:00
String buffer = CARP_MALLOC(n);
buffer[0] = '@';
buffer[1] = '"';
String c = *s;
for (int i = 2; i < n - 2; i++) {
if (*c == '"') buffer[i++] = '\\';
buffer[i] = *c;
c++;
}
buffer[n - 2] = '"';
buffer[n - 1] = '\0';
2018-02-27 16:14:14 +03:00
return buffer;
}
char String_char_MINUS_at(const String *s, int i) {
return (*s)[i];
}
2018-02-27 16:14:14 +03:00
String String_format(const String *str, const String *s) {
int size = snprintf(NULL, 0, *str, *s) + 1;
2018-03-18 16:53:03 +03:00
String buffer = CARP_MALLOC(size);
sprintf(buffer, *str, *s);
2018-02-27 16:14:14 +03:00
return buffer;
}
2020-05-12 02:14:02 +03:00
Array String_chars(const String *ps) {
2020-05-11 17:10:35 +03:00
Char *data;
2018-02-27 16:14:14 +03:00
Array chars;
2020-05-12 02:14:02 +03:00
const char *s = *ps;
const uint8_t *us = (const uint8_t *)s;
uint32_t state = 0;
uint32_t cp = 0;
size_t l = utf8len(s);
chars.len = l;
chars.capacity = l;
2020-05-11 17:10:35 +03:00
data = CARP_MALLOC(chars.capacity * sizeof(*data));
2020-05-12 02:14:02 +03:00
for (size_t si = 0, di = 0; di < l; si++) {
2020-11-17 01:46:16 +03:00
uint32_t r = utf8decode(&state, &cp, us[si]);
switch (r) {
case UTF8_ACCEPT:
data[di++] = cp;
cp = 0;
break;
case UTF8_REJECT:
data[di++] = 0xfffd; // REPLACEMENT CHARACTER
cp = 0;
break;
2020-05-12 02:14:02 +03:00
}
}
2020-05-11 17:10:35 +03:00
chars.data = data;
2018-02-27 16:14:14 +03:00
return chars;
}
String String_from_MINUS_chars(const Array *a) {
2020-05-12 02:14:02 +03:00
Char *data = (Char *)a->data;
2020-05-11 17:10:35 +03:00
size_t cnt = a->len;
size_t sz = wutf8len(data, cnt) + 1;
String s = CARP_MALLOC(sz);
size_t sofar = 0;
2020-05-12 02:14:02 +03:00
for (size_t i = 0; i < cnt; i++) sofar += utf8encode(s + sofar, data[i]);
s[sofar++] = 0;
assert(sofar == sz);
2018-02-27 16:14:14 +03:00
return s;
}
String String_tail(const String *s) {
2020-05-11 17:10:35 +03:00
size_t len = strlen(*s);
String news = CARP_MALLOC(len);
memcpy(news, (*s) + 1, len - 1);
news[len - 1] = '\0';
return news;
2018-02-27 16:14:14 +03:00
}
2018-03-18 16:53:03 +03:00
String String_empty() {
String s = CARP_MALLOC(1);
2018-02-27 16:14:14 +03:00
s[0] = '\0';
return s;
}
2020-05-13 18:15:26 +03:00
Array String_to_MINUS_bytes(const String *s) {
Array chars;
const uint8_t *us = (const uint8_t *)*s;
size_t l = strlen(*s);
chars.len = l;
chars.capacity = l;
chars.data = CARP_MALLOC(chars.capacity);
memcpy(chars.data, us, l);
return chars;
}
2020-07-08 21:39:50 +03:00
String String_from_MINUS_bytes(Array *a) {
String s;
const char *us = (const char *)a->data;
2020-08-24 12:05:47 +03:00
s = CARP_MALLOC(a->len + 1);
2020-07-08 21:39:50 +03:00
memcpy(s, us, a->len);
2020-07-08 23:00:43 +03:00
s[a->len] = '\0';
2020-07-08 21:39:50 +03:00
return s;
}
2018-03-18 16:53:03 +03:00
String Bool_str(bool b) {
const String true_str = "true";
const String false_str = "false";
if (b) {
return String_copy(&true_str);
} else {
return String_copy(&false_str);
}
}
String Bool_format(const String *str, bool b) {
int size = snprintf(NULL, 0, *str, b) + 1;
2018-03-18 16:53:03 +03:00
String buffer = CARP_MALLOC(size);
sprintf(buffer, *str, b);
return buffer;
}
2020-05-12 02:14:02 +03:00
String Char_str(Char c) {
2020-05-09 13:21:14 +03:00
char buf[16];
2020-05-12 02:14:02 +03:00
size_t sz = utf8encode(buf, c);
2020-05-09 13:21:14 +03:00
size_t nsz = sz + 1;
String buffer = CARP_MALLOC(nsz);
memcpy(buffer, buf, nsz);
2020-05-12 02:14:02 +03:00
buffer[nsz - 1] = 0;
return buffer;
}
2020-05-12 02:14:02 +03:00
String Char_prn(Char c) {
char buf[16];
size_t sz = utf8encode(buf, c);
size_t nsz = sz + 1 + 1;
String buffer = CARP_MALLOC(nsz);
buffer[0] = '\\';
memcpy(buffer + 1, buf, sz);
buffer[nsz - 1] = 0;
return buffer;
}
String Char_format(const String *str, char b) {
int size = snprintf(NULL, 0, *str, b) + 1;
2018-03-18 16:53:03 +03:00
String buffer = CARP_MALLOC(size);
sprintf(buffer, *str, b);
return buffer;
}
2018-03-18 16:53:03 +03:00
String Double_str(double x) {
int size = snprintf(NULL, 0, "%g", x) + 1;
2018-03-18 16:53:03 +03:00
String buffer = CARP_MALLOC(size);
sprintf(buffer, "%g", x);
return buffer;
}
String Double_format(const String *s, double x) {
int size = snprintf(NULL, 0, *s, x) + 1;
2018-03-18 16:53:03 +03:00
String buffer = CARP_MALLOC(size);
sprintf(buffer, *s, x);
return buffer;
}
2020-05-12 19:02:30 +03:00
bool Double_from_MINUS_string_MINUS_internal(const String *s, double *target) {
char *err;
*target = strtod(*s, &err);
return *err == 0;
}
2018-03-18 16:53:03 +03:00
String Float_str(float x) {
int size = snprintf(NULL, 0, "%gf", x) + 1;
2018-03-18 16:53:03 +03:00
String buffer = CARP_MALLOC(size);
sprintf(buffer, "%gf", x);
return buffer;
}
String Float_format(const String *str, float x) {
int size = snprintf(NULL, 0, *str, x) + 1;
2018-03-18 16:53:03 +03:00
String buffer = CARP_MALLOC(size);
sprintf(buffer, *str, x);
return buffer;
}
2020-05-12 19:02:30 +03:00
bool Float_from_MINUS_string_MINUS_internal(const String *s, float *target) {
char *err;
*target = strtof(*s, &err);
return *err == 0;
}
2018-03-18 16:53:03 +03:00
String Int_str(int x) {
int size = snprintf(NULL, 0, "%d", x) + 1;
2018-03-18 16:53:03 +03:00
String buffer = CARP_MALLOC(size);
sprintf(buffer, "%d", x);
return buffer;
}
String Int_format(const String *str, int x) {
int size = snprintf(NULL, 0, *str, x) + 1;
2018-03-18 16:53:03 +03:00
String buffer = CARP_MALLOC(size);
sprintf(buffer, *str, x);
return buffer;
}
2020-05-12 19:02:30 +03:00
bool Int_from_MINUS_string_MINUS_internal(const String *s, int *target) {
char *err;
*target = (int)strtol(*s, &err, 10);
return *err == 0;
}
String Long_str(Long x) {
int size = snprintf(NULL, 0, "%" PRIi64, x) + 1;
2018-03-18 16:53:03 +03:00
String buffer = CARP_MALLOC(size);
sprintf(buffer, "%" PRIi64, x);
return buffer;
}
String Long_format(const String *str, Long x) {
int size = snprintf(NULL, 0, *str, x) + 1;
2018-03-18 16:53:03 +03:00
String buffer = CARP_MALLOC(size);
sprintf(buffer, *str, x);
return buffer;
}
2020-05-12 19:02:30 +03:00
bool Long_from_MINUS_string_MINUS_internal(const String *s, Long *target) {
char *err;
*target = strtol(*s, &err, 10);
return *err == 0;
}
2018-05-20 11:25:13 +03:00
2019-10-24 12:23:38 +03:00
String Byte_str(uint8_t x) {
int size = snprintf(NULL, 0, "%ub", x) + 1;
2019-10-24 12:23:38 +03:00
String buffer = CARP_MALLOC(size);
sprintf(buffer, "%ub", x);
2019-10-24 12:23:38 +03:00
return buffer;
}
String Byte_format(const String *str, uint8_t x) {
int size = snprintf(NULL, 0, *str, x) + 1;
2019-10-24 12:23:38 +03:00
String buffer = CARP_MALLOC(size);
sprintf(buffer, *str, x);
2019-10-24 12:23:38 +03:00
return buffer;
}
2020-05-12 19:02:30 +03:00
uint8_t Byte_from_MINUS_string_MINUS_internal(const String *s, byte *target) {
char *err;
*target = (uint8_t)strtol(*s, &err, 10);
return *err == 0;
2019-10-24 12:23:38 +03:00
}
int String_index_MINUS_of_MINUS_from(const String *s, char c, int i) {
2018-05-20 11:41:36 +03:00
/* Return index of first occurrence of `c` in `s` AFTER index i
2018-05-20 11:25:13 +03:00
* Returns -1 if not found
*/
++i; // skip first character as we want AFTER i
2020-05-12 02:14:02 +03:00
size_t len = strlen(*s);
for (; i < len; ++i) {
if (c == (*s)[i]) {
return i;
}
2018-05-20 11:25:13 +03:00
}
return -1;
}
2018-05-20 11:41:36 +03:00
int String_index_MINUS_of(const String *s, char c) {
2018-05-20 11:41:36 +03:00
/* Return index of first occurrence of `c` in `s`
* Returns -1 if not found
*/
return String_index_MINUS_of_MINUS_from(s, c, -1);
}
2020-11-05 18:45:33 +03:00
String Pointer_strp(void *in) {
2020-11-05 18:45:33 +03:00
int size = snprintf(NULL, 0, "%p", in) + 1;
String buffer = CARP_MALLOC(size);
sprintf(buffer, "%p", in);
return buffer;
}