diff options
author | Kaz Kylheku <kaz@kylheku.com> | 2020-02-07 19:47:25 -0800 |
---|---|---|
committer | Kaz Kylheku <kaz@kylheku.com> | 2020-02-07 19:47:25 -0800 |
commit | 418f661cedc045889b23a0f2881a7049b3d008a4 (patch) | |
tree | b14f981b5f75759fa8f7b80631afba75c29339e4 /stream.c | |
parent | 177964f81055367da1b7aec8638dfc8a63ec99c5 (diff) | |
download | txr-418f661cedc045889b23a0f2881a7049b3d008a4.tar.gz txr-418f661cedc045889b23a0f2881a7049b3d008a4.tar.bz2 txr-418f661cedc045889b23a0f2881a7049b3d008a4.zip |
New "m" file open mode: non-truncating "w".
Quite surprisingly ISO C lacks a way in fopen to open a file
for writing such that it is not truncated if it already
exists, and not opened in append mode.
(But you will be glad to know that ISO C is adding incredibly
useful features in this area, like Microsoft's fopen_s!)
Let us add modes "m" and "m+" which will be like "w" and "w+",
but without the truncation to zero length (no O_TRUNC
is passed to open).
* stream.c (w_fopen_mode): New static function.
(open_file, open_tail, tail_strategy): Use w_fopen_mode
instead of directly calling w_fopen.
(do_parse_mode): Handle 'm' and set new notrunc flag.
* stream.h (struct stdio_mode): New member, notrunc flag.
(stdio_mode_init_blank, stdio_mode_init_r,
stdio_mode_init_rpb): Initializer macros updated to include
initializer for notrunc flag.
* txr.1: Documented "m" mode.
Diffstat (limited to 'stream.c')
-rw-r--r-- | stream.c | 35 |
1 files changed, 32 insertions, 3 deletions
@@ -1044,6 +1044,28 @@ static struct strm_ops stdio_ops = static struct strm_ops stdio_sock_ops; #endif +static FILE *w_fopen_mode(const wchar_t *wname, const wchar_t *mode, + const struct stdio_mode m) +{ +#if HAVE_FCNTL + if (m.notrunc) { + char *name = utf8_dup_to(wname); + int flags = (m.read ? O_RDWR : O_WRONLY) | O_CREAT; + int fd = open(name, flags, 0777); + free(name); + if (fd < 0) + return NULL; + return (fd < 0) ? NULL : w_fdopen(fd, mode); + } +#else + if (m.notrunc) + uw_throwf(file_error_s, + lit("open-file: system doesn't support \"o\" mode"), nao); +#endif + return w_fopen(wname, mode); +} + + static void tail_calc(unsigned long *state, int *usec, int *mod) { unsigned long count = (*state)++; @@ -1096,7 +1118,7 @@ static void tail_strategy(val stream, unsigned long *state) /* Try to open the file. */ - if (!(newf = w_fopen(c_str(h->descr), c_str(mode)))) { + if (!(newf = w_fopen_mode(c_str(h->descr), c_str(mode), m))) { /* If already have the file open previously, and the name * does not open any more, then the file has rotated. * Have the caller try to read the last bit of data @@ -1349,6 +1371,12 @@ static struct stdio_mode do_parse_mode(val mode_str, struct stdio_mode m_dfl) m.write = 1; m.append = 1; break; + case 'm': + ms++; + m.write = 1; + m.create = 1; + m.notrunc = 1; + break; default: break; } @@ -3947,7 +3975,8 @@ val open_directory(val path) val open_file(val path, val mode_str) { struct stdio_mode m, m_r = stdio_mode_init_r; - FILE *f = w_fopen(c_str(path), c_str(normalize_mode(&m, mode_str, m_r))); + val norm_mode = normalize_mode(&m, mode_str, m_r); + FILE *f = w_fopen_mode(c_str(path), c_str(norm_mode), m); if (!f) { int eno = errno; @@ -3979,7 +4008,7 @@ val open_tail(val path, val mode_str, val seek_end_p) { struct stdio_mode m, m_r = stdio_mode_init_r; val mode = normalize_mode(&m, mode_str, m_r); - FILE *f = w_fopen(c_str(path), c_str(mode)); + FILE *f = w_fopen_mode(c_str(path), c_str(mode), m); struct stdio_handle *h; val stream; unsigned long state = 0; |