1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1992-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * *
20 ***********************************************************************/
21 #pragma prototyped
22 /*
23 * stty.c
24 * Written by David Korn
25 * Tue Apr 4 10:46:00 EDT 1995
26 */
27
28 static const char usage[] =
29 "[-?@(#)$Id: stty (AT&T Research) 2008-11-10 $\n]"
30 USAGE_LICENSE
31 "[+NAME?stty - set or get terminal modes]"
32 "[+DESCRIPTION?\bstty\b sets certain terminal I/O modes for the device "
33 "that is the current standard input; without arguments, it writes "
34 "the settings of certain modes to standard output.]"
35
36 "[a:all?Writes to standard output all of the mode settings.]"
37 "[g:save?Writes the current settings to standard output in a form that can "
38 "be used as an argument to another \bstty\b command. The \brows\b "
39 "and \bcolumns\b values are not included.]"
40 "[t:terminal-group?Print the terminal group id of the device, -1 if unknown.]"
41 "\n"
42 "\n[mode ...]\n"
43 "\n"
44 "[+EXTENDED DESCRIPTION?Modes are specified either as a single name or "
45 "as a name followed by a value. As indicated below, many of the "
46 "mode names can be preceded by a \b-\b to negate its meaning. "
47 "Modes are listed by group corresponding to field in the "
48 "\btermios\b structure defined in \b<termios.h>\b. Modes "
49 "in the last group are implemented using options in the previous "
50 "groups. Note that many combinations of modes make no sense, but "
51 "no sanity checking is performed. The modes are selected from the "
52 "following:]{\fabc\f}"
53
54 "[+EXIT STATUS?]{"
55 "[+0?All modes reported or set successfully.]"
56 "[+>0?Standard input not a terminaol or one or more modes failed.]"
57 "}"
58 "[+SEE ALSO?\btegetattr\b(2), \btcsetattr\b(2), \bioctl\b(2)]"
59 ;
60
61 #include <cmd.h>
62 #include <ccode.h>
63 #include <ctype.h>
64 #include <ast_tty.h>
65 #if _sys_ioctl
66 #include <sys/ioctl.h>
67 #endif
68
69 #define C(x) ERROR_catalog(x)
70
71 #ifndef _POSIX_VDISABLE
72 # define _POSIX_VDISABLE 0
73 #endif
74
75 #ifndef NCCS
76 # ifdef NCC
77 # define NCCS NCC
78 # else
79 # define NCCS elementsof(((struct termio*)0)->c_cc)
80 # endif
81 #endif
82
83 /* command options */
84 #define A_FLAG 1
85 #define G_FLAG 2
86 #define T_FLAG 4
87
88 /* termios fields */
89 #define C_FLAG 1
90 #define C_LINE 2
91 #define C_SPEED 3
92 #define I_FLAG 4
93 #define O_FLAG 5
94 #define L_FLAG 6
95 #define T_CHAR 7
96 #define W_SIZE 8
97
98 #define BIT 1
99 #define BITS 2
100 #define NUM 3
101 #define CHAR 4
102 #define SPEED 5
103 #define SIZE 6
104 #define MIXED 7
105 #define SANE 8
106 #define COOKED 9
107 #define CASE 10
108 #define TABS 11
109 #define WIND 12
110
111 #undef SS /* who co-opted this namespace? */
112
113 #define IG 0x0001 /* ignore display */
114 #define NL 0x0002 /* entry ends line of display */
115 #define SS 0x0004 /* set in sane mode */
116 #define US 0x0010 /* unset in sane mode */
117
118 typedef struct tty_s
119 {
120 const char name[8];
121 unsigned char type;
122 unsigned char field;
123 short flags;
124 unsigned long mask;
125 unsigned long val;
126 const char description[76];
127 } Tty_t;
128
129 static const Tty_t Ttable[] =
130 {
131 #ifdef CBAUD
132 { "ispeed", NUM, C_SPEED,0, CBAUD, 0, C("\an\a is the input baud rate") },
133 { "ospeed", NUM, C_SPEED,0, CBAUD, 0, C("\an\a is the output baud rate") },
134 { "speed", NUM, C_SPEED,IG, CBAUD },
135 #endif
136 { "0", SPEED, C_FLAG, 0, B0 },
137 { "50", SPEED, C_FLAG, 0, B50 },
138 { "75", SPEED, C_FLAG, 0, B75 },
139 { "110", SPEED, C_FLAG, 0, B110 },
140 { "134", SPEED, C_FLAG, 0, B134 },
141 { "150", SPEED, C_FLAG, 0, B150 },
142 { "200", SPEED, C_FLAG, 0, B200 },
143 { "300", SPEED, C_FLAG, 0, B300 },
144 { "600", SPEED, C_FLAG, 0, B600 },
145 { "1200", SPEED, C_FLAG, 0, B1200 },
146 { "1800", SPEED, C_FLAG, 0, B1800 },
147 { "2400", SPEED, C_FLAG, 0, B2400 },
148 { "4800", SPEED, C_FLAG, 0, B4800 },
149 { "9600", SPEED, C_FLAG, 0, B9600 },
150 { "19200", SPEED, C_FLAG, 0, B19200 },
151 { "38400", SPEED, C_FLAG, 0, B38400 },
152
153 #ifdef TIOCSWINSZ
154 { "rows", WIND, W_SIZE, IG, 0, 24, C("\an\a is the number of lines for display") },
155 { "cols", WIND, W_SIZE, IG, 1, 80, C("\an\a is the number of columns for display") },
156 { "columns", WIND, W_SIZE, IG, 1, 80, C("Same as \bcols\b") },
157 #endif
158 { "intr", CHAR, T_CHAR, SS, VINTR, 'C', C("Send an interrupt signal") },
159 { "quit", CHAR, T_CHAR, SS, VQUIT, '|', C("Send a quit signal") },
160 { "erase", CHAR, T_CHAR, SS, VERASE, 'H', C("Erase the last character entered") },
161 { "kill", CHAR, T_CHAR, NL|SS, VKILL, 'U', C("Erase the current line") },
162 { "eof", CHAR, T_CHAR, SS, VEOF, 'D', C("Send an end of file") },
163 #ifdef VEOL2
164 { "eol2", CHAR, T_CHAR, US, VEOL2, _POSIX_VDISABLE, C("Alternate character to end the line") },
165 #endif /* VEOL2 */
166 #ifdef VSWTCH
167 { "swtch", CHAR, T_CHAR, US, VSWTCH, _POSIX_VDISABLE, C("Switch to a different shell layer") },
168 #endif /* VSWTCH */
169 { "eol", CHAR, T_CHAR, NL|US, VEOL, _POSIX_VDISABLE, C("End the line") },
170 #ifdef VSTART
171 { "start", CHAR, T_CHAR, SS, VSTART, 'Q', C("Restart the output after stopping it") },
172 #endif /* VSTART */
173 #ifdef VSTOP
174 { "stop", CHAR, T_CHAR, SS, VSTOP, 'S', C("Stop the output") },
175 #endif /* VSTOP */
176 #ifdef VDSUSP
177 { "dsusp", CHAR, T_CHAR, SS, VDSUSP, 'Y', C("Send a terminal stop signal after flushing the input") },
178 #endif /* VDSUSP */
179 #ifdef VSUSP
180 { "susp", CHAR, T_CHAR, NL|SS, VSUSP, 'Z', C("Send a terminal stop signal") },
181 #endif /* VSUSP */
182 #ifdef VREPRINT
183 { "rprnt", CHAR, T_CHAR, SS, VREPRINT, 'R', C("Redraw the current line") },
184 #endif /* VREPRINT */
185 #ifdef VDISCARD
186 { "flush", CHAR, T_CHAR, SS, VDISCARD, 'O', C("Discard output") },
187 #endif /* VDISCARD */
188 #ifdef VWERASE
189 { "werase", CHAR, T_CHAR, SS, VWERASE, 'W', C("Erase the last word entered") },
190 #endif /* VWERASE */
191 #ifdef VLNEXT
192 { "lnext", CHAR, T_CHAR, NL|SS, VLNEXT, 'V', C("Enter the next input character literally") },
193 #endif /* VLNEXT */
194
195 #if _mem_c_line_termios
196 { "line", NUM, C_LINE, 0, 0, 0, C("Line discipline number") },
197 #endif
198 { "min", NUM, T_CHAR, 0, VMIN, 0, C("Mininmum number of characters to read in raw mode") },
199 { "time", NUM, T_CHAR, 0, VTIME, 0, C("Number of .1 second intervals with raw mode") },
200
201 { "parenb", BIT, C_FLAG, 0, PARENB, PARENB, C("Enable (disable) parity generation and detection") },
202 { "parodd", BIT, C_FLAG, 0, PARODD, PARODD, C("Use odd (even) parity") },
203 #ifdef PAREXT
204 { "parext", BIT, C_FLAG, 0, PAREXT, PAREXT },
205 #endif /* PAREXT */
206 #ifdef CREAD
207 { "cread", BIT, C_FLAG, SS, CREAD, CREAD, C("Enable (disable) input") },
208 #endif /* CREAD */
209 { "cs5", SIZE, C_FLAG, 0, CSIZE, CS5 , C("Char size 5") },
210 { "cs6", SIZE, C_FLAG, 0, CSIZE, CS6 , C("Char size 6") },
211 { "cs7", SIZE, C_FLAG, 0, CSIZE, CS7 , C("Char size 7") },
212 { "cs8", SIZE, C_FLAG, 0, CSIZE, CS8 , C("Char size 8") },
213 { "hupcl", BIT, C_FLAG, 0, HUPCL, HUPCL, C("Hangup (do not hangup) connection on last close") },
214 { "hup", BIT, C_FLAG, IG, HUPCL, HUPCL, C("Same as \bhupcl\b") },
215 { "cstopb", BIT, C_FLAG, 0, CSTOPB, CSTOPB, C("Use two (one) stop bits") },
216 #ifdef CRTSCTS
217 { "crtscts", BIT, C_FLAG, 0, CRTSCTS, CRTSCTS, C("Enable (disable) RTS/CTS handshaking") },
218 #endif /* CRTSCTS */
219 { "clocal", BIT, C_FLAG, NL, CLOCAL, CLOCAL, C("Disable (enable) modem control signals") },
220
221 { "ignbrk", BIT, I_FLAG, US, IGNBRK, IGNBRK, C("Ignore (do not ignore) break characters") },
222 { "brkint", BIT, I_FLAG, SS, BRKINT, BRKINT, C("Generate (do not generate) INTR signal on break") },
223 { "ignpar", BIT, I_FLAG, 0, IGNPAR, IGNPAR, C("Ignore (do not ignore) characters with parity errors") },
224 { "parmrk", BIT, I_FLAG, 0, PARMRK, PARMRK, C("Mark (do not mark) parity errors") },
225 { "inpck", BIT, I_FLAG, 0, INPCK, INPCK, C("Enable (disable) input parity checking") },
226 { "istrip", BIT, I_FLAG, 0, ISTRIP, ISTRIP, C("Clear (do not clear) high bit of input characters") },
227 { "inlcr", BIT, I_FLAG, US, INLCR, INLCR, C("Translate (do not translate) carriage return to newline") },
228 { "igncr", BIT, I_FLAG, US, IGNCR, IGNCR, C("Ignore (do not ignore) carriage return") },
229 #ifdef IUCLC
230 { "iuclc", BIT, I_FLAG, US, IUCLC, IUCLC, C("Map (do not map) upper-case to lower case") },
231 #endif /* IUCLC */
232 { "ixon", BIT, I_FLAG, 0, IXON, IXON, C("Enable (disable) XON/XOFF flow control. \bstop\b character stops output") },
233 #ifdef IXANY
234 { "ixany", BIT, I_FLAG, US, IXANY, IXANY, C("Any character (only start character) can restart output.") },
235 { "decctlq", BIT, I_FLAG, IG, IXANY, 0, C("Same as \b-ixany\b") },
236 #endif /* IXANY */
237 { "ixoff", BIT, I_FLAG, US, IXOFF, IXOFF, C("Disable (enable) XON/XOFF flow control") },
238 #ifdef IMAXBEL
239 { "imaxbel", BIT, I_FLAG, SS, IMAXBEL, IMAXBEL, C("Beep (do not beep) if a character arrives with full input buffer") },
240 #endif /* IMAXBEL */
241 { "icrnl", BIT, I_FLAG, NL|SS, ICRNL, ICRNL, C("Translate (do not translate) carriage return to newline") },
242
243 { "isig", BIT, L_FLAG, SS, ISIG, ISIG, C("Enable (disable) \bintr\b, \bquit\b, and \bsusp\b special characters") },
244 { "icanon", BIT, L_FLAG, SS, ICANON, ICANON, C("Enable (disable) \berase\b, \bkill\b, \bwerase\b, and \brprnt\b special characters") },
245 { "icannon", BIT, L_FLAG, SS, ICANON, ICANON },
246 #ifdef IEXTEN
247 { "iexten", BIT, L_FLAG, SS, IEXTEN, IEXTEN, C("Enable (disable) non-POSIX special characters") },
248 #endif /* IEXTEN */
249 { "echo", BIT, L_FLAG, SS, ECHO|ECHONL, ECHO|ECHONL, C("Echo (do not echo) input characters") },
250 { "echoe", BIT, L_FLAG, SS, ECHOE, ECHOE, C("Echo (do not echo) erase characters as backspace-space-backspace") },
251 { "echok", BIT, L_FLAG, SS, ECHOK, ECHOK, C("Echo (do not echo) a newline after a kill character") },
252 #ifdef ECHOKE
253 { "echoke", BIT, L_FLAG, SS, ECHOKE, ECHOKE, C("Echo (do not echo) a newline after a kill character") },
254 #endif
255 { "lfkc", BIT, L_FLAG, IG, ECHOK, ECHOK, C("Same as \bechok\b (\b-echok\b); obsolete") },
256 { "echonl", BIT, L_FLAG, SS, ECHONL, ECHONL,"Echo (do not echo) newline even if not echoing other character" },
257 #ifdef ECHOCTL
258 { "echoctl", BIT, L_FLAG, SS, ECHOCTL, ECHOCTL, C("Echo (do not echo) control characters as \b^\b\ac\a") },
259 #else
260 #define ECHOCTL 0
261 #endif /* ECHOCTL */
262 #ifdef ECHOPRT
263 { "echoprt", BIT, L_FLAG, US, ECHOPRT, ECHOPRT, C("Echo (do not echo) erased characters backward, between '\\' and '/'") },
264 #else
265 #define ECHOPRT 0
266 #endif /* ECHOPRT */
267 #ifdef XCASE
268 { "xcase", BIT, L_FLAG, US, XCASE, XCASE, C("Enable (disable) \bicanon\b uppercase as lowercase with '\\' prefix") },
269 #endif /* XCASE */
270 #ifdef DEFECHO
271 { "defecho", BIT, L_FLAG, 0, DEFECHO, DEFECHO },
272 #endif /* DEFECHO */
273 #ifdef FLUSHO
274 { "flusho", BIT, L_FLAG, 0, FLUSHO, FLUSHO, C("Discard (do not discard) written data. Cleared by subsequent input") },
275 #endif /* FLUSHO */
276 #ifdef PENDIN
277 { "pendin", BIT, L_FLAG, 0, PENDIN, PENDIN, C("Redisplay pending input at next read and then automatically clear \bpendin\b") },
278 #endif /* PENDIN */
279 { "noflsh", BIT, L_FLAG, US, NOFLSH, NOFLSH, C("Disable (enable) flushing after \bintr\b and \bquit\b special characters") },
280 #ifdef TOSTOP
281 { "tostop", BIT, L_FLAG, NL|US, TOSTOP, TOSTOP, C("Stop (do not stop) background jobs that try to write to the terminal") },
282 #endif /* TOSTOP */
283 #ifdef OLCUC
284 { "olcuc", BIT, O_FLAG, US, OLCUC, OLCUC, C("Translate (do not translate) lowercase characters to uppercase") },
285 #endif /* OLCUC */
286 #ifdef ONLCR
287 { "onlcr", BIT, O_FLAG, SS, ONLCR, ONLCR, C("Translate (do not translate) newline to carriage return-newline") },
288 #endif /* ONLCR */
289 #ifdef ONLRET
290 { "onlret", BIT, O_FLAG, US, ONLRET, ONLRET, C("Newline performs (does not perform) a carriage return") },
291 #endif /* ONLRET */
292 #ifdef OCRNL
293 { "ocrnl", BIT, O_FLAG, US, OCRNL, OCRNL, C("Translate (do not translate) carriage return to newline") },
294 #endif /* OCRNL */
295 #ifdef ONOCR
296 { "onocr", BIT, O_FLAG, US, ONOCR, ONOCR, C("Do not (do) print carriage returns in the first column") },
297 #endif /* ONOCR */
298 #ifdef OFILL
299 { "ofill", BIT, O_FLAG, US, OFILL, OFILL, C("Use fill characters (use timing) for delays") },
300 #endif /* OFILL */
301 #ifdef OFDEL
302 { "ofdel", BIT, O_FLAG, US, OFDEL, OFDEL, C("Use DEL (NUL) as fill characters for delays") },
303 #endif /* OFDEL */
304 { "opost", BIT, O_FLAG, SS, OPOST, OPOST, C(" Postprocess (do not postprocess) output") },
305 #ifdef CRDLY
306 { "cr0", BITS, O_FLAG, IG|SS, CRDLY, CR0 },
307 { "cr1", BITS, O_FLAG, US, CRDLY, CR1 },
308 { "cr2", BITS, O_FLAG, US, CRDLY, CR2 },
309 { "cr3", BITS, O_FLAG, US, CRDLY, CR3 },
310 #endif
311 #ifdef NLDLY
312 { "nl0", BITS, O_FLAG, IG|US, NLDLY, NL0 },
313 { "nl1", BITS, O_FLAG, US, NLDLY, NL1 },
314 #endif
315 #ifdef TABDLY
316 { "tabs", TABS, O_FLAG, IG, TABDLY, TAB3, C("Preserve (expand to spaces) tabs") },
317 #ifdef TAB0
318 { "tab0", BITS, O_FLAG, IG|SS, TABDLY, TAB0 },
319 #endif
320 #ifdef TAB1
321 { "tab1", BITS, O_FLAG, US, TABDLY, TAB1 },
322 #endif
323 #ifdef TAB2
324 { "tab2", BITS, O_FLAG, US, TABDLY, TAB2 },
325 #endif
326 { "tab3", BITS, O_FLAG, US, TABDLY, TAB3 },
327 #endif
328 #ifdef BSDLY
329 { "bs0", BITS, O_FLAG, IG|SS, BSDLY, BS0 },
330 { "bs1", BITS, O_FLAG, US, BSDLY, BS1 },
331 #endif
332 #ifdef VTDLY
333 { "vt0", BITS, O_FLAG, IG|SS, VTDLY, VT0 },
334 { "vt1", BITS, O_FLAG, US, VTDLY, VT1 },
335 #endif
336 #ifdef FFDLY
337 { "ff0", BITS, O_FLAG, IG|SS, FFDLY, FF0 },
338 { "ff1", BITS, O_FLAG, US, FFDLY, FF1 },
339 #endif
340 { "", MIXED, O_FLAG, NL|IG },
341
342 { "evenp", MIXED, C_FLAG, IG, PARENB, 0, C("Same as \bparenb -parodd cs7\b") },
343 { "oddp", MIXED, C_FLAG, IG, PARODD, 0, C("Same as \bparenb parodd cs7\b") },
344 { "parity", MIXED, C_FLAG, IG, 0, 0, C("Same as parenb \b-parodd cs7\b") },
345 { "ek", MIXED, C_FLAG, IG, 0, 0, C("Reset the \berase\b and \bkill\b special characters to their default values") },
346 { "sane", SANE, C_FLAG, IG, 0, 0, C("Reset all modes to some reasonable values") },
347 { "cooked", COOKED, C_FLAG, IG, 0, 0, C("Disable raw input and output") },
348 { "raw", COOKED, C_FLAG, IG, 0, 0, C("Enable raw input and output") },
349 { "lcase", CASE, C_FLAG, IG, 0 , 0, C("Set \bxcase\b, \biuclc\b, and \bolcuc\b") },
350 { "LCASE", CASE, C_FLAG, IG, 0 , 0, C("Same as \blcase\b") }
351 };
352
353 #if CC_NATIVE == CC_ASCII
354 #define cntl(x) (((x)=='?')?0177:((x)&037))
355 #else
356 #define cntl(x) (((x)=='?')?ccmapc(0177,CC_ASCII,CC_NATIVE):ccmapc(ccmapc(x,CC_NATIVE,CC_ASCII)&037,CC_ASCII,CC_NATIVE))
357 #endif
358
sane(register struct termios * sp)359 static void sane(register struct termios *sp)
360 {
361 register const Tty_t* tp;
362
363 for (tp = Ttable; tp < &Ttable[elementsof(Ttable)]; tp++)
364 if (tp->flags & (SS|US))
365 switch (tp->type)
366 {
367 case BIT:
368 case BITS:
369 switch (tp->field)
370 {
371 case C_FLAG:
372 if (tp->flags & SS)
373 sp->c_cflag |= tp->mask;
374 else
375 sp->c_cflag &= ~tp->mask;
376 break;
377 case I_FLAG:
378 if (tp->flags & SS)
379 sp->c_iflag |= tp->mask;
380 else
381 sp->c_iflag &= ~tp->mask;
382 break;
383 case O_FLAG:
384 if (tp->flags & SS)
385 sp->c_oflag |= tp->mask;
386 else
387 sp->c_oflag &= ~tp->mask;
388 break;
389 case L_FLAG:
390 if (tp->flags & SS)
391 sp->c_lflag |= tp->mask;
392 else
393 sp->c_lflag &= ~tp->mask;
394 break;
395 }
396 break;
397 case CHAR:
398 sp->c_cc[tp->mask] = cntl(tp->val);
399 break;
400 }
401 }
402
gin(char * arg,struct termios * sp)403 static int gin(char *arg,struct termios *sp)
404 {
405 register int i;
406 if(*arg++ != ':')
407 return(0);
408 sp->c_iflag = strtol(arg,&arg,16);
409 if(*arg++ != ':')
410 return(0);
411 sp->c_oflag = strtol(arg,&arg,16);
412 if(*arg++ != ':')
413 return(0);
414 sp->c_cflag = strtol(arg,&arg,16);
415 if(*arg++ != ':')
416 return(0);
417 sp->c_lflag = strtol(arg,&arg,16);
418 if(*arg++ != ':')
419 return(0);
420 for(i=0;i< NCCS; i++)
421 {
422 sp->c_cc[i] = strtol(arg,&arg,16);
423 if(*arg++ != ':')
424 return(0);
425 }
426 #if _mem_c_line_termios
427 sp->c_line =
428 #endif
429 strtol(arg,&arg,16);
430 if(*arg++ != ':')
431 return(0);
432 i = strtol(arg,&arg,16);
433 if(*arg++ != ':')
434 return(0);
435 cfsetispeed(sp, i);
436 i = strtol(arg,&arg,16);
437 if(*arg++ != ':')
438 return(0);
439 cfsetospeed(sp, i);
440 if(*arg)
441 return(0);
442 return(1);
443 }
444
gout(struct termios * sp)445 static void gout(struct termios *sp)
446 {
447 register int i;
448 sfprintf(sfstdout,":%x",sp->c_iflag);
449 sfprintf(sfstdout,":%x",sp->c_oflag);
450 sfprintf(sfstdout,":%x",sp->c_cflag);
451 sfprintf(sfstdout,":%x",sp->c_lflag);
452 for(i=0;i< NCCS; i++)
453 sfprintf(sfstdout,":%x",sp->c_cc[i]);
454 #if _mem_c_line_termios
455 sfprintf(sfstdout,":%x", sp->c_line);
456 #else
457 sfprintf(sfstdout,":%x", 0);
458 #endif
459 sfprintf(sfstdout,":%x",cfgetispeed(sp));
460 sfprintf(sfstdout,":%x",cfgetospeed(sp));
461 sfprintf(sfstdout,":\n");
462 }
463
output(struct termios * sp,int flags)464 static void output(struct termios *sp, int flags)
465 {
466 const Tty_t *tp;
467 struct termios tty;
468 register int delim = ' ';
469 register int i,off,off2;
470 char schar[2];
471 unsigned int ispeed = cfgetispeed(sp);
472 unsigned int ospeed = cfgetospeed(sp);
473 if(flags&G_FLAG)
474 {
475 gout(sp);
476 return;
477 }
478 tty = *sp;
479 sane(&tty);
480 for(i=0; i < elementsof(Ttable); i++)
481 {
482 tp= &Ttable[i];
483 if(tp->flags&IG)
484 {
485 if(tp->flags&NL)
486 sfputc(sfstdout,'\n');
487 continue;
488 }
489 switch(tp->type)
490 {
491 case BIT:
492 case BITS:
493 off = off2 = 1;
494 switch(tp->field)
495 {
496 case C_FLAG:
497 if(sp->c_cflag&tp->mask)
498 off = 0;
499 if(tty.c_cflag&tp->mask)
500 off2 = 0;
501 break;
502 case I_FLAG:
503 if(sp->c_iflag&tp->mask)
504 off = 0;
505 if(tty.c_iflag&tp->mask)
506 off2 = 0;
507 break;
508 case O_FLAG:
509 if((sp->c_oflag&tp->mask)==tp->val)
510 off = 0;
511 if(tty.c_oflag&tp->mask)
512 off2 = 0;
513 break;
514 case L_FLAG:
515 if(sp->c_lflag&tp->mask)
516 off = 0;
517 if(tty.c_lflag&tp->mask)
518 off2 = 0;
519 }
520 if(tp->flags&NL)
521 delim = '\n';
522 if(!flags && off==off2)
523 continue;
524 if(!off)
525 sfprintf(sfstdout,"%s%c",tp->name,delim);
526 else if(tp->type==BIT)
527 sfprintf(sfstdout,"-%s%c",tp->name,delim);
528 delim = ' ';
529 break;
530
531 case CHAR:
532 off = sp->c_cc[tp->mask];
533 if(tp->flags&NL)
534 delim = '\n';
535 if(!flags && off==(unsigned char)tty.c_cc[tp->mask])
536 continue;
537 if(off==_POSIX_VDISABLE)
538 sfprintf(sfstdout,"%s = <undef>;%c",tp->name,delim);
539 else if(isprint(off&0xff))
540 sfprintf(sfstdout,"%s = %c;%c",tp->name,off,delim);
541 else
542 #if CC_NATIVE == CC_ASCII
543 sfprintf(sfstdout,"%s = ^%c;%c",tp->name,off==0177?'?':(off^0100),delim);
544 #else
545 {
546 off = ccmapc(off, CC_NATIVE, CC_ASCII);
547 sfprintf(sfstdout,"%s = ^%c;%c",tp->name,off==0177?'?':ccmapc(off^0100,CC_ASCII,CC_NATIVE),delim);
548 }
549 #endif
550 delim = ' ';
551 break;
552 case SIZE:
553 if((sp->c_cflag&CSIZE)!=tp->mask)
554 continue;
555 if(flags || (sp->c_cflag&CSIZE) != (tty.c_cflag&CSIZE))
556 sfprintf(sfstdout,"%s ",tp->name);
557 break;
558 case SPEED:
559 if(tp->mask==ispeed)
560 {
561 if(ispeed!=ospeed)
562 schar[0]='i';
563 else
564 schar[0]=0;
565 }
566 else if(tp->mask==ospeed)
567 schar[0]='o';
568 else
569 continue;
570 schar[1] = 0;
571 #ifdef TIOCSWINSZ
572 {
573 struct winsize win;
574 off = ioctl(0,TIOCGWINSZ,&win);
575 if(off>=0)
576 sfprintf(sfstdout,"%sspeed %s baud; rows %d; columns %d;\n",schar,tp->name,win.ws_row,win.ws_col);
577 }
578 if(off<0)
579 #endif
580 sfprintf(sfstdout,"%sspeed %s baud;\n",schar,tp->name);
581 }
582 }
583 if(delim=='\n')
584 sfputc(sfstdout,'\n');
585 }
586
lookup(const char * name)587 static const Tty_t *lookup(const char *name)
588 {
589 register int i;
590 for(i=0; i < elementsof(Ttable); i++)
591 {
592 if(strcmp(Ttable[i].name,name)==0)
593 return(&Ttable[i]);
594 }
595 return(0);
596
597 }
598
getspeed(unsigned long val)599 static const Tty_t *getspeed(unsigned long val)
600 {
601 register int i;
602 for(i=0; i < elementsof(Ttable); i++)
603 {
604 if(Ttable[i].type==SPEED && Ttable[i].mask==val)
605 return(&Ttable[i]);
606 }
607 return(0);
608 }
609
gettchar(register const char * cp)610 static int gettchar(register const char *cp)
611 {
612 if(*cp==0)
613 return(-1);
614 if(cp[1]==0)
615 return((unsigned)cp[0]);
616 if(*cp=='^' && cp[1] && cp[2]==0)
617 {
618 switch(cp[1])
619 {
620 case '-':
621 return(-1);
622 default:
623 return(cntl(cp[1]));
624 }
625 }
626 if(streq(cp,"undef") || streq(cp,"<undef>"))
627 return(-1);
628 return(*((unsigned char*)cp));
629 }
630
set(char * argv[],struct termios * sp)631 static void set(char *argv[], struct termios *sp)
632 {
633 const Tty_t *tp;
634 register int c,off;
635 char *cp;
636 char *ep;
637 while(cp = *argv++)
638 {
639 off = 0;
640 if(*cp=='-')
641 {
642 cp++;
643 off=1;
644 }
645 if(!(tp=lookup(cp)) || (off && (tp->type!=BIT) && (tp->type!=TABS)))
646 error(ERROR_exit(1),"%s: unknown mode",cp);
647 switch(tp->type)
648 {
649 case CHAR:
650 if(off)
651 error(ERROR_exit(1),"%s: unknown mode",cp);
652 if(!*argv)
653 error(ERROR_exit(1),"missing argument to %s",cp);
654 c = gettchar(*argv++);
655 if(c>=0)
656 sp->c_cc[tp->mask] = c;
657 else
658 sp->c_cc[tp->mask] = _POSIX_VDISABLE;
659 break;
660 case BIT: case BITS:
661 switch(tp->field)
662 {
663 case C_FLAG:
664 if(off)
665 sp->c_cflag &= ~tp->mask;
666 else
667 sp->c_cflag |= tp->mask;
668 break;
669 case I_FLAG:
670 if(off)
671 sp->c_iflag &= ~tp->mask;
672 else
673 sp->c_iflag |= tp->mask;
674 break;
675 case O_FLAG:
676 sp->c_oflag &= ~tp->mask;
677 sp->c_oflag |= tp->val;
678 break;
679 case L_FLAG:
680 if(off)
681 sp->c_lflag &= ~tp->mask;
682 else
683 sp->c_lflag |= tp->mask;
684 break;
685 }
686 break;
687 case TABS:
688 sp->c_oflag &= ~tp->mask;
689 if(off)
690 sp->c_oflag |= tp->val;
691 break;
692 #ifdef TIOCSWINSZ
693 case WIND:
694 {
695 struct winsize win;
696 int n;
697 if(ioctl(0,TIOCGWINSZ,&win)<0)
698 error(ERROR_system(1),"cannot set %s",tp->name);
699 if(!(cp= *argv))
700 {
701 sfprintf(sfstdout,"%d\n",tp->mask?win.ws_col:win.ws_row);
702 break;
703 }
704 argv++;
705 n=strtol(cp,&cp,10);
706 if(*cp)
707 error(ERROR_system(1),"%d: invalid number of %s",argv[-1],tp->name);
708 if(tp->mask)
709 win.ws_col = n;
710 else
711 win.ws_row = n;
712 if(ioctl(0,TIOCSWINSZ,&win)<0)
713 error(ERROR_system(1),"cannot set %s",tp->name);
714 break;
715 }
716 #endif
717 case NUM:
718 cp = *argv;
719 if (!cp)
720 {
721 if (tp->field == C_SPEED)
722 {
723 if (tp = getspeed(*tp->name == 'i' ? cfgetispeed(sp) : cfgetospeed(sp)))
724 sfprintf(sfstdout, "%s\n", tp->name);
725 break;
726 }
727 error(ERROR_exit(1), "%s: missing numeric argument", tp->name);
728 }
729 argv++;
730 c = (int)strtol(cp, &ep, 10);
731 if (*ep)
732 error(ERROR_exit(1), "%s: %s: numeric argument expected", tp->name, cp);
733 switch (tp->field)
734 {
735 #if _mem_c_line_termios
736 case C_LINE:
737 sp->c_line = c;
738 break;
739 #endif
740 case C_SPEED:
741 if(getspeed(c))
742 {
743 if (*tp->name != 'o')
744 cfsetispeed(sp, c);
745 if (*tp->name != 'i')
746 cfsetospeed(sp, c);
747 }
748 else
749 error(ERROR_exit(1), "%s: %s: invalid speed", tp->name, cp);
750 break;
751 case T_CHAR:
752 sp->c_cc[tp->mask] = c;
753 break;
754 }
755 break;
756 case SPEED:
757 cfsetospeed(sp, tp->mask);
758 cfsetispeed(sp, tp->mask);
759 break;
760 case SIZE:
761 sp->c_cflag &= ~CSIZE;
762 sp->c_cflag |= tp->mask;
763 break;
764 case SANE:
765 sane(sp);
766 break;
767 #if defined(OLCUC) && defined(IUCLC)
768 case CASE:
769 if(off)
770 {
771 sp->c_iflag |= IUCLC;
772 sp->c_oflag |= OLCUC;
773 }
774 else
775 {
776 sp->c_iflag &= ~IUCLC;
777 sp->c_oflag &= ~OLCUC;
778 }
779 break;
780 #endif /* OLCUC && IUCLC */
781 }
782 }
783 }
784
785
listchars(Sfio_t * sp,int type)786 static void listchars(Sfio_t *sp,int type)
787 {
788 int i,c;
789 c = (type==CHAR?'c':'n');
790 for(i=0; i < elementsof(Ttable); i++)
791 {
792 if(Ttable[i].type==type && *Ttable[i].description)
793 sfprintf(sp,"[+%s \a%c\a?%s.]",Ttable[i].name,c,Ttable[i].description);
794 }
795 }
796
listgroup(Sfio_t * sp,int type,const char * description)797 static void listgroup(Sfio_t *sp,int type, const char *description)
798 {
799 int i;
800 sfprintf(sp,"[+");
801 for(i=0; i < elementsof(Ttable); i++)
802 {
803 if(Ttable[i].type==type)
804 sfprintf(sp,"%s ",Ttable[i].name);
805 }
806 sfprintf(sp,"?%s.]",description);
807 }
808
listmask(Sfio_t * sp,unsigned int mask,const char * description)809 static void listmask(Sfio_t *sp,unsigned int mask,const char *description)
810 {
811 int i;
812 sfprintf(sp,"[+");
813 for(i=0; i < elementsof(Ttable); i++)
814 {
815 if(Ttable[i].mask==mask && Ttable[i].type==BITS)
816 sfprintf(sp,"%s ",Ttable[i].name);
817 }
818 sfprintf(sp,"?%s.]",description);
819 }
820
listfields(Sfio_t * sp,int field)821 static void listfields(Sfio_t *sp,int field)
822 {
823 int i;
824 for(i=0; i < elementsof(Ttable); i++)
825 {
826 if(Ttable[i].field==field && Ttable[i].type==BIT && *Ttable[i].description)
827 sfprintf(sp,"[+%s (-%s)?%s.]",Ttable[i].name,Ttable[i].name,Ttable[i].description);
828 }
829 }
830
listmode(Sfio_t * sp,const char * name)831 static void listmode(Sfio_t *sp,const char *name)
832 {
833 sfprintf(sp,"[+%s?%s.]",name,lookup(name)->description);
834 }
835
infof(Opt_t * op,Sfio_t * sp,const char * s,Optdisc_t * dp)836 static int infof(Opt_t* op, Sfio_t* sp, const char* s, Optdisc_t* dp)
837 {
838 NoP(op);
839 NoP(s);
840 NoP(dp);
841 sfprintf(sp,"[+Control Modes.]{");
842 listfields(sp,C_FLAG);
843 listgroup(sp,SPEED,"Attempt to set input and output baud rate to number given. A value of \b0\b causes immediate hangup");
844 listchars(sp,NUM);
845 listgroup(sp,SIZE,"Number of bits in a character");
846 sfprintf(sp,"}[+Input Modes.]{");
847 listfields(sp,I_FLAG);
848 sfprintf(sp,"}[+Output Modes.]{");
849 listfields(sp,O_FLAG);
850 #ifdef CRDLY
851 listmask(sp,CRDLY,"Carriage return delay style");
852 #endif
853 #ifdef NLDLY
854 listmask(sp,NLDLY,"Newline delay style");
855 #endif
856 #ifdef TABDLY
857 listmask(sp,TABDLY,"Horizontal tab delay style");
858 #endif
859 #ifdef BSDLY
860 listmask(sp,BSDLY,"Backspace delay style");
861 #endif
862 #ifdef FFDLY
863 listmask(sp,FFDLY,"Form feed delay style");
864 #endif
865 #ifdef VTDLY
866 listmask(sp,VTDLY,"Vertical tab delay style");
867 #endif
868 sfprintf(sp,"}[+Local Modes.]{");
869 listfields(sp,L_FLAG);
870 sfprintf(sp,"}[+Control Assignments.?If \ac\a is \bundef\b or an empty "
871 "string then the control assignment is disabled.]{");
872 listchars(sp,WIND);
873 listchars(sp,CHAR);
874 sfprintf(sp,"}[+Combination Modes.]{");
875 listmode(sp,"ek");
876 listmode(sp,"evenp");
877 listmode(sp,"lcase");
878 listmode(sp,"oddp");
879 listmode(sp,"parity");
880 listmode(sp,"sane");
881 listmode(sp,"tabs");
882 listmode(sp,"LCASE");
883 sfputc(sp,'}');
884 return(1);
885 }
886
887 #ifndef _lib_tcgetpgrp
888 # ifdef TIOCGPGRP
889 static int _i_;
890 # define tcgetpgrp(a) (ioctl(a, TIOCGPGRP, &_i_)>=0?_i_:-1)
891 # else
892 # define tcgetpgrp(a) (-1)
893 # endif /* TIOCGPGRP */
894 #endif /* _lib_tcgetpgrp */
895
896 int
b_stty(int argc,char ** argv,void * context)897 b_stty(int argc, char** argv, void* context)
898 {
899 struct termios tty;
900 register int n;
901 register int flags = 0;
902 const Tty_t* tp;
903 Optdisc_t disc;
904
905 cmdinit(argc, argv, context, ERROR_CATALOG, ERROR_INTERACTIVE);
906 if (tcgetattr(0, &tty) < 0)
907 error(ERROR_system(1),"not a tty");
908 memset(&disc, 0, sizeof(disc));
909 disc.version = OPT_VERSION;
910 disc.infof = infof;
911 opt_info.disc = &disc;
912 for (;;)
913 {
914 switch (n = optget(argv, usage))
915 {
916 case 'a':
917 case 'g':
918 case 't':
919 if (!opt_info.offset || !argv[opt_info.index][opt_info.offset])
920 {
921 switch (n)
922 {
923 case 'a':
924 flags |= A_FLAG;
925 break;
926 case 'g':
927 flags |= G_FLAG;
928 break;
929 case 't':
930 flags |= T_FLAG;
931 break;
932 }
933 continue;
934 }
935 /*FALLTHROUGH*/
936 case ':':
937 if (!opt_info.offset)
938 error(2, "%s", opt_info.arg);
939 else if (!(tp = lookup(argv[opt_info.index]+1)) || (tp->type != BIT && tp->type != TABS))
940 error(ERROR_exit(1), "%s: unknown mode", argv[opt_info.index]);
941 break;
942 case '?':
943 error(ERROR_usage(2), "%s", opt_info.arg);
944 break;
945 }
946 break;
947 }
948 argv += opt_info.index;
949 if (error_info.errors || (flags && *argv) || (flags&(flags-1)))
950 error(ERROR_usage(2), "%s", optusage(NiL));
951 if (flags & T_FLAG)
952 sfprintf(sfstdout, "%d\n", tcgetpgrp(0));
953 else if (*argv)
954 {
955 if (!argv[1] && **argv == ':')
956 gin(*argv, &tty);
957 else
958 set(argv, &tty);
959 if (tcsetattr(0, TCSANOW, &tty) < 0)
960 error(ERROR_system(1), "cannot set tty");
961 }
962 else
963 output(&tty, flags);
964 return error_info.errors;
965 }
966