--- 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..c65748a --- /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("strtoll %s: invalid\n", numstr); + else if ((ll == LLONG_MIN && errno == ERANGE) || ll < minval) + eprintf("strtoll %s: too small\n", numstr); + else if ((ll == LLONG_MAX && errno == ERANGE) || ll > maxval) + eprintf("strtoll %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.4Received on Mon Mar 28 2016 - 18:52:07 CEST
This archive was generated by hypermail 2.3.0 : Mon Mar 28 2016 - 19:00:21 CEST