xref: /aosp_15_r20/external/toybox/toys/pending/stty.c (revision cf5a6c84e2b8763fc1a7db14496fd4742913b199)
1*cf5a6c84SAndroid Build Coastguard Worker /* stty.c - Get/set terminal configuration.
2*cf5a6c84SAndroid Build Coastguard Worker  *
3*cf5a6c84SAndroid Build Coastguard Worker  * Copyright 2017 The Android Open Source Project.
4*cf5a6c84SAndroid Build Coastguard Worker  *
5*cf5a6c84SAndroid Build Coastguard Worker  * See http://pubs.opengroup.org/onlinepubs/9699919799/utilities/stty.html
6*cf5a6c84SAndroid Build Coastguard Worker 
7*cf5a6c84SAndroid Build Coastguard Worker USE_STTY(NEWTOY(stty, "?aF:g[!ag]", TOYFLAG_BIN))
8*cf5a6c84SAndroid Build Coastguard Worker 
9*cf5a6c84SAndroid Build Coastguard Worker config STTY
10*cf5a6c84SAndroid Build Coastguard Worker   bool "stty"
11*cf5a6c84SAndroid Build Coastguard Worker   default n
12*cf5a6c84SAndroid Build Coastguard Worker   help
13*cf5a6c84SAndroid Build Coastguard Worker     usage: stty [-ag] [-F device] SETTING...
14*cf5a6c84SAndroid Build Coastguard Worker 
15*cf5a6c84SAndroid Build Coastguard Worker     Get/set terminal configuration.
16*cf5a6c84SAndroid Build Coastguard Worker 
17*cf5a6c84SAndroid Build Coastguard Worker     -F	Open device instead of stdin
18*cf5a6c84SAndroid Build Coastguard Worker     -a	Show all current settings (default differences from "sane")
19*cf5a6c84SAndroid Build Coastguard Worker     -g	Show all current settings usable as input to stty
20*cf5a6c84SAndroid Build Coastguard Worker 
21*cf5a6c84SAndroid Build Coastguard Worker     Special characters (syntax ^c or undef): intr quit erase kill eof eol eol2
22*cf5a6c84SAndroid Build Coastguard Worker     swtch start stop susp rprnt werase lnext discard
23*cf5a6c84SAndroid Build Coastguard Worker 
24*cf5a6c84SAndroid Build Coastguard Worker     Control/input/output/local settings as shown by -a, '-' prefix to disable
25*cf5a6c84SAndroid Build Coastguard Worker 
26*cf5a6c84SAndroid Build Coastguard Worker     Combo settings: cooked/raw, evenp/oddp/parity, nl, ek, sane
27*cf5a6c84SAndroid Build Coastguard Worker 
28*cf5a6c84SAndroid Build Coastguard Worker     N	set input and output speed (ispeed N or ospeed N for just one)
29*cf5a6c84SAndroid Build Coastguard Worker     cols N	set number of columns
30*cf5a6c84SAndroid Build Coastguard Worker     rows N	set number of rows
31*cf5a6c84SAndroid Build Coastguard Worker     line N	set line discipline
32*cf5a6c84SAndroid Build Coastguard Worker     min N	set minimum chars per read
33*cf5a6c84SAndroid Build Coastguard Worker     time N	set read timeout
34*cf5a6c84SAndroid Build Coastguard Worker     speed	show speed only
35*cf5a6c84SAndroid Build Coastguard Worker     size	show size only
36*cf5a6c84SAndroid Build Coastguard Worker */
37*cf5a6c84SAndroid Build Coastguard Worker 
38*cf5a6c84SAndroid Build Coastguard Worker #define FOR_stty
39*cf5a6c84SAndroid Build Coastguard Worker #include "toys.h"
40*cf5a6c84SAndroid Build Coastguard Worker 
41*cf5a6c84SAndroid Build Coastguard Worker #include <linux/tty.h>
42*cf5a6c84SAndroid Build Coastguard Worker 
43*cf5a6c84SAndroid Build Coastguard Worker GLOBALS(
44*cf5a6c84SAndroid Build Coastguard Worker   char *F;
45*cf5a6c84SAndroid Build Coastguard Worker 
46*cf5a6c84SAndroid Build Coastguard Worker   int fd, col;
47*cf5a6c84SAndroid Build Coastguard Worker   unsigned output_cols;
48*cf5a6c84SAndroid Build Coastguard Worker )
49*cf5a6c84SAndroid Build Coastguard Worker 
50*cf5a6c84SAndroid Build Coastguard Worker static const int bauds[] = {
51*cf5a6c84SAndroid Build Coastguard Worker   0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800, 9600,
52*cf5a6c84SAndroid Build Coastguard Worker   19200, 38400, 57600, 115200, 230400, 460800, 500000, 576000, 921600,
53*cf5a6c84SAndroid Build Coastguard Worker   1000000, 1152000, 1500000, 2000000, 2500000, 3000000, 3500000, 4000000
54*cf5a6c84SAndroid Build Coastguard Worker };
55*cf5a6c84SAndroid Build Coastguard Worker 
baud(speed_t speed)56*cf5a6c84SAndroid Build Coastguard Worker static int baud(speed_t speed)
57*cf5a6c84SAndroid Build Coastguard Worker {
58*cf5a6c84SAndroid Build Coastguard Worker   if (speed&CBAUDEX) speed=(speed&~CBAUDEX)+15;
59*cf5a6c84SAndroid Build Coastguard Worker   return bauds[speed];
60*cf5a6c84SAndroid Build Coastguard Worker }
61*cf5a6c84SAndroid Build Coastguard Worker 
speed(int baud)62*cf5a6c84SAndroid Build Coastguard Worker static speed_t speed(int baud)
63*cf5a6c84SAndroid Build Coastguard Worker {
64*cf5a6c84SAndroid Build Coastguard Worker   int i;
65*cf5a6c84SAndroid Build Coastguard Worker 
66*cf5a6c84SAndroid Build Coastguard Worker   for (i=0;i<ARRAY_LEN(bauds);i++) if (bauds[i] == baud) break;
67*cf5a6c84SAndroid Build Coastguard Worker   if (i == ARRAY_LEN(bauds)) error_exit("unknown speed: %d", baud);
68*cf5a6c84SAndroid Build Coastguard Worker   return i+4081*(i>=16);
69*cf5a6c84SAndroid Build Coastguard Worker }
70*cf5a6c84SAndroid Build Coastguard Worker 
71*cf5a6c84SAndroid Build Coastguard Worker struct flag {
72*cf5a6c84SAndroid Build Coastguard Worker   char *name;
73*cf5a6c84SAndroid Build Coastguard Worker   int value;
74*cf5a6c84SAndroid Build Coastguard Worker   int mask;
75*cf5a6c84SAndroid Build Coastguard Worker };
76*cf5a6c84SAndroid Build Coastguard Worker 
77*cf5a6c84SAndroid Build Coastguard Worker static const struct flag chars[] = {
78*cf5a6c84SAndroid Build Coastguard Worker   { "intr", VINTR }, { "quit", VQUIT }, { "erase", VERASE }, { "kill", VKILL },
79*cf5a6c84SAndroid Build Coastguard Worker   { "eof", VEOF }, { "eol", VEOL }, { "eol2", VEOL2 }, { "swtch", VSWTC },
80*cf5a6c84SAndroid Build Coastguard Worker   { "start", VSTART }, { "stop", VSTOP }, { "susp", VSUSP },
81*cf5a6c84SAndroid Build Coastguard Worker   { "rprnt", VREPRINT }, { "werase", VWERASE }, { "lnext", VLNEXT },
82*cf5a6c84SAndroid Build Coastguard Worker   { "discard", VDISCARD }, { "min", VMIN }, { "time", VTIME },
83*cf5a6c84SAndroid Build Coastguard Worker };
84*cf5a6c84SAndroid Build Coastguard Worker 
85*cf5a6c84SAndroid Build Coastguard Worker static const struct flag cflags[] = {
86*cf5a6c84SAndroid Build Coastguard Worker   { "parenb", PARENB }, { "parodd", PARODD }, { "cmspar", CMSPAR },
87*cf5a6c84SAndroid Build Coastguard Worker   { "cs5", CS5, CSIZE }, { "cs6", CS6, CSIZE }, { "cs7", CS7, CSIZE },
88*cf5a6c84SAndroid Build Coastguard Worker   { "cs8", CS8, CSIZE }, { "hupcl", HUPCL }, { "cstopb", CSTOPB },
89*cf5a6c84SAndroid Build Coastguard Worker   { "cread", CREAD }, { "clocal", CLOCAL }, { "crtscts", CRTSCTS },
90*cf5a6c84SAndroid Build Coastguard Worker };
91*cf5a6c84SAndroid Build Coastguard Worker 
92*cf5a6c84SAndroid Build Coastguard Worker static const struct flag iflags[] = {
93*cf5a6c84SAndroid Build Coastguard Worker   { "ignbrk", IGNBRK }, { "brkint", BRKINT }, { "ignpar", IGNPAR },
94*cf5a6c84SAndroid Build Coastguard Worker   { "parmrk", PARMRK }, { "inpck", INPCK }, { "istrip", ISTRIP },
95*cf5a6c84SAndroid Build Coastguard Worker   { "inlcr", INLCR }, { "igncr", IGNCR }, { "icrnl", ICRNL }, { "ixon", IXON },
96*cf5a6c84SAndroid Build Coastguard Worker   { "ixoff", IXOFF }, { "iuclc", IUCLC }, { "ixany", IXANY },
97*cf5a6c84SAndroid Build Coastguard Worker   { "imaxbel", IMAXBEL }, { "iutf8", IUTF8 },
98*cf5a6c84SAndroid Build Coastguard Worker };
99*cf5a6c84SAndroid Build Coastguard Worker 
100*cf5a6c84SAndroid Build Coastguard Worker static const struct flag oflags[] = {
101*cf5a6c84SAndroid Build Coastguard Worker   { "opost", OPOST }, { "olcuc", OLCUC }, { "ocrnl", OCRNL },
102*cf5a6c84SAndroid Build Coastguard Worker   { "onlcr", ONLCR }, { "onocr", ONOCR }, { "onlret", ONLRET },
103*cf5a6c84SAndroid Build Coastguard Worker   { "ofill", OFILL }, { "ofdel", OFDEL }, { "nl0", NL0, NLDLY },
104*cf5a6c84SAndroid Build Coastguard Worker   { "nl1", NL1, NLDLY }, { "cr0", CR0, CRDLY }, { "cr1", CR1, CRDLY },
105*cf5a6c84SAndroid Build Coastguard Worker   { "cr2", CR2, CRDLY }, { "cr3", CR3, CRDLY }, { "tab0", TAB0, TABDLY },
106*cf5a6c84SAndroid Build Coastguard Worker   { "tab1", TAB1, TABDLY }, { "tab2", TAB2, TABDLY }, { "tab3", TAB3, TABDLY },
107*cf5a6c84SAndroid Build Coastguard Worker   { "bs0", BS0, BSDLY }, { "bs1", BS1, BSDLY }, { "vt0", VT0, VTDLY },
108*cf5a6c84SAndroid Build Coastguard Worker   { "vt1", VT1, VTDLY }, { "ff0", FF0, FFDLY }, { "ff1", FF1, FFDLY },
109*cf5a6c84SAndroid Build Coastguard Worker };
110*cf5a6c84SAndroid Build Coastguard Worker 
111*cf5a6c84SAndroid Build Coastguard Worker static const struct flag lflags[] = {
112*cf5a6c84SAndroid Build Coastguard Worker   { "isig", ISIG }, { "icanon", ICANON }, { "iexten", IEXTEN },
113*cf5a6c84SAndroid Build Coastguard Worker   { "echo", ECHO }, { "echoe", ECHOE }, { "echok", ECHOK },
114*cf5a6c84SAndroid Build Coastguard Worker   { "echonl", ECHONL }, { "noflsh", NOFLSH }, { "xcase", XCASE },
115*cf5a6c84SAndroid Build Coastguard Worker   { "tostop", TOSTOP }, { "echoprt", ECHOPRT }, { "echoctl", ECHOCTL },
116*cf5a6c84SAndroid Build Coastguard Worker   { "echoke", ECHOKE }, { "flusho", FLUSHO }, { "extproc", EXTPROC },
117*cf5a6c84SAndroid Build Coastguard Worker };
118*cf5a6c84SAndroid Build Coastguard Worker 
119*cf5a6c84SAndroid Build Coastguard Worker static const struct synonym {
120*cf5a6c84SAndroid Build Coastguard Worker   char *from;
121*cf5a6c84SAndroid Build Coastguard Worker   char *to;
122*cf5a6c84SAndroid Build Coastguard Worker } synonyms[] = {
123*cf5a6c84SAndroid Build Coastguard Worker   { "cbreak", "-icanon" }, { "-cbreak", "icanon" },
124*cf5a6c84SAndroid Build Coastguard Worker   { "-cooked", "raw" }, { "-raw", "cooked" },
125*cf5a6c84SAndroid Build Coastguard Worker   { "crterase", "echoe" }, { "-crterase", "-echoe" },
126*cf5a6c84SAndroid Build Coastguard Worker   { "crtkill", "echoke" }, { "-crtkill", "-echoke" },
127*cf5a6c84SAndroid Build Coastguard Worker   { "ctlecho", "echoctl" }, { "-ctlecho", "-echoctl" },
128*cf5a6c84SAndroid Build Coastguard Worker   { "-tandem", "-ixoff" }, { "tandem", "ixoff" },
129*cf5a6c84SAndroid Build Coastguard Worker   { "hup", "hupcl" }, { "-hup", "-hupcl" },
130*cf5a6c84SAndroid Build Coastguard Worker   { "prterase", "echoprt" }, { "-prterase", "-echoprt" },
131*cf5a6c84SAndroid Build Coastguard Worker   { "tabs", "tab0" }, { "-tabs", "tab3" },
132*cf5a6c84SAndroid Build Coastguard Worker };
133*cf5a6c84SAndroid Build Coastguard Worker 
out(const char * fmt,...)134*cf5a6c84SAndroid Build Coastguard Worker static void out(const char *fmt, ...)
135*cf5a6c84SAndroid Build Coastguard Worker {
136*cf5a6c84SAndroid Build Coastguard Worker   va_list va;
137*cf5a6c84SAndroid Build Coastguard Worker   int len;
138*cf5a6c84SAndroid Build Coastguard Worker   char *prefix = " ";
139*cf5a6c84SAndroid Build Coastguard Worker 
140*cf5a6c84SAndroid Build Coastguard Worker   va_start(va, fmt);
141*cf5a6c84SAndroid Build Coastguard Worker   len = vsnprintf(toybuf, sizeof(toybuf), fmt, va);
142*cf5a6c84SAndroid Build Coastguard Worker   va_end(va);
143*cf5a6c84SAndroid Build Coastguard Worker 
144*cf5a6c84SAndroid Build Coastguard Worker   if (TT.output_cols == 0) {
145*cf5a6c84SAndroid Build Coastguard Worker     TT.output_cols = 80;
146*cf5a6c84SAndroid Build Coastguard Worker     terminal_size(&TT.output_cols, NULL);
147*cf5a6c84SAndroid Build Coastguard Worker   }
148*cf5a6c84SAndroid Build Coastguard Worker 
149*cf5a6c84SAndroid Build Coastguard Worker   if (TT.col == 0 || *fmt == '\n') prefix = "";
150*cf5a6c84SAndroid Build Coastguard Worker   else if (TT.col + 1 + len >= TT.output_cols) {
151*cf5a6c84SAndroid Build Coastguard Worker     prefix = "\n";
152*cf5a6c84SAndroid Build Coastguard Worker     TT.col = 0;
153*cf5a6c84SAndroid Build Coastguard Worker   }
154*cf5a6c84SAndroid Build Coastguard Worker   xprintf("%s%s", prefix, toybuf);
155*cf5a6c84SAndroid Build Coastguard Worker 
156*cf5a6c84SAndroid Build Coastguard Worker   if (toybuf[len-1] == '\n') TT.col = 0;
157*cf5a6c84SAndroid Build Coastguard Worker   else TT.col += strlen(prefix) + len;
158*cf5a6c84SAndroid Build Coastguard Worker }
159*cf5a6c84SAndroid Build Coastguard Worker 
show_flags(tcflag_t actual,tcflag_t sane,const struct flag * flags,int len)160*cf5a6c84SAndroid Build Coastguard Worker static void show_flags(tcflag_t actual, tcflag_t sane,
161*cf5a6c84SAndroid Build Coastguard Worker                        const struct flag *flags, int len)
162*cf5a6c84SAndroid Build Coastguard Worker {
163*cf5a6c84SAndroid Build Coastguard Worker   int i, j, value, mask;
164*cf5a6c84SAndroid Build Coastguard Worker 
165*cf5a6c84SAndroid Build Coastguard Worker   // Implement -a by ensuring that sane != actual so we'll show everything.
166*cf5a6c84SAndroid Build Coastguard Worker   if (FLAG(a)) sane = ~actual;
167*cf5a6c84SAndroid Build Coastguard Worker 
168*cf5a6c84SAndroid Build Coastguard Worker   for (i = j = 0; i<len; i++) {
169*cf5a6c84SAndroid Build Coastguard Worker     value = flags[i].value;
170*cf5a6c84SAndroid Build Coastguard Worker     if ((mask = flags[i].mask)) {
171*cf5a6c84SAndroid Build Coastguard Worker       if ((actual&mask)==value && (sane&mask)!=value) {
172*cf5a6c84SAndroid Build Coastguard Worker         out("%s", flags[i].name);
173*cf5a6c84SAndroid Build Coastguard Worker         j++;
174*cf5a6c84SAndroid Build Coastguard Worker       }
175*cf5a6c84SAndroid Build Coastguard Worker     } else {
176*cf5a6c84SAndroid Build Coastguard Worker       if ((actual&value) != (sane&value)) {
177*cf5a6c84SAndroid Build Coastguard Worker         out("%s%s", actual&value?"":"-", flags[i].name);
178*cf5a6c84SAndroid Build Coastguard Worker         j++;
179*cf5a6c84SAndroid Build Coastguard Worker       }
180*cf5a6c84SAndroid Build Coastguard Worker     }
181*cf5a6c84SAndroid Build Coastguard Worker   }
182*cf5a6c84SAndroid Build Coastguard Worker   if (j) out("\n");
183*cf5a6c84SAndroid Build Coastguard Worker }
184*cf5a6c84SAndroid Build Coastguard Worker 
show_size(int verbose)185*cf5a6c84SAndroid Build Coastguard Worker static void show_size(int verbose)
186*cf5a6c84SAndroid Build Coastguard Worker {
187*cf5a6c84SAndroid Build Coastguard Worker   struct winsize ws;
188*cf5a6c84SAndroid Build Coastguard Worker 
189*cf5a6c84SAndroid Build Coastguard Worker   if (ioctl(TT.fd, TIOCGWINSZ, &ws)) perror_exit("TIOCGWINSZ %s", TT.F);
190*cf5a6c84SAndroid Build Coastguard Worker   out(verbose ? "rows %d; columns %d;" : "%d %d\n", ws.ws_row, ws.ws_col);
191*cf5a6c84SAndroid Build Coastguard Worker }
192*cf5a6c84SAndroid Build Coastguard Worker 
show_speed(struct termios * t,int verbose)193*cf5a6c84SAndroid Build Coastguard Worker static void show_speed(struct termios *t, int verbose)
194*cf5a6c84SAndroid Build Coastguard Worker {
195*cf5a6c84SAndroid Build Coastguard Worker   int ispeed = baud(cfgetispeed(t)), ospeed = baud(cfgetospeed(t));
196*cf5a6c84SAndroid Build Coastguard Worker   char *fmt = verbose ? "ispeed %d baud; ospeed %d baud;" : "%d %d\n";
197*cf5a6c84SAndroid Build Coastguard Worker 
198*cf5a6c84SAndroid Build Coastguard Worker   if (ispeed == ospeed) fmt += (verbose ? 17 : 3);
199*cf5a6c84SAndroid Build Coastguard Worker   out(fmt, ispeed, ospeed);
200*cf5a6c84SAndroid Build Coastguard Worker }
201*cf5a6c84SAndroid Build Coastguard Worker 
get_arg(int * i,long long high)202*cf5a6c84SAndroid Build Coastguard Worker static int get_arg(int *i, long long high)
203*cf5a6c84SAndroid Build Coastguard Worker {
204*cf5a6c84SAndroid Build Coastguard Worker   (*i)++;
205*cf5a6c84SAndroid Build Coastguard Worker   if (!toys.optargs[*i]) error_exit("missing arg");
206*cf5a6c84SAndroid Build Coastguard Worker   return atolx_range(toys.optargs[*i], 0, high);
207*cf5a6c84SAndroid Build Coastguard Worker }
208*cf5a6c84SAndroid Build Coastguard Worker 
set_flag(tcflag_t * f,const struct flag * flags,int len,char * name,int on)209*cf5a6c84SAndroid Build Coastguard Worker static int set_flag(tcflag_t *f, const struct flag *flags, int len,
210*cf5a6c84SAndroid Build Coastguard Worker                     char *name, int on)
211*cf5a6c84SAndroid Build Coastguard Worker {
212*cf5a6c84SAndroid Build Coastguard Worker   int i;
213*cf5a6c84SAndroid Build Coastguard Worker 
214*cf5a6c84SAndroid Build Coastguard Worker   for (i=0;i<len;i++) {
215*cf5a6c84SAndroid Build Coastguard Worker     if (!strcmp(flags[i].name, name)) {
216*cf5a6c84SAndroid Build Coastguard Worker       if (on) {
217*cf5a6c84SAndroid Build Coastguard Worker         *f &= ~flags[i].mask;
218*cf5a6c84SAndroid Build Coastguard Worker         *f |= flags[i].value;
219*cf5a6c84SAndroid Build Coastguard Worker       } else {
220*cf5a6c84SAndroid Build Coastguard Worker         if (flags[i].mask) error_exit("%s isn't a boolean", name);
221*cf5a6c84SAndroid Build Coastguard Worker         *f &= ~flags[i].value;
222*cf5a6c84SAndroid Build Coastguard Worker       }
223*cf5a6c84SAndroid Build Coastguard Worker       return 1;
224*cf5a6c84SAndroid Build Coastguard Worker     }
225*cf5a6c84SAndroid Build Coastguard Worker   }
226*cf5a6c84SAndroid Build Coastguard Worker   return 0;
227*cf5a6c84SAndroid Build Coastguard Worker }
228*cf5a6c84SAndroid Build Coastguard Worker 
set_option(struct termios * new,char * option)229*cf5a6c84SAndroid Build Coastguard Worker static void set_option(struct termios *new, char *option)
230*cf5a6c84SAndroid Build Coastguard Worker {
231*cf5a6c84SAndroid Build Coastguard Worker   int on = (*option != '-');
232*cf5a6c84SAndroid Build Coastguard Worker 
233*cf5a6c84SAndroid Build Coastguard Worker   if (!on) option++;
234*cf5a6c84SAndroid Build Coastguard Worker   if (!set_flag(&new->c_cflag, cflags, ARRAY_LEN(cflags), option, on) &&
235*cf5a6c84SAndroid Build Coastguard Worker       !set_flag(&new->c_iflag, iflags, ARRAY_LEN(iflags), option, on) &&
236*cf5a6c84SAndroid Build Coastguard Worker       !set_flag(&new->c_oflag, oflags, ARRAY_LEN(oflags), option, on) &&
237*cf5a6c84SAndroid Build Coastguard Worker       !set_flag(&new->c_lflag, lflags, ARRAY_LEN(lflags), option, on))
238*cf5a6c84SAndroid Build Coastguard Worker     error_exit("unknown option: %s", option);
239*cf5a6c84SAndroid Build Coastguard Worker }
240*cf5a6c84SAndroid Build Coastguard Worker 
set_options(struct termios * new,...)241*cf5a6c84SAndroid Build Coastguard Worker static void set_options(struct termios* new, ...)
242*cf5a6c84SAndroid Build Coastguard Worker {
243*cf5a6c84SAndroid Build Coastguard Worker   va_list va;
244*cf5a6c84SAndroid Build Coastguard Worker   char *option;
245*cf5a6c84SAndroid Build Coastguard Worker 
246*cf5a6c84SAndroid Build Coastguard Worker   va_start(va, new);
247*cf5a6c84SAndroid Build Coastguard Worker   while ((option = va_arg(va, char *))) set_option(new, option);
248*cf5a6c84SAndroid Build Coastguard Worker   va_end(va);
249*cf5a6c84SAndroid Build Coastguard Worker }
250*cf5a6c84SAndroid Build Coastguard Worker 
set_size(int is_rows,unsigned short value)251*cf5a6c84SAndroid Build Coastguard Worker static void set_size(int is_rows, unsigned short value)
252*cf5a6c84SAndroid Build Coastguard Worker {
253*cf5a6c84SAndroid Build Coastguard Worker   struct winsize ws;
254*cf5a6c84SAndroid Build Coastguard Worker 
255*cf5a6c84SAndroid Build Coastguard Worker   if (ioctl(TT.fd, TIOCGWINSZ, &ws)) perror_exit("TIOCGWINSZ %s", TT.F);
256*cf5a6c84SAndroid Build Coastguard Worker   if (is_rows) ws.ws_row = value;
257*cf5a6c84SAndroid Build Coastguard Worker   else ws.ws_col = value;
258*cf5a6c84SAndroid Build Coastguard Worker   if (ioctl(TT.fd, TIOCSWINSZ, &ws)) perror_exit("TIOCSWINSZ %s", TT.F);
259*cf5a6c84SAndroid Build Coastguard Worker }
260*cf5a6c84SAndroid Build Coastguard Worker 
set_special_character(struct termios * new,int * i,char * char_name)261*cf5a6c84SAndroid Build Coastguard Worker static int set_special_character(struct termios *new, int *i, char *char_name)
262*cf5a6c84SAndroid Build Coastguard Worker {
263*cf5a6c84SAndroid Build Coastguard Worker   int j;
264*cf5a6c84SAndroid Build Coastguard Worker 
265*cf5a6c84SAndroid Build Coastguard Worker   // The -2 is to ignore VMIN and VTIME, which are just unsigned integers.
266*cf5a6c84SAndroid Build Coastguard Worker   for (j=0;j<ARRAY_LEN(chars)-2;j++) {
267*cf5a6c84SAndroid Build Coastguard Worker     if (!strcmp(chars[j].name, char_name)) {
268*cf5a6c84SAndroid Build Coastguard Worker       char *arg = toys.optargs[++(*i)];
269*cf5a6c84SAndroid Build Coastguard Worker       cc_t ch;
270*cf5a6c84SAndroid Build Coastguard Worker 
271*cf5a6c84SAndroid Build Coastguard Worker       if (!arg) error_exit("missing arg");
272*cf5a6c84SAndroid Build Coastguard Worker       if (!strcmp(arg, "^-") || !strcmp(arg, "undef")) ch = _POSIX_VDISABLE;
273*cf5a6c84SAndroid Build Coastguard Worker       else if (!strcmp(arg, "^?")) ch = 0x7f;
274*cf5a6c84SAndroid Build Coastguard Worker       else if (arg[0] == '^' && arg[2] == 0) ch = (toupper(arg[1])-'@');
275*cf5a6c84SAndroid Build Coastguard Worker       else if (!arg[1]) ch = arg[0];
276*cf5a6c84SAndroid Build Coastguard Worker       else error_exit("invalid arg: %s", arg);
277*cf5a6c84SAndroid Build Coastguard Worker       new->c_cc[chars[j].value] = ch;
278*cf5a6c84SAndroid Build Coastguard Worker       return 1;
279*cf5a6c84SAndroid Build Coastguard Worker     }
280*cf5a6c84SAndroid Build Coastguard Worker   }
281*cf5a6c84SAndroid Build Coastguard Worker   return 0;
282*cf5a6c84SAndroid Build Coastguard Worker }
283*cf5a6c84SAndroid Build Coastguard Worker 
make_sane(struct termios * t)284*cf5a6c84SAndroid Build Coastguard Worker static void make_sane(struct termios *t)
285*cf5a6c84SAndroid Build Coastguard Worker {
286*cf5a6c84SAndroid Build Coastguard Worker   // POSIX has no opinion about what "sane" means. From "man stty".
287*cf5a6c84SAndroid Build Coastguard Worker   // "cs8" is missing from the man page, but needed to get identical results.
288*cf5a6c84SAndroid Build Coastguard Worker   set_options(t, "cread", "-ignbrk", "brkint", "-inlcr", "-igncr", "icrnl",
289*cf5a6c84SAndroid Build Coastguard Worker     "icanon", "iexten", "echo", "echoe", "echok", "-echonl", "-noflsh",
290*cf5a6c84SAndroid Build Coastguard Worker     "-ixoff", "-iutf8", "-iuclc", "-ixany", "imaxbel", "-xcase", "-olcuc",
291*cf5a6c84SAndroid Build Coastguard Worker     "-ocrnl", "opost", "-ofill", "onlcr", "-onocr", "-onlret", "nl0", "cr0",
292*cf5a6c84SAndroid Build Coastguard Worker     "tab0", "bs0", "vt0", "ff0", "isig", "-tostop", "-ofdel", "-echoprt",
293*cf5a6c84SAndroid Build Coastguard Worker     "echoctl", "echoke", "-extproc", "-flusho", "cs8", NULL);
294*cf5a6c84SAndroid Build Coastguard Worker   memset(t->c_cc, 0, NCCS);
295*cf5a6c84SAndroid Build Coastguard Worker   t->c_cc[VINTR] = 0x3;
296*cf5a6c84SAndroid Build Coastguard Worker   t->c_cc[VQUIT] = 0x1c;
297*cf5a6c84SAndroid Build Coastguard Worker   t->c_cc[VERASE] = 0x7f;
298*cf5a6c84SAndroid Build Coastguard Worker   t->c_cc[VKILL] = 0x15;
299*cf5a6c84SAndroid Build Coastguard Worker   t->c_cc[VEOF] = 0x4;
300*cf5a6c84SAndroid Build Coastguard Worker   t->c_cc[VTIME] = 0;
301*cf5a6c84SAndroid Build Coastguard Worker   t->c_cc[VMIN] = 1;
302*cf5a6c84SAndroid Build Coastguard Worker   t->c_cc[VSWTC] = 0;
303*cf5a6c84SAndroid Build Coastguard Worker   t->c_cc[VSTART] = 0x11;
304*cf5a6c84SAndroid Build Coastguard Worker   t->c_cc[VSTOP] = 0x13;
305*cf5a6c84SAndroid Build Coastguard Worker   t->c_cc[VSUSP] = 0x1a;
306*cf5a6c84SAndroid Build Coastguard Worker   t->c_cc[VEOL] = 0;
307*cf5a6c84SAndroid Build Coastguard Worker   t->c_cc[VREPRINT] = 0x12;
308*cf5a6c84SAndroid Build Coastguard Worker   t->c_cc[VDISCARD] = 0xf;
309*cf5a6c84SAndroid Build Coastguard Worker   t->c_cc[VWERASE] = 0x17;
310*cf5a6c84SAndroid Build Coastguard Worker   t->c_cc[VLNEXT] = 0x16;
311*cf5a6c84SAndroid Build Coastguard Worker   t->c_cc[VEOL2] = 0;
312*cf5a6c84SAndroid Build Coastguard Worker }
313*cf5a6c84SAndroid Build Coastguard Worker 
xtcgetattr(struct termios * t)314*cf5a6c84SAndroid Build Coastguard Worker static void xtcgetattr(struct termios *t)
315*cf5a6c84SAndroid Build Coastguard Worker {
316*cf5a6c84SAndroid Build Coastguard Worker   if (tcgetattr(TT.fd, t)) perror_exit("tcgetattr %s", TT.F);
317*cf5a6c84SAndroid Build Coastguard Worker }
318*cf5a6c84SAndroid Build Coastguard Worker 
stty_main(void)319*cf5a6c84SAndroid Build Coastguard Worker void stty_main(void)
320*cf5a6c84SAndroid Build Coastguard Worker {
321*cf5a6c84SAndroid Build Coastguard Worker   struct termios old, sane;
322*cf5a6c84SAndroid Build Coastguard Worker   int i, j, n;
323*cf5a6c84SAndroid Build Coastguard Worker 
324*cf5a6c84SAndroid Build Coastguard Worker   if (toys.optflags&(FLAG_a|FLAG_g) && *toys.optargs)
325*cf5a6c84SAndroid Build Coastguard Worker     error_exit("no settings with -a/-g");
326*cf5a6c84SAndroid Build Coastguard Worker 
327*cf5a6c84SAndroid Build Coastguard Worker   if (!TT.F) TT.F = "standard input";
328*cf5a6c84SAndroid Build Coastguard Worker   else TT.fd = xopen(TT.F, (O_RDWR*!!*toys.optargs)|O_NOCTTY|O_NONBLOCK);
329*cf5a6c84SAndroid Build Coastguard Worker 
330*cf5a6c84SAndroid Build Coastguard Worker   xtcgetattr(&old);
331*cf5a6c84SAndroid Build Coastguard Worker 
332*cf5a6c84SAndroid Build Coastguard Worker   if (*toys.optargs) {
333*cf5a6c84SAndroid Build Coastguard Worker     struct termios new = old, tmp;
334*cf5a6c84SAndroid Build Coastguard Worker 
335*cf5a6c84SAndroid Build Coastguard Worker     for (i=0; toys.optargs[i]; i++) {
336*cf5a6c84SAndroid Build Coastguard Worker       char *arg = toys.optargs[i];
337*cf5a6c84SAndroid Build Coastguard Worker 
338*cf5a6c84SAndroid Build Coastguard Worker       if (!strcmp(arg, "size")) show_size(0);
339*cf5a6c84SAndroid Build Coastguard Worker       else if (!strcmp(arg, "speed")) show_speed(&old, 0);
340*cf5a6c84SAndroid Build Coastguard Worker       else if (!strcmp(arg, "line")) new.c_line = get_arg(&i, NR_LDISCS);
341*cf5a6c84SAndroid Build Coastguard Worker       else if (!strcmp(arg, "min")) new.c_cc[VMIN] = get_arg(&i, 255);
342*cf5a6c84SAndroid Build Coastguard Worker       else if (!strcmp(arg, "time")) new.c_cc[VTIME] = get_arg(&i, 255);
343*cf5a6c84SAndroid Build Coastguard Worker       else if (sscanf(arg, "%x:%x:%x:%x:%n", &tmp.c_iflag, &tmp.c_oflag,
344*cf5a6c84SAndroid Build Coastguard Worker                         &tmp.c_cflag, &tmp.c_lflag, &n) == 4)
345*cf5a6c84SAndroid Build Coastguard Worker       {
346*cf5a6c84SAndroid Build Coastguard Worker         int value;
347*cf5a6c84SAndroid Build Coastguard Worker 
348*cf5a6c84SAndroid Build Coastguard Worker         new.c_iflag = tmp.c_iflag;
349*cf5a6c84SAndroid Build Coastguard Worker         new.c_oflag = tmp.c_oflag;
350*cf5a6c84SAndroid Build Coastguard Worker         new.c_cflag = tmp.c_cflag;
351*cf5a6c84SAndroid Build Coastguard Worker         new.c_lflag = tmp.c_lflag;
352*cf5a6c84SAndroid Build Coastguard Worker         arg += n;
353*cf5a6c84SAndroid Build Coastguard Worker         for (j=0;j<NCCS;j++) {
354*cf5a6c84SAndroid Build Coastguard Worker           if (sscanf(arg, "%x%n", &value, &n) != 1) error_exit("bad -g string");
355*cf5a6c84SAndroid Build Coastguard Worker           new.c_cc[j] = value;
356*cf5a6c84SAndroid Build Coastguard Worker           arg += n+1;
357*cf5a6c84SAndroid Build Coastguard Worker         }
358*cf5a6c84SAndroid Build Coastguard Worker       } else if (atoi(arg) > 0) {
359*cf5a6c84SAndroid Build Coastguard Worker         int new_speed = speed(atolx_range(arg, 0, 4000000));
360*cf5a6c84SAndroid Build Coastguard Worker 
361*cf5a6c84SAndroid Build Coastguard Worker         cfsetispeed(&new, new_speed);
362*cf5a6c84SAndroid Build Coastguard Worker         cfsetospeed(&new, new_speed);
363*cf5a6c84SAndroid Build Coastguard Worker       } else if (!strcmp(arg, "ispeed"))
364*cf5a6c84SAndroid Build Coastguard Worker         cfsetispeed(&new, speed(get_arg(&i, 4000000)));
365*cf5a6c84SAndroid Build Coastguard Worker       else if (!strcmp(arg, "ospeed"))
366*cf5a6c84SAndroid Build Coastguard Worker         cfsetospeed(&new, speed(get_arg(&i, 4000000)));
367*cf5a6c84SAndroid Build Coastguard Worker       else if (!strcmp(arg, "rows")) set_size(1, get_arg(&i, USHRT_MAX));
368*cf5a6c84SAndroid Build Coastguard Worker       else if (!strcmp(arg, "cols") || !strcmp(arg, "columns"))
369*cf5a6c84SAndroid Build Coastguard Worker         set_size(0, get_arg(&i, USHRT_MAX));
370*cf5a6c84SAndroid Build Coastguard Worker       else if (set_special_character(&new, &i, arg));
371*cf5a6c84SAndroid Build Coastguard Worker         // Already done as a side effect.
372*cf5a6c84SAndroid Build Coastguard Worker       else if (!strcmp(arg, "cooked"))
373*cf5a6c84SAndroid Build Coastguard Worker         set_options(&new, "brkint", "ignpar", "istrip", "icrnl", "ixon",
374*cf5a6c84SAndroid Build Coastguard Worker           "opost", "isig", "icanon", NULL);
375*cf5a6c84SAndroid Build Coastguard Worker       else if (!strcmp(arg, "evenp") || !strcmp(arg, "parity"))
376*cf5a6c84SAndroid Build Coastguard Worker         set_options(&new, "parenb", "cs7", "-parodd", NULL);
377*cf5a6c84SAndroid Build Coastguard Worker       else if (!strcmp(arg, "oddp"))
378*cf5a6c84SAndroid Build Coastguard Worker         set_options(&new, "parenb", "cs7", "parodd", NULL);
379*cf5a6c84SAndroid Build Coastguard Worker       else if (!strcmp(arg, "-parity") || !strcmp(arg, "-evenp") ||
380*cf5a6c84SAndroid Build Coastguard Worker                  !strcmp(arg, "-oddp")) {
381*cf5a6c84SAndroid Build Coastguard Worker         set_options(&new, "-parenb", "cs8", NULL);
382*cf5a6c84SAndroid Build Coastguard Worker       } else if (!strcmp(arg, "raw")) {
383*cf5a6c84SAndroid Build Coastguard Worker         // POSIX and "man stty" differ wildly. This is "man stty".
384*cf5a6c84SAndroid Build Coastguard Worker         set_options(&new, "-ignbrk", "-brkint", "-ignpar", "-parmrk", "-inpck",
385*cf5a6c84SAndroid Build Coastguard Worker           "-istrip", "-inlcr", "-igncr", "-icrnl", "-ixon", "-ixoff", "-iuclc",
386*cf5a6c84SAndroid Build Coastguard Worker           "-ixany", "-imaxbel", "-opost", "-isig", "-icanon", "-xcase", NULL);
387*cf5a6c84SAndroid Build Coastguard Worker         new.c_cc[VMIN] = 1;
388*cf5a6c84SAndroid Build Coastguard Worker         new.c_cc[VTIME] = 0;
389*cf5a6c84SAndroid Build Coastguard Worker       } else if (!strcmp(arg, "nl"))
390*cf5a6c84SAndroid Build Coastguard Worker         set_options(&new, "-icrnl", "-ocrnl", NULL);
391*cf5a6c84SAndroid Build Coastguard Worker       else if (!strcmp(arg, "-nl"))
392*cf5a6c84SAndroid Build Coastguard Worker         set_options(&new, "icrnl", "ocrnl", "-inlcr", "-igncr", NULL);
393*cf5a6c84SAndroid Build Coastguard Worker       else if (!strcmp(arg, "ek")) {
394*cf5a6c84SAndroid Build Coastguard Worker         new.c_cc[VERASE] = 0x7f;
395*cf5a6c84SAndroid Build Coastguard Worker         new.c_cc[VKILL] = 0x15;
396*cf5a6c84SAndroid Build Coastguard Worker       } else if (!strcmp(arg, "sane")) make_sane(&new);
397*cf5a6c84SAndroid Build Coastguard Worker       else {
398*cf5a6c84SAndroid Build Coastguard Worker         // Translate historical cruft into canonical forms.
399*cf5a6c84SAndroid Build Coastguard Worker         for (j=0; j<ARRAY_LEN(synonyms); j++) {
400*cf5a6c84SAndroid Build Coastguard Worker           if (!strcmp(synonyms[j].from, arg)) {
401*cf5a6c84SAndroid Build Coastguard Worker             arg = synonyms[j].to;
402*cf5a6c84SAndroid Build Coastguard Worker             break;
403*cf5a6c84SAndroid Build Coastguard Worker           }
404*cf5a6c84SAndroid Build Coastguard Worker         }
405*cf5a6c84SAndroid Build Coastguard Worker         set_option(&new, arg);
406*cf5a6c84SAndroid Build Coastguard Worker       }
407*cf5a6c84SAndroid Build Coastguard Worker     }
408*cf5a6c84SAndroid Build Coastguard Worker 
409*cf5a6c84SAndroid Build Coastguard Worker     tcsetattr(TT.fd, TCSADRAIN, &new);
410*cf5a6c84SAndroid Build Coastguard Worker     xtcgetattr(&old);
411*cf5a6c84SAndroid Build Coastguard Worker     if (memcmp(&old, &new, sizeof(old)))
412*cf5a6c84SAndroid Build Coastguard Worker       error_exit("unable to perform all requested operations on %s", TT.F);
413*cf5a6c84SAndroid Build Coastguard Worker 
414*cf5a6c84SAndroid Build Coastguard Worker     return;
415*cf5a6c84SAndroid Build Coastguard Worker   }
416*cf5a6c84SAndroid Build Coastguard Worker 
417*cf5a6c84SAndroid Build Coastguard Worker   if (FLAG(g)) {
418*cf5a6c84SAndroid Build Coastguard Worker     xprintf("%x:%x:%x:%x:", old.c_iflag, old.c_oflag, old.c_cflag, old.c_lflag);
419*cf5a6c84SAndroid Build Coastguard Worker     for (i=0;i<NCCS;i++) xprintf("%x%c", old.c_cc[i], i==NCCS-1?'\n':':');
420*cf5a6c84SAndroid Build Coastguard Worker     return;
421*cf5a6c84SAndroid Build Coastguard Worker   }
422*cf5a6c84SAndroid Build Coastguard Worker 
423*cf5a6c84SAndroid Build Coastguard Worker   // Without arguments, "stty" only shows the speed, the line discipline,
424*cf5a6c84SAndroid Build Coastguard Worker   // special characters and any flags that differ from the "sane" settings.
425*cf5a6c84SAndroid Build Coastguard Worker   make_sane(&sane);
426*cf5a6c84SAndroid Build Coastguard Worker   show_speed(&old, 1);
427*cf5a6c84SAndroid Build Coastguard Worker   if (FLAG(a)) show_size(1);
428*cf5a6c84SAndroid Build Coastguard Worker   out("line = %d;\n", old.c_line);
429*cf5a6c84SAndroid Build Coastguard Worker 
430*cf5a6c84SAndroid Build Coastguard Worker   for (i=j=0; i<ARRAY_LEN(chars); i++) {
431*cf5a6c84SAndroid Build Coastguard Worker     char vis[16] = {};
432*cf5a6c84SAndroid Build Coastguard Worker     cc_t ch = old.c_cc[chars[i].value];
433*cf5a6c84SAndroid Build Coastguard Worker 
434*cf5a6c84SAndroid Build Coastguard Worker     if (ch == sane.c_cc[chars[i].value] && !FLAG(a))
435*cf5a6c84SAndroid Build Coastguard Worker       continue;
436*cf5a6c84SAndroid Build Coastguard Worker 
437*cf5a6c84SAndroid Build Coastguard Worker     if (chars[i].value == VMIN || chars[i].value == VTIME)
438*cf5a6c84SAndroid Build Coastguard Worker       snprintf(vis, sizeof(vis), "%u", ch);
439*cf5a6c84SAndroid Build Coastguard Worker     else if (ch == _POSIX_VDISABLE) strcat(vis, "<undef>");
440*cf5a6c84SAndroid Build Coastguard Worker     else {
441*cf5a6c84SAndroid Build Coastguard Worker       if (ch > 0x7f) {
442*cf5a6c84SAndroid Build Coastguard Worker         strcat(vis, "M-");
443*cf5a6c84SAndroid Build Coastguard Worker         ch -= 128;
444*cf5a6c84SAndroid Build Coastguard Worker       }
445*cf5a6c84SAndroid Build Coastguard Worker       if (ch < ' ') sprintf(vis+strlen(vis), "^%c", (ch+'@'));
446*cf5a6c84SAndroid Build Coastguard Worker       else if (ch == 0x7f) strcat(vis, "^?");
447*cf5a6c84SAndroid Build Coastguard Worker       else sprintf(vis+strlen(vis), "%c", ch);
448*cf5a6c84SAndroid Build Coastguard Worker     }
449*cf5a6c84SAndroid Build Coastguard Worker     out("%s = %s;", chars[i].name, vis);
450*cf5a6c84SAndroid Build Coastguard Worker     j++;
451*cf5a6c84SAndroid Build Coastguard Worker   }
452*cf5a6c84SAndroid Build Coastguard Worker   if (j) out("\n");
453*cf5a6c84SAndroid Build Coastguard Worker 
454*cf5a6c84SAndroid Build Coastguard Worker   show_flags(old.c_cflag, sane.c_cflag, cflags, ARRAY_LEN(cflags));
455*cf5a6c84SAndroid Build Coastguard Worker   show_flags(old.c_iflag, sane.c_iflag, iflags, ARRAY_LEN(iflags));
456*cf5a6c84SAndroid Build Coastguard Worker   show_flags(old.c_oflag, sane.c_oflag, oflags, ARRAY_LEN(oflags));
457*cf5a6c84SAndroid Build Coastguard Worker   show_flags(old.c_lflag, sane.c_lflag, lflags, ARRAY_LEN(lflags));
458*cf5a6c84SAndroid Build Coastguard Worker 
459*cf5a6c84SAndroid Build Coastguard Worker   if (TT.fd) close(TT.fd);
460*cf5a6c84SAndroid Build Coastguard Worker }
461