#include String* string_with_capacity(size_t capacity, bool null_terminated) { String* string = malloc(sizeof(*string)); if(!string) return NULL; string->chars = malloc(capacity+(null_terminated?1:0)); if(!string->chars) { free(string); return NULL; } if(null_terminated) string->chars[0] = '\0'; string->length = 0; string->capacity = capacity; string->null_terminated = null_terminated; return string; } void string_remove_range(String* string, size_t index, size_t length) { memmove(string->chars+index, string->chars+index+length, (string->length-(index+length)+(string->null_terminated?1:0))); string->length -= length; } size_t string_strip(String* string, char character) { size_t i, last = 0, offset = 0; bool first = true; for(i = 0; i < string->length; i++) { if(string_at(string,i) == character) { if(first) { first = false; } else { memmove(string->chars+last-offset, string->chars+last+1, i-last-1); offset++; } last = i; } } memmove(string->chars+last-offset, string->chars+last+1, string->length-last-1+(string->null_terminated?1:0)); string->length -= offset+(first ? 0 : 1); return offset; } bool string_insert(String* string, size_t index, char character) { if(!string_grow(string, 1)) return false; memmove(string->chars+index+1, string->chars+index, (string->length-index+(string->null_terminated?1:0))*sizeof(*string->chars)); string->chars[index] = character; string->length++; return true; } char string_pop_at(String* string, size_t index) { char tmp = string_at(string, index); string_remove(string, index); return tmp; } bool string_concat(String* string, const String* other) { if(other->length == 0) return true; if(!string_grow(string, other->length)) return false; memcpy(string->chars+string->length,other->chars,other->length); string->length += other->length; if(string->null_terminated) string->chars[string->length] = '\0'; return true; } bool string_find_char(const String* haystack, char needle, size_t* pos) { char* ret = memchr(haystack->chars, needle, haystack->length); if(!ret) { return false; } else { *pos = (size_t)(ret-haystack->chars); return true; } } int string_cmp(const String* s1, const String* s2) { int ret = memcmp(s1->chars, s2->chars, s1->length < s2->length ? s1->length : s2->length); if(ret == 0 && s1->length != s2->length) return s1->length < s2->length ? -1 : 1; else return ret; } int string_cmp_cstr(const String* s1, const char* s2) { int ret = memcmp(s1->chars, s2, s1->length < strlen(s2) ? s1->length : strlen(s2)); if(ret == 0 && s1->length != strlen(s2)) return s1->length < strlen(s2) ? -1 : 1; else return ret; } size_t string_count(const String* string, char character) { size_t i, ret = 0; for(i = 0; i < string->length; i++) { if(string_at(string, i) == character) ret++; } return ret; } Vector* string_split(const String* string, const char* set, bool null_terminated) { #define CHECKRESULT(x) if(!x){delete_vector(ret, delete_string);return NULL;} size_t i, currentvec = 0, currentlen = 0; char c; const char* orig = set; String* tmp; Vector* ret = new_vector(); bool is_delimiter = true; if(!ret) return NULL; for(i = 0; i < string->length; i++) { for(c = *set++; c != '\0'; c = *set++) { if(string_at(string, i) == c) { is_delimiter = true; currentlen = 0; break; } else { is_delimiter = false; } } if(!is_delimiter) { if(currentlen == 0) { tmp = new_string(null_terminated); CHECKRESULT(tmp); CHECKRESULT(vector_push(ret, tmp)); currentvec++; } currentlen++; CHECKRESULT(string_push(vector_at(ret, currentvec-1), string_at(string, i))); } set = orig; } return ret; #undef CHECKRESULT } bool string_grow(String* string, size_t add) { if(string->length+add < string->length) return false; return string_adjust_size(string, string->length+add); } bool string_adjust_size(String* string, size_t size) { if(size == SIZE_MAX && string->null_terminated) return false; while(string->capacity < size+(string->null_terminated?1:0)) { char* tmp = string->chars; string->chars = cutil_reallocarray_inc(string->chars, sizeof(*string->chars), string->capacity, string->capacity); if(!string->chars) { string->chars = tmp; return false; } string->capacity *= 2; } return true; } void delete_string(void* string) { free(((String*)string)->chars); free(string); } String* from_cstring(const char* cstring, bool null_terminated) { String* string = string_with_capacity(strlen(cstring), null_terminated); if(!string) { return NULL; } else { memcpy(string->chars, cstring, strlen(cstring)); string->length = strlen(cstring); if(null_terminated) string->chars[string->length] = '\0'; return string; } } String* from_cstring_reuse(char* cstring, size_t capacity, bool null_terminated) { String* string; if(!cstring) return NULL; string = malloc(sizeof(*string)); if(!string) return NULL; string->chars = cstring; string->length = strlen(cstring); string->capacity = capacity; string->null_terminated = null_terminated; return string; } String* from_cstring_del(char* cstring, bool null_terminated) { String* ret = from_cstring(cstring, null_terminated); if(!ret) return NULL; free(cstring); return ret; } char* to_cstring(const String* string) { char* cstring = malloc(string->length+1); memcpy(cstring, string->chars, string->length); cstring[string->length] = '\0'; return cstring; } char* to_cstring_del(String* string) { char* ret = to_cstring(string); delete_string(string); return ret; } void string_move(String* dest, String* src) { free(dest->chars); dest->chars = src->chars; free(src); }