1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
|
/// Fixed-size strings with value semantics.
#pragma once
#include <assert.h>
#include <bsd/string.h>
/// 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); \
}
DEF_STRING(sstring, 32) // Small.
DEF_STRING(mstring, 256) // Medium.
DEF_STRING(lstring, 1024) // Large.
DEF_STRING(xlstring, 4096) // Extra large.
|