diff options
Diffstat (limited to 'cstring')
-rw-r--r-- | cstring/CMakeLists.txt | 11 | ||||
-rw-r--r-- | cstring/include/cstring.h | 64 |
2 files changed, 75 insertions, 0 deletions
diff --git a/cstring/CMakeLists.txt b/cstring/CMakeLists.txt new file mode 100644 index 0000000..67fb366 --- /dev/null +++ b/cstring/CMakeLists.txt | |||
@@ -0,0 +1,11 @@ | |||
1 | cmake_minimum_required(VERSION 3.16) | ||
2 | |||
3 | project(cstring) | ||
4 | |||
5 | add_library(cstring INTERFACE) | ||
6 | |||
7 | target_include_directories(cstring INTERFACE | ||
8 | include) | ||
9 | |||
10 | target_link_libraries(cstring INTERFACE | ||
11 | -lbsd) | ||
diff --git a/cstring/include/cstring.h b/cstring/include/cstring.h new file mode 100644 index 0000000..644f1e1 --- /dev/null +++ b/cstring/include/cstring.h | |||
@@ -0,0 +1,64 @@ | |||
1 | /// Fixed-size strings with value semantics. | ||
2 | #pragma once | ||
3 | |||
4 | #include <assert.h> | ||
5 | #include <bsd/string.h> | ||
6 | |||
7 | /// A fixed-size string. | ||
8 | /// The string is null-terminated so that it can be used with the usual C APIs. | ||
9 | #define DEF_STRING(STRING, SIZE) \ | ||
10 | typedef struct STRING { \ | ||
11 | int length; \ | ||
12 | char str[SIZE]; \ | ||
13 | } STRING; \ | ||
14 | \ | ||
15 | static const size_t STRING##_size = SIZE; \ | ||
16 | \ | ||
17 | static inline const char* STRING##_cstring(const STRING* str) { \ | ||
18 | return str->str; \ | ||
19 | } \ | ||
20 | \ | ||
21 | static inline STRING STRING##_make(const char* cstr) { \ | ||
22 | if (!cstr) { \ | ||
23 | return (STRING){0}; \ | ||
24 | } else { \ | ||
25 | STRING str = (STRING){0}; \ | ||
26 | str.length = strlcpy(str.str, cstr, SIZE); \ | ||
27 | return str; \ | ||
28 | } \ | ||
29 | } \ | ||
30 | \ | ||
31 | static inline STRING STRING##_dirname(STRING path) { \ | ||
32 | STRING str = path; \ | ||
33 | for (int i = str.length - 1; i >= 0; --i) { \ | ||
34 | if (str.str[i] == '/' || str.str[i] == '\\') { \ | ||
35 | str.str[i] = 0; \ | ||
36 | str.length = i; \ | ||
37 | return str; \ | ||
38 | } else { \ | ||
39 | str.str[i] = 0; \ | ||
40 | } \ | ||
41 | } \ | ||
42 | str = (STRING){0}; \ | ||
43 | str.str[0] = '.'; \ | ||
44 | str.length = 1; \ | ||
45 | return str; \ | ||
46 | } \ | ||
47 | \ | ||
48 | static inline STRING STRING##_concat(STRING a, STRING b) { \ | ||
49 | assert(a.length + b.length + 1 < SIZE); \ | ||
50 | STRING str = {0}; \ | ||
51 | strlcpy(str.str, a.str, SIZE); \ | ||
52 | strlcpy(str.str + a.length, b.str, SIZE); \ | ||
53 | str.length = a.length + b.length; \ | ||
54 | return str; \ | ||
55 | } \ | ||
56 | \ | ||
57 | static inline STRING STRING##_concat_path(STRING a, STRING b) { \ | ||
58 | return STRING##_concat(STRING##_concat(a, STRING##_make("/")), b); \ | ||
59 | } | ||
60 | |||
61 | DEF_STRING(sstring, 32) // Small. | ||
62 | DEF_STRING(mstring, 256) // Medium. | ||
63 | DEF_STRING(lstring, 1024) // Large. | ||
64 | DEF_STRING(xlstring, 4096) // Extra large. | ||