u64 un_string_get_length(u8 *cstring) { u8* start = cstring; while (*start != '\0') { start++; } return start - cstring; } String un_string_from_cstring(u8* cstring) { String result; u64 length = un_string_get_length(cstring); assert(length < LLONG_MAX); result.size = length; result.data = cstring; return result; } u8* un_string_to_cstring(String string, Allocator alloc) { u8 *mem; assert(string.size > 0); mem = (u8*)un_memory_alloc(string.size + 1, alloc); un_memory_copy(mem, string.data, (u64)string.size); return mem; } String un_string_copy(String source, Allocator alloc) { u8 *mem; String result; mem = (u8*)un_memory_alloc(source.size, alloc); un_memory_copy(mem, source.data, (u64)source.size); result.size = source.size; result.data = mem; return result; } s32 un_string_compare(String left, String right) { s32 result; if (left.size == right.size && left.size == 0) return 0; if (left.size == 0) return -1; if (right.size == 0) return 1; result = un_memory_compare(left.data, right.data, left.size); if (result == 0) { if (left.size > right.size) return 1; if (left.size < right.size) return -1; return 0; } else { return result; } } String un_string_concat(String left, String right, Allocator alloc) { String result = { 0 }; if (left.size == right.size && left.size == 0) { return result; } u8* data = (u8*)un_memory_alloc(left.size + right.size, alloc); if (left.size > 0) { assert(left.data != NULL); un_memory_copy(data, left.data, left.size); } if (right.size > 0) { assert(right.data != NULL); un_memory_copy((data + left.size), right.data, right.size); } result.size = left.size + right.size; result.data = data; return result; } String un_string_swap(String input, u8 from, u8 to, Allocator alloc) { u64 i; String output; output = un_string_copy(input, alloc); for (i = 0; i < input.size; i++) { if (output.data[i] != from) continue; output.data[i] = to; } return output; } List un_string_split(String input, String pattern, Allocator alloc) { List splits; String string; u64 i, start; u64 matches, size; u8 *buffer; UN_CLEAR(splits); if (input.size <= pattern.size) { return splits; } if (pattern.size == 0) { return splits; } for (i = 0, matches = 1; i < (input.size - (pattern.size - 1)); i++) { if (un_memory_compare(input.data + i, pattern.data, pattern.size) != 0) { continue; } matches++; } splits = un_list_create(matches, sizeof(String), alloc); start = 0; for (i = 0; i < (input.size - (pattern.size - 1)); i++) { if (un_memory_compare(input.data + i, pattern.data, pattern.size) != 0) { continue; } size = i - start; if (size == 0) { start = i + pattern.size; continue; } buffer = (u8*)un_memory_alloc(size, alloc); un_memory_copy(buffer, input.data + start, size); string = CLITERAL(String) { .size = size, .data = buffer }; un_list_append(&splits, &string); start = i + pattern.size; } if (start != input.size - pattern.size) { if (un_memory_compare(input.data + start, pattern.data, pattern.size) == 0) { return splits; } size = input.size - start; if (size == 0) { return splits; } buffer = (u8*)un_memory_alloc(size, alloc); un_memory_copy(buffer, input.data + start, size); string = CLITERAL(String) { .size = size, .data = buffer }; un_list_append(&splits, &string); } return splits; } String un_string_join(List string_list, String separator, Allocator alloc) { String cont, temp; u64 i; Allocator talloc; UN_CLEAR(cont); talloc = un_allocator_get_temporary(); assert(string_list.element_size == sizeof(String)); for (i = 0; i < string_list.count; i++) { temp = *(String *)un_list_get(&string_list, i); cont = un_string_concat(cont, temp, talloc); if (i != (string_list.count - 1)) { cont = un_string_concat(cont, separator, talloc); } } return un_string_copy(cont, alloc); } String un_string_substring(String input, u64 start, u64 max_size) { String slice; assert(max_size > 0); slice.size = UN_MIN(max_size, (input.size - (u64)max_size)); slice.data = input.data + start; if (start > (input.size - max_size)) { slice.size = UN_MIN(max_size, (input.size - (u64)max_size)); } else { slice.size = max_size; } slice.data = input.data + start; return slice; } s64 un_string_index_of(String input, u8 value, u64 skip_count) { u64 i; for (i = 0; i < input.size; i++) { if (input.data[i] != value) { continue; } if (skip_count) { skip_count--; } else { return i; } } return -1; } s64 un_string_index_of_last(String input, u8 value) { s64 i, index; index = -1; for (i = 0; i < (s64)input.size; i++) { if (input.data[i] == value) index = i; } return index; } static String format_u64(u64 value) { String output; u64 l, r, size; u8 t; u8 buffer[32]; size = 0; if (value == 0) { return UN_STR("0"); } while (value) { buffer[size++] = '0' + (value % 10); value /= 10; } assert(size <= 20); for (l = 0, r = size - 1; l < r; l++, r--) { t = buffer[l]; buffer[l] = buffer[r]; buffer[r] = t; } output.size = size; output.data = buffer; return un_string_copy(output, un_allocator_get_temporary()); } static String format_s64(s64 value) { String output; u64 l, r, size; b32 negative; u8 t; u8 buffer[32]; size = 0; if (value == 0) { return UN_STR("0"); } negative = false; if (value < 0) { value = -value; negative = true; } while (value) { buffer[size++] = '0' + (value % 10); value /= 10; } if (negative) { buffer[size++] = '-'; } assert(size <= 20); for (l = 0, r = size - 1; l < r; l++, r--) { t = buffer[l]; buffer[l] = buffer[r]; buffer[r] = t; } output.size = size; output.data = buffer; return un_string_copy(output, un_allocator_get_temporary()); } String un_string_format(Allocator alloc, String buffer, ...) { va_list args; String result; va_start(args, buffer); result = un_string_vformat(alloc, buffer, args); va_end(args); return result; } String un_string_vformat(Allocator alloc, String buffer, va_list args) { List output; String s; u64 i, j; u32 b; Allocator talloc = un_allocator_get_temporary(); // @todo @bug: this would fail on realloc, because we need to realloc output = un_list_create(UN_KB(1), sizeof(u8), talloc); for (i = 0; i < buffer.size; i++) { if (buffer.data[i] != '%') { un_list_append(&output, buffer.data + i); continue; } switch (buffer.data[++i]) { case '%': { un_list_append(&output, buffer.data + i); } break; case 'c': { b = va_arg(args, u32); un_list_append(&output, &b); } break; case 'u': { s = format_u64(va_arg(args, u64)); for (j = 0; j < s.size; j++) { un_list_append(&output, s.data + j); } } break; case 'd': { s = format_s64(va_arg(args, u64)); for (j = 0; j < s.size; j++) { un_list_append(&output, s.data + j); } } break; case 's': { s = va_arg(args, String); for (j = 0; j < s.size; j++) { un_list_append(&output, s.data + j); } } break; default: break; } } s.size = (s64)output.count; s.data = output.data; return un_string_copy(s, alloc); }