summaryrefslogtreecommitdiffstats
path: root/stream.c
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2020-02-07 19:47:25 -0800
committerKaz Kylheku <kaz@kylheku.com>2020-02-07 19:47:25 -0800
commit418f661cedc045889b23a0f2881a7049b3d008a4 (patch)
treeb14f981b5f75759fa8f7b80631afba75c29339e4 /stream.c
parent177964f81055367da1b7aec8638dfc8a63ec99c5 (diff)
downloadtxr-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.c35
1 files changed, 32 insertions, 3 deletions
diff --git a/stream.c b/stream.c
index 0ca0f799..c0362f3f 100644
--- a/stream.c
+++ b/stream.c
@@ -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;