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