.
[coreutils.git] / src / stty.c
blobabfa34b25311554bb7921b36cd30d2066498b45b
1 /* stty -- change and print terminal line settings
2 Copyright (C) 90, 91, 92, 93, 94, 1995 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
7 any later version.
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
18 /* Usage: stty [-ag] [--all] [--save] [setting...]
20 Options:
21 -a, --all Write all current settings to stdout in human-readable form.
22 -g, --save Write all current settings to stdout in stty-readable form.
24 If no args are given, write to stdout the baud rate and settings that
25 have been changed from their defaults. Mode reading and changes
26 are done on stdin.
28 David MacKenzie <djm@gnu.ai.mit.edu> */
30 #include <config.h>
31 #include <stdio.h>
32 #include <sys/types.h>
33 #include <termios.h>
34 #ifdef GWINSZ_IN_SYS_IOCTL
35 #include <sys/ioctl.h>
36 #endif
37 #ifdef WINSIZE_IN_PTEM
38 #include <sys/stream.h>
39 #include <sys/ptem.h>
40 #endif
41 #include <getopt.h>
42 #ifdef __STDC__
43 #include <stdarg.h>
44 #define VA_START(args, lastarg) va_start(args, lastarg)
45 #else
46 #include <varargs.h>
47 #define VA_START(args, lastarg) va_start(args)
48 #endif
50 #include "system.h"
51 #include "version.h"
52 #include "long-options.h"
53 #include "error.h"
55 #if defined(GWINSZ_BROKEN) /* Such as for SCO UNIX 3.2.2. */
56 #undef TIOCGWINSZ
57 #endif
59 #ifndef _POSIX_VDISABLE
60 #define _POSIX_VDISABLE ((unsigned char) 0)
61 #endif
63 #define Control(c) ((c) & 0x1f)
64 /* Canonical values for control characters. */
65 #ifndef CINTR
66 #define CINTR Control ('c')
67 #endif
68 #ifndef CQUIT
69 #define CQUIT 28
70 #endif
71 #ifndef CERASE
72 #define CERASE 127
73 #endif
74 #ifndef CKILL
75 #define CKILL Control ('u')
76 #endif
77 #ifndef CEOF
78 #define CEOF Control ('d')
79 #endif
80 #ifndef CEOL
81 #define CEOL _POSIX_VDISABLE
82 #endif
83 #ifndef CSTART
84 #define CSTART Control ('q')
85 #endif
86 #ifndef CSTOP
87 #define CSTOP Control ('s')
88 #endif
89 #ifndef CSUSP
90 #define CSUSP Control ('z')
91 #endif
92 #if defined(VEOL2) && !defined(CEOL2)
93 #define CEOL2 _POSIX_VDISABLE
94 #endif
95 #if defined(VSWTCH) && !defined(CSWTCH)
96 #define CSWTCH _POSIX_VDISABLE
97 #endif
99 /* SunOS 5.3 loses (^Z doesn't work) if `swtch' is the same as `susp'.
100 So the default is to disable `swtch.' */
101 #if defined (__sparc__) && defined (__svr4__)
102 #undef CSWTCH
103 #define CSWTCH _POSIX_VDISABLE
104 #endif
106 #if defined(VWERSE) && !defined (VWERASE) /* AIX-3.2.5 */
107 #define VWERASE VWERSE
108 #endif
109 #if defined(VDSUSP) && !defined (CDSUSP)
110 #define CDSUSP Control ('y')
111 #endif
112 #if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */
113 #define VREPRINT VRPRNT
114 #endif
115 #if defined(VREPRINT) && !defined(CRPRNT)
116 #define CRPRNT Control ('r')
117 #endif
118 #if defined(VWERASE) && !defined(CWERASE)
119 #define CWERASE Control ('w')
120 #endif
121 #if defined(VLNEXT) && !defined(CLNEXT)
122 #define CLNEXT Control ('v')
123 #endif
124 #if defined(VDISCARD) && !defined(VFLUSHO)
125 #define VFLUSHO VDISCARD
126 #endif
127 #if defined(VFLUSH) && !defined(VFLUSHO) /* Ultrix 4.2 */
128 #define VFLUSHO VFLUSH
129 #endif
130 #if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */
131 #define ECHOCTL CTLECH
132 #endif
133 #if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */
134 #define ECHOCTL TCTLECH
135 #endif
136 #if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */
137 #define ECHOKE CRTKIL
138 #endif
139 #if defined(VFLUSHO) && !defined(CFLUSHO)
140 #define CFLUSHO Control ('o')
141 #endif
142 #if defined(VSTATUS) && !defined(CSTATUS)
143 #define CSTATUS Control ('t')
144 #endif
146 static const char *visible ();
147 static unsigned long baud_to_value ();
148 static int recover_mode ();
149 static int screen_columns ();
150 static int set_mode ();
151 static long integer_arg ();
152 static speed_t string_to_baud ();
153 static tcflag_t *mode_type_flag ();
154 static void display_all ();
155 static void display_changed ();
156 static void display_recoverable ();
157 static void display_settings ();
158 static void display_speed ();
159 static void display_window_size ();
160 static void sane_mode ();
161 static void set_control_char ();
162 static void set_speed ();
163 static void set_window_size ();
165 /* Which speeds to set. */
166 enum speed_setting
168 input_speed, output_speed, both_speeds
171 /* What to output and how. */
172 enum output_type
174 changed, all, recoverable /* Default, -a, -g. */
177 /* Which member(s) of `struct termios' a mode uses. */
178 enum mode_type
180 control, input, output, local, combination
183 /* Flags for `struct mode_info'. */
184 #define SANE_SET 1 /* Set in `sane' mode. */
185 #define SANE_UNSET 2 /* Unset in `sane' mode. */
186 #define REV 4 /* Can be turned off by prepending `-'. */
187 #define OMIT 8 /* Don't display value. */
189 /* Each mode. */
190 struct mode_info
192 const char *name; /* Name given on command line. */
193 enum mode_type type; /* Which structure element to change. */
194 char flags; /* Setting and display options. */
195 unsigned long bits; /* Bits to set for this mode. */
196 unsigned long mask; /* Other bits to turn off for this mode. */
199 static struct mode_info mode_info[] =
201 {"parenb", control, REV, PARENB, 0},
202 {"parodd", control, REV, PARODD, 0},
203 {"cs5", control, 0, CS5, CSIZE},
204 {"cs6", control, 0, CS6, CSIZE},
205 {"cs7", control, 0, CS7, CSIZE},
206 {"cs8", control, 0, CS8, CSIZE},
207 {"hupcl", control, REV, HUPCL, 0},
208 {"hup", control, REV | OMIT, HUPCL, 0},
209 {"cstopb", control, REV, CSTOPB, 0},
210 {"cread", control, SANE_SET | REV, CREAD, 0},
211 {"clocal", control, REV, CLOCAL, 0},
212 #ifdef CRTSCTS
213 {"crtscts", control, REV, CRTSCTS, 0},
214 #endif
216 {"ignbrk", input, SANE_UNSET | REV, IGNBRK, 0},
217 {"brkint", input, SANE_SET | REV, BRKINT, 0},
218 {"ignpar", input, REV, IGNPAR, 0},
219 {"parmrk", input, REV, PARMRK, 0},
220 {"inpck", input, REV, INPCK, 0},
221 {"istrip", input, REV, ISTRIP, 0},
222 {"inlcr", input, SANE_UNSET | REV, INLCR, 0},
223 {"igncr", input, SANE_UNSET | REV, IGNCR, 0},
224 {"icrnl", input, SANE_SET | REV, ICRNL, 0},
225 {"ixon", input, REV, IXON, 0},
226 {"ixoff", input, SANE_UNSET | REV, IXOFF, 0},
227 {"tandem", input, REV | OMIT, IXOFF, 0},
228 #ifdef IUCLC
229 {"iuclc", input, SANE_UNSET | REV, IUCLC, 0},
230 #endif
231 #ifdef IXANY
232 {"ixany", input, SANE_UNSET | REV, IXANY, 0},
233 #endif
234 #ifdef IMAXBEL
235 {"imaxbel", input, SANE_SET | REV, IMAXBEL, 0},
236 #endif
238 {"opost", output, SANE_SET | REV, OPOST, 0},
239 #ifdef OLCUC
240 {"olcuc", output, SANE_UNSET | REV, OLCUC, 0},
241 #endif
242 #ifdef OCRNL
243 {"ocrnl", output, SANE_UNSET | REV, OCRNL, 0},
244 #endif
245 #ifdef ONLCR
246 {"onlcr", output, SANE_SET | REV, ONLCR, 0},
247 #endif
248 #ifdef ONOCR
249 {"onocr", output, SANE_UNSET | REV, ONOCR, 0},
250 #endif
251 #ifdef ONLRET
252 {"onlret", output, SANE_UNSET | REV, ONLRET, 0},
253 #endif
254 #ifdef OFILL
255 {"ofill", output, SANE_UNSET | REV, OFILL, 0},
256 #endif
257 #ifdef OFDEL
258 {"ofdel", output, SANE_UNSET | REV, OFDEL, 0},
259 #endif
260 #ifdef NLDLY
261 {"nl1", output, SANE_UNSET, NL1, NLDLY},
262 {"nl0", output, SANE_SET, NL0, NLDLY},
263 #endif
264 #ifdef CRDLY
265 {"cr3", output, SANE_UNSET, CR3, CRDLY},
266 {"cr2", output, SANE_UNSET, CR2, CRDLY},
267 {"cr1", output, SANE_UNSET, CR1, CRDLY},
268 {"cr0", output, SANE_SET, CR0, CRDLY},
269 #endif
270 #ifdef TABDLY
271 {"tab3", output, SANE_UNSET, TAB3, TABDLY},
272 {"tab2", output, SANE_UNSET, TAB2, TABDLY},
273 {"tab1", output, SANE_UNSET, TAB1, TABDLY},
274 {"tab0", output, SANE_SET, TAB0, TABDLY},
275 #else
276 #ifdef OXTABS
277 {"tab3", output, SANE_UNSET, OXTABS, 0},
278 #endif
279 #endif
280 #ifdef BSDLY
281 {"bs1", output, SANE_UNSET, BS1, BSDLY},
282 {"bs0", output, SANE_SET, BS0, BSDLY},
283 #endif
284 #ifdef VTDLY
285 {"vt1", output, SANE_UNSET, VT1, VTDLY},
286 {"vt0", output, SANE_SET, VT0, VTDLY},
287 #endif
288 #ifdef FFDLY
289 {"ff1", output, SANE_UNSET, FF1, FFDLY},
290 {"ff0", output, SANE_SET, FF0, FFDLY},
291 #endif
293 {"isig", local, SANE_SET | REV, ISIG, 0},
294 {"icanon", local, SANE_SET | REV, ICANON, 0},
295 #ifdef IEXTEN
296 {"iexten", local, SANE_SET | REV, IEXTEN, 0},
297 #endif
298 {"echo", local, SANE_SET | REV, ECHO, 0},
299 {"echoe", local, SANE_SET | REV, ECHOE, 0},
300 {"crterase", local, REV | OMIT, ECHOE, 0},
301 {"echok", local, SANE_SET | REV, ECHOK, 0},
302 {"echonl", local, SANE_UNSET | REV, ECHONL, 0},
303 {"noflsh", local, SANE_UNSET | REV, NOFLSH, 0},
304 #ifdef XCASE
305 {"xcase", local, SANE_UNSET | REV, XCASE, 0},
306 #endif
307 #ifdef TOSTOP
308 {"tostop", local, SANE_UNSET | REV, TOSTOP, 0},
309 #endif
310 #ifdef ECHOPRT
311 {"echoprt", local, SANE_UNSET | REV, ECHOPRT, 0},
312 {"prterase", local, REV | OMIT, ECHOPRT, 0},
313 #endif
314 #ifdef ECHOCTL
315 {"echoctl", local, SANE_SET | REV, ECHOCTL, 0},
316 {"ctlecho", local, REV | OMIT, ECHOCTL, 0},
317 #endif
318 #ifdef ECHOKE
319 {"echoke", local, SANE_SET | REV, ECHOKE, 0},
320 {"crtkill", local, REV | OMIT, ECHOKE, 0},
321 #endif
323 {"evenp", combination, REV | OMIT, 0, 0},
324 {"parity", combination, REV | OMIT, 0, 0},
325 {"oddp", combination, REV | OMIT, 0, 0},
326 {"nl", combination, REV | OMIT, 0, 0},
327 {"ek", combination, OMIT, 0, 0},
328 {"sane", combination, OMIT, 0, 0},
329 {"cooked", combination, REV | OMIT, 0, 0},
330 {"raw", combination, REV | OMIT, 0, 0},
331 {"pass8", combination, REV | OMIT, 0, 0},
332 {"litout", combination, REV | OMIT, 0, 0},
333 {"cbreak", combination, REV | OMIT, 0, 0},
334 #ifdef IXANY
335 {"decctlq", combination, REV | OMIT, 0, 0},
336 #endif
337 #if defined (TABDLY) || defined (OXTABS)
338 {"tabs", combination, REV | OMIT, 0, 0},
339 #endif
340 #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
341 {"lcase", combination, REV | OMIT, 0, 0},
342 {"LCASE", combination, REV | OMIT, 0, 0},
343 #endif
344 {"crt", combination, OMIT, 0, 0},
345 {"dec", combination, OMIT, 0, 0},
347 {NULL, control, 0, 0, 0}
350 /* Control character settings. */
351 struct control_info
353 const char *name; /* Name given on command line. */
354 unsigned char saneval; /* Value to set for `stty sane'. */
355 int offset; /* Offset in c_cc. */
358 /* Control characters. */
360 static struct control_info control_info[] =
362 {"intr", CINTR, VINTR},
363 {"quit", CQUIT, VQUIT},
364 {"erase", CERASE, VERASE},
365 {"kill", CKILL, VKILL},
366 {"eof", CEOF, VEOF},
367 {"eol", CEOL, VEOL},
368 #ifdef VEOL2
369 {"eol2", CEOL2, VEOL2},
370 #endif
371 #ifdef VSWTCH
372 {"swtch", CSWTCH, VSWTCH},
373 #endif
374 {"start", CSTART, VSTART},
375 {"stop", CSTOP, VSTOP},
376 {"susp", CSUSP, VSUSP},
377 #ifdef VDSUSP
378 {"dsusp", CDSUSP, VDSUSP},
379 #endif
380 #ifdef VREPRINT
381 {"rprnt", CRPRNT, VREPRINT},
382 #endif
383 #ifdef VWERASE
384 {"werase", CWERASE, VWERASE},
385 #endif
386 #ifdef VLNEXT
387 {"lnext", CLNEXT, VLNEXT},
388 #endif
389 #ifdef VFLUSHO
390 {"flush", CFLUSHO, VFLUSHO},
391 #endif
392 #ifdef VSTATUS
393 {"status", CSTATUS, VSTATUS},
394 #endif
396 /* These must be last because of the display routines. */
397 {"min", 1, VMIN},
398 {"time", 0, VTIME},
399 {NULL, 0, 0}
402 /* The width of the screen, for output wrapping. */
403 static int max_col;
405 /* Current position, to know when to wrap. */
406 static int current_col;
408 static struct option longopts[] =
410 {"all", no_argument, NULL, 'a'},
411 {"save", no_argument, NULL, 'g'},
412 {NULL, 0, NULL, 0}
415 /* The name this program was run with. */
416 char *program_name;
418 /* Print format string MESSAGE and optional args.
419 Wrap to next line first if it won't fit.
420 Print a space first unless MESSAGE will start a new line. */
422 /* VARARGS */
423 static void
424 #ifdef __STDC__
425 wrapf (const char *message,...)
426 #else
427 wrapf (message, va_alist)
428 const char *message;
429 va_dcl
430 #endif
432 va_list args;
433 char buf[1024]; /* Plenty long for our needs. */
434 int buflen;
436 VA_START (args, message);
437 vsprintf (buf, message, args);
438 va_end (args);
439 buflen = strlen (buf);
440 if (current_col + (current_col > 0) + buflen >= max_col)
442 putchar ('\n');
443 current_col = 0;
445 if (current_col > 0)
447 putchar (' ');
448 current_col++;
450 fputs (buf, stdout);
451 current_col += buflen;
454 static void
455 usage (status)
456 int status;
458 if (status != 0)
459 fprintf (stderr, "Try `%s --help' for more information.\n",
460 program_name);
461 else
463 printf ("\
464 Usage: %s [SETTING]...\n\
465 or: %s OPTION\n\
467 program_name, program_name);
468 printf ("\
469 Print or change terminal characteristics.\n\
471 -a, --all print all current settings in human-readable form\n\
472 -g, --save print all current settings in a stty-readable form\n\
473 --help display this help and exit\n\
474 --version output version information and exit\n\
476 Optional - before SETTING indicates negation. An * marks non-POSIX\n\
477 settings. The underlying system defines which settings are available.\n\
479 printf ("\
481 Special characters:\n\
482 * dsusp CHAR CHAR will send a terminal stop signal once input flushed\n\
483 eof CHAR CHAR will send an end of file (terminate the input)\n\
484 eol CHAR CHAR will end the line\n\
485 * eol2 CHAR alternate CHAR for ending the line\n\
486 erase CHAR CHAR will erase the last character typed\n\
487 intr CHAR CHAR will send an interrupt signal\n\
488 kill CHAR CHAR will erase the current line\n\
489 * lnext CHAR CHAR will enter the next character quoted\n\
490 quit CHAR CHAR will send a quit signal\n\
491 * rprnt CHAR CHAR will redraw the current line\n\
492 start CHAR CHAR will restart the output after stopping it\n\
493 stop CHAR CHAR will stop the output\n\
494 susp CHAR CHAR will send a terminal stop signal\n\
495 * swtch CHAR CHAR will switch to a different shell layer\n\
496 * werase CHAR CHAR will erase the last word typed\n\
498 printf ("\
500 Special settings:\n\
501 N set the input and output speeds to N bauds\n\
502 * cols N tell the kernel that the terminal has N columns\n\
503 * columns N same as cols N\n\
504 ispeed N set the input speed to N\n\
505 * line N use line discipline N\n\
506 min N with -icanon, set N characters minimum for a completed read\n\
507 ospeed N set the output speed to N\n\
508 * rows N tell the kernel that the terminal has N rows\n\
509 * size print the number of rows and columns according to the kernel\n\
510 speed print the terminal speed\n\
511 time N with -icanon, set read timeout of N tenths of a second\n\
513 printf ("\
515 Control settings:\n\
516 [-]clocal disable modem control signals\n\
517 [-]cread allow input to be received\n\
518 * [-]crtscts enable RTS/CTS handshaking\n\
519 csN set character size to N bits, N in [5..8]\n\
520 [-]cstopb use two stop bits per character (one with `-')\n\
521 [-]hup send a hangup signal when the last process closes the tty\n\
522 [-]hupcl same as [-]hup\n\
523 [-]parenb generate parity bit in output and expect parity bit in input\n\
524 [-]parodd set odd parity (even with `-')\n\
526 printf ("\
528 Input settings:\n\
529 [-]brkint breaks cause an interrupt signal\n\
530 [-]icrnl translate carriage return to newline\n\
531 [-]ignbrk ignore breaks\n\
532 [-]igncr ignore carriage return\n\
533 [-]ignpar ignore parity errors\n\
534 * [-]imaxbel beep and do not flush a full input buffer on a character\n\
535 [-]inlcr translate newline to carriage return\n\
536 [-]inpck enable input parity checking\n\
537 [-]istrip clear high (8th) bit of input characters\n\
538 * [-]iuclc translate uppercase characters to lowercase\n\
539 * [-]ixany let any character restart output, not only start character\n\
540 [-]ixoff enable sending of start/stop characters\n\
541 [-]ixon enable XON/XOFF flow control\n\
542 [-]parmrk mark parity errors (with a 255-0-character sequence)\n\
543 [-]tandem same as [-]ixoff\n\
545 printf ("\
547 Output settings:\n\
548 * bsN backspace delay style, N in [0..1]\n\
549 * crN carriage return delay style, N in [0..3]\n\
550 * ffN form feed delay style, N in [0..1]\n\
551 * nlN newline delay style, N in [0..1]\n\
552 * [-]ocrnl translate carriage return to newline\n\
553 * [-]ofdel use delete characters for fill instead of null characters\n\
554 * [-]ofill use fill (padding) characters instead of timing for delays\n\
555 * [-]olcuc translate lowercase characters to uppercase\n\
556 * [-]onlcr translate newline to carriage return-newline\n\
557 * [-]onlret newline performs a carriage return\n\
558 * [-]onocr do not print carriage returns in the first column\n\
559 [-]opost postprocess output\n\
560 * tabN horizontal tab delay style, N in [0..3]\n\
561 * tabs same as tab0\n\
562 * -tabs same as tab3\n\
563 * vtN vertical tab delay style, N in [0..1]\n\
565 printf ("\
567 Local settings:\n\
568 [-]crterase echo erase characters as backspace-space-backspace\n\
569 * crtkill kill all line by obeying the echoprt and echoe settings\n\
570 * -crtkill kill all line by obeying the echoctl and echok settings\n\
571 * [-]ctlecho echo control characters in hat notation (`^c')\n\
572 [-]echo echo input characters\n\
573 * [-]echoctl same as [-]ctlecho\n\
574 [-]echoe same as [-]crterase\n\
575 [-]echok echo a newline after a kill character\n\
576 * [-]echoke same as [-]crtkill\n\
577 [-]echonl echo newline even if not echoing other characters\n\
578 * [-]echoprt echo erased characters backward, between `\\' and '/'\n\
579 [-]icanon enable erase, kill, werase, and rprnt special characters\n\
580 [-]iexten enable non-POSIX special characters\n\
581 [-]isig enable interrupt, quit, and suspend special characters\n\
582 [-]noflsh disable flushing after interrupt and quit special characters\n\
583 * [-]prterase same as [-]echoprt\n\
584 * [-]tostop stop background jobs that try to write to the terminal\n\
585 * [-]xcase with icanon, escape with `\\' for uppercase characters\n\
587 printf ("\
589 Combination settings:\n\
590 * [-]LCASE same as [-]lcase\n\
591 cbreak same as -icanon\n\
592 -cbreak same as icanon\n\
593 cooked same as brkint ignpar istrip icrnl ixon opost isig\n\
594 icanon, eof and eol characters to their default values\n\
595 -cooked same as raw\n\
596 crt same as echoe echoctl echoke\n\
597 dec same as echoe echoctl echoke -ixany intr ^c erase 0177\n\
598 kill ^u\n\
599 * [-]decctlq same as [-]ixany\n\
600 ek erase and kill characters to their default values\n\
601 evenp same as parenb -parodd cs7\n\
602 -evenp same as -parenb cs8\n\
603 * [-]lcase same as xcase iuclc olcuc\n\
604 litout same as -parenb -istrip -opost cs8\n\
605 -litout same as parenb istrip opost cs7\n\
606 nl same as -icrnl -onlcr\n\
607 -nl same as icrnl -inlcr -igncr onlcr -ocrnl -onlret\n\
608 oddp same as parenb parodd cs7\n\
609 -oddp same as -parenb cs8\n\
610 [-]parity same as [-]evenp\n\
611 pass8 same as -parenb -istrip cs8\n\
612 -pass8 same as parenb istrip cs7\n\
613 raw same as -ignbrk -brkint -ignpar -parmrk -inpck -istrip\n\
614 -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany\n\
615 -imaxbel -opost -isig -icanon -xcase min 1 time 0\n\
616 -raw same as cooked\n\
617 sane same as cread -ignbrk brkint -inlcr -igncr icrnl\n\
618 -ixoff -iucl -ixany imaxbel opost -olcuc -ocrnl onlcr\n\
619 -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0\n\
620 isig icanon iexten echo echoe echok -echonl -noflsh\n\
621 -xcase -tostop -echoprt echoctl echoke, all special\n\
622 characters to their default values.\n\
624 printf ("\
626 Handle the tty line connected to standard input. Without arguments,\n\
627 prints baud rate, line discipline, and deviations from stty sane. In\n\
628 settings, CHAR is taken literally, or coded as in ^c, 0x37, 0177 or\n\
629 127; special values ^- or undef used to disable special characters.\n\
632 exit (status);
635 void
636 main (argc, argv)
637 int argc;
638 char **argv;
640 struct termios mode;
641 enum output_type output_type;
642 int optc;
643 int require_set_attr;
644 int speed_was_set;
645 int verbose_output;
646 int recoverable_output;
647 int k;
649 program_name = argv[0];
651 parse_long_options (argc, argv, "stty", version_string, usage);
653 output_type = changed;
654 verbose_output = 0;
655 recoverable_output = 0;
657 /* Recognize the long options only. */
658 opterr = 0;
659 while ((optc = getopt_long_only (argc, argv, "ag", longopts, (int *) 0))
660 != EOF)
662 switch (optc)
664 case 'a':
665 verbose_output = 1;
666 output_type = all;
667 break;
669 case 'g':
670 recoverable_output = 1;
671 output_type = recoverable;
672 break;
674 default:
675 break;
679 /* Recognize short options and combinations: -a, -g, -ag, and -ga.
680 They need not precede non-options. We cannot use GNU getopt because
681 it would treat -tabs and -ixany as uses of the -a option. */
682 for (k = optind; k < argc; k++)
684 if (argv[k][0] == '-')
686 if (argv[k][1] == 'a'
687 && argv[k][2] == '\0')
689 ++optind;
690 verbose_output = 1;
692 else if (argv[k][1] == 'g'
693 && argv[k][2] == '\0')
695 ++optind;
696 recoverable_output = 1;
698 else if ((argv[k][1] == 'g'
699 && argv[k][2] == 'a'
700 && argv[k][3] == '\0')
701 || (argv[k][1] == 'a'
702 && argv[k][2] == 'g'
703 && argv[k][3] == '\0'))
705 ++optind;
706 verbose_output = 1;
707 recoverable_output = 1;
712 /* Specifying both -a and -g gets an error. */
713 if (verbose_output && recoverable_output)
714 error (2, 0,
715 "the options for verbose and stty-readable output styles are\n\
716 \tmutually exclusive");
718 /* Specifying any other arguments with -a or -g gets an error. */
719 if (argc - optind > 0 && (verbose_output || recoverable_output))
720 error (2, 0, "when specifying an output style, modes may not be set");
722 /* Initialize to all zeroes so there is no risk memcmp will report a
723 spurious difference in an uninitialized portion of the structure. */
724 memset (&mode, 0, sizeof (mode));
725 if (tcgetattr (0, &mode))
726 error (1, errno, "standard input");
728 if (verbose_output || recoverable_output || argc == 1)
730 max_col = screen_columns ();
731 current_col = 0;
732 display_settings (output_type, &mode);
733 exit (0);
736 speed_was_set = 0;
737 require_set_attr = 0;
738 k = 1;
739 while (k < argc)
741 int match_found = 0;
742 int reversed = 0;
743 int i;
745 if (argv[k][0] == '-')
747 ++argv[k];
748 reversed = 1;
750 for (i = 0; mode_info[i].name != NULL; ++i)
752 if (!strcmp (argv[k], mode_info[i].name))
754 match_found = set_mode (&mode_info[i], reversed, &mode);
755 require_set_attr = 1;
756 break;
759 if (match_found == 0 && reversed)
761 error (0, 0, "invalid argument `%s'", --argv[k]);
762 usage (1);
764 if (match_found == 0)
766 for (i = 0; control_info[i].name != NULL; ++i)
768 if (!strcmp (argv[k], control_info[i].name))
770 if (k == argc - 1)
772 error (0, 0, "missing argument to `%s'", argv[k]);
773 usage (1);
775 match_found = 1;
776 ++k;
777 set_control_char (&control_info[i], argv[k], &mode);
778 require_set_attr = 1;
779 break;
783 if (match_found == 0)
785 if (!strcmp (argv[k], "ispeed"))
787 if (k == argc - 1)
789 error (0, 0, "missing argument to `%s'", argv[k]);
790 usage (1);
792 ++k;
793 set_speed (input_speed, argv[k], &mode);
794 speed_was_set = 1;
795 require_set_attr = 1;
797 else if (!strcmp (argv[k], "ospeed"))
799 if (k == argc - 1)
801 error (0, 0, "missing argument to `%s'", argv[k]);
802 usage (1);
804 ++k;
805 set_speed (output_speed, argv[k], &mode);
806 speed_was_set = 1;
807 require_set_attr = 1;
809 #ifdef TIOCGWINSZ
810 else if (!strcmp (argv[k], "rows"))
812 if (k == argc - 1)
814 error (0, 0, "missing argument to `%s'", argv[k]);
815 usage (1);
817 ++k;
818 set_window_size ((int) integer_arg (argv[k]), -1);
820 else if (!strcmp (argv[k], "cols")
821 || !strcmp (argv[k], "columns"))
823 if (k == argc - 1)
825 error (0, 0, "missing argument to `%s'", argv[k]);
826 usage (1);
828 ++k;
829 set_window_size (-1, (int) integer_arg (argv[k]));
831 else if (!strcmp (argv[k], "size"))
833 max_col = screen_columns ();
834 current_col = 0;
835 display_window_size (0);
837 #endif
838 #ifdef HAVE_C_LINE
839 else if (!strcmp (argv[k], "line"))
841 if (k == argc - 1)
843 error (0, 0, "missing argument to `%s'", argv[k]);
844 usage (1);
846 ++k;
847 mode.c_line = integer_arg (argv[k]);
848 require_set_attr = 1;
850 #endif
851 else if (!strcmp (argv[k], "speed"))
853 max_col = screen_columns ();
854 display_speed (&mode, 0);
856 else if (string_to_baud (argv[k]) != (speed_t) -1)
858 set_speed (both_speeds, argv[k], &mode);
859 speed_was_set = 1;
860 require_set_attr = 1;
862 else
864 if (recover_mode (argv[k], &mode) == 0)
866 error (0, 0, "invalid argument `%s'", argv[k]);
867 usage (1);
869 require_set_attr = 1;
872 k++;
875 if (require_set_attr)
877 struct termios new_mode;
879 if (tcsetattr (0, TCSADRAIN, &mode))
880 error (1, errno, "standard input");
882 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
883 it performs *any* of the requested operations. This means it
884 can report `success' when it has actually failed to perform
885 some proper subset of the requested operations. To detect
886 this partial failure, get the current terminal attributes and
887 compare them to the requested ones. */
889 /* Initialize to all zeroes so there is no risk memcmp will report a
890 spurious difference in an uninitialized portion of the structure. */
891 memset (&new_mode, 0, sizeof (new_mode));
892 if (tcgetattr (0, &new_mode))
893 error (1, errno, "standard input");
895 /* Normally, one shouldn't use memcmp to compare structures that
896 may have `holes' containing uninitialized data, but we have been
897 careful to initialize the storage of these two variables to all
898 zeroes. One might think it more efficient simply to compare the
899 modified fields, but that would require enumerating those fields --
900 and not all systems have the same fields in this structure. */
902 if (memcmp (&mode, &new_mode, sizeof (mode)) != 0)
904 #ifdef CIBAUD
905 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
906 tcgetattr(&m1); tcsetattr(&m1); tcgetattr(&m2);
907 sometimes (m1 != m2). The only difference is in the four bits
908 of the c_cflag field corresponding to the baud rate. To save
909 Sun users a little confusion, don't report an error if this
910 happens. But suppress the error only if we haven't tried to
911 set the baud rate explicitly -- otherwise we'd never give an
912 error for a true failure to set the baud rate. */
914 new_mode.c_cflag &= (~CIBAUD);
915 if (speed_was_set || memcmp (&mode, &new_mode, sizeof (mode)) != 0)
916 #endif
918 int i;
919 error (1, 0,
920 "standard input: unable to perform all requested operations");
921 printf ("new_mode: mode\n");
922 for (i=0; i<sizeof(new_mode); i++)
923 printf ("0x%02x: 0x%02x\n",
924 *(((unsigned char *) &new_mode) + i),
925 *(((unsigned char *) &mode) + i));
930 exit (0);
933 /* Return 0 if not applied because not reversible; otherwise return 1. */
935 static int
936 set_mode (info, reversed, mode)
937 struct mode_info *info;
938 int reversed;
939 struct termios *mode;
941 tcflag_t *bitsp;
943 if (reversed && (info->flags & REV) == 0)
944 return 0;
946 bitsp = mode_type_flag (info->type, mode);
948 if (bitsp == NULL)
950 /* Combination mode. */
951 if (!strcmp (info->name, "evenp") || !strcmp (info->name, "parity"))
953 if (reversed)
954 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
955 else
956 mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
958 else if (!strcmp (info->name, "oddp"))
960 if (reversed)
961 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
962 else
963 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
965 else if (!strcmp (info->name, "nl"))
967 if (reversed)
969 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
970 mode->c_oflag = (mode->c_oflag
971 #ifdef ONLCR
972 | ONLCR
973 #endif
975 #ifdef OCRNL
976 & ~OCRNL
977 #endif
978 #ifdef ONLRET
979 & ~ONLRET
980 #endif
983 else
985 mode->c_iflag = mode->c_iflag & ~ICRNL;
986 #ifdef ONLCR
987 mode->c_oflag = mode->c_oflag & ~ONLCR;
988 #endif
991 else if (!strcmp (info->name, "ek"))
993 mode->c_cc[VERASE] = CERASE;
994 mode->c_cc[VKILL] = CKILL;
996 else if (!strcmp (info->name, "sane"))
997 sane_mode (mode);
998 else if (!strcmp (info->name, "cbreak"))
1000 if (reversed)
1001 mode->c_lflag |= ICANON;
1002 else
1003 mode->c_lflag &= ~ICANON;
1005 else if (!strcmp (info->name, "pass8"))
1007 if (reversed)
1009 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1010 mode->c_iflag |= ISTRIP;
1012 else
1014 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1015 mode->c_iflag &= ~ISTRIP;
1018 else if (!strcmp (info->name, "litout"))
1020 if (reversed)
1022 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1023 mode->c_iflag |= ISTRIP;
1024 mode->c_oflag |= OPOST;
1026 else
1028 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1029 mode->c_iflag &= ~ISTRIP;
1030 mode->c_oflag &= ~OPOST;
1033 else if (!strcmp (info->name, "raw") || !strcmp (info->name, "cooked"))
1035 if ((info->name[0] == 'r' && reversed)
1036 || (info->name[0] == 'c' && !reversed))
1038 /* Cooked mode. */
1039 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1040 mode->c_oflag |= OPOST;
1041 mode->c_lflag |= ISIG | ICANON;
1042 #if VMIN == VEOF
1043 mode->c_cc[VEOF] = CEOF;
1044 #endif
1045 #if VTIME == VEOL
1046 mode->c_cc[VEOL] = CEOL;
1047 #endif
1049 else
1051 /* Raw mode. */
1052 mode->c_iflag = 0;
1053 mode->c_oflag &= ~OPOST;
1054 mode->c_lflag &= ~(ISIG | ICANON
1055 #ifdef XCASE
1056 | XCASE
1057 #endif
1059 mode->c_cc[VMIN] = 1;
1060 mode->c_cc[VTIME] = 0;
1063 #ifdef IXANY
1064 else if (!strcmp (info->name, "decctlq"))
1066 if (reversed)
1067 mode->c_iflag |= IXANY;
1068 else
1069 mode->c_iflag &= ~IXANY;
1071 #endif
1072 #ifdef TABDLY
1073 else if (!strcmp (info->name, "tabs"))
1075 if (reversed)
1076 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1077 else
1078 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1080 #else
1081 #ifdef OXTABS
1082 else if (!strcmp (info->name, "tabs"))
1084 if (reversed)
1085 mode->c_oflag = mode->c_oflag | OXTABS;
1086 else
1087 mode->c_oflag = mode->c_oflag & ~OXTABS;
1089 #endif
1090 #endif
1091 #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
1092 else if (!strcmp (info->name, "lcase")
1093 || !strcmp (info->name, "LCASE"))
1095 if (reversed)
1097 mode->c_lflag &= ~XCASE;
1098 mode->c_iflag &= ~IUCLC;
1099 mode->c_oflag &= ~OLCUC;
1101 else
1103 mode->c_lflag |= XCASE;
1104 mode->c_iflag |= IUCLC;
1105 mode->c_oflag |= OLCUC;
1108 #endif
1109 else if (!strcmp (info->name, "crt"))
1110 mode->c_lflag |= ECHOE
1111 #ifdef ECHOCTL
1112 | ECHOCTL
1113 #endif
1114 #ifdef ECHOKE
1115 | ECHOKE
1116 #endif
1118 else if (!strcmp (info->name, "dec"))
1120 mode->c_cc[VINTR] = 3; /* ^C */
1121 mode->c_cc[VERASE] = 127; /* DEL */
1122 mode->c_cc[VKILL] = 21; /* ^U */
1123 mode->c_lflag |= ECHOE
1124 #ifdef ECHOCTL
1125 | ECHOCTL
1126 #endif
1127 #ifdef ECHOKE
1128 | ECHOKE
1129 #endif
1131 #ifdef IXANY
1132 mode->c_iflag &= ~IXANY;
1133 #endif
1136 else if (reversed)
1137 *bitsp = *bitsp & ~info->mask & ~info->bits;
1138 else
1139 *bitsp = (*bitsp & ~info->mask) | info->bits;
1141 return 1;
1144 static void
1145 set_control_char (info, arg, mode)
1146 struct control_info *info;
1147 char *arg;
1148 struct termios *mode;
1150 unsigned char value;
1152 if (!strcmp (info->name, "min") || !strcmp (info->name, "time"))
1153 value = integer_arg (arg);
1154 else if (arg[0] == '\0' || arg[1] == '\0')
1155 value = arg[0];
1156 else if (!strcmp (arg, "^-") || !strcmp (arg, "undef"))
1157 value = _POSIX_VDISABLE;
1158 else if (arg[0] == '^' && arg[1] != '\0') /* Ignore any trailing junk. */
1160 if (arg[1] == '?')
1161 value = 127;
1162 else
1163 value = arg[1] & ~0140; /* Non-letters get weird results. */
1165 else
1166 value = integer_arg (arg);
1167 mode->c_cc[info->offset] = value;
1170 static void
1171 set_speed (type, arg, mode)
1172 enum speed_setting type;
1173 char *arg;
1174 struct termios *mode;
1176 speed_t baud;
1178 baud = string_to_baud (arg);
1179 if (type == input_speed || type == both_speeds)
1180 cfsetispeed (mode, baud);
1181 if (type == output_speed || type == both_speeds)
1182 cfsetospeed (mode, baud);
1185 #ifdef TIOCGWINSZ
1187 /* Get window size information. First try getting the information
1188 associated with standard output and if that fails, try standard input.
1189 Return zero for success, non-zero if both ioctl's failed. */
1191 static int
1192 get_win_size (win)
1193 struct winsize *win;
1195 int err;
1197 err = ioctl (1, TIOCGWINSZ, (char *) win);
1198 if (err != 0)
1199 err = ioctl (0, TIOCGWINSZ, (char *) win);
1200 return err;
1203 static void
1204 set_window_size (rows, cols)
1205 int rows, cols;
1207 struct winsize win;
1209 if (get_win_size (&win))
1211 if (errno != EINVAL)
1212 error (1, errno, "standard input");
1213 memset (&win, 0, sizeof (win));
1216 if (rows >= 0)
1217 win.ws_row = rows;
1218 if (cols >= 0)
1219 win.ws_col = cols;
1221 #ifdef TIOCSSIZE
1222 /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
1223 The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
1224 This comment from sys/ttold.h describes Sun's twisted logic - a better
1225 test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
1226 At any rate, the problem is gone in Solaris 2.x.
1228 Unfortunately, the old TIOCSSIZE code does collide with TIOCSWINSZ,
1229 but they can be disambiguated by checking whether a "struct ttysize"
1230 structure's "ts_lines" field is greater than 64K or not. If so,
1231 it's almost certainly a "struct winsize" instead.
1233 At any rate, the bug manifests itself when ws_row == 0; the symptom is
1234 that ws_row is set to ws_col, and ws_col is set to (ws_xpixel<<16) +
1235 ws_ypixel. Since GNU stty sets rows and columns separately, this bug
1236 caused "stty rows 0 cols 0" to set rows to cols and cols to 0, while
1237 "stty cols 0 rows 0" would do the right thing. On a little-endian
1238 machine like the sun386i, the problem is the same, but for ws_col == 0.
1240 The workaround is to do the ioctl once with row and col = 1 to set the
1241 pixel info, and then do it again using a TIOCSSIZE to set rows/cols. */
1243 if (win.ws_row == 0 || win.ws_col == 0)
1245 struct ttysize ttysz;
1247 ttysz.ts_lines = win.ws_row;
1248 ttysz.ts_cols = win.ws_col;
1250 win.ws_row = 1;
1251 win.ws_col = 1;
1253 if (ioctl (0, TIOCSWINSZ, (char *) &win))
1254 error (1, errno, "standard input");
1256 if (ioctl (0, TIOCSSIZE, (char *) &ttysz))
1257 error (1, errno, "standard input");
1258 return;
1260 #endif
1262 if (ioctl (0, TIOCSWINSZ, (char *) &win))
1263 error (1, errno, "standard input");
1266 static void
1267 display_window_size (fancy)
1268 int fancy;
1270 struct winsize win;
1272 if (get_win_size (&win))
1274 if (errno != EINVAL)
1275 error (1, errno, "standard input");
1277 else
1279 wrapf (fancy ? "rows %d; columns %d;" : "%d %d\n",
1280 win.ws_row, win.ws_col);
1281 if (!fancy)
1282 current_col = 0;
1285 #endif
1287 static int
1288 screen_columns ()
1290 #ifdef TIOCGWINSZ
1291 struct winsize win;
1293 if (get_win_size (&win))
1295 /* With Solaris 2.[123], this ioctl fails and errno is set to
1296 EINVAL for telnet (but not rlogin) sessions. */
1297 if (errno != EINVAL)
1298 error (1, errno, "standard input");
1300 else if (win.ws_col > 0)
1301 return win.ws_col;
1302 #endif
1303 if (getenv ("COLUMNS"))
1304 return atoi (getenv ("COLUMNS"));
1305 return 80;
1308 static tcflag_t *
1309 mode_type_flag (type, mode)
1310 enum mode_type type;
1311 struct termios *mode;
1313 switch (type)
1315 case control:
1316 return &mode->c_cflag;
1318 case input:
1319 return &mode->c_iflag;
1321 case output:
1322 return &mode->c_oflag;
1324 case local:
1325 return &mode->c_lflag;
1327 case combination:
1328 return NULL;
1330 default:
1331 abort ();
1335 static void
1336 display_settings (output_type, mode)
1337 enum output_type output_type;
1338 struct termios *mode;
1340 switch (output_type)
1342 case changed:
1343 display_changed (mode);
1344 break;
1346 case all:
1347 display_all (mode);
1348 break;
1350 case recoverable:
1351 display_recoverable (mode);
1352 break;
1356 static void
1357 display_changed (mode)
1358 struct termios *mode;
1360 int i;
1361 int empty_line;
1362 tcflag_t *bitsp;
1363 unsigned long mask;
1364 enum mode_type prev_type = control;
1366 display_speed (mode, 1);
1367 #ifdef HAVE_C_LINE
1368 wrapf ("line = %d;", mode->c_line);
1369 #endif
1370 putchar ('\n');
1371 current_col = 0;
1373 empty_line = 1;
1374 for (i = 0; strcmp (control_info[i].name, "min"); ++i)
1376 if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
1377 continue;
1378 empty_line = 0;
1379 wrapf ("%s = %s;", control_info[i].name,
1380 visible (mode->c_cc[control_info[i].offset]));
1382 if ((mode->c_lflag & ICANON) == 0)
1384 wrapf ("min = %d; time = %d;\n", (int) mode->c_cc[VMIN],
1385 (int) mode->c_cc[VTIME]);
1387 else if (empty_line == 0)
1388 putchar ('\n');
1389 current_col = 0;
1391 empty_line = 1;
1392 for (i = 0; mode_info[i].name != NULL; ++i)
1394 if (mode_info[i].flags & OMIT)
1395 continue;
1396 if (mode_info[i].type != prev_type)
1398 if (empty_line == 0)
1400 putchar ('\n');
1401 current_col = 0;
1402 empty_line = 1;
1404 prev_type = mode_info[i].type;
1407 bitsp = mode_type_flag (mode_info[i].type, mode);
1408 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1409 if ((*bitsp & mask) == mode_info[i].bits)
1411 if (mode_info[i].flags & SANE_UNSET)
1413 wrapf ("%s", mode_info[i].name);
1414 empty_line = 0;
1417 else if ((mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
1419 wrapf ("-%s", mode_info[i].name);
1420 empty_line = 0;
1423 if (empty_line == 0)
1424 putchar ('\n');
1425 current_col = 0;
1428 static void
1429 display_all (mode)
1430 struct termios *mode;
1432 int i;
1433 tcflag_t *bitsp;
1434 unsigned long mask;
1435 enum mode_type prev_type = control;
1437 display_speed (mode, 1);
1438 #ifdef TIOCGWINSZ
1439 display_window_size (1);
1440 #endif
1441 #ifdef HAVE_C_LINE
1442 wrapf ("line = %d;", mode->c_line);
1443 #endif
1444 putchar ('\n');
1445 current_col = 0;
1447 for (i = 0; strcmp (control_info[i].name, "min"); ++i)
1449 wrapf ("%s = %s;", control_info[i].name,
1450 visible (mode->c_cc[control_info[i].offset]));
1452 wrapf ("min = %d; time = %d;\n", mode->c_cc[VMIN], mode->c_cc[VTIME]);
1453 current_col = 0;
1455 for (i = 0; mode_info[i].name != NULL; ++i)
1457 if (mode_info[i].flags & OMIT)
1458 continue;
1459 if (mode_info[i].type != prev_type)
1461 putchar ('\n');
1462 current_col = 0;
1463 prev_type = mode_info[i].type;
1466 bitsp = mode_type_flag (mode_info[i].type, mode);
1467 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1468 if ((*bitsp & mask) == mode_info[i].bits)
1469 wrapf ("%s", mode_info[i].name);
1470 else if (mode_info[i].flags & REV)
1471 wrapf ("-%s", mode_info[i].name);
1473 putchar ('\n');
1474 current_col = 0;
1477 static void
1478 display_speed (mode, fancy)
1479 struct termios *mode;
1480 int fancy;
1482 if (cfgetispeed (mode) == 0 || cfgetispeed (mode) == cfgetospeed (mode))
1483 wrapf (fancy ? "speed %lu baud;" : "%lu\n",
1484 baud_to_value (cfgetospeed (mode)));
1485 else
1486 wrapf (fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n",
1487 baud_to_value (cfgetispeed (mode)),
1488 baud_to_value (cfgetospeed (mode)));
1489 if (!fancy)
1490 current_col = 0;
1493 static void
1494 display_recoverable (mode)
1495 struct termios *mode;
1497 int i;
1499 printf ("%lx:%lx:%lx:%lx",
1500 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
1501 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
1502 for (i = 0; i < NCCS; ++i)
1503 printf (":%x", (unsigned int) mode->c_cc[i]);
1504 putchar ('\n');
1507 static int
1508 recover_mode (arg, mode)
1509 char *arg;
1510 struct termios *mode;
1512 int i, n;
1513 unsigned int chr;
1514 unsigned long iflag, oflag, cflag, lflag;
1516 /* Scan into temporaries since it is too much trouble to figure out
1517 the right format for `tcflag_t'. */
1518 if (sscanf (arg, "%lx:%lx:%lx:%lx%n",
1519 &iflag, &oflag, &cflag, &lflag, &n) != 4)
1520 return 0;
1521 mode->c_iflag = iflag;
1522 mode->c_oflag = oflag;
1523 mode->c_cflag = cflag;
1524 mode->c_lflag = lflag;
1525 arg += n;
1526 for (i = 0; i < NCCS; ++i)
1528 if (sscanf (arg, ":%x%n", &chr, &n) != 1)
1529 return 0;
1530 mode->c_cc[i] = chr;
1531 arg += n;
1533 return 1;
1536 struct speed_map
1538 const char *string; /* ASCII representation. */
1539 speed_t speed; /* Internal form. */
1540 unsigned long value; /* Numeric value. */
1543 struct speed_map speeds[] =
1545 {"0", B0, 0},
1546 {"50", B50, 50},
1547 {"75", B75, 75},
1548 {"110", B110, 110},
1549 {"134", B134, 134},
1550 {"134.5", B134, 134},
1551 {"150", B150, 150},
1552 {"200", B200, 200},
1553 {"300", B300, 300},
1554 {"600", B600, 600},
1555 {"1200", B1200, 1200},
1556 {"1800", B1800, 1800},
1557 {"2400", B2400, 2400},
1558 {"4800", B4800, 4800},
1559 {"9600", B9600, 9600},
1560 {"19200", B19200, 19200},
1561 {"38400", B38400, 38400},
1562 {"exta", B19200, 19200},
1563 {"extb", B38400, 38400},
1564 #ifdef B57600
1565 {"57600", B57600, 57600},
1566 #endif
1567 #ifdef B115200
1568 {"115200", B115200, 115200},
1569 #endif
1570 {NULL, 0, 0}
1573 static speed_t
1574 string_to_baud (arg)
1575 char *arg;
1577 int i;
1579 for (i = 0; speeds[i].string != NULL; ++i)
1580 if (!strcmp (arg, speeds[i].string))
1581 return speeds[i].speed;
1582 return (speed_t) -1;
1585 static unsigned long
1586 baud_to_value (speed)
1587 speed_t speed;
1589 int i;
1591 for (i = 0; speeds[i].string != NULL; ++i)
1592 if (speed == speeds[i].speed)
1593 return speeds[i].value;
1594 return 0;
1597 static void
1598 sane_mode (mode)
1599 struct termios *mode;
1601 int i;
1602 tcflag_t *bitsp;
1604 for (i = 0; control_info[i].name; ++i)
1606 #if VMIN == VEOF
1607 if (!strcmp (control_info[i].name, "min"))
1608 break;
1609 #endif
1610 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1613 for (i = 0; mode_info[i].name != NULL; ++i)
1615 if (mode_info[i].flags & SANE_SET)
1617 bitsp = mode_type_flag (mode_info[i].type, mode);
1618 *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits;
1620 else if (mode_info[i].flags & SANE_UNSET)
1622 bitsp = mode_type_flag (mode_info[i].type, mode);
1623 *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits;
1628 /* Return a string that is the printable representation of character CH. */
1629 /* Adapted from `cat' by Torbjorn Granlund. */
1631 static const char *
1632 visible (ch)
1633 unsigned char ch;
1635 static char buf[10];
1636 char *bpout = buf;
1638 if (ch == _POSIX_VDISABLE)
1639 return "<undef>";
1641 if (ch >= 32)
1643 if (ch < 127)
1644 *bpout++ = ch;
1645 else if (ch == 127)
1647 *bpout++ = '^';
1648 *bpout++ = '?';
1650 else
1652 *bpout++ = 'M',
1653 *bpout++ = '-';
1654 if (ch >= 128 + 32)
1656 if (ch < 128 + 127)
1657 *bpout++ = ch - 128;
1658 else
1660 *bpout++ = '^';
1661 *bpout++ = '?';
1664 else
1666 *bpout++ = '^';
1667 *bpout++ = ch - 128 + 64;
1671 else
1673 *bpout++ = '^';
1674 *bpout++ = ch + 64;
1676 *bpout = '\0';
1677 return (const char *) buf;
1680 /* Parse string S as an integer, using decimal radix by default,
1681 but allowing octal and hex numbers as in C. */
1682 /* From `od' by Richard Stallman. */
1684 static long
1685 integer_arg (s)
1686 char *s;
1688 long value;
1689 int radix = 10;
1690 char *p = s;
1691 int c;
1693 if (*p != '0')
1694 radix = 10;
1695 else if (*++p == 'x')
1697 radix = 16;
1698 p++;
1700 else
1701 radix = 8;
1703 value = 0;
1704 while (((c = *p++) >= '0' && c <= '9')
1705 || (radix == 16 && (c & ~40) >= 'A' && (c & ~40) <= 'Z'))
1707 value *= radix;
1708 if (c >= '0' && c <= '9')
1709 value += c - '0';
1710 else
1711 value += (c & ~40) - 'A';
1714 if (c == 'b')
1715 value *= 512;
1716 else if (c == 'B')
1717 value *= 1024;
1718 else
1719 p--;
1721 if (*p)
1723 error (0, 0, "invalid integer argument `%s'", s);
1724 usage (1);
1726 return value;