1#pragma once
2
3#include <fcntl.h>
4#include <unistd.h>
5#include <sys/stat.h>
6
7#include <pw.h>
8
9#ifdef __cplusplus
10extern "C" {
11#endif
12
13/*
14 * File type supports the following interfaces:
15 * - Fd
16 * - File
17 * - Reader
18 * - Writer
19 */
20
21extern uint16_t PwTypeId_File;
22
23#define pw_is_file(value) pw_is_subtype((value), PwTypeId_File)
24
25
26/*
27 * In addition to interfaces supported by File, BufferedFile type also supports:
28 * - BufferedFile
29 * - LineReader
30 *
31 * LineReader has dual purpose. Its `read_line`, `unread_line` can be used as normal
32 * methods, but when wrapped with `start` and `stop`, it can be considered as a singleton
33 * iterator, comprised of both iterable and iterator.
34 *
35 * This means nested iterations aren't possible but they do not make
36 * sense for files either.
37 */
38
39extern uint16_t PwTypeId_BufferedFile;
40
41#define pw_is_buffered_file(value) pw_is_subtype((value), PwTypeId_BufferedFile)
42
43PW_STRUCT(PwBufferedFileCtorArgs) {
44 PwCtorArgs* next;
45 uint16_t type_id;
46
47 unsigned read_bufsize;
48 unsigned write_bufsize;
49};
50
51
52/****************************************************************
53 * File interface
54 */
55
56extern uint16_t PwInterfaceId_File;
57
58PW_METHOD_BEGIN(File, open)
59 bool (*PwFunc_File_open)(PwMethod_File_open* mthis, PwValuePtr self, PwValuePtr file_name, int flags, mode_t mode)
60PW_METHOD_END(File, open)
61/*
62 * Open or create file with `open` function from standard C library.
63 * `file_name` can be either string or list of path components.
64 * `mode` is unused when file is not created
65 */
66
67PW_METHOD_BEGIN(File, get_name)
68 bool (*PwFunc_File_get_name)(PwMethod_File_get_name* mthis, PwValuePtr self, PwValuePtr result)
69PW_METHOD_END(File, get_name)
70/*
71 * Get file name.
72 */
73
74PW_METHOD_BEGIN(File, set_name)
75 bool (*PwFunc_File_set_name)(PwMethod_File_set_name* mthis, PwValuePtr self, PwValuePtr file_name)
76PW_METHOD_END(File, set_name)
77/*
78 * Set file name.
79 * This works only if file descriptor was set with `set_fd` method.
80 */
81
82PW_METHOD_BEGIN(File, seek)
83 bool (*PwFunc_File_seek)(PwMethod_File_seek* mthis, PwValuePtr self, off_t offset, int whence, off_t* position)
84PW_METHOD_END(File, seek)
85/*
86 * XXX all clear but a good comment would be good
87 * position can be nullptr
88 */
89
90PW_METHOD_BEGIN(File, tell)
91 bool (*PwFunc_File_tell)(PwMethod_File_tell* mthis, PwValuePtr self, off_t* position)
92PW_METHOD_END(File, tell)
93/*
94 * XXX all clear but a good comment would be good
95 */
96
97#define PW_FILE_INTERFACE_METHODS \
98 X(open, 1) \
99 X(get_name, 1) \
100 X(set_name, 1) \
101 X(seek, 1) \
102 X(tell)
103 // TODO truncate, etc.
104
105PW_INTERFACE_BEGIN(File)
106#define X(name, ...) PwMethod_File_##name name;
107 PW_FILE_INTERFACE_METHODS
108#undef X
109PW_INTERFACE_END(File)
110
111
112/****************************************************************
113 * BufferedFile interface
114 */
115
116extern uint16_t PwInterfaceId_BufferedFile;
117
118PW_METHOD_BEGIN(BufferedFile, flush)
119 bool (*PwFunc_BufferedFile_flush)(PwMethod_BufferedFile_flush* mthis, PwValuePtr self)
120PW_METHOD_END(BufferedFile, flush)
121/*
122 * Flush write buffer.
123 */
124
125#define PW_BUFFERED_FILE_INTERFACE_METHODS \
126 X(flush)
127
128PW_INTERFACE_BEGIN(BufferedFile)
129#define X(name, ...) PwMethod_BufferedFile_##name name;
130 PW_BUFFERED_FILE_INTERFACE_METHODS
131#undef X
132PW_INTERFACE_END(BufferedFile)
133
134
135/****************************************************************
136 * Shorthand functions
137 */
138
139// `pw_file_open` and `pw_file_from_fd` return BufferedFile
140// with read buffer equals to page size and with no write bufer
141
142#define pw_file_open(file_name, flags, mode, result) _Generic((file_name), \
143 char*: _pw_file_open_ascii, \
144 char8_t*: _pw_file_open_utf8, \
145 char32_t*: _pw_file_open_utf32, \
146 PwValuePtr: _pw_file_open \
147 )((file_name), (flags), (mode), (result))
148
149[[nodiscard]] bool _pw_file_open(PwValuePtr file_name, int flags, mode_t mode, PwValuePtr result);
150
151[[nodiscard]] static inline bool _pw_file_open_ascii(char* file_name, int flags, mode_t mode, PwValuePtr result) { _PwValue fname = PwStaticString(file_name); return _pw_file_open(&fname, flags, mode, result); }
152[[nodiscard]] static inline bool _pw_file_open_utf8 (char8_t* file_name, int flags, mode_t mode, PwValuePtr result) { PwValue fname = PW_NULL; if (!pw_create_string(&fname, file_name)) { return false; } return _pw_file_open(&fname, flags, mode, result); }
153[[nodiscard]] static inline bool _pw_file_open_utf32(char32_t* file_name, int flags, mode_t mode, PwValuePtr result) { _PwValue fname = PwStaticStringUtf32(file_name); return _pw_file_open(&fname, flags, mode, result); }
154
155[[nodiscard]] bool pw_file_from_fd(int fd, bool take_ownership, PwValuePtr result);
156
157
158// unbuffered file
159
160#define pw_file_open_unbuffered(file_name, flags, mode, result) _Generic((file_name), \
161 char*: _pw_file_open_unbuffered_ascii, \
162 char8_t*: _pw_file_open_unbuffered_utf8, \
163 char32_t*: _pw_file_open_unbuffered_utf32, \
164 PwValuePtr: _pw_file_open_unbuffered \
165 )((file_name), (flags), (mode), (result))
166
167[[nodiscard]] bool _pw_file_open_unbuffered(PwValuePtr file_name, int flags, mode_t mode, PwValuePtr result);
168
169[[nodiscard]] static inline bool _pw_file_open_unbuffered_ascii(char* file_name, int flags, mode_t mode, PwValuePtr result) { _PwValue fname = PwStaticString(file_name); return _pw_file_open_unbuffered(&fname, flags, mode, result); }
170[[nodiscard]] static inline bool _pw_file_open_unbuffered_utf8 (char8_t* file_name, int flags, mode_t mode, PwValuePtr result) { PwValue fname = PW_NULL; if (!pw_create_string(&fname, file_name)) { return false; } return _pw_file_open_unbuffered(&fname, flags, mode, result); }
171[[nodiscard]] static inline bool _pw_file_open_unbuffered_utf32(char32_t* file_name, int flags, mode_t mode, PwValuePtr result) { _PwValue fname = PwStaticStringUtf32(file_name); return _pw_file_open_unbuffered(&fname, flags, mode, result); }
172
173
174[[nodiscard]] static inline bool pw_file_get_name(PwValuePtr file, PwValuePtr result)
175{
176 return pw_call(File, get_name, file, result);
177}
178
179[[nodiscard]] static inline bool pw_file_set_name(PwValuePtr file, PwValuePtr file_name)
180{
181 return pw_call(File, set_name, file, file_name);
182}
183
184[[nodiscard]] static inline bool pw_seek(PwValuePtr file, off_t offset, int whence, off_t* position)
185{
186 return pw_call(File, seek, file, offset, whence, position);
187}
188
189[[nodiscard]] static inline bool pw_tell(PwValuePtr file, off_t* position)
190{
191 return pw_call(File, tell, file, position);
192}
193
194[[nodiscard]] static inline bool pw_flush(PwValuePtr file)
195{
196 return pw_call(BufferedFile, flush, file);
197}
198
199
200/****************************************************************
201 * Miscellaneous functions
202 */
203
204[[nodiscard]] bool pw_read_file(PwValuePtr file, PwValuePtr content, unsigned max_length);
205/*
206 * Read `file` appending the data to `content` which should be a raw ascii string with char_size 1.
207 */
208
209[[nodiscard]] bool pw_load_file(PwValuePtr filename, PwValuePtr content);
210/*
211 * Read content of file as raw ascii string with char_size 1.
212 */
213
214[[nodiscard]] bool pw_load_text_file(PwValuePtr filename, PwValuePtr content);
215/*
216 * Read content of file, decode UTF-8.
217 */
218
219[[nodiscard]] bool pw_write_file(PwValuePtr filename, PwValuePtr content);
220/*
221 * Write `content` to file as raw data. The byte order for char_size > 1 is machine-dependent.
222 */
223
224[[nodiscard]] bool pw_write_text_file(PwValuePtr filename, PwValuePtr content);
225/*
226 * Write `content` to file in UTF-8.
227 */
228
229[[nodiscard]] bool pw_rename_file(PwValuePtr old_filename, PwValuePtr new_filename);
230/*
231 * Change the name or location of a file.
232 */
233
234[[nodiscard]] bool pw_fstat(PwValuePtr file_name, struct stat* statbuf);
235/*
236 * Invoke `stat` function.
237 */
238
239[[nodiscard]] bool pw_file_exists(PwValuePtr file_name, bool* exists);
240/*
241 * Set file/dir existence indicator and return true.
242 * Return false in case of other error.
243 */
244
245[[nodiscard]] bool pw_file_size(PwValuePtr file_name, off_t* size);
246/*
247 * Return file size as Unsigned or Status if error.
248 */
249
250[[nodiscard]] bool pw_mkdir(PwValuePtr path);
251/*
252 * Make directory.
253 */
254
255[[nodiscard]] bool pw_makedirs(PwValuePtr path);
256/*
257 * Make directories.
258 * `path` can be either string or list
259 */
260
261[[nodiscard]] bool pw_makedirs_for_file(PwValuePtr path);
262/*
263 * Make directories except for the last component of `path`.
264 * `path` can be either string or list
265 */
266
267
268#ifdef __cplusplus
269}
270#endif