From f223fb0b0b946d21e469e7ff5e3dcfe2cdd42115 Mon Sep 17 00:00:00 2001 From: 3gg <3gg@shellblade.net> Date: Thu, 5 Jan 2023 09:09:16 -0800 Subject: Add length() and append(). --- cstring/include/cstring.h | 140 ++++++++++++++++++++++++++-------------------- 1 file changed, 79 insertions(+), 61 deletions(-) (limited to 'cstring/include') diff --git a/cstring/include/cstring.h b/cstring/include/cstring.h index ae650eb..c8362ea 100644 --- a/cstring/include/cstring.h +++ b/cstring/include/cstring.h @@ -7,67 +7,85 @@ /// A fixed-size string. /// The string is null-terminated so that it can be used with the usual C APIs. -#define DEF_STRING(STRING, SIZE) \ - typedef struct STRING { \ - int length; \ - char str[SIZE]; \ - } STRING; \ - \ - static const size_t STRING##_size = SIZE; \ - \ - static inline const char* STRING##_cstring(const STRING* str) { \ - return str->str; \ - } \ - \ - static inline STRING STRING##_make(const char* cstr) { \ - if (!cstr) { \ - return (STRING){0}; \ - } else { \ - STRING str = (STRING){0}; \ - str.length = strlcpy(str.str, cstr, SIZE); \ - return str; \ - } \ - } \ - \ - static inline STRING STRING##_dirname(STRING path) { \ - STRING str = path; \ - for (int i = str.length - 1; i >= 0; --i) { \ - if (str.str[i] == '/' || str.str[i] == '\\') { \ - str.str[i] = 0; \ - str.length = i; \ - return str; \ - } else { \ - str.str[i] = 0; \ - } \ - } \ - str = (STRING){0}; \ - str.str[0] = '.'; \ - str.length = 1; \ - return str; \ - } \ - \ - static inline STRING STRING##_concat(STRING a, STRING b) { \ - assert(a.length + b.length + 1 < SIZE); \ - STRING str = {0}; \ - strlcpy(str.str, a.str, SIZE); \ - strlcpy(str.str + a.length, b.str, SIZE); \ - str.length = a.length + b.length; \ - return str; \ - } \ - \ - static inline STRING STRING##_concat_path(STRING a, STRING b) { \ - return STRING##_concat(STRING##_concat(a, STRING##_make("/")), b); \ - } \ - \ - static inline bool STRING##_eq(STRING a, STRING b) { \ - if (a.length != b.length) { \ - return false; \ - } \ - return strncmp(a.str, b.str, a.length) == 0; \ - } \ - \ - static inline bool STRING##_eq_cstr(STRING a, const char* b) { \ - return strncmp(a.str, b, a.length) == 0; \ +// +// TODO: The asserts on length should be hard asserts, not just asserts in debug +// builds. +#define DEF_STRING(STRING, SIZE) \ + typedef struct STRING { \ + size_t length; \ + char str[SIZE]; \ + } STRING; \ + \ + static const size_t STRING##_size = SIZE; \ + \ + static inline const char* STRING##_cstring(const STRING* str) { \ + return str->str; \ + } \ + \ + static inline size_t STRING##_length(STRING str) { return str.length; } \ + \ + static inline STRING STRING##_make(const char* cstr) { \ + if (!cstr) { \ + return (STRING){0}; \ + } else { \ + STRING str = (STRING){0}; \ + str.length = strlcpy(str.str, cstr, SIZE); \ + return str; \ + } \ + } \ + \ + static inline STRING STRING##_dirname(STRING path) { \ + STRING str = path; \ + for (int i = str.length - 1; i >= 0; --i) { \ + if (str.str[i] == '/' || str.str[i] == '\\') { \ + str.str[i] = 0; \ + str.length = i; \ + return str; \ + } else { \ + str.str[i] = 0; \ + } \ + } \ + str = (STRING){0}; \ + str.str[0] = '.'; \ + str.length = 1; \ + return str; \ + } \ + \ + static inline void STRING##_append_cstr(STRING* a, const char* b) { \ + size_t b_length = strlen(b); \ + assert(a->length + b_length + 1 < SIZE); \ + strlcpy(a->str + a->length, b, SIZE); \ + a->length = a->length + b_length; \ + } \ + \ + static inline void STRING##_append(STRING* a, STRING b) { \ + assert(a->length + b.length + 1 < SIZE); \ + strlcpy(a->str + a->length, b.str, SIZE); \ + a->length = a->length + b.length; \ + } \ + \ + static inline STRING STRING##_concat(STRING a, STRING b) { \ + assert(a.length + b.length + 1 < SIZE); \ + STRING str = {0}; \ + strlcpy(str.str, a.str, SIZE); \ + strlcpy(str.str + a.length, b.str, SIZE); \ + str.length = a.length + b.length; \ + return str; \ + } \ + \ + static inline STRING STRING##_concat_path(STRING a, STRING b) { \ + return STRING##_concat(STRING##_concat(a, STRING##_make("/")), b); \ + } \ + \ + static inline bool STRING##_eq(STRING a, STRING b) { \ + if (a.length != b.length) { \ + return false; \ + } \ + return strncmp(a.str, b.str, a.length) == 0; \ + } \ + \ + static inline bool STRING##_eq_cstr(STRING a, const char* b) { \ + return strncmp(a.str, b, a.length) == 0; \ } DEF_STRING(sstring, 32) // Small. -- cgit v1.2.3