diff options
-rw-r--r-- | stream.c | 35 | ||||
-rw-r--r-- | stream.h | 7 | ||||
-rw-r--r-- | txr.1 | 10 |
3 files changed, 45 insertions, 7 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; @@ -108,6 +108,7 @@ struct stdio_mode { unsigned create : 1; unsigned append : 1; unsigned binary : 1; + unsigned notrunc : 1; unsigned interactive : 1; unsigned unbuf : 1; unsigned linebuf : 1; @@ -115,9 +116,9 @@ struct stdio_mode { int redir[STDIO_MODE_NREDIRS][2]; }; -#define stdio_mode_init_blank { 0, 0, 0, 0, 0, 0, 0, 0, 0, -1 } -#define stdio_mode_init_r { 0, 1, 0, 0, 0, 0, 0, 0, 0, -1 } -#define stdio_mode_init_rpb { 0, 1, 1, 0, 0, 1, 0, 0, 0, -1 } +#define stdio_mode_init_blank { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -1 } +#define stdio_mode_init_r { 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, -1 } +#define stdio_mode_init_rpb { 0, 1, 1, 0, 0, 1, 0, 0, 0, 0, -1 } #define std_input (deref(lookup_var_l(nil, stdin_s))) #define std_output (deref(lookup_var_l(nil, stdout_s))) @@ -48925,7 +48925,7 @@ grammar. Note that it permits no whitespace characters: .mono .mets < mode-string := [ < mode ] [ < options ] .mets < mode := { < selector [ + ] | + } -.mets < selector := { r | w | a } +.mets < selector := { r | w | a | m } .mets < options := { b | l | u | < digit | < redirection } .mets < digit := { 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 } .onom @@ -48968,6 +48968,14 @@ to zero length. If it doesn't exist, it is created. .coIP w+ The file is opened for reading and writing. If it exists, it is truncated to zero length. If it doesn't exist, it is created. +.coIP m +The file is opened for modification. This is the same as +.code w +except that the file is not truncated if it exists. +.coIP m+ +The file is opened for reading and modification. This is the same as +.code w+ +except that the file is not truncated if it exists. .coIP a The file is opened for writing. If it doesn't exist, it is created. If it exists, the current position is advanced to |