#include "iron_string.h" #include #include #include #include void *gc_alloc(size_t size); void *gc_leaf(void *ptr); char *string_alloc(int size) { char *r = gc_alloc(size); gc_leaf(r); return r; } char *string_join(char *a, char *b) { char *r = string_alloc(strlen(a) + strlen(b) + 1); strcpy(r, a); strcat(r, b); return r; } char *string_copy(char *a) { if (a == NULL) { return NULL; } char *r = string_alloc(strlen(a) + 1); strcpy(r, a); return r; } int string_length(char *str) { return strlen(str); } bool string_equals(char *a, char *b) { if (a == NULL || b == NULL) { return false; } return strcmp(a, b) == 0; } char *i32_to_string(int32_t i) { int l = snprintf(NULL, 0, "%d", i); char *r = string_alloc(l + 1); sprintf(r, "%d", i); return r; } char *i32_to_string_hex(int32_t i) { int l = snprintf(NULL, 0, "%X", i); char *r = string_alloc(l + 1); sprintf(r, "%X", i); return r; } char *i64_to_string(int64_t i) { int l = snprintf(NULL, 0, "%ld", i); char *r = string_alloc(l + 1); sprintf(r, "%ld", i); return r; } char *u64_to_string(uint64_t i) { int l = snprintf(NULL, 0, "%lu", i); char *r = string_alloc(l + 1); sprintf(r, "%lu", i); return r; } char *f32_to_string_with_zeros(float f) { int l = snprintf(NULL, 0, "%f", f); char *r = string_alloc(l + 1); sprintf(r, "%f", f); return r; } char *f32_to_string(float f) { char *r = f32_to_string_with_zeros(f); string_strip_trailing_zeros(r); return r; } void string_strip_trailing_zeros(char *str) { int len = strlen(str); while (str[--len] == '0') { str[len] = '\0'; } if (str[len] == '.') { str[len] = '\0'; } } int32_t string_index_of_pos(char *s, char *search, int pos) { char *found = strstr(s + pos, search); if (found != NULL) { return found - s; } return -1; } int32_t string_index_of(char *s, char *search) { return string_index_of_pos(s, search, 0); } int32_t string_last_index_of(char *str, char *search) { char *s = str; char *found = NULL; while (1) { char *p = strstr(s, search); if (p == NULL) { break; } found = p; s = p + 1; } if (found != NULL) { return found - str; } return -1; } any_array_t *string_split(char *s, char *sep) { char *r = string_alloc(strlen(s) + 1); // Modified by strtok any_array_t *a = gc_alloc(sizeof(any_array_t)); strcpy(r, s); int count = 0; char *token = strtok(r, sep); while (token != NULL) { count++; token = strtok(NULL, sep); } any_array_resize(a, count); strcpy(r, s); token = strtok(r, sep); while (token != NULL) { any_array_push(a, string_copy(token)); // Make a copy to keep gc ref // TODO: this works only for single char sep token = strtok(NULL, sep); } if (a->length == 0) { // Separator not found any_array_push(a, r); } return a; } char *string_array_join(any_array_t *a, char *separator) { int len = 0; int len_sep = strlen(separator); for (int i = 0; i < a->length; ++i) { len += strlen(a->buffer[i]); if (i < a->length - 1) { len += len_sep; } } char *r = string_alloc(len + 1); for (int i = 0; i < a->length; ++i) { strcat(r, a->buffer[i]); if (i < a->length - 1) { strcat(r, separator); } } return r; } char *string_replace_all(char *s, char *search, char *replace) { char *buffer = string_alloc(1024); char *buffer_pos = buffer; size_t search_len = strlen(search); size_t replace_len = strlen(replace); while (1) { char *p = strstr(s, search); if (p == NULL) { strcpy(buffer_pos, s); break; } memcpy(buffer_pos, s, p - s); buffer_pos += p - s; memcpy(buffer_pos, replace, replace_len); buffer_pos += replace_len; s = p + search_len; } return buffer; } char *substring(char *s, int32_t start, int32_t end) { char *buffer = string_alloc(end - start + 1); for (int i = 0; i < end - start; ++i) { buffer[i] = s[start + i]; } return buffer; } char *string_from_char_code(int32_t c) { char *r = string_alloc(2); r[0] = c; r[1] = '\0'; return r; } int32_t char_code_at(char *s, int32_t i) { return s[i]; } char *char_at(char *s, int32_t i) { char *r = string_alloc(2); r[0] = s[i]; r[1] = '\0'; return r; } bool starts_with(char *s, char *start) { return strncmp(start, s, strlen(start)) == 0; } bool ends_with(char *s, char *end) { size_t len_s = strlen(s); size_t len_end = strlen(end); return strncmp(s + len_s - len_end, end, len_end) == 0; } char *to_lower_case(char *s) { char *r = string_alloc(strlen(s) + 1); strcpy(r, s); int len = string_length(r); for (int i = 0; i < len; ++i) { r[i] = tolower(r[i]); } return r; } char *to_upper_case(char *s) { char *r = string_alloc(strlen(s) + 1); strcpy(r, s); int len = string_length(r); for (int i = 0; i < len; ++i) { r[i] = toupper(r[i]); } return r; } char *trim_end(char *str) { int pos = string_length(str) - 1; while (pos >= 0 && (str[pos] == ' ' || str[pos] == '\n' || str[pos] == '\r')) { pos--; } return substring(str, 0, pos + 1); } // Per Lowgren, CC BY-SA 3.0 // https://stackoverflow.com/a/35332046 #define is_unicode(c) (((c) & 0xc0) == 0xc0) int string_utf8_decode(const char *str, int *i) { const unsigned char *s = (const unsigned char *)str; int u = *s, l = 1; if (is_unicode(u)) { int a = (u & 0x20) ? ((u & 0x10) ? ((u & 0x08) ? ((u & 0x04) ? 6 : 5) : 4) : 3) : 2; if (a < 6 || !(u & 0x02)) { int b, p = 0; u = ((u << (a + 1)) & 0xff) >> (a + 1); for (b = 1; b < a; ++b) u = (u << 6) | (s[l++] & 0x3f); } } if (i) *i += l; return u; }