---
Makefile | 1 +
TODO | 1 +
stty.c | 762 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 764 insertions(+)
create mode 100644 stty.c
diff --git a/Makefile b/Makefile
index 59616a4..dc85510 100644
--- a/Makefile
+++ b/Makefile
_AT_@ -74,6 +74,7 @@ BIN = \
respawn \
rmmod \
stat \
+ stty \
su \
swaplabel \
swapoff \
diff --git a/TODO b/TODO
index 3e89e68..3f273b2 100644
--- a/TODO
+++ b/TODO
_AT_@ -24,6 +24,7 @@ rfkill
rmgroup
rmuser
setcap
+stty manpage
tabs
taskset
top
diff --git a/stty.c b/stty.c
new file mode 100644
index 0000000..4f38256
--- /dev/null
+++ b/stty.c
_AT_@ -0,0 +1,762 @@
+/* See LICENSE file for copyright and license details. */
+#include <ctype.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+#include <unistd.h>
+
+#include "util.h"
+
+/*
+ * Petty POSIX violations:
+ *
+ * - XBD 12.2 is not honoured precisely. This is for
+ * convenience and compatibility with other implementations.
+ */
+
+#define CC_MAX 255
+
+static int output_size_requested = 0;
+static int output_speed_requested = 0;
+static int drain_requested = 1;
+
+static void sane(int, struct termios *);
+static void setwinsize(long, long);
+static void ispeed(char *, struct termios *);
+static void ospeed(char *, struct termios *);
+
+static void
+raw(int unset, struct termios *m)
+{
+ if (!unset) {
+ m->c_iflag = 0;
+ m->c_lflag &= ~XCASE;
+ m->c_cc[VMIN] = 1;
+ m->c_cc[VTIME] = 0;
+ } else {
+ m->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
+ }
+}
+
+static void
+evenp(int unset, struct termios *m)
+{
+ m->c_oflag &= ~CSIZE;
+ m->c_oflag &= ~(unset ? PARENB : PARODD);
+ m->c_oflag |= unset ? CS8 : (CS7 | PARENB);
+}
+
+
+static void
+dec(int unset, struct termios *m)
+{
+ m->c_cc[VINTR] = CINTR;
+ m->c_cc[VKILL] = CKILL;
+ m->c_cc[VERASE] = CERASE;
+ (void) unset;
+}
+
+static void
+ek(int unset, struct termios *m)
+{
+ m->c_cc[VKILL] = CKILL;
+ m->c_cc[VERASE] = CERASE;
+ (void) unset;
+}
+
+static void
+nl(int unset, struct termios *m)
+{
+ if (unset) {
+ m->c_iflag &= ~(INLCR | IGNCR);
+ m->c_oflag &= ~(OCRNL | ONLRET);
+ }
+}
+
+static void
+oddp(int unset, struct termios *m)
+{
+ m->c_oflag &= ~CSIZE;
+ m->c_oflag &= ~(unset ? PARENB : 0);
+ m->c_oflag |= unset ? CS8 : (CS7 | PARODD | PARENB);
+}
+
+static void drain(int unset, struct termios *m) { drain_requested = !unset; (void) m; }
+static void cooked(int unset, struct termios *m) { raw(!unset, m); }
+static void pass8(int unset, struct termios *m) { m->c_cflag &= ~CSIZE, m->c_cflag |= unset ? CS7 : CS8; }
+static void size(int unset, struct termios *m) { output_size_requested = 1; (void) m; (void) unset; }
+static void speed(int unset, struct termios *m) { output_speed_requested = 1; (void) m; (void) unset; }
+static void tabs(int unset, struct termios *m) { m->c_oflag &= ~TABDLY, m->c_oflag |= unset ? TAB3 : TAB0; }
+static void cols(char *arg, struct termios *m) { setwinsize(-1, estrtonum(arg, 0, USHRT_MAX)); (void) m; }
+static void line(char *arg, struct termios *m) { m->c_line = estrtonum(arg, 0, 255); }
+static void min(char *arg, struct termios *m) { m->c_cc[VMIN] = estrtonum(arg, 0, CC_MAX); }
+static void rows(char *arg, struct termios *m) { setwinsize(estrtonum(arg, 0, USHRT_MAX), -1); (void) m; }
+static void stime(char *arg, struct termios *m) { m->c_cc[VTIME] = estrtonum(arg, 0, CC_MAX); }
+
+enum type { CTRL, IN, OUT, LOCAL, COMB, SPEC };
+enum {
+ BOOL = 1,
+ DUP = 2,
+ SANE = 4,
+ INSANE = 8,
+ CBREAK = 16,
+ DECCTLQ = 32,
+ LCASE = 64,
+ PASS8 = 128,
+ LITOUT = 256,
+ CRT = 1024,
+ DEC = 2048,
+ NL = 4096,
+ COOKED = 8192
+};
+
+struct mode {
+ const char *op;
+ enum type type;
+ tcflag_t set;
+ tcflag_t clear;
+ void (*fun)(int, struct termios *);
+ int flags;
+};
+
+struct key {
+ const char *op;
+ size_t index;
+ cc_t sanevalue;
+};
+
+struct intvalued {
+ const char *op;
+ void (*fun)(char *, struct termios *);
+};
+
+struct speed {
+ const char *str;
+ speed_t speed;
+};
+
+static const struct mode modes[] = {
+ {"clocal", CTRL, CLOCAL, 0, 0, BOOL},
+ {"cmspar", CTRL, CMSPAR, 0, 0, BOOL},
+ {"cread", CTRL, CREAD, 0, 0, BOOL | SANE},
+ {"crtscts", CTRL, CRTSCTS, 0, 0, BOOL},
+ {"cs5", CTRL, CS5, CSIZE, 0, 0},
+ {"cs6", CTRL, CS6, CSIZE, 0, 0},
+ {"cs7", CTRL, CS7, CSIZE, 0, 0},
+ {"cs8", CTRL, CS8, CSIZE, 0, 0},
+ {"cstopb", CTRL, CSTOPB, 0, 0, BOOL},
+ {"hup", CTRL, HUPCL, 0, 0, BOOL | DUP},
+ {"hupcl", CTRL, HUPCL, 0, 0, BOOL},
+ {"parenb", CTRL, PARENB, 0, 0, BOOL | PASS8 | LITOUT},
+ {"parodd", CTRL, PARODD, 0, 0, BOOL},
+
+ {"brkint", IN, BRKINT, 0, 0, BOOL | SANE},
+ {"icrnl", IN, ICRNL, 0, 0, BOOL | SANE | NL},
+ {"ignbrk", IN, IGNBRK, 0, 0, BOOL | INSANE},
+ {"igncr", IN, IGNCR, 0, 0, BOOL | INSANE},
+ {"ignpar", IN, IGNPAR, 0, 0, BOOL},
+ {"imaxbel", IN, IMAXBEL, 0, 0, BOOL | SANE},
+ {"inlcr", IN, INLCR, 0, 0, BOOL | INSANE},
+ {"inpck", IN, INPCK, 0, 0, BOOL},
+ {"istrip", IN, ISTRIP, 0, 0, BOOL | PASS8 | LITOUT},
+ {"iuclc", IN, IUCLC, 0, 0, BOOL | INSANE | LCASE},
+ {"iutf8", IN, IUTF8, 0, 0, BOOL | SANE},
+ {"ixany", IN, IXANY, 0, 0, BOOL | INSANE | DECCTLQ},
+ {"ixoff", IN, IXOFF, 0, 0, BOOL | INSANE},
+ {"ixon", IN, IXON, 0, 0, BOOL},
+ {"parmrk", IN, PARMRK, 0, 0, BOOL},
+ {"tandem", IN, IXOFF, 0, 0, BOOL | DUP},
+
+ {"bs0", OUT, BS0, BSDLY, 0, SANE},
+ {"bs1", OUT, BS1, BSDLY, 0, INSANE},
+ {"cr0", OUT, CR0, CRDLY, 0, SANE},
+ {"cr1", OUT, CR1, CRDLY, 0, INSANE},
+ {"cr2", OUT, CR2, CRDLY, 0, INSANE},
+ {"cr3", OUT, CR3, CRDLY, 0, INSANE},
+ {"ff0", OUT, FF0, FFDLY, 0, SANE},
+ {"ff1", OUT, FF1, FFDLY, 0, INSANE},
+ {"nl0", OUT, NL0, NLDLY, 0, SANE},
+ {"nl1", OUT, NL1, NLDLY, 0, INSANE},
+ {"ocrnl", OUT, OCRNL, 0, 0, BOOL | INSANE},
+ {"ofdel", OUT, OFDEL, 0, 0, BOOL | INSANE},
+ {"ofill", OUT, OFILL, 0, 0, BOOL | INSANE},
+ {"olcuc", OUT, OLCUC, 0, 0, BOOL | INSANE | LCASE},
+ {"onlcr", OUT, ONLCR, 0, 0, BOOL | SANE | NL},
+ {"onlret", OUT, ONLRET, 0, 0, BOOL | INSANE},
+ {"onocr", OUT, ONOCR, 0, 0, BOOL | INSANE},
+ {"opost", OUT, OPOST, 0, 0, BOOL | SANE | LITOUT | COOKED},
+ {"tab0", OUT, TAB0, TABDLY, 0, SANE},
+ {"tab1", OUT, TAB1, TABDLY, 0, INSANE},
+ {"tab2", OUT, TAB2, TABDLY, 0, INSANE},
+ {"tab3", OUT, TAB3, TABDLY, 0, INSANE},
+ {"vt0", OUT, VT0, VTDLY, 0, SANE},
+ {"vt1", OUT, VT1, VTDLY, 0, INSANE},
+
+ {"crterase", LOCAL, ECHOE, 0, 0, BOOL | DUP},
+ {"crtkill", LOCAL, ECHOKE, 0, 0, BOOL | DUP},
+ {"ctlecho", LOCAL, ECHOCTL, 0, 0, BOOL | DUP},
+ {"echo", LOCAL, ECHO, 0, 0, BOOL | SANE},
+ {"echoctl", LOCAL, ECHOCTL, 0, 0, BOOL | SANE | CRT | DEC},
+ {"echoe", LOCAL, ECHOE, 0, 0, BOOL | SANE | CRT | DEC},
+ {"echok", LOCAL, ECHOK, 0, 0, BOOL | SANE},
+ {"echoke", LOCAL, ECHOKE, 0, 0, BOOL | SANE | CRT | DEC},
+ {"echonl", LOCAL, ECHONL, 0, 0, BOOL | INSANE},
+ {"echoprt", LOCAL, ECHOPRT, 0, 0, BOOL | INSANE},
+ {"extproc", LOCAL, EXTPROC, 0, 0, BOOL | INSANE},
+ {"flusho", LOCAL, FLUSHO, 0, 0, BOOL | INSANE},
+ {"icanon", LOCAL, ICANON, 0, 0, BOOL | SANE | CBREAK | COOKED},
+ {"iexten", LOCAL, IEXTEN, 0, 0, BOOL | SANE},
+ {"isig", LOCAL, ISIG, 0, 0, BOOL | SANE | COOKED},
+ {"noflsh", LOCAL, NOFLSH, 0, 0, BOOL | INSANE},
+ {"prterase", LOCAL, ECHOPRT, 0, 0, BOOL | DUP},
+ {"tostop", LOCAL, TOSTOP, 0, 0, BOOL | INSANE},
+ {"xcase", LOCAL, XCASE, 0, 0, BOOL | INSANE | LCASE},
+
+ {"cbreak", COMB, 0, CBREAK, 0, BOOL | DUP},
+ {"cooked", COMB, COOKED, 0, cooked, BOOL | DUP},
+ {"crt", COMB, CRT, 0, 0, DUP},
+ {"dec", COMB, DEC, DECCTLQ, dec, DUP},
+ {"decctlq", COMB, 0, DECCTLQ, 0, BOOL | DUP},
+ {"ek", COMB, 0, 0, ek, DUP},
+ {"evenp", COMB, 0, 0, evenp, BOOL | DUP},
+ {"LCASE", COMB, LCASE, 0, 0, BOOL | DUP},
+ {"lcase", COMB, LCASE, 0, 0, BOOL | DUP},
+ {"litout", COMB, 0, LITOUT, pass8, BOOL | DUP},
+ {"nl", COMB, 0, NL, nl, BOOL | DUP},
+ {"oddp", COMB, 0, 0, oddp, BOOL | DUP},
+ {"parity", COMB, 0, 0, evenp, BOOL | DUP},
+ {"pass8", COMB, 0, PASS8, pass8, BOOL | DUP},
+ {"raw", COMB, 0, COOKED, raw, BOOL | DUP},
+ {"sane", COMB, SANE, INSANE, sane, DUP},
+ {"tabs", COMB, 0, 0, tabs, BOOL | DUP},
+
+ {"size", SPEC, 0, 0, size, DUP},
+ {"speed", SPEC, 0, 0, speed, DUP},
+ {"drain", SPEC, 0, 0, drain, BOOL | DUP},
+
+ {0, 0, 0, 0, 0, 0}
+};
+
+static const struct key keys[] = {
+ {"discard", VDISCARD, CDISCARD},
+ {"eof", VEOF, CEOF},
+ {"eol", VEOL, CEOL},
+ {"eol2", VEOL2, _POSIX_VDISABLE},
+ {"erase", VERASE, CERASE},
+ {"intr", VINTR, CINTR},
+ {"kill", VKILL, CKILL},
+ {"lnext", VLNEXT, CLNEXT},
+ {"quit", VQUIT, CQUIT},
+ {"rprnt", VREPRINT, CRPRNT},
+ {"start", VSTART, CSTART},
+ {"stop", VSTOP, CSTOP},
+ {"susp", VSUSP, CSUSP},
+ {"swtch", VSWTC, _POSIX_VDISABLE},
+ {"werase", VWERASE, CWERASE},
+ {0, 0, 0}
+};
+
+static const struct intvalued ints[] = {
+ {"cols", cols},
+ {"columns", cols},
+ {"line", line},
+ {"min", min},
+ {"rows", rows},
+ {"time", stime},
+ {"ispeed", ispeed},
+ {"ospeed", ospeed},
+ {0, 0}
+};
+
+#define B(baud) {#baud, B##baud}
+static const struct speed speeds[] = {
+ B(0), B(50), B(75), B(110), B(134), B(150), B(200), B(300),
+ B(600), B(1200), B(1800), B(2400), B(4800), B(9600), B(19200), B(38400),
+ B(57600), B(115200), B(230400), B(460800), B(500000), B(576000), B(921600), B(1000000),
+ B(1152000), B(1500000), B(2000000), B(2500000), B(3000000), B(3500000), B(4000000),
+ {"134.5", B134},
+ {"exta", B19200},
+ {"extb", B38400},
+ {0, 0}
+};
+#undef B
+
+static void
+sane(int unset, struct termios *m)
+{
+ const struct key *op = keys;
+ for (; op->op; op++)
+ m->c_cc[op->index] = op->sanevalue;
+ m->c_cc[VMIN] = 1;
+ m->c_cc[VTIME] = 0;
+ (void) unset;
+}
+
+static int
+isxnumber(char* str)
+{
+ if (!*str)
+ return 0;
+ for (; *str; str++)
+ if (!isxdigit(*str))
+ return 0;
+ return 1;
+}
+
+static void
+decodehex(char *dest, char* src)
+{
+ while (*src) {
+ char hi = *src++;
+ char lo = *src++;
+ hi = (hi & 15) + 9 * !isdigit(hi);
+ lo = (lo & 15) + 9 * !isdigit(lo);
+ *dest++ = (hi << 4) | lo;
+ }
+}
+
+static void
+setwinsize(long y, long x)
+{
+ struct winsize winsize;
+ if (ioctl(STDIN_FILENO, TIOCGWINSZ, &winsize))
+ eprintf("TIOCGWINSZ <stdin>:");
+ if (y >= 0)
+ winsize.ws_row = y;
+ if (x >= 0)
+ winsize.ws_col = x;
+ if (ioctl(STDIN_FILENO, TIOCSWINSZ, &winsize))
+ eprintf("TIOCSWINSZ <stdin>:");
+}
+
+static void
+setoperand_mode(int unset, const struct mode *op, struct termios *mode)
+{
+ tcflag_t *bitsp = 0;
+
+ switch (op->type) {
+ case CTRL: bitsp = &mode->c_cflag; break;
+ case IN: bitsp = &mode->c_iflag; break;
+ case OUT: bitsp = &mode->c_oflag; break;
+ case LOCAL: bitsp = &mode->c_lflag; break;
+ case SPEC: break;
+ default: abort();
+ }
+
+ if (bitsp) {
+ *bitsp &= ~op->clear;
+ if (!unset)
+ *bitsp |= op->set;
+ else
+ *bitsp &= ~op->set;
+ }
+
+ if (op->fun)
+ op->fun(unset, mode);
+}
+
+static int
+parseoperand_mode(char *arg, struct termios *mode)
+{
+ const struct mode *op = modes;
+ const struct mode *op_proper;
+ int unset = *arg == '-';
+ int flags_set, flags_unset;
+
+ arg += unset;
+ while (op->op && strcmp(arg, op->op))
+ op++;
+ if (!op->op)
+ return -1;
+ if (unset && !(op->flags & BOOL))
+ return -1;
+
+ switch (op->type) {
+ case CTRL:
+ case IN:
+ case OUT:
+ case LOCAL:
+ case SPEC:
+ setoperand_mode(unset, op, mode);
+ return 0;
+ case COMB:
+ break;
+ default:
+ abort();
+ }
+
+ flags_set = (int)(op->set);
+ flags_unset = (int)(op->clear);
+ op_proper = op;
+
+ if (flags_unset || flags_set) {
+ for (op = modes; op->op; op++) {
+ if (op->type == COMB)
+ continue;
+ if (flags_unset && (op->flags & flags_unset))
+ setoperand_mode(!unset, op, mode);
+ if (flags_set && (op->flags & flags_set))
+ setoperand_mode(unset, op, mode);
+ }
+ }
+
+ if (op_proper->fun)
+ op_proper->fun(unset, mode);
+
+ return 0;
+}
+
+static long long
+estrtonum_radix(const char *numstr, long long minval, long long maxval, int radix)
+{
+ long long ll = 0;
+ char *ep;
+ errno = 0;
+ ll = strtoll(numstr, &ep, radix);
+ if (numstr == ep || *ep != '\0')
+ eprintf("estrtonum_radix %s: invalid\n", numstr);
+ else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval)
+ eprintf("estrtonum_radix %s: too small\n", numstr);
+ else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval)
+ eprintf("estrtonum_radix %s: too large\n", numstr);
+ return ll;
+}
+
+static int
+parseoperand_key(char *arg0, char *arg1, struct termios *mode)
+{
+ const struct key *op = keys;
+ cc_t value;
+
+ while (op->op && strcmp(arg0, op->op))
+ op++;
+ if (!op->op)
+ return -1;
+
+ if (!arg1)
+ eprintf("missing argument for operand: %s\n", arg0);
+
+ if (!strcmp(arg1, "^-") || !strcmp(arg1, "undef"))
+ value = _POSIX_VDISABLE;
+ else if (!strcmp(arg1, "^?"))
+ value = 127;
+ else if (!arg1[0] || !arg1[1])
+ value = arg1[0];
+ else if (arg1[0] == '^')
+ value = (cc_t)(arg1[1]) & ~0x60;
+ else if (strstr(arg1, "0x") == arg1)
+ value = estrtonum_radix(arg1 + 2, 0, CC_MAX, 16);
+ else if (arg1[0] == '0' && arg1[1])
+ value = estrtonum_radix(arg1 + 1, 0, CC_MAX, 8);
+ else
+ value = estrtonum_radix(arg1 + 0, 0, CC_MAX, 10);
+
+ mode->c_cc[op->index] = value;
+ return 0;
+}
+
+static int
+parseoperand_int(char *arg0, char *arg1, struct termios *mode)
+{
+ const struct intvalued *op = ints;
+
+ while (op->op && strcmp(arg0, op->op))
+ op++;
+ if (!op->op)
+ return -1;
+
+ if (!arg1)
+ eprintf("missing argument for operand: %s\n", arg0);
+
+ op->fun(arg1, mode);
+ return 0;
+}
+
+static const char *
+baudtostr(speed_t baud)
+{
+ const struct speed *speed = speeds;
+ while (speed->str && speed->speed != baud)
+ speed++;
+ return speed->str ? speed->str : "0";
+}
+
+static int
+parsespeed(char *arg, struct speed *ret)
+{
+ const struct speed *speed = speeds;
+ while (speed->str && strcmp(arg, speed->str))
+ speed++;
+ if (!speed->str)
+ return -1;
+ *ret = *speed;
+ return 0;
+}
+
+static void
+eparsespeed(char *arg, struct speed *ret)
+{
+ if (parsespeed(arg, ret))
+ eprintf("invalid speed parameter: %s\n", arg);
+}
+
+static void
+ispeed(char *arg, struct termios *m)
+{
+ struct speed speed;
+ eparsespeed(arg, &speed);
+ if (cfsetispeed(m, speed.speed))
+ eprintf("cfsetispeed %s:", speed.str);
+}
+
+static void
+ospeed(char *arg, struct termios *m)
+{
+ struct speed speed;
+ eparsespeed(arg, &speed);
+ if (cfsetospeed(m, speed.speed))
+ eprintf("cfsetospeed %s:", speed.str);
+}
+
+static void
+printtoken(const char *fmt, ...)
+{
+ static size_t width = 0;
+ static size_t pos = 0;
+ static char buf[BUFSIZ];
+ va_list ap;
+ int len;
+
+ if (!width) {
+ struct winsize winsize;
+ if (!ioctl(STDOUT_FILENO, TIOCGWINSZ, &winsize))
+ if (winsize.ws_col > 40)
+ width = winsize.ws_col;
+ if (!width)
+ width = SIZE_MAX;
+ }
+
+ if (!strcmp(fmt, "\n")) {
+ if (pos)
+ printf("\n");
+ pos = 0;
+ return;
+ }
+
+ va_start(ap, fmt);
+ len = vsnprintf(buf, sizeof(buf), fmt, ap);
+ va_end(ap);
+ if (len < 0 || (size_t)len >= sizeof(buf))
+ eprintf("vsnprintf:");
+
+ if (pos + !!pos + len > width) {
+ printf("\n");
+ pos = 0;
+ } else if (pos) {
+ printf(" ");
+ pos++;
+ }
+
+ printf("%s", buf);
+ pos += len;
+}
+
+static const char*
+keytostr(cc_t key)
+{
+ static char buf[5];
+ int r;
+ if (key == _POSIX_VDISABLE)
+ return "undef";
+ else if (key < (cc_t)' ')
+ r = snprintf(buf, sizeof(buf), "^%c", key + '_AT_');
+ else if (key < 127)
+ r = snprintf(buf, sizeof(buf), "%c", key);
+ else if (key == 127)
+ r = snprintf(buf, sizeof(buf), "^?");
+ else if (key < 128 + ' ')
+ r = snprintf(buf, sizeof(buf), "M-^%c", key - 128 + '_AT_');
+ else if (key == 128 + 127)
+ r = snprintf(buf, sizeof(buf), "M-^?");
+ else
+ r = snprintf(buf, sizeof(buf), "M-%c", key - 128);
+ if (r < 0 || (size_t)r >= sizeof(buf))
+ eprintf("snprintf:");
+ return buf;
+}
+
+static void
+displaysettings(struct termios *m, int all)
+{
+ const struct key *kbd = keys;
+ const struct mode *mod = modes;
+ struct winsize winsize;
+ speed_t in, out;
+ tcflag_t *bitsp, mask;
+
+ in = cfgetispeed(m);
+ out = cfgetospeed(m);
+ if (!in || in == out) {
+ if (all || out != B38400)
+ printtoken("speed %s baud;", baudtostr(out));
+ } else {
+ printtoken("ispeed %s baud;", baudtostr(in));
+ printtoken("ospeed %s baud;", baudtostr(out));
+ }
+
+ if (all) {
+ if (ioctl(STDIN_FILENO, TIOCGWINSZ, &winsize))
+ eprintf("TIOCGWINSZ <stdin>:");
+ printtoken("rows %u;", winsize.ws_row);
+ printtoken("columns %u;", winsize.ws_col);
+ }
+ printtoken("\n");
+
+ if (all || m->c_line != 0)
+ printtoken("line = %u;", (unsigned long)(m->c_line));
+ if (all || (m->c_cc[VMIN] != 1 && !(m->c_lflag & ICANON)))
+ printtoken("min = %u;", (unsigned long)(m->c_cc[VMIN]));
+ if (all || (m->c_cc[VTIME] != 0 && !(m->c_lflag & ICANON)))
+ printtoken("time = %u;", (unsigned long)(m->c_cc[VTIME]));
+ printtoken("\n");
+
+ for (; kbd->op; kbd++)
+ if (all || m->c_cc[kbd->index] != kbd->sanevalue)
+ printtoken("%s = %s;", kbd->op, keytostr(m->c_cc[kbd->index]));
+ printtoken("\n");
+
+ for (; mod->op; mod++) {
+ switch (mod->type) {
+ case CTRL: bitsp = &m->c_cflag; break;
+ case IN: bitsp = &m->c_iflag; break;
+ case OUT: bitsp = &m->c_oflag; break;
+ case LOCAL: bitsp = &m->c_lflag; break;
+ default: bitsp = 0; break;
+ }
+ if (!bitsp || (mod->flags & DUP))
+ continue;
+ mask = mod->clear ? mod->clear : mod->set;
+ if ((*bitsp & mask) == mod->set) {
+ if (all || (mod->flags & INSANE) || !(mod->flags & SANE))
+ printtoken("%s", mod->op);
+ }
+ else if (mod->flags & BOOL) {
+ if (all || (mod->flags & SANE) || !(mod->flags & INSANE))
+ printtoken("-%s", mod->op);
+ }
+ }
+ printtoken("\n");
+}
+
+static void
+usage(void)
+{
+ eprintf("usage: %s [-a | -g] [operand ...]\n", argv0);
+}
+
+int
+main(int argc, char *argv[])
+{
+ struct termios mode;
+ struct termios mode2;
+ struct winsize winsize;
+ struct speed speed;
+ int aflag = 0;
+ int gflag = 0;
+ size_t n;
+ unsigned char *buf;
+ char *p;
+ speed_t in, out;
+
+ for (argv0 = *argv++, argc--; argc; argv++, argc--) {
+ if (!strcmp(*argv, "-ag") || !strcmp(*argv, "-ga")) {
+ aflag = gflag = 1;
+ } else if (!strcmp(*argv, "-g")) {
+ gflag = 1;
+ } else if (!strcmp(*argv, "-a")) {
+ aflag = 1;
+ } else if (!strcmp(*argv, "--")) {
+ argv++, argc--;
+ break;
+ } else {
+ break;
+ }
+ }
+
+ if (aflag && gflag)
+ usage();
+
+ memset(&mode, 0, sizeof(mode));
+ if (tcgetattr(STDIN_FILENO, &mode))
+ eprintf("tcgetattr <stdin>:");
+ memcpy(&mode2, &mode, sizeof(mode));
+
+ for (; *argv; argv++) {
+ if (**argv == '=') {
+ p = *argv + 1;
+ if (strlen(p) != sizeof(mode) * 2 || !isxnumber(p))
+ goto invalid;
+ decodehex((char *)&mode, p);
+ } else if (!parseoperand_mode(*argv, &mode)) {
+ /* do nothing. */
+ } else if (!parseoperand_key(argv[0], argv[1], &mode)) {
+ argv++;
+ } else if (!parseoperand_int(argv[0], argv[1], &mode)) {
+ argv++;
+ } else if (!parsespeed(*argv, &speed)) {
+ if (cfsetispeed(&mode, speed.speed))
+ eprintf("cfsetispeed %s:", speed.str);
+ if (cfsetospeed(&mode, speed.speed))
+ eprintf("cfsetospeed %s:", speed.str);
+ } else {
+ goto invalid;
+ }
+ }
+
+ if (memcmp(&mode, &mode2, sizeof(mode))) {
+ memset(&mode2, 0, sizeof(mode2));
+ if (tcsetattr(STDIN_FILENO, drain_requested ? TCSADRAIN : TCSANOW, &mode))
+ eprintf("tcsetattr <stdin>:");
+ if (tcgetattr(STDIN_FILENO, &mode2))
+ eprintf("tcgetattr <stdin>:");
+ if (memcmp(&mode, &mode2, sizeof(mode)))
+ eprintf("tcsetattr <stdin>: unable to apply all operands\n");
+ }
+
+ if (gflag) {
+ buf = (unsigned char *)&mode;
+ printf("=");
+ for (n = sizeof(mode); n--; buf++)
+ printf("%02x", *buf);
+ printf("\n");
+ }
+
+ if (output_size_requested) {
+ if (ioctl(STDIN_FILENO, TIOCGWINSZ, &winsize))
+ eprintf("TIOCGWINSZ <stdin>:");
+ printf("%u %u\n", winsize.ws_row, winsize.ws_col);
+ }
+
+ if (output_speed_requested) {
+ in = cfgetispeed(&mode);
+ out = cfgetospeed(&mode);
+ if (!in || in == out)
+ printf("%s\n", baudtostr(out));
+ else
+ printf("%s %s\n", baudtostr(in), baudtostr(out));
+ }
+
+ if ((aflag || !argc) && !gflag)
+ displaysettings(&mode, aflag);
+
+ return 0;
+
+invalid:
+ eprintf("invalid operand: %s\n", *argv);
+}
--
2.7.4
Received on Mon Mar 28 2016 - 18:49:53 CEST
This archive was generated by hypermail 2.3.0 : Mon Mar 28 2016 - 19:00:18 CEST