// LCZ libraries v0.1b #include "lstring.h" #include #include #include #include #include // String building / constructors String string_take(char *src) { String res; res.text = src; res.length = rstring_length(src); return res; } DString dstring_take(char *src) { DString res; res.text = src; res.length = rstring_length(src); res.capacity = res.length; return res; } String string_copy(const char *src, u64 length) { String res; res.text = malloc(length + 1); assert(res.text != NULL); memcpy(res.text, src, length); res.text[length] = '\0'; res.length = length; return res; } DString dstring_copy(const char *src, u64 length) { DString res; res.text = malloc(length + 1); assert(res.text != NULL); memcpy(res.text, src, length); res.text[length] = '\0'; res.length = length; res.capacity = length; return res; } DString dstring_new(u64 capacity) { DString res; res.text = malloc(capacity + 1); assert(res.text != NULL); res.text[0] = '\0'; res.length = 0; res.capacity = capacity; return res; } // n = number of strings, ... = , const char *src1, u64 length1, ... String string_concat(u32 n, ...) { va_list ap; va_start(ap, n); const char *strings[n]; u64 sizes[n]; u64 tot_len = 0; for (u32 i = 0; i < n; i++) { strings[i] = va_arg(ap, const char *); sizes[i] = va_arg(ap, u64); tot_len += sizes[i]; } String res; res.text = malloc(tot_len + 1); assert(res.text != NULL); res.length = tot_len; char *cursor = res.text; for (u32 i = 0; i < n; i++) { memcpy(cursor, strings[i], sizes[i]); cursor += sizes[i]; } *cursor = '\0'; va_end(ap); return res; } // n = number of strings, ... = , const char *src1, u64 length1, ... DString dstring_concat(u32 n, ...) { va_list ap; const char *strings[n]; u64 sizes[n]; u64 tot_len = 0; va_start(ap, n); for (u32 i = 0; i < n; i++) { strings[i] = va_arg(ap, const char *); sizes[i] = va_arg(ap, u64); tot_len += sizes[i]; } DString res; res.text = malloc(tot_len + 1); assert(res.text != NULL); res.length = tot_len; res.capacity = tot_len; char *cursor = res.text; for (u32 i = 0; i < n; i++) { memcpy(cursor, strings[i], sizes[i]); cursor += sizes[i]; } *cursor = '\0'; va_end(ap); return res; } // Compute string length, excluding zero-terminator u64 rstring_length(const char *src) { u64 length = 0; while(*(src++) != '\0') length++; return length; } // Comparison int rstring_compare(const char* left, const char *right) { do { if (*left < *right) return -1; if (*left > *right) return +1; right++; } while (*(left++)); return 0; } bool string_equal(String left, String right) { if (left.length != right.length) return false; char *l = left.text; char *r = right.text; char *l_end = l + left.length; while (l != l_end) { if (*l != *r) return false; l++; r++; } return true; } bool string_find(String str, u64 start_index, String to_find, u64 *found_index) { // @TODO: Replace with better algorithm (Knuth-Morris-Pratt?) char *end = str.text + str.length; char *last_valid_start = end - to_find.length; for (char *curr = str.text + start_index; curr <= last_valid_start; curr++) { bool found = true; for (u64 i = 0; i < to_find.length; i++) { if (curr[i] != to_find.text[i]) { found = false; break; } } if (found) { *found_index = curr - str.text; return true; } } return false; } String string_substring(String *str, u64 start, u64 end) { String res; res.text = &str->text[start]; end = (end < str->length ? end : str->length); end = (start < end ? end : start); res.length = end - start; return res; } String string_trim(String *str) { u64 start = 0; u64 end = str->length; while(start < str->length && isspace(str->text[start])) start++; while(end > start && isspace(str->text[end-1])) end--; return string_substring(str, start, end); } // DString specific operations void dstring_reserve(DString *dstr, u64 new_length) { if (dstr->length < new_length) dstr->text = realloc(dstr->text, new_length + 1); // + 1 --> reserve space for '\0' assert(dstr->text != NULL); } void dstring_append(DString *dstr, const char *to_append, u64 count) { u64 len; // Make sure we have enought space len = dstr->length + count; dstring_reserve(dstr, len); // Copy bytes memcpy(dstr->text + dstr->length, to_append, count); dstr->text[len] = '\0'; dstr->length = len; } void dstring_insert(DString *dstr, u64 index, const char *to_insert, u64 count) { u64 len; char *insert_start; char *insert_end; // Make sure we have enought space len = dstr->length + count; dstring_reserve(dstr, len); // Move content to make space for the data we have to insert insert_start = dstr->text + index; insert_end = insert_start + count; memmove(insert_end, insert_start, dstr->length - index + 1); // Insert memcpy(insert_start, to_insert, count); dstr->length = len; } void dstring_erase(DString *dstr, u64 index, u64 count) { if (index + count > dstr->length) count = dstr->length - index; char *start = dstr->text + index; char *end = start + count; u64 to_move_from_end = dstr->length - index - count + 1; // Remember to move terminating zero memmove(start, end, to_move_from_end); dstr->length -= count; } void dstring_replace(DString *dstr, u64 index, u64 rem_count, const char *to_insert, u64 ins_count) { if (index + rem_count > dstr->length) rem_count = dstr->length - index; u64 len = dstr->length - rem_count + ins_count; dstring_reserve(dstr, len); char *start = dstr->text + index; char *rem_end = start + rem_count; char *ins_end = start + ins_count; u64 to_move_from_end = dstr->length - index - rem_count + 1; memmove(ins_end, rem_end, to_move_from_end); memcpy(start, to_insert, ins_count); dstr->length = len; }