summaryrefslogtreecommitdiff
path: root/include/al/wstr.h
blob: 561e236010a81a943e9791a4c75b091cf28a3363 (plain)
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
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
#ifndef _AL_WSTR_H
#define _AL_WSTR_H

#include "lib.h"
#include "str.h"

#include <wchar.h>

typedef struct {
    u32 len;
    u32 alloc;
    wchar_t *__sized_by(alloc) data;
} wstr;

#define al_wstr_zero() (wstr){ 0, 0, NULL }

#define al_wstr_at(w, i) (w)->data[i]
#define al_wstr_atr(w, i) (w)->data[(w)->len + i]

#define al_wide_string_if_literal(w) ((wchar_t *)(L"" w)) // use al_wstr_cr for runtime.
#define al_wstr_c(w) (&((wstr){ (u32)((sizeof(w) / sizeof(wchar_t)) - 1), 0, al_wide_string_if_literal(w) }))
#define al_wstr_cr(w) (&((wstr){ (u32)wcslen(w), 0, ((wchar_t *)(w)) })) // runtime
#define al_wstr_w(w, i, n) (&((wstr){ ((u32)(n)), 0, &al_wstr_at(w, i) }))
#define al_wstr_substr(w, start, end) al_wstr_w(w, start, ((end) - (start)))

#define AL_WSTR_FMT "%ls"
#define AL_WSTR_PRINTF(w) (w)->data

AL_UNUSED_FUNCTION_PUSH

static inline s32 al_wchar_width(wchar_t wc)
{
#ifdef AL_HAVE_WIDE_STRING_WIDTH
    return wcwidth(wc);
#else
    (void)wc;
    al_assert_and_return(0);
#endif
}

static inline void al_wstr_free(wstr *w)
{
    if (w->alloc > 0) al_free(w->data);
}

static inline u32 al_wstr_reserve(wstr *w, u32 size)
{
    if (size <= w->alloc) {
        return w->alloc;
    }

    size = size < al_grow_step ? al_next_power_of_two(size) :
        (size + al_grow_step) & ~al_grow_step;

    w->data = (wchar_t *)(!w->data ? al_malloc(size) : al_realloc(w->data, size));
    al_assert(w->data);

    return size;
}

static inline void al_wstr_sized(wstr *w, u32 size)
{
    *w = al_wstr_zero();
    w->alloc = al_wstr_reserve(w, size * sizeof(wchar_t));
}

static inline void al_wstr_clone(wstr *dest, wstr *src)
{
    u32 len = src->len + 1;
    al_wstr_sized(dest, len);
    al_memcpy(dest->data, src->data, len * sizeof(wchar_t));
    dest->len = src->len;
}

static inline bool al_wstr_from_cstr(wstr *w, char *c)
{
#ifdef AL_HAVE_WIDE_STRING
    mbstate_t mbstate = { 0 };
    size_t len = mbsrtowcs(NULL, (const char **)&c, 0, &mbstate);
    if (len == (size_t)-1) {
        return false;
    }
    al_wstr_sized(w, (u32)(len + 1));
    w->len = (u32)mbsrtowcs(w->data, (const char **)&c, len, &mbstate);
    al_assert(w->len == (u32)len);
    w->data[w->len] = L'\0';
    return true;
#else
    (void)c;
    (void)w;
    al_assert_and_return(false);
#endif
}

static inline void al_wstr_from_str(wstr *w, str *s)
{
    char *c_str = al_str_to_c_str(s);
    al_wstr_from_cstr(w, c_str);
    al_free(c_str);
}

static inline bool al_wstr_to_str(wstr *w, str *s)
{
    // This is broken on windows. locale issue?
#ifdef AL_HAVE_WIDE_STRING
    wchar_t *data = w->data;
    mbstate_t mbstate = { 0 };
    size_t len = wcsrtombs(NULL, (const wchar_t **)&w->data, 0, &mbstate);
    if (len == (size_t)-1) {
        return false;
    }
    al_str_sized(s, (u32)len);
    // Excludes the null terminator.
    s->len = (u32)wcsrtombs(s->data, (const wchar_t **)&w->data, len, &mbstate);
    al_assert(s->len == (u32)len);
    w->data = data;
    return true;
#else
    (void)s;
    (void)w;
    al_assert_and_return(false);
#endif
}

static inline s32 al_wstr_width(wstr *w)
{
#ifdef AL_HAVE_WIDE_STRING_WIDTH
    return wcswidth(w->data, w->len);
#else
    (void)w;
    al_assert_and_return(0);
#endif
}

static inline s32 al_wstr_cmp(wstr *w, wstr *c, u32 start, u32 len)
{
#ifdef AL_HAVE_WIDE_STRING
    return wcsncmp(&al_wstr_at(w, start), c->data, len);
#else
    (void)w;
    (void)c;
    (void)start;
    (void)len;
    al_assert_and_return(0);
#endif
}

static inline s32 al_wstr_find(wstr *w, wchar_t c)
{
    for (s32 i = 0; i < (s32)w->len; i++) {
        if (al_wstr_at(w, i) == c) {
            return i;
        }
    }
    return -1;
}

static inline s32 al_wstr_rfind(wstr *w, wchar_t c)
{
    for (s32 i = (s32)w->len - 1; i >= 0; i--) {
        if (al_wstr_at(w, i) == c) {
            return i;
        }
    }
    return -1;
}

AL_UNUSED_FUNCTION_POP

#endif // _AL_WSTR_H