aboutsummaryrefslogtreecommitdiff
path: root/cstring
diff options
context:
space:
mode:
author3gg <3gg@shellblade.net>2023-01-05 09:09:16 -0800
committer3gg <3gg@shellblade.net>2023-01-05 09:09:16 -0800
commitf223fb0b0b946d21e469e7ff5e3dcfe2cdd42115 (patch)
tree1c676669f7e5947239534306f1a1fee8f975289f /cstring
parent685950d3f2ac8e893a23443f9e087294cce2c6fa (diff)
Add length() and append().
Diffstat (limited to 'cstring')
-rw-r--r--cstring/include/cstring.h140
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
73DEF_STRING(sstring, 32) // Small. 91DEF_STRING(sstring, 32) // Small.