diff options
author | 3gg <3gg@shellblade.net> | 2023-01-05 09:09:16 -0800 |
---|---|---|
committer | 3gg <3gg@shellblade.net> | 2023-01-05 09:09:16 -0800 |
commit | f223fb0b0b946d21e469e7ff5e3dcfe2cdd42115 (patch) | |
tree | 1c676669f7e5947239534306f1a1fee8f975289f /cstring/include/cstring.h | |
parent | 685950d3f2ac8e893a23443f9e087294cce2c6fa (diff) |
Add length() and append().
Diffstat (limited to 'cstring/include/cstring.h')
-rw-r--r-- | cstring/include/cstring.h | 140 |
1 files changed, 79 insertions, 61 deletions
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 @@ | |||
7 | 7 | ||
8 | /// A fixed-size string. | 8 | /// A fixed-size string. |
9 | /// The string is null-terminated so that it can be used with the usual C APIs. | 9 | /// The string is null-terminated so that it can be used with the usual C APIs. |
10 | #define DEF_STRING(STRING, SIZE) \ | 10 | // |
11 | typedef struct STRING { \ | 11 | // TODO: The asserts on length should be hard asserts, not just asserts in debug |
12 | int length; \ | 12 | // builds. |
13 | char str[SIZE]; \ | 13 | #define DEF_STRING(STRING, SIZE) \ |
14 | } STRING; \ | 14 | typedef struct STRING { \ |
15 | \ | 15 | size_t length; \ |
16 | static const size_t STRING##_size = SIZE; \ | 16 | char str[SIZE]; \ |
17 | \ | 17 | } STRING; \ |
18 | static inline const char* STRING##_cstring(const STRING* str) { \ | 18 | \ |
19 | return str->str; \ | 19 | static const size_t STRING##_size = SIZE; \ |
20 | } \ | 20 | \ |
21 | \ | 21 | static inline const char* STRING##_cstring(const STRING* str) { \ |
22 | static inline STRING STRING##_make(const char* cstr) { \ | 22 | return str->str; \ |
23 | if (!cstr) { \ | 23 | } \ |
24 | return (STRING){0}; \ | 24 | \ |
25 | } else { \ | 25 | static inline size_t STRING##_length(STRING str) { return str.length; } \ |
26 | STRING str = (STRING){0}; \ | 26 | \ |
27 | str.length = strlcpy(str.str, cstr, SIZE); \ | 27 | static inline STRING STRING##_make(const char* cstr) { \ |
28 | return str; \ | 28 | if (!cstr) { \ |
29 | } \ | 29 | return (STRING){0}; \ |
30 | } \ | 30 | } else { \ |
31 | \ | 31 | STRING str = (STRING){0}; \ |
32 | static inline STRING STRING##_dirname(STRING path) { \ | 32 | str.length = strlcpy(str.str, cstr, SIZE); \ |
33 | STRING str = path; \ | 33 | return str; \ |
34 | for (int i = str.length - 1; i >= 0; --i) { \ | 34 | } \ |
35 | if (str.str[i] == '/' || str.str[i] == '\\') { \ | 35 | } \ |
36 | str.str[i] = 0; \ | 36 | \ |
37 | str.length = i; \ | 37 | static inline STRING STRING##_dirname(STRING path) { \ |
38 | return str; \ | 38 | STRING str = path; \ |
39 | } else { \ | 39 | for (int i = str.length - 1; i >= 0; --i) { \ |
40 | str.str[i] = 0; \ | 40 | if (str.str[i] == '/' || str.str[i] == '\\') { \ |
41 | } \ | 41 | str.str[i] = 0; \ |
42 | } \ | 42 | str.length = i; \ |
43 | str = (STRING){0}; \ | 43 | return str; \ |
44 | str.str[0] = '.'; \ | 44 | } else { \ |
45 | str.length = 1; \ | 45 | str.str[i] = 0; \ |
46 | return str; \ | 46 | } \ |
47 | } \ | 47 | } \ |
48 | \ | 48 | str = (STRING){0}; \ |
49 | static inline STRING STRING##_concat(STRING a, STRING b) { \ | 49 | str.str[0] = '.'; \ |
50 | assert(a.length + b.length + 1 < SIZE); \ | 50 | str.length = 1; \ |
51 | STRING str = {0}; \ | 51 | return str; \ |
52 | strlcpy(str.str, a.str, SIZE); \ | 52 | } \ |
53 | strlcpy(str.str + a.length, b.str, SIZE); \ | 53 | \ |
54 | str.length = a.length + b.length; \ | 54 | static inline void STRING##_append_cstr(STRING* a, const char* b) { \ |
55 | return str; \ | 55 | size_t b_length = strlen(b); \ |
56 | } \ | 56 | assert(a->length + b_length + 1 < SIZE); \ |
57 | \ | 57 | strlcpy(a->str + a->length, b, SIZE); \ |
58 | static inline STRING STRING##_concat_path(STRING a, STRING b) { \ | 58 | a->length = a->length + b_length; \ |
59 | return STRING##_concat(STRING##_concat(a, STRING##_make("/")), b); \ | 59 | } \ |
60 | } \ | 60 | \ |
61 | \ | 61 | static inline void STRING##_append(STRING* a, STRING b) { \ |
62 | static inline bool STRING##_eq(STRING a, STRING b) { \ | 62 | assert(a->length + b.length + 1 < SIZE); \ |
63 | if (a.length != b.length) { \ | 63 | strlcpy(a->str + a->length, b.str, SIZE); \ |
64 | return false; \ | 64 | a->length = a->length + b.length; \ |
65 | } \ | 65 | } \ |
66 | return strncmp(a.str, b.str, a.length) == 0; \ | 66 | \ |
67 | } \ | 67 | static inline STRING STRING##_concat(STRING a, STRING b) { \ |
68 | \ | 68 | assert(a.length + b.length + 1 < SIZE); \ |
69 | static inline bool STRING##_eq_cstr(STRING a, const char* b) { \ | 69 | STRING str = {0}; \ |
70 | return strncmp(a.str, b, a.length) == 0; \ | 70 | strlcpy(str.str, a.str, SIZE); \ |
71 | strlcpy(str.str + a.length, b.str, SIZE); \ | ||
72 | str.length = a.length + b.length; \ | ||
73 | return str; \ | ||
74 | } \ | ||
75 | \ | ||
76 | static inline STRING STRING##_concat_path(STRING a, STRING b) { \ | ||
77 | return STRING##_concat(STRING##_concat(a, STRING##_make("/")), b); \ | ||
78 | } \ | ||
79 | \ | ||
80 | static inline bool STRING##_eq(STRING a, STRING b) { \ | ||
81 | if (a.length != b.length) { \ | ||
82 | return false; \ | ||
83 | } \ | ||
84 | return strncmp(a.str, b.str, a.length) == 0; \ | ||
85 | } \ | ||
86 | \ | ||
87 | static inline bool STRING##_eq_cstr(STRING a, const char* b) { \ | ||
88 | return strncmp(a.str, b, a.length) == 0; \ | ||
71 | } | 89 | } |
72 | 90 | ||
73 | DEF_STRING(sstring, 32) // Small. | 91 | DEF_STRING(sstring, 32) // Small. |