summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKaz Kylheku <kaz@kylheku.com>2016-05-18 06:18:54 -0700
committerKaz Kylheku <kaz@kylheku.com>2016-05-18 06:18:54 -0700
commit6ca427f995a76ed9c5bae2ab86f864ea5ae4d376 (patch)
tree144ba53e9636aec6418c37225a74359bc20ac626
parentd2bc824b4f91f6aa462e27f8b5dde6dee1cc031f (diff)
downloadtxr-6ca427f995a76ed9c5bae2ab86f864ea5ae4d376.tar.gz
txr-6ca427f995a76ed9c5bae2ab86f864ea5ae4d376.tar.bz2
txr-6ca427f995a76ed9c5bae2ab86f864ea5ae4d376.zip
Adding termios support.
* Makefile (termios.o): New object file. * lib.c (init): Call termios_init. * lisplib.c (termios_set_entries, termios_instantiate): New functions. (lisplib_init): Register new functions in autoload table. * share/txr/stdlib/termios.tl: New file. * termios.c, termios.h: New files. * txr.1: Documented termios.
-rw-r--r--Makefile1
-rw-r--r--lib.c4
-rw-r--r--lisplib.c28
-rw-r--r--share/txr/stdlib/termios.tl78
-rw-r--r--termios.c560
-rw-r--r--termios.h27
-rw-r--r--txr.1710
7 files changed, 1407 insertions, 1 deletions
diff --git a/Makefile b/Makefile
index 6fb88e8e..84034cbb 100644
--- a/Makefile
+++ b/Makefile
@@ -53,6 +53,7 @@ OBJS-$(have_glob) += glob.o
OBJS-$(have_ftw) += ftw.o
OBJS-$(have_posix_sigs) += signal.o
OBJS-$(have_sockets) += socket.o
+OBJS-$(have_termios) += termios.o
OBJS-$(have_termios) += linenoise/linenoise.o
EXTRA_OBJS-$(add_win_res) += win/txr.res
diff --git a/lib.c b/lib.c
index 4b158752..03409125 100644
--- a/lib.c
+++ b/lib.c
@@ -63,6 +63,7 @@
#include "syslog.h"
#include "glob.h"
#include "ftw.h"
+#include "termios.h"
#include "cadr.h"
#include "struct.h"
#include "txr.h"
@@ -9394,6 +9395,9 @@ void init(const wchar_t *pn, mem_t *(*oom)(mem_t *, size_t),
#if HAVE_FTW
ftw_init();
#endif
+#if HAVE_TERMIOS
+ termios_init();
+#endif
cadr_init();
time_init();
diff --git a/lisplib.c b/lisplib.c
index f98ddf1a..1c65cd92 100644
--- a/lisplib.c
+++ b/lisplib.c
@@ -281,7 +281,6 @@ static val yield_instantiate(val set_fun)
}
#if HAVE_SOCKETS
-
static val sock_set_entries(val dlt, val fun)
{
val name[] = {
@@ -313,6 +312,30 @@ static val sock_instantiate(val set_fun)
#endif
+#if HAVE_TERMIOS
+
+static val termios_set_entries(val dlt, val fun)
+{
+ val name[] = {
+ lit("set-iflags"), lit("set-oflags"), lit("set-cflags"), lit("set-lflags"),
+ lit("clear-iflags"), lit("clear-oflags"), lit("clear-cflags"), lit("clear-lflags"),
+ lit("go-raw"), lit("go-cbreak"), lit("go-canon"),
+ lit("string-encode"), lit("string-decode"), nil
+ };
+ set_dlt_entries(dlt, name, fun);
+ return nil;
+}
+
+static val termios_instantiate(val set_fun)
+{
+ funcall1(set_fun, nil);
+ load(format(nil, lit("~a/termios.tl"), stdlib_path, nao));
+ sock_load_init();
+ return nil;
+}
+
+#endif
+
val dlt_register(val dlt,
val (*instantiate)(val),
val (*set_entries)(val, val))
@@ -339,6 +362,9 @@ void lisplib_init(void)
#if HAVE_SOCKETS
dlt_register(dl_table, sock_instantiate, sock_set_entries);
#endif
+#if HAVE_TERMIOS
+ dlt_register(dl_table, termios_instantiate, termios_set_entries);
+#endif
}
val lisplib_try_load(val sym)
diff --git a/share/txr/stdlib/termios.tl b/share/txr/stdlib/termios.tl
new file mode 100644
index 00000000..84a6d006
--- /dev/null
+++ b/share/txr/stdlib/termios.tl
@@ -0,0 +1,78 @@
+;; Copyright 2016
+;; Kaz Kylheku <kaz@kylheku.com>
+;; Vancouver, Canada
+;; All rights reserved.
+;;
+;; Redistribution of this software in source and binary forms, with or without
+;; modification, is permitted provided that the following two conditions are met.
+;;
+;; Use of this software in any manner constitutes agreement with the disclaimer
+;; which follows the two conditions.
+;;
+;; 1. Redistributions of source code must retain the above copyright
+;; notice, this list of conditions and the following disclaimer.
+;; 2. Redistributions in binary form must reproduce the above copyright
+;; notice, this list of conditions and the following disclaimer in
+;; the documentation and/or other materials provided with the
+;; distribution.
+;;
+;; THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+;; WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+;; MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE
+;; COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DAMAGES, HOWEVER CAUSED,
+;; AND UNDER ANY THEORY OF LIABILITY, ARISING IN ANY WAY OUT OF THE USE OF THIS
+;; SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+(defmeth termios set-iflags (tio . values)
+ (set tio.iflag (logior tio.iflag . values)))
+
+(defmeth termios set-oflags (tio . values)
+ (set tio.oflag (logior tio.oflag . values)))
+
+(defmeth termios set-cflags (tio . values)
+ (set tio.cflag (logior tio.cflag . values)))
+
+(defmeth termios set-lflags (tio . values)
+ (set tio.lflag (logior tio.lflag . values)))
+
+(defmeth termios clear-iflags (tio . values)
+ (set tio.iflag (logand tio.iflag (lognot (logior . values)))))
+
+(defmeth termios clear-oflags (tio . values)
+ (set tio.oflag (logand tio.oflag (lognot (logior . values)))))
+
+(defmeth termios clear-cflags (tio . values)
+ (set tio.cflag (logand tio.cflag (lognot (logior . values)))))
+
+(defmeth termios clear-lflags (tio . values)
+ (set tio.lflag (logand tio.lflag (lognot (logior . values)))))
+
+(defmeth termios go-raw (tio)
+ tio.(clear-iflags ignbrk brkint parmrk istrip inlcr igncr icrnl ixon)
+ tio.(clear-oflags opost)
+ tio.(clear-cflags csize parenb)
+ tio.(clear-lflags echo echonl icanon isig)
+ (if (boundp 'iexten)
+ tio.(clear-lflags iexten))
+ tio.(set-cflags cs8)
+ (set tio.[cc vmin] 1)
+ (set tio.[cc vtime] 0))
+
+(defmeth termios go-cbreak (tio)
+ tio.(clear-iflags icrnl)
+ tio.(clear-lflags icanon)
+ tio.(set-lfags isig)
+ (set tio.[cc vmin] 1)
+ (set tio.[cc vtime] 0))
+
+(defmeth termios string-encode (tio)
+ (let ((*print-base* 16))
+ tio.(sys:encode-speeds)
+ (downcase-str `@{tio.iflag}:@{tio.oflag}:@{tio.cflag}:@{tio.lflag}:\
+ @{(list-vec tio.cc) ":"}`)))
+
+(defmeth termios string-decode (tio string)
+ (let ((vals (mapcar (op int-str @1 16) (split-str string ":"))))
+ (lset tio.iflag tio.oflag tio.cflag tio.lflag vals)
+ (set tio.cc (vec-list (cddddr vals)))
+ tio.(sys:decode-speeds)))
diff --git a/termios.c b/termios.c
new file mode 100644
index 00000000..cda32a55
--- /dev/null
+++ b/termios.c
@@ -0,0 +1,560 @@
+/* Copyright 2016
+ * Kaz Kylheku <kaz@kylheku.com>
+ * Vancouver, Canada
+ * All rights reserved.
+ *
+ * Redistribution of this software in source and binary forms, with or without
+ * modification, is permitted provided that the following two conditions are met.
+ *
+ * Use of this software in any manner constitutes agreement with the disclaimer
+ * which follows the two conditions.
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DAMAGES, HOWEVER CAUSED,
+ * AND UNDER ANY THEORY OF LIABILITY, ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wchar.h>
+#include <signal.h>
+#include <dirent.h>
+#include <errno.h>
+#include "config.h"
+#include <termios.h>
+#include ALLOCA_H
+#include "lib.h"
+#include "gc.h"
+#include "args.h"
+#include "eval.h"
+#include "signal.h"
+#include "unwind.h"
+#include "stream.h"
+#include "struct.h"
+#include "termios.h"
+
+val termios_s, iflag_s, oflag_s, cflag_s, lflag_s, cc_s, ispeed_s, ospeed_s;
+
+static cnum termios_speed_to_baud(speed_t code)
+{
+ switch (code) {
+ case B0: return 0;
+ case B50: return 50;
+ case B75: return 75;
+ case B110: return 110;
+ case B134: return 134;
+ case B150: return 150;
+ case B200: return 200;
+ case B300: return 300;
+ case B600: return 600;
+ case B1200: return 1200;
+ case B1800: return 1800;
+ case B2400: return 2400;
+ case B4800: return 4800;
+ case B9600: return 9600;
+ case B19200: return 19200;
+ case B38400: return 38400;
+#ifdef B57600
+ case B57600: return 57600;
+#endif
+#ifdef B115200
+ case B115200: return 115200;
+#endif
+#ifdef B230400
+ case B230400: return 230400;
+#endif
+#ifdef B460800
+ case B460800: return 460800;
+#endif
+#ifdef B500000
+ case B500000: return 500000;
+#endif
+#ifdef B576000
+ case B576000: return 576000;
+#endif
+#ifdef B921600
+ case B921600: return 921600;
+#endif
+#ifdef B1000000
+ case B1000000: return 1000000;
+#endif
+#ifdef B1152000
+ case B1152000: return 1152000;
+#endif
+#ifdef B1500000
+ case B1500000: return 1500000;
+#endif
+#ifdef B2000000
+ case B2000000: return 2000000;
+#endif
+#ifdef B2500000
+ case B2500000: return 2500000;
+#endif
+#ifdef B3000000
+ case B3000000: return 3000000;
+#endif
+#ifdef B3500000
+ case B3500000: return 3500000;
+#endif
+#ifdef B4000000
+ case B4000000: return 4000000;
+#endif
+ default: return 9600;
+ }
+}
+
+static speed_t termios_baud_to_speed(cnum baud)
+{
+ switch (baud) {
+ case 0: return B0;
+ case 50: return B50;
+ case 75: return B75;
+ case 110: return B110;
+ case 134: return B134;
+ case 150: return B150;
+ case 200: return B200;
+ case 300: return B300;
+ case 600: return B600;
+ case 1200: return B1200;
+ case 1800: return B1800;
+ case 2400: return B2400;
+ case 4800: return B4800;
+ case 9600: return B9600;
+ case 19200: return B19200;
+ case 38400: return B38400;
+#ifdef B57600
+ case 57600: return B57600;
+#endif
+#ifdef B115200
+ case 115200: return B115200;
+#endif
+#ifdef B230400
+ case 230400: return B230400;
+#endif
+#ifdef B460800
+ case 460800: return B460800;
+#endif
+#ifdef B500000
+ case 500000: return B500000;
+#endif
+#ifdef B576000
+ case 576000: return B576000;
+#endif
+#ifdef B921600
+ case 921600: return B921600;
+#endif
+#ifdef B1000000
+ case 1000000: return B1000000;
+#endif
+#ifdef B1152000
+ case 1152000: return B1152000;
+#endif
+#ifdef B1500000
+ case 1500000: return B1500000;
+#endif
+#ifdef B2000000
+ case 2000000: return B2000000;
+#endif
+#ifdef B2500000
+ case 2500000: return B2500000;
+#endif
+#ifdef B3000000
+ case 3000000: return B3000000;
+#endif
+#ifdef B3500000
+ case 3500000: return B3500000;
+#endif
+#ifdef B4000000
+ case 4000000: return B4000000;
+#endif
+ default:
+ uw_throwf(error_s, lit("unsupported tty speed: ~a"), num(baud), nao);
+ }
+}
+
+static val termios_unpack(struct termios *in)
+{
+ args_decl(args, ARGS_MIN);
+ val out = make_struct(termios_s, nil, args);
+ int i, cc_sz = (int) (sizeof in->c_cc / sizeof in->c_cc[0]);
+ val cc = vector(num_fast(cc_sz), nil);
+
+ slotset(out, iflag_s, num(in->c_iflag));
+ slotset(out, oflag_s, num(in->c_oflag));
+ slotset(out, cflag_s, num(in->c_cflag));
+ slotset(out, lflag_s, num(in->c_lflag));
+ slotset(out, cc_s, cc);
+ slotset(out, ispeed_s, num(termios_speed_to_baud(cfgetispeed(in))));
+ slotset(out, ospeed_s, num(termios_speed_to_baud(cfgetospeed(in))));
+
+ for (i = 0; i < cc_sz; i++)
+ set(vecref_l(cc, num_fast(i)), num(in->c_cc[i]));
+
+ return out;
+}
+
+static void termios_pack(struct termios *out, val in)
+{
+ int i, cc_sz = (int) (sizeof out->c_cc / sizeof out->c_cc[0]);
+ val cc = slot(in, cc_s);
+
+ out->c_iflag = c_num(slot(in, iflag_s));
+ out->c_oflag = c_num(slot(in, oflag_s));
+ out->c_cflag = c_num(slot(in, cflag_s));
+ out->c_lflag = c_num(slot(in, lflag_s));
+
+ cfsetispeed(out, termios_baud_to_speed(c_num(slot(in, ispeed_s))));
+ cfsetospeed(out, termios_baud_to_speed(c_num(slot(in, ospeed_s))));
+
+ for (i = 0; i < cc_sz; i++) {
+ val ch = vecref(cc, num_fast(i));
+ cnum c = c_num(ch);
+
+ out->c_cc[i] = c;
+
+ if (out->c_cc[i] != c)
+ uw_throwf(system_error_s, lit("value ~s is out of range for c_cc[~a] "
+ "of struct termios"),
+ ch, num_fast(i), nao);
+ }
+}
+
+static val get_fd(val stream)
+{
+ val fd;
+
+ if (missingp(stream))
+ fd = stream_fd(std_input);
+ else if (integerp(stream))
+ fd = stream;
+ else
+ fd = stream_fd(stream);
+
+ return fd;
+}
+
+static val tcgetattr_wrap(val stream)
+{
+ struct termios tio;
+ int res;
+ val fd = get_fd(stream);
+
+ res = tcgetattr(c_num(fd), &tio);
+
+ if (res < 0)
+ uw_throwf(system_error_s, lit("tcgetattr failed: ~d/~s"),
+ num(errno), string_utf8(strerror(errno)), nao);
+
+ return termios_unpack(&tio);
+}
+
+static val tcsetattr_wrap(val termios, val actions, val stream)
+{
+ struct termios tio;
+ int res;
+ val fd = get_fd(stream);
+
+ actions = default_arg(actions, num(TCSADRAIN));
+
+ res = tcgetattr(c_num(fd), &tio);
+
+ if (res < 0)
+ uw_throwf(system_error_s, lit("tcgetattr failed: ~d/~s"),
+ num(errno), string_utf8(strerror(errno)), nao);
+
+ termios_pack(&tio, termios);
+
+ res = tcsetattr(c_num(fd), c_num(actions), &tio);
+
+ if (res < 0)
+ uw_throwf(system_error_s, lit("tcsetattr failed: ~d/~s"),
+ num(errno), string_utf8(strerror(errno)), nao);
+
+ return termios;
+}
+
+static val tcsendbreak_wrap(val duration, val stream)
+{
+ val fd = get_fd(stream);
+ int res = tcsendbreak(c_num(fd), if3(missingp(duration),
+ 500, c_num(duration)));
+
+ if (res < 0)
+ uw_throwf(system_error_s, lit("tcsendbreak failed: ~d/~s"),
+ num(errno), string_utf8(strerror(errno)), nao);
+
+ return t;
+}
+
+static val tcdrain_wrap(val stream)
+{
+ val fd = get_fd(stream);
+ int res = tcdrain(c_num(fd));
+
+ if (res < 0)
+ uw_throwf(system_error_s, lit("tcdrain failed: ~d/~s"),
+ num(errno), string_utf8(strerror(errno)), nao);
+
+ return t;
+}
+
+static val tcflush_wrap(val queue, val stream)
+{
+ val fd = get_fd(stream);
+ int res = tcflush(c_num(fd), c_num(queue));
+
+ if (res < 0)
+ uw_throwf(system_error_s, lit("tcflush failed: ~d/~s"),
+ num(errno), string_utf8(strerror(errno)), nao);
+
+ return t;
+}
+
+static val tcflow_wrap(val action, val stream)
+{
+ val fd = get_fd(stream);
+ int res = tcflow(c_num(fd), c_num(action));
+
+ if (res < 0)
+ uw_throwf(system_error_s, lit("tcflow failed: ~d/~s"),
+ num(errno), string_utf8(strerror(errno)), nao);
+
+ return t;
+}
+
+static val encode_speeds(val termios)
+{
+ struct termios tio = { 0 };
+
+ tio.c_iflag = c_num(slot(termios, iflag_s));
+ tio.c_cflag = c_num(slot(termios, cflag_s));
+ cfsetispeed(&tio, termios_baud_to_speed(c_num(slot(termios, ispeed_s))));
+ cfsetospeed(&tio, termios_baud_to_speed(c_num(slot(termios, ospeed_s))));
+ slotset(termios, iflag_s, num(tio.c_iflag));
+ slotset(termios, cflag_s, num(tio.c_cflag));
+
+ return termios;
+}
+
+static val decode_speeds(val termios)
+{
+ struct termios tio = { 0 };
+
+ tio.c_cflag = c_num(slot(termios, cflag_s));
+ tio.c_iflag = c_num(slot(termios, iflag_s));
+ slotset(termios, ispeed_s, num(termios_speed_to_baud(cfgetispeed(&tio))));
+ slotset(termios, ospeed_s, num(termios_speed_to_baud(cfgetospeed(&tio))));
+
+ return termios;
+}
+
+void termios_init(void)
+{
+ val termios_t;
+
+ termios_s = intern(lit("termios"), user_package);
+ iflag_s = intern(lit("iflag"), user_package);
+ oflag_s = intern(lit("oflag"), user_package);
+ cflag_s = intern(lit("cflag"), user_package);
+ lflag_s = intern(lit("lflag"), user_package);
+ cc_s = intern(lit("cc"), user_package);
+ ispeed_s = intern(lit("ispeed"), user_package);
+ ospeed_s = intern(lit("ospeed"), user_package);
+
+ termios_t = make_struct_type(termios_s, nil, nil,
+ list(iflag_s, oflag_s, cflag_s, lflag_s,
+ cc_s, ispeed_s, ospeed_s, nao),
+ nil, nil, nil, nil);
+
+ reg_fun(intern(lit("tcgetattr"), user_package), func_n1o(tcgetattr_wrap, 0));
+ reg_fun(intern(lit("tcsetattr"), user_package), func_n3o(tcsetattr_wrap, 1));
+ reg_fun(intern(lit("tcsendbreak"), user_package), func_n2o(tcsendbreak_wrap, 0));
+ reg_fun(intern(lit("tcdrain"), user_package), func_n1(tcdrain_wrap));
+ reg_fun(intern(lit("tcflush"), user_package), func_n2(tcflush_wrap));
+ reg_fun(intern(lit("tcflow"), user_package), func_n2(tcflow_wrap));
+ static_slot_ensure(termios_t, intern(lit("encode-speeds"), system_package),
+ func_n1(encode_speeds), nil);
+ static_slot_ensure(termios_t, intern(lit("decode-speeds"), system_package),
+ func_n1(decode_speeds), nil);
+
+ /* cc array indexes */
+ reg_varl(intern(lit("vintr"), user_package), num_fast(VINTR));
+ reg_varl(intern(lit("vquit"), user_package), num_fast(VQUIT));
+ reg_varl(intern(lit("verase"), user_package), num_fast(VERASE));
+ reg_varl(intern(lit("vkill"), user_package), num_fast(VKILL));
+ reg_varl(intern(lit("veof"), user_package), num_fast(VEOF));
+ reg_varl(intern(lit("vtime"), user_package), num_fast(VTIME));
+ reg_varl(intern(lit("vmin"), user_package), num_fast(VMIN));
+#ifdef VSWTC
+ reg_varl(intern(lit("vswtc"), user_package), num_fast(VSWTC));
+#endif
+ reg_varl(intern(lit("vstart"), user_package), num_fast(VSTART));
+ reg_varl(intern(lit("vstop"), user_package), num_fast(VSTOP));
+ reg_varl(intern(lit("vsusp"), user_package), num_fast(VSUSP));
+ reg_varl(intern(lit("veol"), user_package), num_fast(VEOL));
+#ifdef VREPRINT
+ reg_varl(intern(lit("vreprint"), user_package), num_fast(VREPRINT));
+#endif
+#ifdef VDISCARD
+ reg_varl(intern(lit("vdiscard"), user_package), num_fast(VDISCARD));
+#endif
+#ifdef VWERASE
+ reg_varl(intern(lit("vwerase"), user_package), num_fast(VWERASE));
+#endif
+#ifdef VLNEXT
+ reg_varl(intern(lit("vlnext"), user_package), num_fast(VLNEXT));
+#endif
+#ifdef VEOL2
+ reg_varl(intern(lit("veol2"), user_package), num_fast(VEOL2));
+#endif
+ /* iflag bits */
+ reg_varl(intern(lit("ignbrk"), user_package), num_fast(IGNBRK));
+ reg_varl(intern(lit("brkint"), user_package), num_fast(BRKINT));
+ reg_varl(intern(lit("ignpar"), user_package), num_fast(IGNPAR));
+ reg_varl(intern(lit("parmrk"), user_package), num_fast(PARMRK));
+ reg_varl(intern(lit("inpck"), user_package), num_fast(INPCK));
+ reg_varl(intern(lit("istrip"), user_package), num_fast(ISTRIP));
+ reg_varl(intern(lit("inlcr"), user_package), num_fast(INLCR));
+ reg_varl(intern(lit("igncr"), user_package), num_fast(IGNCR));
+ reg_varl(intern(lit("icrnl"), user_package), num_fast(ICRNL));
+#ifdef IUCLC
+ reg_varl(intern(lit("iuclc"), user_package), num_fast(IUCLC));
+#endif
+ reg_varl(intern(lit("ixon"), user_package), num_fast(IXON));
+ reg_varl(intern(lit("ixany"), user_package), num_fast(IXANY));
+ reg_varl(intern(lit("ixoff"), user_package), num_fast(IXOFF));
+#ifdef IMAXBEL
+ reg_varl(intern(lit("imaxbel"), user_package), num_fast(IMAXBEL));
+#endif
+#ifdef IUTF8
+ reg_varl(intern(lit("iutf8"), user_package), num_fast(IUTF8));
+#endif
+ /* oflag bits */
+ reg_varl(intern(lit("opost"), user_package), num_fast(OPOST));
+#ifdef OLCUC
+ reg_varl(intern(lit("olcuc"), user_package), num_fast(OLCUC));
+#endif
+ reg_varl(intern(lit("onlcr"), user_package), num_fast(ONLCR));
+ reg_varl(intern(lit("ocrnl"), user_package), num_fast(OCRNL));
+ reg_varl(intern(lit("onocr"), user_package), num_fast(ONOCR));
+ reg_varl(intern(lit("onlret"), user_package), num_fast(ONLRET));
+ reg_varl(intern(lit("ofill"), user_package), num_fast(OFILL));
+#ifdef OFDEL
+ reg_varl(intern(lit("ofdel"), user_package), num_fast(OFDEL));
+#endif
+ reg_varl(intern(lit("vtdly"), user_package), num_fast(VTDLY));
+ reg_varl(intern(lit("vt0"), user_package), num_fast(VT0));
+ reg_varl(intern(lit("vt1"), user_package), num_fast(VT1));
+#ifdef NLDLY
+ reg_varl(intern(lit("nldly"), user_package), num_fast(NLDLY));
+ reg_varl(intern(lit("nl0"), user_package), num_fast(NL0));
+ reg_varl(intern(lit("nl1"), user_package), num_fast(NL1));
+#endif
+#ifdef CRDLY
+ reg_varl(intern(lit("crdly"), user_package), num_fast(CRDLY));
+ reg_varl(intern(lit("cr0"), user_package), num_fast(CR0));
+ reg_varl(intern(lit("cr1"), user_package), num_fast(CR1));
+ reg_varl(intern(lit("cr2"), user_package), num_fast(CR2));
+ reg_varl(intern(lit("cr3"), user_package), num_fast(CR3));
+#endif
+#ifdef TABDLY
+ reg_varl(intern(lit("tabdly"), user_package), num_fast(TABDLY));
+ reg_varl(intern(lit("tab0"), user_package), num_fast(TAB0));
+ reg_varl(intern(lit("tab1"), user_package), num_fast(TAB1));
+ reg_varl(intern(lit("tab2"), user_package), num_fast(TAB2));
+ reg_varl(intern(lit("tab3"), user_package), num_fast(TAB3));
+#endif
+#ifdef BSDLY
+ reg_varl(intern(lit("bsdly"), user_package), num_fast(BSDLY));
+ reg_varl(intern(lit("bs0"), user_package), num_fast(BS0));
+ reg_varl(intern(lit("bs1"), user_package), num_fast(BS1));
+#endif
+#ifdef FFDLY
+ reg_varl(intern(lit("ffdly"), user_package), num_fast(FFDLY));
+ reg_varl(intern(lit("ff0"), user_package), num_fast(FF0));
+ reg_varl(intern(lit("ff1"), user_package), num_fast(FF1));
+#endif
+ /* cflag bits */
+ reg_varl(intern(lit("csize"), user_package), num_fast(CSIZE));
+ reg_varl(intern(lit("cs5"), user_package), num_fast(CS5));
+ reg_varl(intern(lit("cs6"), user_package), num_fast(CS6));
+ reg_varl(intern(lit("cs7"), user_package), num_fast(CS7));
+ reg_varl(intern(lit("cs8"), user_package), num_fast(CS8));
+ reg_varl(intern(lit("cstopb"), user_package), num_fast(CSTOPB));
+ reg_varl(intern(lit("cread"), user_package), num_fast(CREAD));
+ reg_varl(intern(lit("parenb"), user_package), num_fast(PARENB));
+ reg_varl(intern(lit("parodd"), user_package), num_fast(PARODD));
+ reg_varl(intern(lit("hupcl"), user_package), num_fast(HUPCL));
+ reg_varl(intern(lit("clocal"), user_package), num_fast(CLOCAL));
+#ifdef CBAUD
+ reg_varl(intern(lit("cbaud"), user_package), num_fast(CBAUD));
+#endif
+#ifdef CBAUDEX
+ reg_varl(intern(lit("cbaudex"), user_package), num_fast(CBAUDEX));
+#endif
+#ifdef CMSPAR
+ reg_varl(intern(lit("cmspar"), user_package), num_fast(CMSPAR));
+#endif
+#ifdef CRTSCTS
+ reg_varl(intern(lit("crtscts"), user_package), num_fast(CRTSCTS));
+#endif
+ /* lflag bits */
+ reg_varl(intern(lit("isig"), user_package), num_fast(ISIG));
+ reg_varl(intern(lit("icanon"), user_package), num_fast(ICANON));
+ reg_varl(intern(lit("echo"), user_package), num_fast(ECHO));
+ reg_varl(intern(lit("echoe"), user_package), num_fast(ECHOE));
+ reg_varl(intern(lit("echok"), user_package), num_fast(ECHOK));
+ reg_varl(intern(lit("echonl"), user_package), num_fast(ECHONL));
+ reg_varl(intern(lit("noflsh"), user_package), num_fast(NOFLSH));
+ reg_varl(intern(lit("tostop"), user_package), num_fast(TOSTOP));
+#ifdef IEXTEN
+ reg_varl(intern(lit("iexten"), user_package), num_fast(IEXTEN));
+#endif
+#ifdef XCASE
+ reg_varl(intern(lit("xcase"), user_package), num_fast(XCASE));
+#endif
+#ifdef ECHOCTL
+ reg_varl(intern(lit("echoctl"), user_package), num_fast(ECHOCTL));
+#endif
+#ifdef ECHOPRT
+ reg_varl(intern(lit("echoprt"), user_package), num_fast(ECHOPRT));
+#endif
+#ifdef ECHOKE
+ reg_varl(intern(lit("echoke"), user_package), num_fast(ECHOKE));
+#endif
+#ifdef FLUSHO
+ reg_varl(intern(lit("flusho"), user_package), num_fast(FLUSHO));
+#endif
+#ifdef PENDIN
+ reg_varl(intern(lit("pendin"), user_package), num_fast(PENDIN));
+#endif
+#ifdef EXTPROC
+ reg_varl(intern(lit("extproc"), user_package), num_fast(EXTPROC));
+#endif
+ /* tcflow */
+ reg_varl(intern(lit("tcooff"), user_package), num_fast(TCOOFF));
+ reg_varl(intern(lit("tcoon"), user_package), num_fast(TCOON));
+ reg_varl(intern(lit("tcioff"), user_package), num_fast(TCIOFF));
+ reg_varl(intern(lit("tcion"), user_package), num_fast(TCION));
+ /* tcflush */
+ reg_varl(intern(lit("tciflush"), user_package), num_fast(TCIFLUSH));
+ reg_varl(intern(lit("tcoflush"), user_package), num_fast(TCOFLUSH));
+ reg_varl(intern(lit("tcioflush"), user_package), num_fast(TCIOFLUSH));
+ /* tcsetattr */
+ reg_varl(intern(lit("tcsanow"), user_package), num_fast(TCSANOW));
+ reg_varl(intern(lit("tcsadrain"), user_package), num_fast(TCSADRAIN));
+ reg_varl(intern(lit("tcsaflush"), user_package), num_fast(TCSAFLUSH));
+}
diff --git a/termios.h b/termios.h
new file mode 100644
index 00000000..df8fb83d
--- /dev/null
+++ b/termios.h
@@ -0,0 +1,27 @@
+/* Copyright 2016
+ * Kaz Kylheku <kaz@kylheku.com>
+ * Vancouver, Canada
+ * All rights reserved.
+ *
+ * Redistribution of this software in source and binary forms, with or without
+ * modification, is permitted provided that the following two conditions are met.
+ *
+ * Use of this software in any manner constitutes agreement with the disclaimer
+ * which follows the two conditions.
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL THE
+ * COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DAMAGES, HOWEVER CAUSED,
+ * AND UNDER ANY THEORY OF LIABILITY, ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+void termios_init(void);
diff --git a/txr.1 b/txr.1
index 84218ef9..7dd08b90 100644
--- a/txr.1
+++ b/txr.1
@@ -39486,6 +39486,716 @@ excluding the contiguous all-zero bits in the least significant position:
how many times the address can be shifted to the right before a 1 appears
in the least significant bit.
+.SS* Unix Terminal Control
+
+\*(TX provides access to the terminal control "termios" interfaces defined by
+POSIX, and some of the extensions to it in Linux. By using termios, programs
+can control serial devices, consoles and virtual terminals. Terminal control
+in POSIX revolves around a C language structure called
+.codn "struct termios" .
+This is mirrored in a \*(TL structure also called
+.codn termios .
+
+Like-named \*(TL functions are provided which correspond to the C functions
+.codn tcgetattr ,
+.codn tcsetattr ,
+.codn tcsendbreak ,
+.codn tcdrain ,
+.code tcflush
+and
+.codn tcflow .
+
+These have somewhat different argument conventions. The TTY device is specified last,
+so that it can conveniently default to the
+.code *stdin*
+stream. A TTY device can be specified as either a stream object or a numeric
+file descriptor.
+
+The functions
+.codn cfgetispeed ,
+.codn cfgetospeed ,
+.code cfsetispeed
+and
+.code cfsetospeed
+are not provided, because they are unnecessary. Device speed (informally, "baud rate")
+is specified directly as a integer value in the
+.code termios
+structure. The \*(TL termios functions automatically convert between integer
+values and the speed constants (like
+.codn B38400 )
+used by the C API.
+
+All of the various termios-related constants are provided, including some non-standard
+ones. They appear in lower case. For instance
+.code IGNBRK
+and
+.code PARENB
+are simply known as the predefined \*(TL variables
+.code ignbrk
+and
+.codn parenb .
+
+.coNP Structure @ termios
+.synb
+.mets (defstruct termios nil
+.mets \ \ iflag oflag cflag lflag
+.mets \ \ cc ispeed ospeed)
+.syne
+.desc
+The
+.code termios
+structure represents the kernel level terminal device configuration.
+It holds hardware related setting such as serial line speed, parity
+and handshaking. It also holds software settings like translations,
+and settings affecting input behaviors. The structure closely corresponds
+to the C language
+.code termios
+structure which exists in the POSIX API.
+
+The
+.codn iflag ,
+.codn oflag ,
+.code cflag
+and
+.code lflag
+slots correspond to the
+.codn c_iflag ,
+.codn c_oflag ,
+.code c_cflag
+and
+.code c_lflag
+members of the C structure. They hold integer values representing
+bit fields.
+
+The
+.code cc
+slot corresponds to the
+.code c_cc
+member of the C structure. Whereas the
+C structure's
+.code c_cc
+member is an array of the C type
+.codn cc_t ,
+the
+.code cc
+slot is a vector of integers, whose values must have the same range as the
+.code cc_t
+type.
+
+.coNP Variables @, ignbrk @, brkint @, ignpar @, parmrk @, inpck @, istrip @, inlcr @, igncr @, icrnl @, iuclc @, ixon @, ixany @, ixoff @ imaxbel and @ iutf8
+.desc
+These variables specify bitmask values for the
+.code iflag
+slot of the
+.code termios
+structure. They correspond to the C language preprocessor symbols
+.codn IGNBRK ,
+.codn BRKINT ,
+.code IGNPAR
+and so forth.
+
+The
+.code imaxbel
+and
+.code iutf8
+variables are specific to Linux and may not be present.
+Portable code should test for their presence with
+.codn boundp .
+
+The
+.code iuclc
+variable is a legacy feature not found on all systems.
+
+Note: the
+.code termios
+methods
+.code set-iflags
+and
+.code clear-iflags
+provide a convenient means for setting and clearing combinations of
+these flags.
+
+.coNP Variables @, opost @, olcuc @, onlcr @, ocrnl @, onocr @, onlret @, ofill @, ofdel @, vtdly @, vt0 @, vt1 @, nldly @, nl0 @, nl1 @, crdly @, cr0 @, cr1 @, cr2 @, cr3 @, tabdly @, tab0 @, tab1 @, tab2 @, tab3 @, bsdly @, bs0 @, bs1 @, ffdly @ ff0 and @ ff1
+.desc
+These variables specify bitmask values for the
+.code oflag
+slot of the
+.code termios
+structure. They correspond to the C language preprocessor symbols
+.codn OPOST ,
+.codn OLCUC ,
+.code ONLCR
+and so forth.
+
+The variable
+.code ofdel
+is Linux-specific. Portable programs should test for its presence using
+.codn boundp .
+
+The
+.code olcuc
+variable is a legacy feature not found on all systems.
+
+Likewise, whether the following groups of symbols are present is
+platform-specific:
+.codn nldly ,
+.code nl0
+and
+.codn nl1 ;
+.codn crdly ,
+.codn cr0 ,
+.codn cr1 ,
+.code cr2
+and
+.codn cr3 ;
+.codn tabdly ,
+.codn tab0 ,
+.codn tab1 ,
+.code tab2
+and
+.codn tab3 ;
+.codn bsdly ,
+.code bs0
+and
+.codn bs1 ;
+and
+.codn ffdly ,
+.code ff0
+and
+.codn ff1 .
+
+Note: the
+.code termios
+methods
+.code set-oflags
+and
+.code clear-oflags
+provide a convenient means for setting and clearing combinations of
+these flags.
+
+.coNP Variables @, csize @, cs5 @, cs6 @, cs7 @, cs8 @, cstopb @, cread @, parenb @, parodd @, hupcl @, clocal @, cbaud @, cbaudex @ cmspar and @ crtscts
+.desc
+These variables specify bitmask values for the
+.code cflag
+slot of the
+.code termios
+structure. They correspond to the C language preprocessor symbols
+.codn CSIZE ,
+.codn CS5 ,
+.code CS6
+and so forth.
+
+The following are present on Linux, and may not be available
+on other platforms. Portable code should test for them using
+.codn boundp :
+.codn cbaud ,
+.codn cbaudex ,
+.code cmspar
+and
+.codn crtscts .
+
+Note: the
+.code termios
+methods
+.code set-cflags
+and
+.code clear-cflags
+provide a convenient means for setting and clearing combinations of
+these flags.
+
+.coNP Variables @, isig @, icanon @, echo @, echoe @, echok @, echonl @, noflsh @, tostop @, iexten @, xcase @, echoctl @, echoprt @, echoke @, flusho @ pendin and @ extproc
+.desc
+These variables specify bitmask values for the
+.code lflag
+slot of the
+.code termios
+structure. They correspond to the C language preprocessor symbols
+.codn ISIG ,
+.codn ICANON ,
+.code ECHO
+and so forth.
+
+The following are present on Linux, and may not be available
+on other platforms. Portable code should test for them using
+.codn boundp :
+.codn iexten ,
+.codn xcase ,
+.codn echoctl ,
+.codn echoprt ,
+.codn echoke ,
+.codn flusho ,
+.code pendin
+and
+.codn extproc .
+
+Note: the
+.code termios
+methods
+.code set-lflags
+and
+.code clear-lflags
+provide a convenient means for setting and clearing combinations of
+these flags.
+
+.coNP Variables @, vintr @, vquit @, verase @, vkill @, veof @, vtime @, vmin @, vswtc @, vstart @, vstop @, vsusp @, veol @, vreprint @, vdiscard @, vwerase @ vlnext and @ veol2
+.desc
+These variables specify integer offsets into the vector stored in the
+.code cc
+slot of the
+.code termios
+structure. They correspond to the C language preprocessor symbols
+.codn VINTR ,
+.codn VQUIT ,
+.code VERASE
+and so forth.
+
+The following are present on Linux, and may not be available
+on other platforms. Portable code should test for them using
+.codn boundp :
+.codn vswtc ,
+.codn vreprint ,
+.codn vdiscard ,
+.code vlnext
+and
+.codn veol2 .
+
+.coNP Variables @, tcooff @, tcoon @ tcioff and @ tcion
+.desc
+These variables hold integer values suitable as the
+.meta action
+argument of the
+.code tcflow
+function. They correspond to the C language preprocessor symbols
+.codn TCOOFF ,
+.codn TCOON ,
+.code TCIOFF
+and
+.codn TCION .
+
+.coNP Variables @, tciflush @ tcoflush and @ tcioflush
+.desc
+These variables hold integer values suitable as the
+.meta queue
+argument of the
+.code tcflush
+function. They correspond to the C language preprocessor symbols
+.codn TCIFLUSH ,
+.code TCOFLUSH
+and
+.codn TCIOFLUSH .
+
+.coNP Variables @, tcsanow @ tcsadrain and @ tcsaflush
+.desc
+These variables hold integer values suitable as the
+.meta actions
+argument of the
+.code tcsetattr
+function. They correspond to the C language preprocessor symbols
+.codn TCSANOW ,
+.code TCSADRAIN
+and
+.codn TCSAFLUSH .
+
+.coNP Functions @ tcgetattr and @ tcsetattr
+.synb
+.mets (tcgetattr <> [ device ])
+.mets (tcsetattr < termios < actions <> [ device ])
+.syne
+.desc
+The
+.code tcgetattr
+and
+.code tcsetattr
+functions, respectively, retrieve and install the configuration
+of the terminal driver associated with the specified device.
+
+These functions are wrappers for the like-named POSIX C library functions,
+but with different argument conventions, and operating using
+a \*(TL structure.
+
+The
+.code tcgetattr
+function, if successful, returns a new instance of the
+.code termios
+structure.
+
+The
+.code tcsetattr
+function requires an instance of a
+.code termios
+structure as an argument to its
+.meta termios
+parameter.
+
+A program may alter the settings of a terminal device by
+retrieving them using
+.codn tcgetattr ,
+manipulating the structure returned by this function, and
+then using
+.code tcsetattr
+to install the modified structure into the device.
+
+The
+.meta actions
+argument of
+.code tcsetattr
+may be given as the value of one of the variables
+.codn tcsanow ,
+.code tcsadrain
+or
+.codn tcsaflush .
+If it is omitted, the default is
+.codn tcsadrain .
+
+If an argument is given for
+.meta device
+it must be either a stream, or an integer file descriptor.
+In either case, it is expected to be associated with a
+terminal (TTY) device.
+
+If the argument is omitted, it defaults to the stream currently
+stored in the
+.code *stdin*
+stream special variable, expected to be associated with
+a terminal device.
+
+.TP* Notes:
+
+The C
+.code termios
+structure usually does not have members for representing the input
+and output speed. \*(TL does not use such members, in any case, even
+if they are present. The speeds are encoded in the
+.code cc_iflag
+and
+.code cc_lflag
+bitmasks. When retrieving the settings, the
+.code tcgetattr
+function uses the POSIX functions
+.code cfgetispeed
+and
+.code cfgetospeed
+to retrieve the speed values from the C structure. These values
+are installed as the
+.code ispeed
+and
+.code ospeed
+slots of the Lisp structure. A reverse conversion takes place
+when setting are installed using
+.codn tcsetattr :
+the speed values are taken from the slots, and installed into
+the C structure using
+.code cfsetispeed
+and
+.code cfsetospeed
+before the structure is passed to the C
+.code tcsetattr
+function.
+
+On Linux, TTY devices do not have a separate input and output speed.
+The C
+.code termios
+structure stores only one speed which is taken as both the input
+and output speed, with a special exception. The input speed may be
+programmed as zero. In that case, it is independently represented.
+speed may be programmed as zero.
+
+.coNP Function @ tcsendbreak
+.synb
+.mets (tcsendbreak >> [ duration <> [ device ]])
+.syne
+.desc
+The
+.code tcsendbreak
+function generates a break signal on serial devices. The
+.meta duration
+parameter specifies the length of the break signal in milliseconds.
+If the argument is omitted, the value 500 is used.
+
+The
+.meta device
+parameter is exactly the same as that of the
+.code tcsetattr
+function.
+
+.coNP Function @ tcdrain
+.synb
+.mets (tcdrain <> [ device ])
+.syne
+.desc
+The
+.code tcdrain
+function waits until all queued output on a terminal
+device has been transmitted. It is a direct wrapper
+for the like-named POSIX C function.
+
+The
+.meta device
+parameter is exactly the same as that of the
+.code tcsetattr
+function.
+
+.coNP Function @ tcflush
+.synb
+.mets (tcflush < queue <> [ device ])
+.syne
+.desc
+The
+.code tcflush
+function discards either untransmitted output data,
+or received and yet unread input data, depending on the
+value of the
+.meta queue
+argument. It is a direct wrapper for the like-named
+POSIX C function.
+
+The
+.meta queue
+argument should be the value of one of the variables
+.codn tciflush ,
+.code tcoflush
+and
+.codn tcioflush ,
+which specify the flushing of input data, output
+data or both.
+
+The
+.meta device
+parameter is exactly the same as that of the
+.code tcsetattr
+function.
+
+.coNP Function @ tcflow
+.synb
+.mets (tcflow < action <> [ device ])
+.syne
+.desc
+The
+.code tcflow
+function provides bi-directional flow control on the
+specified terminal device. It is a direct wrapper
+for the like-named POSIX C function.
+
+The
+.meta action
+argument should be the value of one of the
+variables
+.codn tcooff ,
+.codn tcoon ,
+.code tcioff
+and
+.codn tcion .
+
+The
+.meta device
+parameter is exactly the same as that of the
+.code tcsetattr
+function.
+
+.coNP Methods @, set-iflags @, set-oflags @, set-cflags @, set-lflags @, clear-iflags @, clear-oflags @ clear-cflags and @ clear-lflags
+.synb
+.mets << termios .(set-iflags << flags *)
+.mets << termios .(set-oflags << flags *)
+.mets << termios .(set-cflags << flags *)
+.mets << termios .(set-lflags << flags *)
+.mets << termios .(clear-iflags << flags *)
+.mets << termios .(clear-oflags << flags *)
+.mets << termios .(clear-cflags << flags *)
+.mets << termios .(clear-lflags << flags *)
+.syne
+.desc
+These methods of the
+.code termios
+structure set or clear multiple flags of the four bitmask flag fields.
+
+The
+.meta flags
+arguments specify zero or more integer values. These values
+are combined together bitwise, as if by the
+.code logior
+function to form a single effective mask.
+If there are no
+.meta flags
+arguments, then the effective mask is zero.
+
+The
+.code set-iflags
+method sets, in the
+.code iflag
+member of the
+.meta termios
+structure, all of the bits which
+are set in the effective mask. That is to say,
+the effective mask is combined with the value in
+.code iflag
+by a
+.code logior
+operation, and the result is stored back into
+.codn iflag .
+Similarly, the
+.codn set-oflags ,
+.code set-cflags
+and
+.code set-lflags
+methods operate on the
+.codn oflag ,
+.code cflag
+and
+.code lflag
+slots of the structure.
+
+The
+.code clear-iflags
+method clears, in the
+.code iflag
+member of the
+.meta termios
+structure, all of the bits which are
+set in the effective mask. That is to say,
+the effective mask is bitwise inverted as if
+by the
+.code lognot
+function, and then combined with the
+existing value of the
+.code iflag
+slot using
+.codn logand .
+The resulting value is stored back into the
+.code iflag
+slot.
+Similarly, the
+.codn clear-oflags ,
+.code clear-cflags
+and
+.code clear-lflags
+methods operate on the
+.codn oflag ,
+.code cflag
+and
+.code lflag
+slots of the structure.
+
+Note: the methods
+.codn go-raw ,
+.code go-cbreak
+and
+.code go-canon
+are provided for changing the settings to raw, "cbreak" and canonical mode.
+These methods should be preferred to directly manipulating the flag and
+.code cc
+slots.
+
+.TP* Example
+
+In this example,
+.code tio
+is assumed to be a variable holding an instance of a
+.code termios
+struct:
+
+.cblk
+ ;; clear the ignbrk, brkint, and various other flags:
+ tio.(clear-iflags ignbrk brkint parmrk istrip inlcr igncr icrnl ixon)
+
+ ;; set the csize and parenb flags:
+ tio.(set-cflags csize parenb)
+.cble
+
+.coNP Methods @ go-raw and @ go-cbreak
+.synb
+.mets << termios .(go-raw)
+.mets << termios .(go-cbreak)
+.syne
+.desc
+The
+.code go-raw
+and
+.code go-cbreak
+methods of the
+.code termios
+structure manipulate the flag slots, as well as certain elements
+of the
+.code cc
+slot, in order to prepare the terminal settings for, respectively,
+"raw" and "cbreak" mode, described below.
+
+Note that manipulating the
+.code termios
+structure doesn't actually put these settings into effect in
+the terminal device; the settings represented by the structure must
+be installed into the device using
+.codn tcsetattr .
+There is no way to reverse the effect of these methods.
+To precisely restore the previous terminal settings, the program
+should retain a copy of the original
+.code termios
+structure.
+
+"Raw" mode refers to a configuration of the terminal device driver in which input
+and output is passed transparently and without accumulation, conversion or
+interpretation. Input isn't buffered into lines; as soon as a single byte is
+received, it is available to the program. No special input characters such as
+commands for generating an interrupt or process suspend request are processed
+by the terminal driver; all characters are treated as input data. Input isn't
+echoed; the only output which takes place is that generated by program
+output requests to the device.
+
+"Cbreak" mode is named after a concept and function in the "curses" terminal
+control library. It refers to a configuration of the terminal device driver
+which is less transparent than "raw" mode. Input isn't buffered into lines,
+and line editing commands are ordinary input characters, allowing
+character-at-a-time input. However, most input translations are preserved,
+except that the conversion of CR characters to NL is disabled. The
+signal-generating characters are processed in this mode. This latter feature of
+the configuration is the likely inspiration for the word "cbreak". Unless
+otherwise configured, the interrupt character corresponds to the Ctrl-C key,
+and "break" is another term for an interactive interruption.
+
+.coNP Methods @ string-encode and @ string-decode
+.synb
+.mets << termios .(string-encode)
+.mets << termios .(string-decode << string )
+.syne
+.desc
+The
+.code string-encode
+method converts the terminal state stored in a
+.code termios
+structure into a textual format, returning that representation
+as a character string.
+
+The
+.code string-decode
+method parses the character representation produced by
+.code string-encode
+and populates the
+.meta termios
+structure with the settings are encoded in that string.
+
+If a string is passed to
+.code string-decode
+which wasn't produced by
+.codn string-encode ,
+the behavior is unspecified. An exception may or may not be
+thrown, and the contents of
+.meta termios
+may or may not be affected.
+
+Note: the textual representation produced by
+.code string-encode
+is intended to be identical to that produced by the
+.code -g
+option of the GNU Coreutils version of the
+.code stty
+utility, on the same platform. That is to say, the output of
+.code "stty -g"
+may be used as input into
+.codn string-decode ,
+and the output of
+.code string-encode
+may be used as an argument to
+.codn stty .
+
.SS* Web Programming Support
.coNP Functions @ url-encode and @ url-decode