.
[coreutils.git] / src / stty.c
blob0e587a0eab006df9da31d93892fc98bef0303bef
1 /* stty -- change and print terminal line settings
2 Copyright (C) 90, 91, 92, 93, 94, 95, 1996 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 Foundation,
16 Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 "long-options.h"
52 #include "error.h"
53 #include "xstrtol.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 /* Which speeds to set. */
147 enum speed_setting
149 input_speed, output_speed, both_speeds
152 /* What to output and how. */
153 enum output_type
155 changed, all, recoverable /* Default, -a, -g. */
158 /* Which member(s) of `struct termios' a mode uses. */
159 enum mode_type
161 control, input, output, local, combination
164 /* Flags for `struct mode_info'. */
165 #define SANE_SET 1 /* Set in `sane' mode. */
166 #define SANE_UNSET 2 /* Unset in `sane' mode. */
167 #define REV 4 /* Can be turned off by prepending `-'. */
168 #define OMIT 8 /* Don't display value. */
170 /* Each mode. */
171 struct mode_info
173 const char *name; /* Name given on command line. */
174 enum mode_type type; /* Which structure element to change. */
175 char flags; /* Setting and display options. */
176 unsigned long bits; /* Bits to set for this mode. */
177 unsigned long mask; /* Other bits to turn off for this mode. */
180 static struct mode_info mode_info[] =
182 {"parenb", control, REV, PARENB, 0},
183 {"parodd", control, REV, PARODD, 0},
184 {"cs5", control, 0, CS5, CSIZE},
185 {"cs6", control, 0, CS6, CSIZE},
186 {"cs7", control, 0, CS7, CSIZE},
187 {"cs8", control, 0, CS8, CSIZE},
188 {"hupcl", control, REV, HUPCL, 0},
189 {"hup", control, REV | OMIT, HUPCL, 0},
190 {"cstopb", control, REV, CSTOPB, 0},
191 {"cread", control, SANE_SET | REV, CREAD, 0},
192 {"clocal", control, REV, CLOCAL, 0},
193 #ifdef CRTSCTS
194 {"crtscts", control, REV, CRTSCTS, 0},
195 #endif
197 {"ignbrk", input, SANE_UNSET | REV, IGNBRK, 0},
198 {"brkint", input, SANE_SET | REV, BRKINT, 0},
199 {"ignpar", input, REV, IGNPAR, 0},
200 {"parmrk", input, REV, PARMRK, 0},
201 {"inpck", input, REV, INPCK, 0},
202 {"istrip", input, REV, ISTRIP, 0},
203 {"inlcr", input, SANE_UNSET | REV, INLCR, 0},
204 {"igncr", input, SANE_UNSET | REV, IGNCR, 0},
205 {"icrnl", input, SANE_SET | REV, ICRNL, 0},
206 {"ixon", input, REV, IXON, 0},
207 {"ixoff", input, SANE_UNSET | REV, IXOFF, 0},
208 {"tandem", input, REV | OMIT, IXOFF, 0},
209 #ifdef IUCLC
210 {"iuclc", input, SANE_UNSET | REV, IUCLC, 0},
211 #endif
212 #ifdef IXANY
213 {"ixany", input, SANE_UNSET | REV, IXANY, 0},
214 #endif
215 #ifdef IMAXBEL
216 {"imaxbel", input, SANE_SET | REV, IMAXBEL, 0},
217 #endif
219 {"opost", output, SANE_SET | REV, OPOST, 0},
220 #ifdef OLCUC
221 {"olcuc", output, SANE_UNSET | REV, OLCUC, 0},
222 #endif
223 #ifdef OCRNL
224 {"ocrnl", output, SANE_UNSET | REV, OCRNL, 0},
225 #endif
226 #ifdef ONLCR
227 {"onlcr", output, SANE_SET | REV, ONLCR, 0},
228 #endif
229 #ifdef ONOCR
230 {"onocr", output, SANE_UNSET | REV, ONOCR, 0},
231 #endif
232 #ifdef ONLRET
233 {"onlret", output, SANE_UNSET | REV, ONLRET, 0},
234 #endif
235 #ifdef OFILL
236 {"ofill", output, SANE_UNSET | REV, OFILL, 0},
237 #endif
238 #ifdef OFDEL
239 {"ofdel", output, SANE_UNSET | REV, OFDEL, 0},
240 #endif
241 #ifdef NLDLY
242 {"nl1", output, SANE_UNSET, NL1, NLDLY},
243 {"nl0", output, SANE_SET, NL0, NLDLY},
244 #endif
245 #ifdef CRDLY
246 {"cr3", output, SANE_UNSET, CR3, CRDLY},
247 {"cr2", output, SANE_UNSET, CR2, CRDLY},
248 {"cr1", output, SANE_UNSET, CR1, CRDLY},
249 {"cr0", output, SANE_SET, CR0, CRDLY},
250 #endif
251 #ifdef TABDLY
252 {"tab3", output, SANE_UNSET, TAB3, TABDLY},
253 {"tab2", output, SANE_UNSET, TAB2, TABDLY},
254 {"tab1", output, SANE_UNSET, TAB1, TABDLY},
255 {"tab0", output, SANE_SET, TAB0, TABDLY},
256 #else
257 # ifdef OXTABS
258 {"tab3", output, SANE_UNSET, OXTABS, 0},
259 # endif
260 #endif
261 #ifdef BSDLY
262 {"bs1", output, SANE_UNSET, BS1, BSDLY},
263 {"bs0", output, SANE_SET, BS0, BSDLY},
264 #endif
265 #ifdef VTDLY
266 {"vt1", output, SANE_UNSET, VT1, VTDLY},
267 {"vt0", output, SANE_SET, VT0, VTDLY},
268 #endif
269 #ifdef FFDLY
270 {"ff1", output, SANE_UNSET, FF1, FFDLY},
271 {"ff0", output, SANE_SET, FF0, FFDLY},
272 #endif
274 {"isig", local, SANE_SET | REV, ISIG, 0},
275 {"icanon", local, SANE_SET | REV, ICANON, 0},
276 #ifdef IEXTEN
277 {"iexten", local, SANE_SET | REV, IEXTEN, 0},
278 #endif
279 {"echo", local, SANE_SET | REV, ECHO, 0},
280 {"echoe", local, SANE_SET | REV, ECHOE, 0},
281 {"crterase", local, REV | OMIT, ECHOE, 0},
282 {"echok", local, SANE_SET | REV, ECHOK, 0},
283 {"echonl", local, SANE_UNSET | REV, ECHONL, 0},
284 {"noflsh", local, SANE_UNSET | REV, NOFLSH, 0},
285 #ifdef XCASE
286 {"xcase", local, SANE_UNSET | REV, XCASE, 0},
287 #endif
288 #ifdef TOSTOP
289 {"tostop", local, SANE_UNSET | REV, TOSTOP, 0},
290 #endif
291 #ifdef ECHOPRT
292 {"echoprt", local, SANE_UNSET | REV, ECHOPRT, 0},
293 {"prterase", local, REV | OMIT, ECHOPRT, 0},
294 #endif
295 #ifdef ECHOCTL
296 {"echoctl", local, SANE_SET | REV, ECHOCTL, 0},
297 {"ctlecho", local, REV | OMIT, ECHOCTL, 0},
298 #endif
299 #ifdef ECHOKE
300 {"echoke", local, SANE_SET | REV, ECHOKE, 0},
301 {"crtkill", local, REV | OMIT, ECHOKE, 0},
302 #endif
304 {"evenp", combination, REV | OMIT, 0, 0},
305 {"parity", combination, REV | OMIT, 0, 0},
306 {"oddp", combination, REV | OMIT, 0, 0},
307 {"nl", combination, REV | OMIT, 0, 0},
308 {"ek", combination, OMIT, 0, 0},
309 {"sane", combination, OMIT, 0, 0},
310 {"cooked", combination, REV | OMIT, 0, 0},
311 {"raw", combination, REV | OMIT, 0, 0},
312 {"pass8", combination, REV | OMIT, 0, 0},
313 {"litout", combination, REV | OMIT, 0, 0},
314 {"cbreak", combination, REV | OMIT, 0, 0},
315 #ifdef IXANY
316 {"decctlq", combination, REV | OMIT, 0, 0},
317 #endif
318 #if defined (TABDLY) || defined (OXTABS)
319 {"tabs", combination, REV | OMIT, 0, 0},
320 #endif
321 #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
322 {"lcase", combination, REV | OMIT, 0, 0},
323 {"LCASE", combination, REV | OMIT, 0, 0},
324 #endif
325 {"crt", combination, OMIT, 0, 0},
326 {"dec", combination, OMIT, 0, 0},
328 {NULL, control, 0, 0, 0}
331 /* Control character settings. */
332 struct control_info
334 const char *name; /* Name given on command line. */
335 unsigned char saneval; /* Value to set for `stty sane'. */
336 int offset; /* Offset in c_cc. */
339 /* Control characters. */
341 static struct control_info control_info[] =
343 {"intr", CINTR, VINTR},
344 {"quit", CQUIT, VQUIT},
345 {"erase", CERASE, VERASE},
346 {"kill", CKILL, VKILL},
347 {"eof", CEOF, VEOF},
348 {"eol", CEOL, VEOL},
349 #ifdef VEOL2
350 {"eol2", CEOL2, VEOL2},
351 #endif
352 #ifdef VSWTCH
353 {"swtch", CSWTCH, VSWTCH},
354 #endif
355 {"start", CSTART, VSTART},
356 {"stop", CSTOP, VSTOP},
357 {"susp", CSUSP, VSUSP},
358 #ifdef VDSUSP
359 {"dsusp", CDSUSP, VDSUSP},
360 #endif
361 #ifdef VREPRINT
362 {"rprnt", CRPRNT, VREPRINT},
363 #endif
364 #ifdef VWERASE
365 {"werase", CWERASE, VWERASE},
366 #endif
367 #ifdef VLNEXT
368 {"lnext", CLNEXT, VLNEXT},
369 #endif
370 #ifdef VFLUSHO
371 {"flush", CFLUSHO, VFLUSHO},
372 #endif
373 #ifdef VSTATUS
374 {"status", CSTATUS, VSTATUS},
375 #endif
377 /* These must be last because of the display routines. */
378 {"min", 1, VMIN},
379 {"time", 0, VTIME},
380 {NULL, 0, 0}
383 static const char *visible __P ((unsigned int ch));
384 static unsigned long baud_to_value __P ((speed_t speed));
385 static int recover_mode __P ((char *arg, struct termios *mode));
386 static int screen_columns __P ((void));
387 static int set_mode __P ((struct mode_info *info, int reversed,
388 struct termios *mode));
389 static long integer_arg __P ((const char *s));
390 static speed_t string_to_baud __P ((const char *arg));
391 static tcflag_t *mode_type_flag __P ((enum mode_type type,
392 struct termios *mode));
393 static void display_all __P ((struct termios *mode));
394 static void display_changed __P ((struct termios *mode));
395 static void display_recoverable __P ((struct termios *mode));
396 static void display_settings __P ((enum output_type output_type,
397 struct termios *mode));
398 static void display_speed __P ((struct termios *mode, int fancy));
399 static void display_window_size __P ((int fancy));
400 static void sane_mode __P ((struct termios *mode));
401 static void set_control_char __P ((struct control_info *info, const char *arg,
402 struct termios *mode));
403 static void set_speed __P ((enum speed_setting type, const char *arg,
404 struct termios *mode));
405 static void set_window_size __P ((int rows, int cols));
407 /* The width of the screen, for output wrapping. */
408 static int max_col;
410 /* Current position, to know when to wrap. */
411 static int current_col;
413 static struct option longopts[] =
415 {"all", no_argument, NULL, 'a'},
416 {"save", no_argument, NULL, 'g'},
417 {NULL, 0, NULL, 0}
420 /* The name this program was run with. */
421 char *program_name;
423 /* Print format string MESSAGE and optional args.
424 Wrap to next line first if it won't fit.
425 Print a space first unless MESSAGE will start a new line. */
427 /* VARARGS */
428 static void
429 #ifdef __STDC__
430 wrapf (const char *message,...)
431 #else
432 wrapf (message, va_alist)
433 const char *message;
434 va_dcl
435 #endif
437 va_list args;
438 char buf[1024]; /* Plenty long for our needs. */
439 int buflen;
441 VA_START (args, message);
442 vsprintf (buf, message, args);
443 va_end (args);
444 buflen = strlen (buf);
445 if (current_col + (current_col > 0) + buflen >= max_col)
447 putchar ('\n');
448 current_col = 0;
450 if (current_col > 0)
452 putchar (' ');
453 current_col++;
455 fputs (buf, stdout);
456 current_col += buflen;
459 static void
460 usage (int status)
462 if (status != 0)
463 fprintf (stderr, _("Try `%s --help' for more information.\n"),
464 program_name);
465 else
467 printf (_("\
468 Usage: %s [SETTING]...\n\
469 or: %s OPTION\n\
471 program_name, program_name);
472 printf (_("\
473 Print or change terminal characteristics.\n\
475 -a, --all print all current settings in human-readable form\n\
476 -g, --save print all current settings in a stty-readable form\n\
477 --help display this help and exit\n\
478 --version output version information and exit\n\
480 Optional - before SETTING indicates negation. An * marks non-POSIX\n\
481 settings. The underlying system defines which settings are available.\n\
482 "));
483 printf (_("\
485 Special characters:\n\
486 * dsusp CHAR CHAR will send a terminal stop signal once input flushed\n\
487 eof CHAR CHAR will send an end of file (terminate the input)\n\
488 eol CHAR CHAR will end the line\n\
489 * eol2 CHAR alternate CHAR for ending the line\n\
490 erase CHAR CHAR will erase the last character typed\n\
491 intr CHAR CHAR will send an interrupt signal\n\
492 kill CHAR CHAR will erase the current line\n\
493 * lnext CHAR CHAR will enter the next character quoted\n\
494 quit CHAR CHAR will send a quit signal\n\
495 * rprnt CHAR CHAR will redraw the current line\n\
496 start CHAR CHAR will restart the output after stopping it\n\
497 stop CHAR CHAR will stop the output\n\
498 susp CHAR CHAR will send a terminal stop signal\n\
499 * swtch CHAR CHAR will switch to a different shell layer\n\
500 * werase CHAR CHAR will erase the last word typed\n\
501 "));
502 printf (_("\
504 Special settings:\n\
505 N set the input and output speeds to N bauds\n\
506 * cols N tell the kernel that the terminal has N columns\n\
507 * columns N same as cols N\n\
508 ispeed N set the input speed to N\n\
509 * line N use line discipline N\n\
510 min N with -icanon, set N characters minimum for a completed read\n\
511 ospeed N set the output speed to N\n\
512 * rows N tell the kernel that the terminal has N rows\n\
513 * size print the number of rows and columns according to the kernel\n\
514 speed print the terminal speed\n\
515 time N with -icanon, set read timeout of N tenths of a second\n\
516 "));
517 printf (_("\
519 Control settings:\n\
520 [-]clocal disable modem control signals\n\
521 [-]cread allow input to be received\n\
522 * [-]crtscts enable RTS/CTS handshaking\n\
523 csN set character size to N bits, N in [5..8]\n\
524 [-]cstopb use two stop bits per character (one with `-')\n\
525 [-]hup send a hangup signal when the last process closes the tty\n\
526 [-]hupcl same as [-]hup\n\
527 [-]parenb generate parity bit in output and expect parity bit in input\n\
528 [-]parodd set odd parity (even with `-')\n\
529 "));
530 printf (_("\
532 Input settings:\n\
533 [-]brkint breaks cause an interrupt signal\n\
534 [-]icrnl translate carriage return to newline\n\
535 [-]ignbrk ignore break characters\n\
536 [-]igncr ignore carriage return\n\
537 [-]ignpar ignore characters with parity errors\n\
538 * [-]imaxbel beep and do not flush a full input buffer on a character\n\
539 [-]inlcr translate newline to carriage return\n\
540 [-]inpck enable input parity checking\n\
541 [-]istrip clear high (8th) bit of input characters\n\
542 * [-]iuclc translate uppercase characters to lowercase\n\
543 * [-]ixany let any character restart output, not only start character\n\
544 [-]ixoff enable sending of start/stop characters\n\
545 [-]ixon enable XON/XOFF flow control\n\
546 [-]parmrk mark parity errors (with a 255-0-character sequence)\n\
547 [-]tandem same as [-]ixoff\n\
548 "));
549 printf (_("\
551 Output settings:\n\
552 * bsN backspace delay style, N in [0..1]\n\
553 * crN carriage return delay style, N in [0..3]\n\
554 * ffN form feed delay style, N in [0..1]\n\
555 * nlN newline delay style, N in [0..1]\n\
556 * [-]ocrnl translate carriage return to newline\n\
557 * [-]ofdel use delete characters for fill instead of null characters\n\
558 * [-]ofill use fill (padding) characters instead of timing for delays\n\
559 * [-]olcuc translate lowercase characters to uppercase\n\
560 * [-]onlcr translate newline to carriage return-newline\n\
561 * [-]onlret newline performs a carriage return\n\
562 * [-]onocr do not print carriage returns in the first column\n\
563 [-]opost postprocess output\n\
564 * tabN horizontal tab delay style, N in [0..3]\n\
565 * tabs same as tab0\n\
566 * -tabs same as tab3\n\
567 * vtN vertical tab delay style, N in [0..1]\n\
568 "));
569 printf (_("\
571 Local settings:\n\
572 [-]crterase echo erase characters as backspace-space-backspace\n\
573 * crtkill kill all line by obeying the echoprt and echoe settings\n\
574 * -crtkill kill all line by obeying the echoctl and echok settings\n\
575 * [-]ctlecho echo control characters in hat notation (`^c')\n\
576 [-]echo echo input characters\n\
577 * [-]echoctl same as [-]ctlecho\n\
578 [-]echoe same as [-]crterase\n\
579 [-]echok echo a newline after a kill character\n\
580 * [-]echoke same as [-]crtkill\n\
581 [-]echonl echo newline even if not echoing other characters\n\
582 * [-]echoprt echo erased characters backward, between `\\' and '/'\n\
583 [-]icanon enable erase, kill, werase, and rprnt special characters\n\
584 [-]iexten enable non-POSIX special characters\n\
585 [-]isig enable interrupt, quit, and suspend special characters\n\
586 [-]noflsh disable flushing after interrupt and quit special characters\n\
587 * [-]prterase same as [-]echoprt\n\
588 * [-]tostop stop background jobs that try to write to the terminal\n\
589 * [-]xcase with icanon, escape with `\\' for uppercase characters\n\
590 "));
591 printf (_("\
593 Combination settings:\n\
594 * [-]LCASE same as [-]lcase\n\
595 cbreak same as -icanon\n\
596 -cbreak same as icanon\n\
597 cooked same as brkint ignpar istrip icrnl ixon opost isig\n\
598 icanon, eof and eol characters to their default values\n\
599 -cooked same as raw\n\
600 crt same as echoe echoctl echoke\n\
601 dec same as echoe echoctl echoke -ixany intr ^c erase 0177\n\
602 kill ^u\n\
603 * [-]decctlq same as [-]ixany\n\
604 ek erase and kill characters to their default values\n\
605 evenp same as parenb -parodd cs7\n\
606 -evenp same as -parenb cs8\n\
607 * [-]lcase same as xcase iuclc olcuc\n\
608 litout same as -parenb -istrip -opost cs8\n\
609 -litout same as parenb istrip opost cs7\n\
610 nl same as -icrnl -onlcr\n\
611 -nl same as icrnl -inlcr -igncr onlcr -ocrnl -onlret\n\
612 oddp same as parenb parodd cs7\n\
613 -oddp same as -parenb cs8\n\
614 [-]parity same as [-]evenp\n\
615 pass8 same as -parenb -istrip cs8\n\
616 -pass8 same as parenb istrip cs7\n\
617 raw same as -ignbrk -brkint -ignpar -parmrk -inpck -istrip\n\
618 -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany\n\
619 -imaxbel -opost -isig -icanon -xcase min 1 time 0\n\
620 -raw same as cooked\n\
621 sane same as cread -ignbrk brkint -inlcr -igncr icrnl\n\
622 -ixoff -iucl -ixany imaxbel opost -olcuc -ocrnl onlcr\n\
623 -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0\n\
624 isig icanon iexten echo echoe echok -echonl -noflsh\n\
625 -xcase -tostop -echoprt echoctl echoke, all special\n\
626 characters to their default values.\n\
627 "));
628 printf (_("\
630 Handle the tty line connected to standard input. Without arguments,\n\
631 prints baud rate, line discipline, and deviations from stty sane. In\n\
632 settings, CHAR is taken literally, or coded as in ^c, 0x37, 0177 or\n\
633 127; special values ^- or undef used to disable special characters.\n\
634 "));
636 exit (status);
640 main (int argc, char **argv)
642 struct termios mode;
643 enum output_type output_type;
644 int optc;
645 int require_set_attr;
646 int speed_was_set;
647 int verbose_output;
648 int recoverable_output;
649 int k;
651 program_name = argv[0];
652 setlocale (LC_ALL, "");
653 bindtextdomain (PACKAGE, LOCALEDIR);
654 textdomain (PACKAGE);
656 parse_long_options (argc, argv, "stty", PACKAGE_VERSION, usage);
658 output_type = changed;
659 verbose_output = 0;
660 recoverable_output = 0;
662 /* Recognize the long options only. */
663 opterr = 0;
664 while ((optc = getopt_long_only (argc, argv, "ag", longopts, (int *) 0))
665 != EOF)
667 switch (optc)
669 case 'a':
670 verbose_output = 1;
671 output_type = all;
672 break;
674 case 'g':
675 recoverable_output = 1;
676 output_type = recoverable;
677 break;
679 default:
680 break;
684 /* Recognize short options and combinations: -a, -g, -ag, and -ga.
685 They need not precede non-options. We cannot use GNU getopt because
686 it would treat -tabs and -ixany as uses of the -a option. */
687 for (k = optind; k < argc; k++)
689 if (argv[k][0] == '-')
691 if (argv[k][1] == 'a'
692 && argv[k][2] == '\0')
694 ++optind;
695 verbose_output = 1;
697 else if (argv[k][1] == 'g'
698 && argv[k][2] == '\0')
700 ++optind;
701 recoverable_output = 1;
703 else if ((argv[k][1] == 'g'
704 && argv[k][2] == 'a'
705 && argv[k][3] == '\0')
706 || (argv[k][1] == 'a'
707 && argv[k][2] == 'g'
708 && argv[k][3] == '\0'))
710 ++optind;
711 verbose_output = 1;
712 recoverable_output = 1;
717 /* Specifying both -a and -g gets an error. */
718 if (verbose_output && recoverable_output)
719 error (2, 0,
720 _("the options for verbose and stty-readable output styles are\n\
721 \tmutually exclusive"));
723 /* Specifying any other arguments with -a or -g gets an error. */
724 if (argc - optind > 0 && (verbose_output || recoverable_output))
725 error (2, 0, _("when specifying an output style, modes may not be set"));
727 /* Initialize to all zeroes so there is no risk memcmp will report a
728 spurious difference in an uninitialized portion of the structure. */
729 memset (&mode, 0, sizeof (mode));
730 if (tcgetattr (0, &mode))
731 error (1, errno, _("standard input"));
733 if (verbose_output || recoverable_output || argc == 1)
735 max_col = screen_columns ();
736 current_col = 0;
737 display_settings (output_type, &mode);
738 exit (0);
741 speed_was_set = 0;
742 require_set_attr = 0;
743 k = 1;
744 while (k < argc)
746 int match_found = 0;
747 int reversed = 0;
748 int i;
750 if (argv[k][0] == '-')
752 ++argv[k];
753 reversed = 1;
755 for (i = 0; mode_info[i].name != NULL; ++i)
757 if (!strcmp (argv[k], mode_info[i].name))
759 match_found = set_mode (&mode_info[i], reversed, &mode);
760 require_set_attr = 1;
761 break;
764 if (match_found == 0 && reversed)
766 error (0, 0, _("invalid argument `%s'"), --argv[k]);
767 usage (1);
769 if (match_found == 0)
771 for (i = 0; control_info[i].name != NULL; ++i)
773 if (!strcmp (argv[k], control_info[i].name))
775 if (k == argc - 1)
777 error (0, 0, _("missing argument to `%s'"), argv[k]);
778 usage (1);
780 match_found = 1;
781 ++k;
782 set_control_char (&control_info[i], argv[k], &mode);
783 require_set_attr = 1;
784 break;
788 if (match_found == 0)
790 if (!strcmp (argv[k], "ispeed"))
792 if (k == argc - 1)
794 error (0, 0, _("missing argument to `%s'"), argv[k]);
795 usage (1);
797 ++k;
798 set_speed (input_speed, argv[k], &mode);
799 speed_was_set = 1;
800 require_set_attr = 1;
802 else if (!strcmp (argv[k], "ospeed"))
804 if (k == argc - 1)
806 error (0, 0, _("missing argument to `%s'"), argv[k]);
807 usage (1);
809 ++k;
810 set_speed (output_speed, argv[k], &mode);
811 speed_was_set = 1;
812 require_set_attr = 1;
814 #ifdef TIOCGWINSZ
815 else if (!strcmp (argv[k], "rows"))
817 if (k == argc - 1)
819 error (0, 0, _("missing argument to `%s'"), argv[k]);
820 usage (1);
822 ++k;
823 set_window_size ((int) integer_arg (argv[k]), -1);
825 else if (!strcmp (argv[k], "cols")
826 || !strcmp (argv[k], "columns"))
828 if (k == argc - 1)
830 error (0, 0, _("missing argument to `%s'"), argv[k]);
831 usage (1);
833 ++k;
834 set_window_size (-1, (int) integer_arg (argv[k]));
836 else if (!strcmp (argv[k], "size"))
838 max_col = screen_columns ();
839 current_col = 0;
840 display_window_size (0);
842 #endif
843 #ifdef HAVE_C_LINE
844 else if (!strcmp (argv[k], "line"))
846 if (k == argc - 1)
848 error (0, 0, _("missing argument to `%s'"), argv[k]);
849 usage (1);
851 ++k;
852 mode.c_line = integer_arg (argv[k]);
853 require_set_attr = 1;
855 #endif
856 else if (!strcmp (argv[k], "speed"))
858 max_col = screen_columns ();
859 display_speed (&mode, 0);
861 else if (string_to_baud (argv[k]) != (speed_t) -1)
863 set_speed (both_speeds, argv[k], &mode);
864 speed_was_set = 1;
865 require_set_attr = 1;
867 else
869 if (recover_mode (argv[k], &mode) == 0)
871 error (0, 0, _("invalid argument `%s'"), argv[k]);
872 usage (1);
874 require_set_attr = 1;
877 k++;
880 if (require_set_attr)
882 struct termios new_mode;
884 if (tcsetattr (0, TCSADRAIN, &mode))
885 error (1, errno, _("standard input"));
887 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
888 it performs *any* of the requested operations. This means it
889 can report `success' when it has actually failed to perform
890 some proper subset of the requested operations. To detect
891 this partial failure, get the current terminal attributes and
892 compare them to the requested ones. */
894 /* Initialize to all zeroes so there is no risk memcmp will report a
895 spurious difference in an uninitialized portion of the structure. */
896 memset (&new_mode, 0, sizeof (new_mode));
897 if (tcgetattr (0, &new_mode))
898 error (1, errno, _("standard input"));
900 /* Normally, one shouldn't use memcmp to compare structures that
901 may have `holes' containing uninitialized data, but we have been
902 careful to initialize the storage of these two variables to all
903 zeroes. One might think it more efficient simply to compare the
904 modified fields, but that would require enumerating those fields --
905 and not all systems have the same fields in this structure. */
907 if (memcmp (&mode, &new_mode, sizeof (mode)) != 0)
909 #ifdef CIBAUD
910 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
911 tcgetattr(&m1); tcsetattr(&m1); tcgetattr(&m2);
912 sometimes (m1 != m2). The only difference is in the four bits
913 of the c_cflag field corresponding to the baud rate. To save
914 Sun users a little confusion, don't report an error if this
915 happens. But suppress the error only if we haven't tried to
916 set the baud rate explicitly -- otherwise we'd never give an
917 error for a true failure to set the baud rate. */
919 new_mode.c_cflag &= (~CIBAUD);
920 if (speed_was_set || memcmp (&mode, &new_mode, sizeof (mode)) != 0)
921 #endif
923 size_t i;
924 error (1, 0,
925 _("standard input: unable to perform all requested operations"));
926 printf (_("new_mode: mode\n"));
927 for (i = 0; i < sizeof (new_mode); i++)
928 printf ("0x%02x: 0x%02x\n",
929 *(((unsigned char *) &new_mode) + i),
930 *(((unsigned char *) &mode) + i));
935 exit (0);
938 /* Return 0 if not applied because not reversible; otherwise return 1. */
940 static int
941 set_mode (struct mode_info *info, int reversed, struct termios *mode)
943 tcflag_t *bitsp;
945 if (reversed && (info->flags & REV) == 0)
946 return 0;
948 bitsp = mode_type_flag (info->type, mode);
950 if (bitsp == NULL)
952 /* Combination mode. */
953 if (!strcmp (info->name, "evenp") || !strcmp (info->name, "parity"))
955 if (reversed)
956 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
957 else
958 mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
960 else if (!strcmp (info->name, "oddp"))
962 if (reversed)
963 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
964 else
965 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
967 else if (!strcmp (info->name, "nl"))
969 if (reversed)
971 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
972 mode->c_oflag = (mode->c_oflag
973 #ifdef ONLCR
974 | ONLCR
975 #endif
977 #ifdef OCRNL
978 & ~OCRNL
979 #endif
980 #ifdef ONLRET
981 & ~ONLRET
982 #endif
985 else
987 mode->c_iflag = mode->c_iflag & ~ICRNL;
988 #ifdef ONLCR
989 mode->c_oflag = mode->c_oflag & ~ONLCR;
990 #endif
993 else if (!strcmp (info->name, "ek"))
995 mode->c_cc[VERASE] = CERASE;
996 mode->c_cc[VKILL] = CKILL;
998 else if (!strcmp (info->name, "sane"))
999 sane_mode (mode);
1000 else if (!strcmp (info->name, "cbreak"))
1002 if (reversed)
1003 mode->c_lflag |= ICANON;
1004 else
1005 mode->c_lflag &= ~ICANON;
1007 else if (!strcmp (info->name, "pass8"))
1009 if (reversed)
1011 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1012 mode->c_iflag |= ISTRIP;
1014 else
1016 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1017 mode->c_iflag &= ~ISTRIP;
1020 else if (!strcmp (info->name, "litout"))
1022 if (reversed)
1024 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1025 mode->c_iflag |= ISTRIP;
1026 mode->c_oflag |= OPOST;
1028 else
1030 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1031 mode->c_iflag &= ~ISTRIP;
1032 mode->c_oflag &= ~OPOST;
1035 else if (!strcmp (info->name, "raw") || !strcmp (info->name, "cooked"))
1037 if ((info->name[0] == 'r' && reversed)
1038 || (info->name[0] == 'c' && !reversed))
1040 /* Cooked mode. */
1041 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1042 mode->c_oflag |= OPOST;
1043 mode->c_lflag |= ISIG | ICANON;
1044 #if VMIN == VEOF
1045 mode->c_cc[VEOF] = CEOF;
1046 #endif
1047 #if VTIME == VEOL
1048 mode->c_cc[VEOL] = CEOL;
1049 #endif
1051 else
1053 /* Raw mode. */
1054 mode->c_iflag = 0;
1055 mode->c_oflag &= ~OPOST;
1056 mode->c_lflag &= ~(ISIG | ICANON
1057 #ifdef XCASE
1058 | XCASE
1059 #endif
1061 mode->c_cc[VMIN] = 1;
1062 mode->c_cc[VTIME] = 0;
1065 #ifdef IXANY
1066 else if (!strcmp (info->name, "decctlq"))
1068 if (reversed)
1069 mode->c_iflag |= IXANY;
1070 else
1071 mode->c_iflag &= ~IXANY;
1073 #endif
1074 #ifdef TABDLY
1075 else if (!strcmp (info->name, "tabs"))
1077 if (reversed)
1078 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1079 else
1080 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1082 #else
1083 # ifdef OXTABS
1084 else if (!strcmp (info->name, "tabs"))
1086 if (reversed)
1087 mode->c_oflag = mode->c_oflag | OXTABS;
1088 else
1089 mode->c_oflag = mode->c_oflag & ~OXTABS;
1091 # endif
1092 #endif
1093 #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
1094 else if (!strcmp (info->name, "lcase")
1095 || !strcmp (info->name, "LCASE"))
1097 if (reversed)
1099 mode->c_lflag &= ~XCASE;
1100 mode->c_iflag &= ~IUCLC;
1101 mode->c_oflag &= ~OLCUC;
1103 else
1105 mode->c_lflag |= XCASE;
1106 mode->c_iflag |= IUCLC;
1107 mode->c_oflag |= OLCUC;
1110 #endif
1111 else if (!strcmp (info->name, "crt"))
1112 mode->c_lflag |= ECHOE
1113 #ifdef ECHOCTL
1114 | ECHOCTL
1115 #endif
1116 #ifdef ECHOKE
1117 | ECHOKE
1118 #endif
1120 else if (!strcmp (info->name, "dec"))
1122 mode->c_cc[VINTR] = 3; /* ^C */
1123 mode->c_cc[VERASE] = 127; /* DEL */
1124 mode->c_cc[VKILL] = 21; /* ^U */
1125 mode->c_lflag |= ECHOE
1126 #ifdef ECHOCTL
1127 | ECHOCTL
1128 #endif
1129 #ifdef ECHOKE
1130 | ECHOKE
1131 #endif
1133 #ifdef IXANY
1134 mode->c_iflag &= ~IXANY;
1135 #endif
1138 else if (reversed)
1139 *bitsp = *bitsp & ~info->mask & ~info->bits;
1140 else
1141 *bitsp = (*bitsp & ~info->mask) | info->bits;
1143 return 1;
1146 static void
1147 set_control_char (struct control_info *info, const 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 (enum speed_setting type, const char *arg, struct termios *mode)
1173 speed_t baud;
1175 baud = string_to_baud (arg);
1176 if (type == input_speed || type == both_speeds)
1177 cfsetispeed (mode, baud);
1178 if (type == output_speed || type == both_speeds)
1179 cfsetospeed (mode, baud);
1182 #ifdef TIOCGWINSZ
1184 /* Get window size information. First try getting the information
1185 associated with standard output and if that fails, try standard input.
1186 Return zero for success, nonzero if both ioctl's failed. */
1188 static int
1189 get_win_size (struct winsize *win)
1191 int err;
1193 err = ioctl (1, TIOCGWINSZ, (char *) win);
1194 if (err != 0)
1195 err = ioctl (0, TIOCGWINSZ, (char *) win);
1196 return err;
1199 static void
1200 set_window_size (int rows, int cols)
1202 struct winsize win;
1204 if (get_win_size (&win))
1206 if (errno != EINVAL)
1207 error (1, errno, _("standard input"));
1208 memset (&win, 0, sizeof (win));
1211 if (rows >= 0)
1212 win.ws_row = rows;
1213 if (cols >= 0)
1214 win.ws_col = cols;
1216 # ifdef TIOCSSIZE
1217 /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
1218 The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
1219 This comment from sys/ttold.h describes Sun's twisted logic - a better
1220 test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
1221 At any rate, the problem is gone in Solaris 2.x.
1223 Unfortunately, the old TIOCSSIZE code does collide with TIOCSWINSZ,
1224 but they can be disambiguated by checking whether a "struct ttysize"
1225 structure's "ts_lines" field is greater than 64K or not. If so,
1226 it's almost certainly a "struct winsize" instead.
1228 At any rate, the bug manifests itself when ws_row == 0; the symptom is
1229 that ws_row is set to ws_col, and ws_col is set to (ws_xpixel<<16) +
1230 ws_ypixel. Since GNU stty sets rows and columns separately, this bug
1231 caused "stty rows 0 cols 0" to set rows to cols and cols to 0, while
1232 "stty cols 0 rows 0" would do the right thing. On a little-endian
1233 machine like the sun386i, the problem is the same, but for ws_col == 0.
1235 The workaround is to do the ioctl once with row and col = 1 to set the
1236 pixel info, and then do it again using a TIOCSSIZE to set rows/cols. */
1238 if (win.ws_row == 0 || win.ws_col == 0)
1240 struct ttysize ttysz;
1242 ttysz.ts_lines = win.ws_row;
1243 ttysz.ts_cols = win.ws_col;
1245 win.ws_row = 1;
1246 win.ws_col = 1;
1248 if (ioctl (0, TIOCSWINSZ, (char *) &win))
1249 error (1, errno, _("standard input"));
1251 if (ioctl (0, TIOCSSIZE, (char *) &ttysz))
1252 error (1, errno, _("standard input"));
1253 return;
1255 # endif
1257 if (ioctl (0, TIOCSWINSZ, (char *) &win))
1258 error (1, errno, _("standard input"));
1261 static void
1262 display_window_size (int fancy)
1264 struct winsize win;
1266 if (get_win_size (&win))
1268 if (errno != EINVAL)
1269 error (1, errno, _("standard input"));
1271 else
1273 wrapf (fancy ? "rows %d; columns %d;" : "%d %d\n",
1274 win.ws_row, win.ws_col);
1275 if (!fancy)
1276 current_col = 0;
1279 #endif
1281 static int
1282 screen_columns (void)
1284 #ifdef TIOCGWINSZ
1285 struct winsize win;
1287 if (get_win_size (&win))
1289 /* With Solaris 2.[123], this ioctl fails and errno is set to
1290 EINVAL for telnet (but not rlogin) sessions. */
1291 if (errno != EINVAL)
1292 error (1, errno, _("standard input"));
1294 else if (win.ws_col > 0)
1295 return win.ws_col;
1296 #endif
1297 if (getenv ("COLUMNS"))
1298 return atoi (getenv ("COLUMNS"));
1299 return 80;
1302 static tcflag_t *
1303 mode_type_flag (enum mode_type type, struct termios *mode)
1305 switch (type)
1307 case control:
1308 return &mode->c_cflag;
1310 case input:
1311 return &mode->c_iflag;
1313 case output:
1314 return &mode->c_oflag;
1316 case local:
1317 return &mode->c_lflag;
1319 case combination:
1320 return NULL;
1322 default:
1323 abort ();
1327 static void
1328 display_settings (enum output_type output_type, struct termios *mode)
1330 switch (output_type)
1332 case changed:
1333 display_changed (mode);
1334 break;
1336 case all:
1337 display_all (mode);
1338 break;
1340 case recoverable:
1341 display_recoverable (mode);
1342 break;
1346 static void
1347 display_changed (struct termios *mode)
1349 int i;
1350 int empty_line;
1351 tcflag_t *bitsp;
1352 unsigned long mask;
1353 enum mode_type prev_type = control;
1355 display_speed (mode, 1);
1356 #ifdef HAVE_C_LINE
1357 wrapf ("line = %d;", mode->c_line);
1358 #endif
1359 putchar ('\n');
1360 current_col = 0;
1362 empty_line = 1;
1363 for (i = 0; strcmp (control_info[i].name, "min"); ++i)
1365 if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
1366 continue;
1367 empty_line = 0;
1368 wrapf ("%s = %s;", control_info[i].name,
1369 visible (mode->c_cc[control_info[i].offset]));
1371 if ((mode->c_lflag & ICANON) == 0)
1373 wrapf ("min = %d; time = %d;\n", (int) mode->c_cc[VMIN],
1374 (int) mode->c_cc[VTIME]);
1376 else if (empty_line == 0)
1377 putchar ('\n');
1378 current_col = 0;
1380 empty_line = 1;
1381 for (i = 0; mode_info[i].name != NULL; ++i)
1383 if (mode_info[i].flags & OMIT)
1384 continue;
1385 if (mode_info[i].type != prev_type)
1387 if (empty_line == 0)
1389 putchar ('\n');
1390 current_col = 0;
1391 empty_line = 1;
1393 prev_type = mode_info[i].type;
1396 bitsp = mode_type_flag (mode_info[i].type, mode);
1397 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1398 if ((*bitsp & mask) == mode_info[i].bits)
1400 if (mode_info[i].flags & SANE_UNSET)
1402 wrapf ("%s", mode_info[i].name);
1403 empty_line = 0;
1406 else if ((mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
1408 wrapf ("-%s", mode_info[i].name);
1409 empty_line = 0;
1412 if (empty_line == 0)
1413 putchar ('\n');
1414 current_col = 0;
1417 static void
1418 display_all (struct termios *mode)
1420 int i;
1421 tcflag_t *bitsp;
1422 unsigned long mask;
1423 enum mode_type prev_type = control;
1425 display_speed (mode, 1);
1426 #ifdef TIOCGWINSZ
1427 display_window_size (1);
1428 #endif
1429 #ifdef HAVE_C_LINE
1430 wrapf ("line = %d;", mode->c_line);
1431 #endif
1432 putchar ('\n');
1433 current_col = 0;
1435 for (i = 0; strcmp (control_info[i].name, "min"); ++i)
1437 wrapf ("%s = %s;", control_info[i].name,
1438 visible (mode->c_cc[control_info[i].offset]));
1440 wrapf ("min = %d; time = %d;\n", mode->c_cc[VMIN], mode->c_cc[VTIME]);
1441 current_col = 0;
1443 for (i = 0; mode_info[i].name != NULL; ++i)
1445 if (mode_info[i].flags & OMIT)
1446 continue;
1447 if (mode_info[i].type != prev_type)
1449 putchar ('\n');
1450 current_col = 0;
1451 prev_type = mode_info[i].type;
1454 bitsp = mode_type_flag (mode_info[i].type, mode);
1455 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1456 if ((*bitsp & mask) == mode_info[i].bits)
1457 wrapf ("%s", mode_info[i].name);
1458 else if (mode_info[i].flags & REV)
1459 wrapf ("-%s", mode_info[i].name);
1461 putchar ('\n');
1462 current_col = 0;
1465 static void
1466 display_speed (struct termios *mode, int fancy)
1468 if (cfgetispeed (mode) == 0 || cfgetispeed (mode) == cfgetospeed (mode))
1469 wrapf (fancy ? "speed %lu baud;" : "%lu\n",
1470 baud_to_value (cfgetospeed (mode)));
1471 else
1472 wrapf (fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n",
1473 baud_to_value (cfgetispeed (mode)),
1474 baud_to_value (cfgetospeed (mode)));
1475 if (!fancy)
1476 current_col = 0;
1479 static void
1480 display_recoverable (struct termios *mode)
1482 int i;
1484 printf ("%lx:%lx:%lx:%lx",
1485 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
1486 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
1487 for (i = 0; i < NCCS; ++i)
1488 printf (":%x", (unsigned int) mode->c_cc[i]);
1489 putchar ('\n');
1492 static int
1493 recover_mode (char *arg, struct termios *mode)
1495 int i, n;
1496 unsigned int chr;
1497 unsigned long iflag, oflag, cflag, lflag;
1499 /* Scan into temporaries since it is too much trouble to figure out
1500 the right format for `tcflag_t'. */
1501 if (sscanf (arg, "%lx:%lx:%lx:%lx%n",
1502 &iflag, &oflag, &cflag, &lflag, &n) != 4)
1503 return 0;
1504 mode->c_iflag = iflag;
1505 mode->c_oflag = oflag;
1506 mode->c_cflag = cflag;
1507 mode->c_lflag = lflag;
1508 arg += n;
1509 for (i = 0; i < NCCS; ++i)
1511 if (sscanf (arg, ":%x%n", &chr, &n) != 1)
1512 return 0;
1513 mode->c_cc[i] = chr;
1514 arg += n;
1516 return 1;
1519 struct speed_map
1521 const char *string; /* ASCII representation. */
1522 speed_t speed; /* Internal form. */
1523 unsigned long value; /* Numeric value. */
1526 struct speed_map speeds[] =
1528 {"0", B0, 0},
1529 {"50", B50, 50},
1530 {"75", B75, 75},
1531 {"110", B110, 110},
1532 {"134", B134, 134},
1533 {"134.5", B134, 134},
1534 {"150", B150, 150},
1535 {"200", B200, 200},
1536 {"300", B300, 300},
1537 {"600", B600, 600},
1538 {"1200", B1200, 1200},
1539 {"1800", B1800, 1800},
1540 {"2400", B2400, 2400},
1541 {"4800", B4800, 4800},
1542 {"9600", B9600, 9600},
1543 {"19200", B19200, 19200},
1544 {"38400", B38400, 38400},
1545 {"exta", B19200, 19200},
1546 {"extb", B38400, 38400},
1547 #ifdef B57600
1548 {"57600", B57600, 57600},
1549 #endif
1550 #ifdef B115200
1551 {"115200", B115200, 115200},
1552 #endif
1553 {NULL, 0, 0}
1556 static speed_t
1557 string_to_baud (const char *arg)
1559 int i;
1561 for (i = 0; speeds[i].string != NULL; ++i)
1562 if (!strcmp (arg, speeds[i].string))
1563 return speeds[i].speed;
1564 return (speed_t) -1;
1567 static unsigned long
1568 baud_to_value (speed_t speed)
1570 int i;
1572 for (i = 0; speeds[i].string != NULL; ++i)
1573 if (speed == speeds[i].speed)
1574 return speeds[i].value;
1575 return 0;
1578 static void
1579 sane_mode (struct termios *mode)
1581 int i;
1582 tcflag_t *bitsp;
1584 for (i = 0; control_info[i].name; ++i)
1586 #if VMIN == VEOF
1587 if (!strcmp (control_info[i].name, "min"))
1588 break;
1589 #endif
1590 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1593 for (i = 0; mode_info[i].name != NULL; ++i)
1595 if (mode_info[i].flags & SANE_SET)
1597 bitsp = mode_type_flag (mode_info[i].type, mode);
1598 *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits;
1600 else if (mode_info[i].flags & SANE_UNSET)
1602 bitsp = mode_type_flag (mode_info[i].type, mode);
1603 *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits;
1608 /* Return a string that is the printable representation of character CH. */
1609 /* Adapted from `cat' by Torbjorn Granlund. */
1611 static const char *
1612 visible (unsigned int ch)
1614 static char buf[10];
1615 char *bpout = buf;
1617 if (ch == _POSIX_VDISABLE)
1618 return _("<undef>");
1620 if (ch >= 32)
1622 if (ch < 127)
1623 *bpout++ = ch;
1624 else if (ch == 127)
1626 *bpout++ = '^';
1627 *bpout++ = '?';
1629 else
1631 *bpout++ = 'M',
1632 *bpout++ = '-';
1633 if (ch >= 128 + 32)
1635 if (ch < 128 + 127)
1636 *bpout++ = ch - 128;
1637 else
1639 *bpout++ = '^';
1640 *bpout++ = '?';
1643 else
1645 *bpout++ = '^';
1646 *bpout++ = ch - 128 + 64;
1650 else
1652 *bpout++ = '^';
1653 *bpout++ = ch + 64;
1655 *bpout = '\0';
1656 return (const char *) buf;
1659 /* Parse string S as an integer, using decimal radix by default,
1660 but allowing octal and hex numbers as in C. */
1661 /* From `od' by Richard Stallman. */
1663 static long
1664 integer_arg (const char *s)
1666 long value;
1667 if (xstrtol (s, NULL, 0, &value, "bB") != LONGINT_OK)
1669 error (0, 0, _("invalid integer argument `%s'"), s);
1670 usage (1);
1672 return value;