LexLeo 0.0.0-dev+f8e5087-dirty
Technical documentation
Loading...
Searching...
No Matches
osal_file_win32.c
Go to the documentation of this file.
1// src/foundation/osal/osal_file/src/win32/osal_file_win32.c
2
3#include "osal/file/osal_file_types.h"
5#include "osal/file/osal_file_ops.h"
6
8
14#include "policy/lexleo_panic.h"
15
16struct osal_file_t {
17 FILE *fp;
18 const osal_mem_ops_t *mem;
19};
20
22{
23 if (st) *st = v;
24}
25
27 switch (e) {
28 case 0: return OSAL_FILE_OK;
29#ifdef ENOENT
30 case ENOENT: return OSAL_FILE_NOENT;
31#endif
32#ifdef EACCES
33 case EACCES: return OSAL_FILE_PERM;
34#endif
35#ifdef EPERM
36 case EPERM: return OSAL_FILE_PERM;
37#endif
38 default: return OSAL_FILE_IO;
39 }
40}
41
42static const wchar_t *wmode_from_flags(uint32_t flags, osal_file_status_t *st)
43{
44 const bool r = (flags & OSAL_FILE_READ) != 0;
45 const bool w = (flags & OSAL_FILE_WRITE) != 0;
46 const bool a = (flags & OSAL_FILE_APPEND) != 0;
47 const bool t = (flags & OSAL_FILE_TRUNC) != 0;
48 const bool c = (flags & OSAL_FILE_CREATE) != 0;
49
50 if (a) {
51 if (r) return L"a+b";
52 return L"ab";
53 }
54
55 if (w) {
56 if (t) {
57 if (r) return L"w+b";
58 return L"wb";
59 }
60 if (c) {
61 if (r) return L"a+b";
62 return L"ab";
63 }
64 if (r) return L"r+b";
66 return NULL;
67 }
68
69 if (r) return L"rb";
70
72 return NULL;
73}
74
75static wchar_t *utf8_to_wide(const char *s, const osal_mem_ops_t *mem) {
76 if (!s || !mem || !mem->calloc || !mem->free) return NULL;
77 int len = MultiByteToWideChar(CP_UTF8, 0, s, -1, NULL, 0);
78 if (len <= 0) return NULL;
79
80 wchar_t *w = (wchar_t *)mem->calloc((size_t)len, sizeof(*w));
81 if (!w) return NULL;
82
83 int ok = MultiByteToWideChar(CP_UTF8, 0, s, -1, w, len);
84 if (ok <= 0) {
85 mem->free(w);
86 return NULL;
87 }
88 return w;
89}
90
92 const char *path_utf8,
93 uint32_t flags,
95 const osal_file_env_t *env )
96{
97 if (st) *st = OSAL_FILE_ERR;
98 if (!path_utf8 || !*path_utf8) return NULL;
99
100 osal_file_env_t default_env;
101 const osal_file_env_t *use_env = env;
102
103 if (!use_env) {
105 use_env = &default_env;
106 }
107
108 const osal_mem_ops_t *mem = use_env->mem;
109 if (!mem || !mem->calloc || !mem->free) return NULL;
110
111 const wchar_t *mode = wmode_from_flags(flags, st);
112 if (!mode) return NULL;
113
114 wchar_t *wpath = utf8_to_wide(path_utf8, mem);
115 if (!wpath) {
117 return NULL;
118 }
119
120 errno = 0;
121 FILE *fp = _wfopen(wpath, mode);
122 mem->free(wpath);
123
124 if (!fp) {
125 set_status(st, map_errno(errno));
126 return NULL;
127 }
128
129 osal_file_t *f = (osal_file_t *)mem->calloc(1, sizeof(*f));
130 if (!f) {
131 fclose(fp);
133 return NULL;
134 }
135
136 f->fp = fp;
137 f->mem = mem;
138
140 return f;
141}
142
143static size_t win_read(osal_file_t *f, void *buf, size_t n, osal_file_status_t *st)
144{
145 if (st) *st = OSAL_FILE_ERR;
146 if (!f || !f->fp || (!buf && n)) return 0;
147
148 errno = 0;
149 size_t got = fread(buf, 1, n, f->fp);
150
151 if (got < n) {
152 if (ferror(f->fp)) {
153 clearerr(f->fp);
154 set_status(st, map_errno(errno));
155 return got;
156 }
157 }
158
160 return got;
161}
162
163static size_t win_write(osal_file_t *f, const void *buf, size_t n, osal_file_status_t *st)
164{
165 if (st) *st = OSAL_FILE_ERR;
166 if (!f || !f->fp || (!buf && n)) return 0;
167
168 errno = 0;
169 size_t put = fwrite(buf, 1, n, f->fp);
170
171 if (put < n) {
172 set_status(st, map_errno(errno));
173 return put;
174 }
175
177 return put;
178}
179
181{
182 if (!f || !f->fp) return OSAL_FILE_ERR;
183 errno = 0;
184 if (fflush(f->fp) != 0) return map_errno(errno);
185 return OSAL_FILE_OK;
186}
187
189{
190 if (!f) return OSAL_FILE_OK;
191
193
194 if (f->fp) {
195 errno = 0;
196 if (fclose(f->fp) != 0) st = map_errno(errno);
197 f->fp = NULL;
198 }
199
200 if (!f->mem || !f->mem->free) {
201 // log
202 lexleo_panic("osal_file: invalid allocator in close");
203 return OSAL_FILE_ERR;
204 }
205
206 f->mem->free(f);
207 return st;
208}
209
211{
212 static const osal_file_ops_t OPS = {
213 .open = win_open,
214 .read = win_read,
215 .write = win_write,
216 .flush = win_flush,
217 .close = win_close,
218 };
219 return &OPS;
220}
@ OSAL_FILE_WRITE
@ OSAL_FILE_TRUNC
@ OSAL_FILE_APPEND
@ OSAL_FILE_CREATE
@ OSAL_FILE_READ
osal_file_status_t
@ OSAL_FILE_PERM
@ OSAL_FILE_OK
@ OSAL_FILE_IO
@ OSAL_FILE_NOENT
@ OSAL_FILE_ERR
static osal_file_status_t win_close(osal_file_t *f)
static const wchar_t * wmode_from_flags(uint32_t flags, osal_file_status_t *st)
static void set_status(osal_file_status_t *st, osal_file_status_t v)
const osal_file_ops_t * osal_file_win32_ops(void)
static size_t win_read(osal_file_t *f, void *buf, size_t n, osal_file_status_t *st)
static osal_file_t * win_open(const char *path_utf8, uint32_t flags, osal_file_status_t *st, const osal_file_env_t *env)
static size_t win_write(osal_file_t *f, const void *buf, size_t n, osal_file_status_t *st)
static osal_file_status_t win_flush(osal_file_t *f)
static osal_file_status_t map_errno(int e)
static wchar_t * utf8_to_wide(const char *s, const osal_mem_ops_t *mem)
void lexleo_panic(const char *msg) __attribute__((noreturn))
osal_file_env_t osal_file_default_env(const osal_mem_ops_t *mem_ops)
Definition osal_file.c:81
const osal_mem_ops_t * osal_mem_default_ops(void)
const osal_mem_ops_t * mem
osal_file_t *(* open)(const char *path_utf8, uint32_t flags, osal_file_status_t *status, const osal_file_env_t *env)
const osal_mem_ops_t * mem
void *(* calloc)(size_t nmemb, size_t size)
void(* free)(void *ptr)