summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2015-03-29 13:16:46 -0700
committerKaz Kylheku <kaz@kylheku.com>2015-03-29 13:16:46 -0700
commitc6e5383217c70914a933f1911bf48a1e54b26595 (patch)
tree5e40a74c23c75fc2bd786490732682618585ec9e
parent084bde656bac142bba5311b519c7bb78e2c45dad (diff)
downloadtxr-c6e5383217c70914a933f1911bf48a1e54b26595.tar.gz
txr-c6e5383217c70914a933f1911bf48a1e54b26595.tar.bz2
txr-c6e5383217c70914a933f1911bf48a1e54b26595.zip
New -n option. New "i" mode letter in file opening functions.
* stream.c (struct stdio_mode): New struct type. (stdio_mode_init_trivial): New initializer macro. (parse_mode, format_mode, normalize_mode, set_mode_props): New static functions. (make_stdio_stream_common): the isatty check, and automatic marking of tty device streams as real-time is no longer done, unless backward compatibility 105 or earlier is requested. (open_file, open_tail, open_command, open_process): Use new mode parsing, which supports the "i" flag. (stream_init): If we have isatty, and standard input is a tty, then mark the *std-input* stream as real-time. * txr.1: Document -n/--noninteractive option. Fix typo where real-time-stream-p is referred to as stream-real-time-p. Document "i" flag on open-file and others. * txr.c (opt_noninteractive): New global. (help): Help text for -n/--noninteractive. (txr_main): Handle new options. * txr.h (opt_noninteractive): Declared.
-rw-r--r--ChangeLog26
-rw-r--r--stream.c147
-rw-r--r--txr.187
-rw-r--r--txr.c12
-rw-r--r--txr.h1
5 files changed, 242 insertions, 31 deletions
diff --git a/ChangeLog b/ChangeLog
index 054fcfc7..e3652cdd 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,29 @@
+2015-03-29 Kaz Kylheku <kaz@kylheku.com>
+
+ New -n option. New "i" mode letter in file opening functions.
+
+ * stream.c (struct stdio_mode): New struct type.
+ (stdio_mode_init_trivial): New initializer macro.
+ (parse_mode, format_mode, normalize_mode, set_mode_props):
+ New static functions.
+ (make_stdio_stream_common): the isatty check, and automatic marking
+ of tty device streams as real-time is no longer done, unless
+ backward compatibility 105 or earlier is requested.
+ (open_file, open_tail, open_command, open_process): Use new
+ mode parsing, which supports the "i" flag.
+ (stream_init): If we have isatty, and standard input is a tty,
+ then mark the *std-input* stream as real-time.
+
+ * txr.1: Document -n/--noninteractive option. Fix typo where
+ real-time-stream-p is referred to as stream-real-time-p.
+ Document "i" flag on open-file and others.
+
+ * txr.c (opt_noninteractive): New global.
+ (help): Help text for -n/--noninteractive.
+ (txr_main): Handle new options.
+
+ * txr.h (opt_noninteractive): Declared.
+
2015-03-28 Kaz Kylheku <kaz@kylheku.com>
* eval.c (prinl, pprinl): Become external functions.
diff --git a/stream.c b/stream.c
index 94eaf2e4..42711681 100644
--- a/stream.c
+++ b/stream.c
@@ -1220,6 +1220,122 @@ static struct strm_ops dir_ops =
dir_get_error_str,
dir_clear_error);
+struct stdio_mode {
+ int malformed;
+ int read;
+ int write;
+ int create;
+ int append;
+ int binary;
+ int interactive;
+};
+
+#define stdio_mode_init_trivial(read) { 0, read, 0, 0, 0, 0, 0 }
+
+static struct stdio_mode parse_mode(val mode_str)
+{
+ struct stdio_mode m = stdio_mode_init_trivial(0);
+ const wchar_t *ms = c_str(mode_str);
+
+ switch (*ms) {
+ case 'r':
+ ms++;
+ m.read = 1;
+ break;
+ case 'w':
+ ms++;
+ m.write = 1;
+ m.create = 1;
+ break;
+ case 'a':
+ ms++;
+ m.write = 1;
+ m.append = 1;
+ break;
+ default:
+ m.malformed = 1;
+ return m;
+ }
+
+ if (*ms == '+') {
+ ms++;
+ if (m.read)
+ m.write = 1;
+ m.read = 1;
+ }
+
+ for (; *ms; ms++) {
+ switch (*ms) {
+ case 'b':
+ m.binary = 1;
+ break;
+ case 'i':
+ m.interactive = 1;
+ break;
+ default:
+ m.malformed = 1;
+ return m;
+ }
+ }
+
+ return m;
+}
+
+static val format_mode(const struct stdio_mode m)
+{
+ wchar_t buf[8], *ptr = buf;
+
+ if (m.malformed)
+ return lit("###");
+
+ if (m.append) {
+ *ptr++ = 'a';
+ if (m.read)
+ *ptr++ = '+';
+ } else if (m.create) {
+ *ptr++ = 'w';
+ if (m.read)
+ *ptr++ = '+';
+ } else {
+ *ptr++ = 'r';
+ if (m.write)
+ *ptr++ = '+';
+ }
+
+ if (m.binary)
+ *ptr++ = 'b';
+
+ *ptr = 0;
+ return string(buf);
+}
+
+static val normalize_mode(struct stdio_mode *m, val mode_str)
+{
+ struct stdio_mode blank = stdio_mode_init_trivial(1);
+
+ if (null_or_missing_p(mode_str)) {
+ *m = blank;
+ return lit("r");
+ } else {
+ *m = parse_mode(mode_str);
+
+ if (m->malformed)
+ uw_throwf(file_error_s, lit("invalid file open mode ~a"), mode_str, nao);
+
+ if (!m->interactive)
+ return mode_str;
+
+ return format_mode(*m);
+ }
+}
+
+static val set_mode_props(const struct stdio_mode m, val stream)
+{
+ if (m.interactive)
+ stream_set_prop(stream, real_time_k, t);
+ return stream;
+}
+
static val make_stdio_stream_common(FILE *f, val descr, struct cobj_ops *ops)
{
struct stdio_handle *h = coerce(struct stdio_handle *, chk_malloc(sizeof *h));
@@ -1233,7 +1349,8 @@ static val make_stdio_stream_common(FILE *f, val descr, struct cobj_ops *ops)
h->mode = nil;
h->is_rotated = 0;
#if HAVE_ISATTY
- h->is_real_time = (h->f != 0 && isatty(fileno(h->f)) == 1);
+ h->is_real_time = if3(opt_compat && opt_compat <= 105,
+ (h->f != 0 && isatty(fileno(h->f)) == 1), 0);
#else
h->is_real_time = 0;
#endif
@@ -2183,18 +2300,20 @@ val open_directory(val path)
val open_file(val path, val mode_str)
{
- FILE *f = w_fopen(c_str(path), c_str(default_arg(mode_str, lit("r"))));
+ struct stdio_mode m;
+ FILE *f = w_fopen(c_str(path), c_str(normalize_mode(&m, mode_str)));
if (!f)
uw_throwf(file_error_s, lit("error opening ~a: ~a/~s"),
path, num(errno), string_utf8(strerror(errno)), nao);
- return make_stdio_stream(f, path);
+ return set_mode_props(m, make_stdio_stream(f, path));
}
val open_tail(val path, val mode_str, val seek_end_p)
{
- val mode = default_arg(mode_str, lit("r"));
+ struct stdio_mode m;
+ val mode = normalize_mode(&m, mode_str);
FILE *f = w_fopen(c_str(path), c_str(mode));
struct stdio_handle *h;
val stream;
@@ -2210,24 +2329,27 @@ val open_tail(val path, val mode_str, val seek_end_p)
h->mode = mode;
if (!f)
tail_strategy(stream, &state);
- return stream;
+ return set_mode_props(m, stream);
}
val open_command(val path, val mode_str)
{
- FILE *f = w_popen(c_str(path), c_str(default_arg(mode_str, lit("r"))));
+ struct stdio_mode m;
+ FILE *f = w_popen(c_str(path), c_str(normalize_mode(&m, mode_str)));
if (!f)
uw_throwf(file_error_s, lit("error opening pipe ~a: ~a/~s"),
path, num(errno), string_utf8(strerror(errno)), nao);
- return make_pipe_stream(f, path);
+ return set_mode_props(m, make_pipe_stream(f, path));
}
#if HAVE_FORK_STUFF
val open_process(val name, val mode_str, val args)
{
- int input = equal(mode_str, lit("r")) || equal(mode_str, lit("rb"));
+ struct stdio_mode m;
+ val mode = normalize_mode(&m, mode_str);
+ int input = m.read != 0;
int fd[2];
pid_t pid;
char **argv = 0;
@@ -2277,7 +2399,7 @@ val open_process(val name, val mode_str, val args)
_exit(errno);
} else {
int whichfd;
- char *utf8mode = utf8_dup_to(c_str(mode_str));
+ char *utf8mode = utf8_dup_to(c_str(mode));
FILE *f;
if (input) {
@@ -2309,7 +2431,7 @@ val open_process(val name, val mode_str, val args)
free(utf8mode);
/* TODO: catch potential OOM exception here and kill process. */
- return make_pipevp_stream(f, name, pid);
+ return set_mode_props(m, make_pipevp_stream(f, name, pid));
}
}
#else
@@ -2712,6 +2834,11 @@ void stream_init(void)
reg_var(stdnull_s = intern(lit("*stdnull*"), user_package),
make_null_stream());
+#if HAVE_ISATTY
+ if (isatty(fileno(stdin)) == 1)
+ stream_set_prop(std_input, real_time_k, t);
+#endif
+
reg_fun(format_s, func_n2v(formatv));
reg_fun(intern(lit("make-string-input-stream"), user_package), func_n1(make_string_input_stream));
reg_fun(intern(lit("make-string-byte-input-stream"), user_package), func_n1(make_string_byte_input_stream));
diff --git a/txr.1 b/txr.1
index daf29a76..ba159f56 100644
--- a/txr.1
+++ b/txr.1
@@ -446,9 +446,32 @@ of the query, only during its execution.
.coIP -d
.coIP --debugger
-
Invoke the interactive \*(TX debugger. See the DEBUGGER section.
+.coIP -n
+.coIP --noninteractive
+This option affects behavior related to \*(TX's
+.code *std-input*
+stream. Normally, if this stream is connected to a terminal device, it is
+automatically marked as having the real-time property when \*(TX starts up (see
+the functions .code stream-set-prop and
+.codn real-time-stream-p ).
+The
+.code -n
+option suppresses this behavior; the
+.code *std-input*
+stream remains ordinary.
+
+The \*(TX pattern language reads standard input via
+a lazy list, created by applying the
+.code lazy-stream-cons
+function to the
+.code *std-input*
+stream. If that stream is marked real-time, then the lazy list which is
+returned by that function has behaviors that are better suited for scanning
+interactive input. A more detailed explanation is given under the description
+of this function.
+
.coIP -v
Verbose operation. Detailed logging is enabled.
@@ -22344,12 +22367,15 @@ item.
The ordinary lazy streams read ahead by one line and suppress this extra
item, so their representation is more accurate.
-Streams connected to TTY devices (devices which for which the
+When \*(TX starts up, it automatically marks the
+.code *std-input*
+stream as real-time, if it is connected to a TTY device (a device for which
+the POSIX function
.code isatty
-POSIX function reports true) are automatically marked as real-time. This is
-only supported on platforms that have an
-.code isatty
-function.
+reports true). This is only supported on platforms that have this function.
+The behvior is overridden by the
+.code -n
+command line option.
.coNP Function @ make-string-input-stream
.synb
@@ -22849,7 +22875,7 @@ also returned if the property exists, but its value happens to be
Properties are currently used for marking certain streams as "real-time" (see
the
-.code stream-real-time-p
+.code real-time-stream-p
function above), and also for setting the priority at
which messages are reported to syslog by the
.code *stdlog*
@@ -23182,11 +23208,11 @@ The
argument is a string which uses the same
conventions as the mode argument of the C language
.code fopen
-function.
+function, with some extensions.
The mode string determines whether the stream is an input stream
or output stream. Note that the
.str b
-mode is not supported.
+mode is passed through to the C library, but has no special meaning to \*(TX.
Whether a stream is text or binary depends on which operations
are invoked on it.
@@ -23196,9 +23222,14 @@ argument is omitted, mode
.str r
is used.
+The option letter
+.str i
+is supported. If present, it will create a stream which has the real-time
+property set.
+
.coNP Function @ open-tail
.synb
-.mets (open-tail < path <> [[ mode-string ] << seek-to-end-p ])
+.mets (open-tail < path >> [ mode-string <> [ seek-to-end-p ]])
.syne
.desc
The
@@ -23211,14 +23242,12 @@ The
argument is a string which uses
the same conventions as the mode argument of the C language
.code fopen
-function.
-If it is missing, it defaults to
-.strn r .
-Note that the
-.str b
-mode is not supported.
-Whether a stream is text or binary depends on which operations are invoked on
-it.
+function. If this argument is omitted, then
+.str r
+is used.
+See the
+.code open-file
+function for a discussion of modes.
The
.code seek-to-end-p
@@ -23307,7 +23336,9 @@ the
argument is optional, defaulting to
the value
.str r
-if it is missing.
+if it is missing. See the
+.code open-file
+function for a discussion of modes.
The
.code open-command
@@ -27219,9 +27250,23 @@ option can be used to request emulation of old behavior.
The option was introduced in \*(TX 98, and so the oldest \*(TX version which
can be emulated is \*(TX 97.
-Here are values which have a special meaning as arguments to the
+Here are version values which have a special meaning as arguments to the
+.code -C
+option, along with a description of what behaviors are affected. For each
+of these version values, the described behaviors are provided if
.code -C
-option, along with a description of what behaviors are affected:
+is given an argument which is equal or lower. For instance
+.code -C 103
+selects the behaviors described below for verison 105, but not those for 102.
+
+.IP 105
+Provides the behavior that the
+.code open-file
+function automatically marks a stream open on a TTY devices as a real-time stream
+(subject to the availability of the POSIX
+.code isatty
+function).
+
.IP 102
Up to \*(TX 102, the
.code get-string
diff --git a/txr.c b/txr.c
index d0e97a42..7a774b69 100644
--- a/txr.c
+++ b/txr.c
@@ -60,6 +60,7 @@ const wchli_t *version = wli(TXR_VER);
const wchar_t *progname = L"txr";
static const char *progname_u8;
static val progpath = nil;
+int opt_noninteractive;
int opt_compat;
/*
@@ -111,6 +112,8 @@ static void help(void)
" if termination is unsuccessful.\n"
"-l If dumping bindings, use TXR Lisp format.\n"
"-d Debugger mode.\n"
+"-n Noninteractive input mode for standard input stream,\n"
+" even if its connected to a terminal device.\n"
"-a N Generate array variables up to N dimensions.\n"
" N is a decimal integer. The default value is 1.\n"
" Additional dimensions beyond N are fudged\n"
@@ -137,6 +140,7 @@ static void help(void)
" section at the bottom of the license.\n"
"--lisp-bindings Synonym for -l\n"
"--debugger Synonym for -d\n"
+"--noninteractive Synonym for -n\n"
"--compat=N Synonym for -C N\n"
"--gc-delta=N Invoke garbage collection when malloc activity\n"
" increments by N megabytes since last collection.\n"
@@ -499,6 +503,10 @@ int txr_main(int argc, char **argv)
prog_string, arg, nao);
return EXIT_FAILURE;
#endif
+ } else if (equal(opt, lit("noninteractive"))) {
+ opt_noninteractive = 1;
+ stream_set_prop(std_input, real_time_k, nil);
+ continue;
}
}
@@ -587,6 +595,10 @@ int txr_main(int argc, char **argv)
return EXIT_FAILURE;
#endif
break;
+ case 'n':
+ opt_noninteractive = 1;
+ stream_set_prop(std_input, real_time_k, nil);
+ break;
case 'a':
case 'c':
case 'e':
diff --git a/txr.h b/txr.h
index 5140712f..be82ebfc 100644
--- a/txr.h
+++ b/txr.h
@@ -33,6 +33,7 @@ extern int opt_gc_debug;
extern int opt_vg_debug;
#endif
extern int opt_derivative_regex;
+extern int opt_noninteractive;
extern int opt_compat;
extern alloc_bytes_t opt_gc_delta;
extern const wchli_t *version;