10f66f451Sopenharmony_ci/* stty.c - Get/set terminal configuration.
20f66f451Sopenharmony_ci *
30f66f451Sopenharmony_ci * Copyright 2017 The Android Open Source Project.
40f66f451Sopenharmony_ci *
50f66f451Sopenharmony_ci * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/stty.html
60f66f451Sopenharmony_ci
70f66f451Sopenharmony_ciUSE_STTY(NEWTOY(stty, "?aF:g[!ag]", TOYFLAG_BIN))
80f66f451Sopenharmony_ci
90f66f451Sopenharmony_ciconfig STTY
100f66f451Sopenharmony_ci  bool "stty"
110f66f451Sopenharmony_ci  default n
120f66f451Sopenharmony_ci  help
130f66f451Sopenharmony_ci    usage: stty [-ag] [-F device] SETTING...
140f66f451Sopenharmony_ci
150f66f451Sopenharmony_ci    Get/set terminal configuration.
160f66f451Sopenharmony_ci
170f66f451Sopenharmony_ci    -F	Open device instead of stdin
180f66f451Sopenharmony_ci    -a	Show all current settings (default differences from "sane")
190f66f451Sopenharmony_ci    -g	Show all current settings usable as input to stty
200f66f451Sopenharmony_ci
210f66f451Sopenharmony_ci    Special characters (syntax ^c or undef): intr quit erase kill eof eol eol2
220f66f451Sopenharmony_ci    swtch start stop susp rprnt werase lnext discard
230f66f451Sopenharmony_ci
240f66f451Sopenharmony_ci    Control/input/output/local settings as shown by -a, '-' prefix to disable
250f66f451Sopenharmony_ci
260f66f451Sopenharmony_ci    Combo settings: cooked/raw, evenp/oddp/parity, nl, ek, sane
270f66f451Sopenharmony_ci
280f66f451Sopenharmony_ci    N	set input and output speed (ispeed N or ospeed N for just one)
290f66f451Sopenharmony_ci    cols N	set number of columns
300f66f451Sopenharmony_ci    rows N	set number of rows
310f66f451Sopenharmony_ci    line N	set line discipline
320f66f451Sopenharmony_ci    min N	set minimum chars per read
330f66f451Sopenharmony_ci    time N	set read timeout
340f66f451Sopenharmony_ci    speed	show speed only
350f66f451Sopenharmony_ci    size	show size only
360f66f451Sopenharmony_ci*/
370f66f451Sopenharmony_ci
380f66f451Sopenharmony_ci#define FOR_stty
390f66f451Sopenharmony_ci#include "toys.h"
400f66f451Sopenharmony_ci
410f66f451Sopenharmony_ci#include <linux/tty.h>
420f66f451Sopenharmony_ci
430f66f451Sopenharmony_ciGLOBALS(
440f66f451Sopenharmony_ci  char *device;
450f66f451Sopenharmony_ci
460f66f451Sopenharmony_ci  int fd, col;
470f66f451Sopenharmony_ci  unsigned output_cols;
480f66f451Sopenharmony_ci)
490f66f451Sopenharmony_ci
500f66f451Sopenharmony_cistatic const int bauds[] = {
510f66f451Sopenharmony_ci  0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600,
520f66f451Sopenharmony_ci  19200, 38400, 57600, 115200, 230400, 460800, 500000, 576000, 921600,
530f66f451Sopenharmony_ci  1000000, 1152000, 1500000, 2000000, 2500000, 3000000, 3500000, 4000000
540f66f451Sopenharmony_ci};
550f66f451Sopenharmony_ci
560f66f451Sopenharmony_cistatic int baud(speed_t speed)
570f66f451Sopenharmony_ci{
580f66f451Sopenharmony_ci  if (speed&CBAUDEX) speed=(speed&~CBAUDEX)+15;
590f66f451Sopenharmony_ci  return bauds[speed];
600f66f451Sopenharmony_ci}
610f66f451Sopenharmony_ci
620f66f451Sopenharmony_cistatic speed_t speed(int baud)
630f66f451Sopenharmony_ci{
640f66f451Sopenharmony_ci  int i;
650f66f451Sopenharmony_ci
660f66f451Sopenharmony_ci  for (i=0;i<ARRAY_LEN(bauds);i++) if (bauds[i] == baud) break;
670f66f451Sopenharmony_ci  if (i == ARRAY_LEN(bauds)) error_exit("unknown speed: %d", baud);
680f66f451Sopenharmony_ci  return i+4081*(i>16);
690f66f451Sopenharmony_ci}
700f66f451Sopenharmony_ci
710f66f451Sopenharmony_cistruct flag {
720f66f451Sopenharmony_ci  char *name;
730f66f451Sopenharmony_ci  int value;
740f66f451Sopenharmony_ci  int mask;
750f66f451Sopenharmony_ci};
760f66f451Sopenharmony_ci
770f66f451Sopenharmony_cistatic const struct flag chars[] = {
780f66f451Sopenharmony_ci  { "intr", VINTR }, { "quit", VQUIT }, { "erase", VERASE }, { "kill", VKILL },
790f66f451Sopenharmony_ci  { "eof", VEOF }, { "eol", VEOL }, { "eol2", VEOL2 }, { "swtch", VSWTC },
800f66f451Sopenharmony_ci  { "start", VSTART }, { "stop", VSTOP }, { "susp", VSUSP },
810f66f451Sopenharmony_ci  { "rprnt", VREPRINT }, { "werase", VWERASE }, { "lnext", VLNEXT },
820f66f451Sopenharmony_ci  { "discard", VDISCARD }, { "min", VMIN }, { "time", VTIME },
830f66f451Sopenharmony_ci};
840f66f451Sopenharmony_ci
850f66f451Sopenharmony_cistatic const struct flag cflags[] = {
860f66f451Sopenharmony_ci  { "parenb", PARENB }, { "parodd", PARODD }, { "cmspar", CMSPAR },
870f66f451Sopenharmony_ci  { "cs5", CS5, CSIZE }, { "cs6", CS6, CSIZE }, { "cs7", CS7, CSIZE },
880f66f451Sopenharmony_ci  { "cs8", CS8, CSIZE }, { "hupcl", HUPCL }, { "cstopb", CSTOPB },
890f66f451Sopenharmony_ci  { "cread", CREAD }, { "clocal", CLOCAL }, { "crtscts", CRTSCTS },
900f66f451Sopenharmony_ci};
910f66f451Sopenharmony_ci
920f66f451Sopenharmony_cistatic const struct flag iflags[] = {
930f66f451Sopenharmony_ci  { "ignbrk", IGNBRK }, { "brkint", BRKINT }, { "ignpar", IGNPAR },
940f66f451Sopenharmony_ci  { "parmrk", PARMRK }, { "inpck", INPCK }, { "istrip", ISTRIP },
950f66f451Sopenharmony_ci  { "inlcr", INLCR }, { "igncr", IGNCR }, { "icrnl", ICRNL }, { "ixon", IXON },
960f66f451Sopenharmony_ci  { "ixoff", IXOFF }, { "iuclc", IUCLC }, { "ixany", IXANY },
970f66f451Sopenharmony_ci  { "imaxbel", IMAXBEL }, { "iutf8", IUTF8 },
980f66f451Sopenharmony_ci};
990f66f451Sopenharmony_ci
1000f66f451Sopenharmony_cistatic const struct flag oflags[] = {
1010f66f451Sopenharmony_ci  { "opost", OPOST }, { "olcuc", OLCUC }, { "ocrnl", OCRNL },
1020f66f451Sopenharmony_ci  { "onlcr", ONLCR }, { "onocr", ONOCR }, { "onlret", ONLRET },
1030f66f451Sopenharmony_ci  { "ofill", OFILL }, { "ofdel", OFDEL }, { "nl0", NL0, NLDLY },
1040f66f451Sopenharmony_ci  { "nl1", NL1, NLDLY }, { "cr0", CR0, CRDLY }, { "cr1", CR1, CRDLY },
1050f66f451Sopenharmony_ci  { "cr2", CR2, CRDLY }, { "cr3", CR3, CRDLY }, { "tab0", TAB0, TABDLY },
1060f66f451Sopenharmony_ci  { "tab1", TAB1, TABDLY }, { "tab2", TAB2, TABDLY }, { "tab3", TAB3, TABDLY },
1070f66f451Sopenharmony_ci  { "bs0", BS0, BSDLY }, { "bs1", BS1, BSDLY }, { "vt0", VT0, VTDLY },
1080f66f451Sopenharmony_ci  { "vt1", VT1, VTDLY }, { "ff0", FF0, FFDLY }, { "ff1", FF1, FFDLY },
1090f66f451Sopenharmony_ci};
1100f66f451Sopenharmony_ci
1110f66f451Sopenharmony_cistatic const struct flag lflags[] = {
1120f66f451Sopenharmony_ci  { "isig", ISIG }, { "icanon", ICANON }, { "iexten", IEXTEN },
1130f66f451Sopenharmony_ci  { "echo", ECHO }, { "echoe", ECHOE }, { "echok", ECHOK },
1140f66f451Sopenharmony_ci  { "echonl", ECHONL }, { "noflsh", NOFLSH }, { "xcase", XCASE },
1150f66f451Sopenharmony_ci  { "tostop", TOSTOP }, { "echoprt", ECHOPRT }, { "echoctl", ECHOCTL },
1160f66f451Sopenharmony_ci  { "echoke", ECHOKE }, { "flusho", FLUSHO }, { "extproc", EXTPROC },
1170f66f451Sopenharmony_ci};
1180f66f451Sopenharmony_ci
1190f66f451Sopenharmony_cistatic const struct synonym {
1200f66f451Sopenharmony_ci  char *from;
1210f66f451Sopenharmony_ci  char *to;
1220f66f451Sopenharmony_ci} synonyms[] = {
1230f66f451Sopenharmony_ci  { "cbreak", "-icanon" }, { "-cbreak", "icanon" }, { "-cooked", "raw" },
1240f66f451Sopenharmony_ci  { "crterase", "echoe" }, { "-crterase", "-echoe" }, { "crtkill", "echoke" },
1250f66f451Sopenharmony_ci  { "-crtkill", "-echoke" }, { "ctlecho", "echoctl" }, { "-tandem", "-ixoff" },
1260f66f451Sopenharmony_ci  { "-ctlecho", "-echoctl" }, { "hup", "hupcl" }, { "-hup", "-hupcl" },
1270f66f451Sopenharmony_ci  { "prterase", "echoprt" }, { "-prterase", "-echoprt" }, { "-raw", "cooked" },
1280f66f451Sopenharmony_ci  { "tabs", "tab0" }, { "-tabs", "tab3" }, { "tandem", "ixoff" },
1290f66f451Sopenharmony_ci};
1300f66f451Sopenharmony_ci
1310f66f451Sopenharmony_cistatic void out(const char *fmt, ...)
1320f66f451Sopenharmony_ci{
1330f66f451Sopenharmony_ci  va_list va;
1340f66f451Sopenharmony_ci  int len;
1350f66f451Sopenharmony_ci  char *prefix = " ";
1360f66f451Sopenharmony_ci
1370f66f451Sopenharmony_ci  va_start(va, fmt);
1380f66f451Sopenharmony_ci  len = vsnprintf(toybuf, sizeof(toybuf), fmt, va);
1390f66f451Sopenharmony_ci  va_end(va);
1400f66f451Sopenharmony_ci
1410f66f451Sopenharmony_ci  if (TT.output_cols == 0) {
1420f66f451Sopenharmony_ci    TT.output_cols = 80;
1430f66f451Sopenharmony_ci    terminal_size(&TT.output_cols, NULL);
1440f66f451Sopenharmony_ci  }
1450f66f451Sopenharmony_ci
1460f66f451Sopenharmony_ci  if (TT.col == 0 || *fmt == '\n') prefix = "";
1470f66f451Sopenharmony_ci  else if (TT.col + 1 + len >= TT.output_cols) {
1480f66f451Sopenharmony_ci    prefix = "\n";
1490f66f451Sopenharmony_ci    TT.col = 0;
1500f66f451Sopenharmony_ci  }
1510f66f451Sopenharmony_ci  xprintf("%s%s", prefix, toybuf);
1520f66f451Sopenharmony_ci
1530f66f451Sopenharmony_ci  if (toybuf[len-1] == '\n') TT.col = 0;
1540f66f451Sopenharmony_ci  else TT.col += strlen(prefix) + len;
1550f66f451Sopenharmony_ci}
1560f66f451Sopenharmony_ci
1570f66f451Sopenharmony_cistatic void show_flags(tcflag_t actual, tcflag_t sane,
1580f66f451Sopenharmony_ci                       const struct flag *flags, int len)
1590f66f451Sopenharmony_ci{
1600f66f451Sopenharmony_ci  int i, j, value, mask;
1610f66f451Sopenharmony_ci
1620f66f451Sopenharmony_ci  // Implement -a by ensuring that sane != actual so we'll show everything.
1630f66f451Sopenharmony_ci  if (toys.optflags&FLAG_a) sane = ~actual;
1640f66f451Sopenharmony_ci
1650f66f451Sopenharmony_ci  for (i=j=0;i<len;i++) {
1660f66f451Sopenharmony_ci    value = flags[i].value;
1670f66f451Sopenharmony_ci    if ((mask = flags[i].mask)) {
1680f66f451Sopenharmony_ci      if ((actual&mask)==value && (sane&mask)!=value) {
1690f66f451Sopenharmony_ci        out("%s", flags[i].name);
1700f66f451Sopenharmony_ci        j++;
1710f66f451Sopenharmony_ci      }
1720f66f451Sopenharmony_ci    } else {
1730f66f451Sopenharmony_ci      if ((actual&value) != (sane&value)) {
1740f66f451Sopenharmony_ci        out("%s%s", actual&value?"":"-", flags[i].name);
1750f66f451Sopenharmony_ci        j++;
1760f66f451Sopenharmony_ci      }
1770f66f451Sopenharmony_ci    }
1780f66f451Sopenharmony_ci  }
1790f66f451Sopenharmony_ci  if (j) out("\n");
1800f66f451Sopenharmony_ci}
1810f66f451Sopenharmony_ci
1820f66f451Sopenharmony_cistatic void show_size(int verbose)
1830f66f451Sopenharmony_ci{
1840f66f451Sopenharmony_ci  struct winsize ws;
1850f66f451Sopenharmony_ci
1860f66f451Sopenharmony_ci  if (ioctl(TT.fd, TIOCGWINSZ, &ws)) perror_exit("TIOCGWINSZ %s", TT.device);
1870f66f451Sopenharmony_ci  out(verbose ? "rows %d; columns %d;" : "%d %d\n", ws.ws_row, ws.ws_col);
1880f66f451Sopenharmony_ci}
1890f66f451Sopenharmony_ci
1900f66f451Sopenharmony_cistatic void show_speed(struct termios *t, int verbose)
1910f66f451Sopenharmony_ci{
1920f66f451Sopenharmony_ci  int ispeed = baud(cfgetispeed(t)), ospeed = baud(cfgetospeed(t));
1930f66f451Sopenharmony_ci  char *fmt = verbose ? "ispeed %d baud; ospeed %d baud;" : "%d %d\n";
1940f66f451Sopenharmony_ci
1950f66f451Sopenharmony_ci  if (ispeed == ospeed) fmt += (verbose ? 17 : 3);
1960f66f451Sopenharmony_ci  out(fmt, ispeed, ospeed);
1970f66f451Sopenharmony_ci}
1980f66f451Sopenharmony_ci
1990f66f451Sopenharmony_cistatic int get_arg(int *i, long long low, long long high)
2000f66f451Sopenharmony_ci{
2010f66f451Sopenharmony_ci  (*i)++;
2020f66f451Sopenharmony_ci  if (!toys.optargs[*i]) error_exit("missing arg");
2030f66f451Sopenharmony_ci  return atolx_range(toys.optargs[*i], low, high);
2040f66f451Sopenharmony_ci}
2050f66f451Sopenharmony_ci
2060f66f451Sopenharmony_cistatic int set_flag(tcflag_t *f, const struct flag *flags, int len,
2070f66f451Sopenharmony_ci                    char *name, int on)
2080f66f451Sopenharmony_ci{
2090f66f451Sopenharmony_ci  int i;
2100f66f451Sopenharmony_ci
2110f66f451Sopenharmony_ci  for (i=0;i<len;i++) {
2120f66f451Sopenharmony_ci    if (!strcmp(flags[i].name, name)) {
2130f66f451Sopenharmony_ci      if (on) {
2140f66f451Sopenharmony_ci        *f &= ~flags[i].mask;
2150f66f451Sopenharmony_ci        *f |= flags[i].value;
2160f66f451Sopenharmony_ci      } else {
2170f66f451Sopenharmony_ci        if (flags[i].mask) error_exit("%s isn't a boolean", name);
2180f66f451Sopenharmony_ci        *f &= ~flags[i].value;
2190f66f451Sopenharmony_ci      }
2200f66f451Sopenharmony_ci      return 1;
2210f66f451Sopenharmony_ci    }
2220f66f451Sopenharmony_ci  }
2230f66f451Sopenharmony_ci  return 0;
2240f66f451Sopenharmony_ci}
2250f66f451Sopenharmony_ci
2260f66f451Sopenharmony_cistatic void set_option(struct termios *new, char *option)
2270f66f451Sopenharmony_ci{
2280f66f451Sopenharmony_ci  int on = (*option != '-');
2290f66f451Sopenharmony_ci
2300f66f451Sopenharmony_ci  if (!on) option++;
2310f66f451Sopenharmony_ci  if (!set_flag(&new->c_cflag, cflags, ARRAY_LEN(cflags), option, on) &&
2320f66f451Sopenharmony_ci      !set_flag(&new->c_iflag, iflags, ARRAY_LEN(iflags), option, on) &&
2330f66f451Sopenharmony_ci      !set_flag(&new->c_oflag, oflags, ARRAY_LEN(oflags), option, on) &&
2340f66f451Sopenharmony_ci      !set_flag(&new->c_lflag, lflags, ARRAY_LEN(lflags), option, on))
2350f66f451Sopenharmony_ci    error_exit("unknown option: %s", option);
2360f66f451Sopenharmony_ci}
2370f66f451Sopenharmony_ci
2380f66f451Sopenharmony_cistatic void set_options(struct termios* new, ...)
2390f66f451Sopenharmony_ci{
2400f66f451Sopenharmony_ci  va_list va;
2410f66f451Sopenharmony_ci  char *option;
2420f66f451Sopenharmony_ci
2430f66f451Sopenharmony_ci  va_start(va, new);
2440f66f451Sopenharmony_ci  while ((option = va_arg(va, char *))) set_option(new, option);
2450f66f451Sopenharmony_ci  va_end(va);
2460f66f451Sopenharmony_ci}
2470f66f451Sopenharmony_ci
2480f66f451Sopenharmony_cistatic void set_size(int is_rows, unsigned short value)
2490f66f451Sopenharmony_ci{
2500f66f451Sopenharmony_ci  struct winsize ws;
2510f66f451Sopenharmony_ci
2520f66f451Sopenharmony_ci  if (ioctl(TT.fd, TIOCGWINSZ, &ws)) perror_exit("TIOCGWINSZ %s", TT.device);
2530f66f451Sopenharmony_ci  if (is_rows) ws.ws_row = value;
2540f66f451Sopenharmony_ci  else ws.ws_col = value;
2550f66f451Sopenharmony_ci  if (ioctl(TT.fd, TIOCSWINSZ, &ws)) perror_exit("TIOCSWINSZ %s", TT.device);
2560f66f451Sopenharmony_ci}
2570f66f451Sopenharmony_ci
2580f66f451Sopenharmony_cistatic int set_special_character(struct termios *new, int *i, char *char_name)
2590f66f451Sopenharmony_ci{
2600f66f451Sopenharmony_ci  int j;
2610f66f451Sopenharmony_ci
2620f66f451Sopenharmony_ci  // The -2 is to ignore VMIN and VTIME, which are just unsigned integers.
2630f66f451Sopenharmony_ci  for (j=0;j<ARRAY_LEN(chars)-2;j++) {
2640f66f451Sopenharmony_ci    if (!strcmp(chars[j].name, char_name)) {
2650f66f451Sopenharmony_ci      char *arg = toys.optargs[++(*i)];
2660f66f451Sopenharmony_ci      cc_t ch;
2670f66f451Sopenharmony_ci
2680f66f451Sopenharmony_ci      if (!arg) error_exit("missing arg");
2690f66f451Sopenharmony_ci      if (!strcmp(arg, "^-") || !strcmp(arg, "undef")) ch = _POSIX_VDISABLE;
2700f66f451Sopenharmony_ci      else if (!strcmp(arg, "^?")) ch = 0x7f;
2710f66f451Sopenharmony_ci      else if (arg[0] == '^' && arg[2] == 0) ch = (toupper(arg[1])-'@');
2720f66f451Sopenharmony_ci      else if (!arg[1]) ch = arg[0];
2730f66f451Sopenharmony_ci      else error_exit("invalid arg: %s", arg);
2740f66f451Sopenharmony_ci      xprintf("setting %s to %s (%02x)\n", char_name, arg, ch);
2750f66f451Sopenharmony_ci      new->c_cc[chars[j].value] = ch;
2760f66f451Sopenharmony_ci      return 1;
2770f66f451Sopenharmony_ci    }
2780f66f451Sopenharmony_ci  }
2790f66f451Sopenharmony_ci  return 0;
2800f66f451Sopenharmony_ci}
2810f66f451Sopenharmony_ci
2820f66f451Sopenharmony_cistatic void make_sane(struct termios *t)
2830f66f451Sopenharmony_ci{
2840f66f451Sopenharmony_ci  // POSIX has no opinion about what "sane" means. From "man stty".
2850f66f451Sopenharmony_ci  // "cs8" is missing from the man page, but needed to get identical results.
2860f66f451Sopenharmony_ci  set_options(t, "cread", "-ignbrk", "brkint", "-inlcr", "-igncr", "icrnl",
2870f66f451Sopenharmony_ci    "icanon", "iexten", "echo", "echoe", "echok", "-echonl", "-noflsh",
2880f66f451Sopenharmony_ci    "-ixoff", "-iutf8", "-iuclc", "-ixany", "imaxbel", "-xcase", "-olcuc",
2890f66f451Sopenharmony_ci    "-ocrnl", "opost", "-ofill", "onlcr", "-onocr", "-onlret", "nl0", "cr0",
2900f66f451Sopenharmony_ci    "tab0", "bs0", "vt0", "ff0", "isig", "-tostop", "-ofdel", "-echoprt",
2910f66f451Sopenharmony_ci    "echoctl", "echoke", "-extproc", "-flusho", "cs8", NULL);
2920f66f451Sopenharmony_ci  memset(t->c_cc, 0, NCCS);
2930f66f451Sopenharmony_ci  t->c_cc[VINTR] = 0x3;
2940f66f451Sopenharmony_ci  t->c_cc[VQUIT] = 0x1c;
2950f66f451Sopenharmony_ci  t->c_cc[VERASE] = 0x7f;
2960f66f451Sopenharmony_ci  t->c_cc[VKILL] = 0x15;
2970f66f451Sopenharmony_ci  t->c_cc[VEOF] = 0x4;
2980f66f451Sopenharmony_ci  t->c_cc[VTIME] = 0;
2990f66f451Sopenharmony_ci  t->c_cc[VMIN] = 1;
3000f66f451Sopenharmony_ci  t->c_cc[VSWTC] = 0;
3010f66f451Sopenharmony_ci  t->c_cc[VSTART] = 0x11;
3020f66f451Sopenharmony_ci  t->c_cc[VSTOP] = 0x13;
3030f66f451Sopenharmony_ci  t->c_cc[VSUSP] = 0x1a;
3040f66f451Sopenharmony_ci  t->c_cc[VEOL] = 0;
3050f66f451Sopenharmony_ci  t->c_cc[VREPRINT] = 0x12;
3060f66f451Sopenharmony_ci  t->c_cc[VDISCARD] = 0xf;
3070f66f451Sopenharmony_ci  t->c_cc[VWERASE] = 0x17;
3080f66f451Sopenharmony_ci  t->c_cc[VLNEXT] = 0x16;
3090f66f451Sopenharmony_ci  t->c_cc[VEOL2] = 0;
3100f66f451Sopenharmony_ci}
3110f66f451Sopenharmony_ci
3120f66f451Sopenharmony_cistatic void xtcgetattr(struct termios *t)
3130f66f451Sopenharmony_ci{
3140f66f451Sopenharmony_ci  if (tcgetattr(TT.fd, t)) perror_exit("tcgetattr %s", TT.device);
3150f66f451Sopenharmony_ci}
3160f66f451Sopenharmony_ci
3170f66f451Sopenharmony_cistatic void do_stty()
3180f66f451Sopenharmony_ci{
3190f66f451Sopenharmony_ci  struct termios old, sane;
3200f66f451Sopenharmony_ci  int i, j, n;
3210f66f451Sopenharmony_ci
3220f66f451Sopenharmony_ci  xtcgetattr(&old);
3230f66f451Sopenharmony_ci
3240f66f451Sopenharmony_ci  if (*toys.optargs) {
3250f66f451Sopenharmony_ci    struct termios new = old;
3260f66f451Sopenharmony_ci
3270f66f451Sopenharmony_ci    for (i=0; toys.optargs[i]; i++) {
3280f66f451Sopenharmony_ci      char *arg = toys.optargs[i];
3290f66f451Sopenharmony_ci
3300f66f451Sopenharmony_ci      if (!strcmp(arg, "size")) show_size(0);
3310f66f451Sopenharmony_ci      else if (!strcmp(arg, "speed")) show_speed(&old, 0);
3320f66f451Sopenharmony_ci      else if (!strcmp(arg, "line")) new.c_line = get_arg(&i, N_TTY, NR_LDISCS);
3330f66f451Sopenharmony_ci      else if (!strcmp(arg, "min")) new.c_cc[VMIN] = get_arg(&i, 0, 255);
3340f66f451Sopenharmony_ci      else if (!strcmp(arg, "time")) new.c_cc[VTIME] = get_arg(&i, 0, 255);
3350f66f451Sopenharmony_ci      else if (atoi(arg) > 0) {
3360f66f451Sopenharmony_ci        int new_speed = speed(atolx_range(arg, 0, 4000000));
3370f66f451Sopenharmony_ci
3380f66f451Sopenharmony_ci        cfsetispeed(&new, new_speed);
3390f66f451Sopenharmony_ci        cfsetospeed(&new, new_speed);
3400f66f451Sopenharmony_ci      } else if (!strcmp(arg, "ispeed"))
3410f66f451Sopenharmony_ci        cfsetispeed(&new, speed(get_arg(&i, 0, 4000000)));
3420f66f451Sopenharmony_ci      else if (!strcmp(arg, "ospeed"))
3430f66f451Sopenharmony_ci        cfsetospeed(&new, speed(get_arg(&i, 0, 4000000)));
3440f66f451Sopenharmony_ci      else if (!strcmp(arg, "rows")) set_size(1, get_arg(&i, 0, USHRT_MAX));
3450f66f451Sopenharmony_ci      else if (!strcmp(arg, "cols") || !strcmp(arg, "columns"))
3460f66f451Sopenharmony_ci        set_size(0, get_arg(&i, 0, USHRT_MAX));
3470f66f451Sopenharmony_ci      else if (sscanf(arg, "%x:%x:%x:%x:%n", &new.c_iflag, &new.c_oflag,
3480f66f451Sopenharmony_ci                        &new.c_cflag, &new.c_lflag, &n) == 4)
3490f66f451Sopenharmony_ci      {
3500f66f451Sopenharmony_ci        int value;
3510f66f451Sopenharmony_ci
3520f66f451Sopenharmony_ci        arg += n;
3530f66f451Sopenharmony_ci        for (j=0;j<NCCS;j++) {
3540f66f451Sopenharmony_ci          if (sscanf(arg, "%x%n", &value, &n) != 1) error_exit("bad -g string");
3550f66f451Sopenharmony_ci          new.c_cc[j] = value;
3560f66f451Sopenharmony_ci          arg += n+1;
3570f66f451Sopenharmony_ci        }
3580f66f451Sopenharmony_ci      } else if (set_special_character(&new, &i, arg));
3590f66f451Sopenharmony_ci        // Already done as a side effect.
3600f66f451Sopenharmony_ci      else if (!strcmp(arg, "cooked"))
3610f66f451Sopenharmony_ci        set_options(&new, "brkint", "ignpar", "istrip", "icrnl", "ixon",
3620f66f451Sopenharmony_ci          "opost", "isig", "icanon", NULL);
3630f66f451Sopenharmony_ci      else if (!strcmp(arg, "evenp") || !strcmp(arg, "parity"))
3640f66f451Sopenharmony_ci        set_options(&new, "parenb", "cs7", "-parodd", NULL);
3650f66f451Sopenharmony_ci      else if (!strcmp(arg, "oddp"))
3660f66f451Sopenharmony_ci        set_options(&new, "parenb", "cs7", "parodd", NULL);
3670f66f451Sopenharmony_ci      else if (!strcmp(arg, "-parity") || !strcmp(arg, "-evenp") ||
3680f66f451Sopenharmony_ci                 !strcmp(arg, "-oddp")) {
3690f66f451Sopenharmony_ci        set_options(&new, "-parenb", "cs8", NULL);
3700f66f451Sopenharmony_ci      } else if (!strcmp(arg, "raw")) {
3710f66f451Sopenharmony_ci        // POSIX and "man stty" differ wildly. This is "man stty".
3720f66f451Sopenharmony_ci        set_options(&new, "-ignbrk", "-brkint", "-ignpar", "-parmrk", "-inpck",
3730f66f451Sopenharmony_ci          "-istrip", "-inlcr", "-igncr", "-icrnl", "-ixon", "-ixoff", "-iuclc",
3740f66f451Sopenharmony_ci          "-ixany", "-imaxbel", "-opost", "-isig", "-icanon", "-xcase", NULL);
3750f66f451Sopenharmony_ci        new.c_cc[VMIN] = 1;
3760f66f451Sopenharmony_ci        new.c_cc[VTIME] = 0;
3770f66f451Sopenharmony_ci      } else if (!strcmp(arg, "nl"))
3780f66f451Sopenharmony_ci        set_options(&new, "-icrnl", "-ocrnl", NULL);
3790f66f451Sopenharmony_ci      else if (!strcmp(arg, "-nl"))
3800f66f451Sopenharmony_ci        set_options(&new, "icrnl", "ocrnl", "-inlcr", "-igncr", NULL);
3810f66f451Sopenharmony_ci      else if (!strcmp(arg, "ek")) {
3820f66f451Sopenharmony_ci        new.c_cc[VERASE] = 0x7f;
3830f66f451Sopenharmony_ci        new.c_cc[VKILL] = 0x15;
3840f66f451Sopenharmony_ci      } else if (!strcmp(arg, "sane")) make_sane(&new);
3850f66f451Sopenharmony_ci      else {
3860f66f451Sopenharmony_ci        // Translate historical cruft into canonical forms.
3870f66f451Sopenharmony_ci        for (j=0;j<ARRAY_LEN(synonyms);j++) {
3880f66f451Sopenharmony_ci          if (!strcmp(synonyms[j].from, arg)) {
3890f66f451Sopenharmony_ci            arg = synonyms[j].to;
3900f66f451Sopenharmony_ci            break;
3910f66f451Sopenharmony_ci          }
3920f66f451Sopenharmony_ci        }
3930f66f451Sopenharmony_ci        set_option(&new, arg);
3940f66f451Sopenharmony_ci      }
3950f66f451Sopenharmony_ci    }
3960f66f451Sopenharmony_ci    tcsetattr(TT.fd, TCSAFLUSH, &new);
3970f66f451Sopenharmony_ci    xtcgetattr(&old);
3980f66f451Sopenharmony_ci    if (memcmp(&old, &new, sizeof(old)))
3990f66f451Sopenharmony_ci      error_exit("unable to perform all requested operations on %s", TT.device);
4000f66f451Sopenharmony_ci
4010f66f451Sopenharmony_ci    return;
4020f66f451Sopenharmony_ci  }
4030f66f451Sopenharmony_ci
4040f66f451Sopenharmony_ci  if (toys.optflags&FLAG_g) {
4050f66f451Sopenharmony_ci    xprintf("%x:%x:%x:%x:", old.c_iflag, old.c_oflag, old.c_cflag, old.c_lflag);
4060f66f451Sopenharmony_ci    for (i=0;i<NCCS;i++) xprintf("%x%c", old.c_cc[i], i==NCCS-1?'\n':':');
4070f66f451Sopenharmony_ci    return;
4080f66f451Sopenharmony_ci  }
4090f66f451Sopenharmony_ci
4100f66f451Sopenharmony_ci  // Without arguments, "stty" only shows the speed, the line discipline,
4110f66f451Sopenharmony_ci  // special characters and any flags that differ from the "sane" settings.
4120f66f451Sopenharmony_ci  make_sane(&sane);
4130f66f451Sopenharmony_ci  show_speed(&old, 1);
4140f66f451Sopenharmony_ci  if (toys.optflags&FLAG_a) show_size(1);
4150f66f451Sopenharmony_ci  out("line = %d;\n", old.c_line);
4160f66f451Sopenharmony_ci
4170f66f451Sopenharmony_ci  for (i=j=0;i<ARRAY_LEN(chars);i++) {
4180f66f451Sopenharmony_ci    char vis[16] = {};
4190f66f451Sopenharmony_ci    cc_t ch = old.c_cc[chars[i].value];
4200f66f451Sopenharmony_ci
4210f66f451Sopenharmony_ci    if (ch == sane.c_cc[chars[i].value] && (toys.optflags&FLAG_a)==0)
4220f66f451Sopenharmony_ci      continue;
4230f66f451Sopenharmony_ci
4240f66f451Sopenharmony_ci    if (chars[i].value == VMIN || chars[i].value == VTIME) {
4250f66f451Sopenharmony_ci      snprintf(vis, sizeof(vis), "%u", ch);
4260f66f451Sopenharmony_ci    } else if (ch == _POSIX_VDISABLE) {
4270f66f451Sopenharmony_ci      strcat(vis, "<undef>");
4280f66f451Sopenharmony_ci    } else {
4290f66f451Sopenharmony_ci      if (ch > 0x7f) {
4300f66f451Sopenharmony_ci        strcat(vis, "M-");
4310f66f451Sopenharmony_ci        ch -= 128;
4320f66f451Sopenharmony_ci      }
4330f66f451Sopenharmony_ci      if (ch < ' ') sprintf(vis+strlen(vis), "^%c", (ch+'@'));
4340f66f451Sopenharmony_ci      else if (ch == 0x7f) strcat(vis, "^?");
4350f66f451Sopenharmony_ci      else sprintf(vis+strlen(vis), "%c", ch);
4360f66f451Sopenharmony_ci    }
4370f66f451Sopenharmony_ci    out("%s = %s;", chars[i].name, vis);
4380f66f451Sopenharmony_ci    j++;
4390f66f451Sopenharmony_ci  }
4400f66f451Sopenharmony_ci  if (j) out("\n");
4410f66f451Sopenharmony_ci
4420f66f451Sopenharmony_ci  show_flags(old.c_cflag, sane.c_cflag, cflags, ARRAY_LEN(cflags));
4430f66f451Sopenharmony_ci  show_flags(old.c_iflag, sane.c_iflag, iflags, ARRAY_LEN(iflags));
4440f66f451Sopenharmony_ci  show_flags(old.c_oflag, sane.c_oflag, oflags, ARRAY_LEN(oflags));
4450f66f451Sopenharmony_ci  show_flags(old.c_lflag, sane.c_lflag, lflags, ARRAY_LEN(lflags));
4460f66f451Sopenharmony_ci}
4470f66f451Sopenharmony_ci
4480f66f451Sopenharmony_civoid stty_main(void)
4490f66f451Sopenharmony_ci{
4500f66f451Sopenharmony_ci  if (toys.optflags&(FLAG_a|FLAG_g) && *toys.optargs)
4510f66f451Sopenharmony_ci    error_exit("can't make settings with -a/-g");
4520f66f451Sopenharmony_ci
4530f66f451Sopenharmony_ci  if (!TT.device) TT.device = "standard input";
4540f66f451Sopenharmony_ci  else TT.fd=xopen(TT.device, (O_RDWR*!!*toys.optargs)|O_NOCTTY|O_NONBLOCK);
4550f66f451Sopenharmony_ci
4560f66f451Sopenharmony_ci  do_stty();
4570f66f451Sopenharmony_ci
4580f66f451Sopenharmony_ci  if (CFG_TOYBOX_FREE && TT.device) close(TT.fd);
4590f66f451Sopenharmony_ci}
460