*** empty log message ***
[coreutils.git] / src / stty.c
blob1a03492389efadd65443c9935f8575a9be6c7ae2
1 /* stty -- change and print terminal line settings
2 Copyright (C) 1990-1999 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] [-F device] [--file=device] [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.
23 -F, --file Open and use the specified device instead of stdin
25 If no args are given, write to stdout the baud rate and settings that
26 have been changed from their defaults. Mode reading and changes
27 are done on the specified device, or stdin if none was specified.
29 David MacKenzie <djm@gnu.ai.mit.edu> */
31 #include <config.h>
33 #ifdef TERMIOS_NEEDS_XOPEN_SOURCE
34 # define _XOPEN_SOURCE
35 #endif
37 #include <stdio.h>
38 #include <sys/types.h>
39 #if HAVE_TERMIOS_H
40 # include <termios.h>
41 #endif
42 #ifdef GWINSZ_IN_SYS_IOCTL
43 # include <sys/ioctl.h>
44 #endif
45 #ifdef WINSIZE_IN_PTEM
46 # include <sys/stream.h>
47 # include <sys/ptem.h>
48 #endif
49 #ifdef GWINSZ_IN_SYS_PTY
50 # include <sys/ioctl.h>
51 # include <sys/tty.h>
52 # include <sys/pty.h>
53 #endif
54 #include <getopt.h>
55 #if PROTOTYPES
56 # include <stdarg.h>
57 # define VA_START(args, lastarg) va_start(args, lastarg)
58 #else
59 # include <varargs.h>
60 # define VA_START(args, lastarg) va_start(args)
61 #endif
63 #include "system.h"
64 #include "long-options.h"
65 #include "error.h"
66 #include "xstrtol.h"
68 /* The official name of this program (e.g., no `g' prefix). */
69 #define PROGRAM_NAME "stty"
71 #define AUTHORS "David MacKenzie"
73 #ifndef _POSIX_VDISABLE
74 # define _POSIX_VDISABLE ((unsigned char) 0)
75 #endif
77 #define Control(c) ((c) & 0x1f)
78 /* Canonical values for control characters. */
79 #ifndef CINTR
80 # define CINTR Control ('c')
81 #endif
82 #ifndef CQUIT
83 # define CQUIT 28
84 #endif
85 #ifndef CERASE
86 # define CERASE 127
87 #endif
88 #ifndef CKILL
89 # define CKILL Control ('u')
90 #endif
91 #ifndef CEOF
92 # define CEOF Control ('d')
93 #endif
94 #ifndef CEOL
95 # define CEOL _POSIX_VDISABLE
96 #endif
97 #ifndef CSTART
98 # define CSTART Control ('q')
99 #endif
100 #ifndef CSTOP
101 # define CSTOP Control ('s')
102 #endif
103 #ifndef CSUSP
104 # define CSUSP Control ('z')
105 #endif
106 #if defined(VEOL2) && !defined(CEOL2)
107 # define CEOL2 _POSIX_VDISABLE
108 #endif
109 /* ISC renamed swtch to susp for termios, but we'll accept either name. */
110 #if defined(VSUSP) && !defined(VSWTCH)
111 # define VSWTCH VSUSP
112 # define CSWTCH CSUSP
113 #endif
114 #if defined(VSWTCH) && !defined(CSWTCH)
115 # define CSWTCH _POSIX_VDISABLE
116 #endif
118 /* SunOS 5.3 loses (^Z doesn't work) if `swtch' is the same as `susp'.
119 So the default is to disable `swtch.' */
120 #if defined (__sparc__) && defined (__svr4__)
121 # undef CSWTCH
122 # define CSWTCH _POSIX_VDISABLE
123 #endif
125 #if defined(VWERSE) && !defined (VWERASE) /* AIX-3.2.5 */
126 # define VWERASE VWERSE
127 #endif
128 #if defined(VDSUSP) && !defined (CDSUSP)
129 # define CDSUSP Control ('y')
130 #endif
131 #if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */
132 # define VREPRINT VRPRNT
133 #endif
134 #if defined(VREPRINT) && !defined(CRPRNT)
135 # define CRPRNT Control ('r')
136 #endif
137 #if defined(VWERASE) && !defined(CWERASE)
138 # define CWERASE Control ('w')
139 #endif
140 #if defined(VLNEXT) && !defined(CLNEXT)
141 # define CLNEXT Control ('v')
142 #endif
143 #if defined(VDISCARD) && !defined(VFLUSHO)
144 # define VFLUSHO VDISCARD
145 #endif
146 #if defined(VFLUSH) && !defined(VFLUSHO) /* Ultrix 4.2 */
147 # define VFLUSHO VFLUSH
148 #endif
149 #if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */
150 # define ECHOCTL CTLECH
151 #endif
152 #if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */
153 # define ECHOCTL TCTLECH
154 #endif
155 #if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */
156 # define ECHOKE CRTKIL
157 #endif
158 #if defined(VFLUSHO) && !defined(CFLUSHO)
159 # define CFLUSHO Control ('o')
160 #endif
161 #if defined(VSTATUS) && !defined(CSTATUS)
162 # define CSTATUS Control ('t')
163 #endif
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 static const char *visible PARAMS ((unsigned int ch));
403 static unsigned long baud_to_value PARAMS ((speed_t speed));
404 static int recover_mode PARAMS ((char *arg, struct termios *mode));
405 static int screen_columns PARAMS ((void));
406 static int set_mode PARAMS ((struct mode_info *info, int reversed,
407 struct termios *mode));
408 static long integer_arg PARAMS ((const char *s));
409 static speed_t string_to_baud PARAMS ((const char *arg));
410 static tcflag_t *mode_type_flag PARAMS ((enum mode_type type,
411 struct termios *mode));
412 static void display_all PARAMS ((struct termios *mode, int fd,
413 const char *device_name));
414 static void display_changed PARAMS ((struct termios *mode));
415 static void display_recoverable PARAMS ((struct termios *mode));
416 static void display_settings PARAMS ((enum output_type output_type,
417 struct termios *mode, int fd,
418 const char *device_name));
419 static void display_speed PARAMS ((struct termios *mode, int fancy));
420 static void display_window_size PARAMS ((int fancy, int fd,
421 const char *device_name));
422 static void sane_mode PARAMS ((struct termios *mode));
423 static void set_control_char PARAMS ((struct control_info *info,
424 const char *arg,
425 struct termios *mode));
426 static void set_speed PARAMS ((enum speed_setting type, const char *arg,
427 struct termios *mode));
428 static void set_window_size PARAMS ((int rows, int cols, int fd,
429 const char *device_name));
431 /* The width of the screen, for output wrapping. */
432 static int max_col;
434 /* Current position, to know when to wrap. */
435 static int current_col;
437 static struct option longopts[] =
439 {"all", no_argument, NULL, 'a'},
440 {"save", no_argument, NULL, 'g'},
441 {"file", required_argument, NULL, 'F'},
442 {NULL, 0, NULL, 0}
445 /* The name this program was run with. */
446 char *program_name;
448 /* Print format string MESSAGE and optional args.
449 Wrap to next line first if it won't fit.
450 Print a space first unless MESSAGE will start a new line. */
452 /* VARARGS */
453 static void
454 #if PROTOTYPES
455 wrapf (const char *message,...)
456 #else
457 wrapf (message, va_alist)
458 const char *message;
459 va_dcl
460 #endif
462 va_list args;
463 char buf[1024]; /* Plenty long for our needs. */
464 int buflen;
466 VA_START (args, message);
467 vsprintf (buf, message, args);
468 va_end (args);
469 buflen = strlen (buf);
470 if (current_col + (current_col > 0) + buflen >= max_col)
472 putchar ('\n');
473 current_col = 0;
475 if (current_col > 0)
477 putchar (' ');
478 current_col++;
480 fputs (buf, stdout);
481 current_col += buflen;
484 void
485 usage (int status)
487 if (status != 0)
488 fprintf (stderr, _("Try `%s --help' for more information.\n"),
489 program_name);
490 else
492 printf (_("\
493 Usage: %s [-F device] [--file=device] [SETTING]...\n\
494 or: %s [-F device] [--file=device] [-a|--all]\n\
495 or: %s [-F device] [--file=device] [-g|--save]\n\
497 program_name, program_name, program_name);
498 printf (_("\
499 Print or change terminal characteristics.\n\
501 -a, --all print all current settings in human-readable form\n\
502 -g, --save print all current settings in a stty-readable form\n\
503 -F, --file open and use the specified device instead of stdin\n\
504 --help display this help and exit\n\
505 --version output version information and exit\n\
507 Optional - before SETTING indicates negation. An * marks non-POSIX\n\
508 settings. The underlying system defines which settings are available.\n\
509 "));
510 printf (_("\
512 Special characters:\n\
513 * dsusp CHAR CHAR will send a terminal stop signal once input flushed\n\
514 eof CHAR CHAR will send an end of file (terminate the input)\n\
515 eol CHAR CHAR will end the line\n\
516 * eol2 CHAR alternate CHAR for ending the line\n\
517 erase CHAR CHAR will erase the last character typed\n\
518 intr CHAR CHAR will send an interrupt signal\n\
519 kill CHAR CHAR will erase the current line\n\
520 * lnext CHAR CHAR will enter the next character quoted\n\
521 quit CHAR CHAR will send a quit signal\n\
522 * rprnt CHAR CHAR will redraw the current line\n\
523 start CHAR CHAR will restart the output after stopping it\n\
524 stop CHAR CHAR will stop the output\n\
525 susp CHAR CHAR will send a terminal stop signal\n\
526 * swtch CHAR CHAR will switch to a different shell layer\n\
527 * werase CHAR CHAR will erase the last word typed\n\
528 "));
529 printf (_("\
531 Special settings:\n\
532 N set the input and output speeds to N bauds\n\
533 * cols N tell the kernel that the terminal has N columns\n\
534 * columns N same as cols N\n\
535 ispeed N set the input speed to N\n\
536 * line N use line discipline N\n\
537 min N with -icanon, set N characters minimum for a completed read\n\
538 ospeed N set the output speed to N\n\
539 * rows N tell the kernel that the terminal has N rows\n\
540 * size print the number of rows and columns according to the kernel\n\
541 speed print the terminal speed\n\
542 time N with -icanon, set read timeout of N tenths of a second\n\
543 "));
544 printf (_("\
546 Control settings:\n\
547 [-]clocal disable modem control signals\n\
548 [-]cread allow input to be received\n\
549 * [-]crtscts enable RTS/CTS handshaking\n\
550 csN set character size to N bits, N in [5..8]\n\
551 [-]cstopb use two stop bits per character (one with `-')\n\
552 [-]hup send a hangup signal when the last process closes the tty\n\
553 [-]hupcl same as [-]hup\n\
554 [-]parenb generate parity bit in output and expect parity bit in input\n\
555 [-]parodd set odd parity (even with `-')\n\
556 "));
557 printf (_("\
559 Input settings:\n\
560 [-]brkint breaks cause an interrupt signal\n\
561 [-]icrnl translate carriage return to newline\n\
562 [-]ignbrk ignore break characters\n\
563 [-]igncr ignore carriage return\n\
564 [-]ignpar ignore characters with parity errors\n\
565 * [-]imaxbel beep and do not flush a full input buffer on a character\n\
566 [-]inlcr translate newline to carriage return\n\
567 [-]inpck enable input parity checking\n\
568 [-]istrip clear high (8th) bit of input characters\n\
569 * [-]iuclc translate uppercase characters to lowercase\n\
570 * [-]ixany let any character restart output, not only start character\n\
571 [-]ixoff enable sending of start/stop characters\n\
572 [-]ixon enable XON/XOFF flow control\n\
573 [-]parmrk mark parity errors (with a 255-0-character sequence)\n\
574 [-]tandem same as [-]ixoff\n\
575 "));
576 printf (_("\
578 Output settings:\n\
579 * bsN backspace delay style, N in [0..1]\n\
580 * crN carriage return delay style, N in [0..3]\n\
581 * ffN form feed delay style, N in [0..1]\n\
582 * nlN newline delay style, N in [0..1]\n\
583 * [-]ocrnl translate carriage return to newline\n\
584 * [-]ofdel use delete characters for fill instead of null characters\n\
585 * [-]ofill use fill (padding) characters instead of timing for delays\n\
586 * [-]olcuc translate lowercase characters to uppercase\n\
587 * [-]onlcr translate newline to carriage return-newline\n\
588 * [-]onlret newline performs a carriage return\n\
589 * [-]onocr do not print carriage returns in the first column\n\
590 [-]opost postprocess output\n\
591 * tabN horizontal tab delay style, N in [0..3]\n\
592 * tabs same as tab0\n\
593 * -tabs same as tab3\n\
594 * vtN vertical tab delay style, N in [0..1]\n\
595 "));
596 printf (_("\
598 Local settings:\n\
599 [-]crterase echo erase characters as backspace-space-backspace\n\
600 * crtkill kill all line by obeying the echoprt and echoe settings\n\
601 * -crtkill kill all line by obeying the echoctl and echok settings\n\
602 * [-]ctlecho echo control characters in hat notation (`^c')\n\
603 [-]echo echo input characters\n\
604 * [-]echoctl same as [-]ctlecho\n\
605 [-]echoe same as [-]crterase\n\
606 [-]echok echo a newline after a kill character\n\
607 * [-]echoke same as [-]crtkill\n\
608 [-]echonl echo newline even if not echoing other characters\n\
609 * [-]echoprt echo erased characters backward, between `\\' and '/'\n\
610 [-]icanon enable erase, kill, werase, and rprnt special characters\n\
611 [-]iexten enable non-POSIX special characters\n\
612 [-]isig enable interrupt, quit, and suspend special characters\n\
613 [-]noflsh disable flushing after interrupt and quit special characters\n\
614 * [-]prterase same as [-]echoprt\n\
615 * [-]tostop stop background jobs that try to write to the terminal\n\
616 * [-]xcase with icanon, escape with `\\' for uppercase characters\n\
617 "));
618 printf (_("\
620 Combination settings:\n\
621 * [-]LCASE same as [-]lcase\n\
622 cbreak same as -icanon\n\
623 -cbreak same as icanon\n\
624 cooked same as brkint ignpar istrip icrnl ixon opost isig\n\
625 icanon, eof and eol characters to their default values\n\
626 -cooked same as raw\n\
627 crt same as echoe echoctl echoke\n\
628 dec same as echoe echoctl echoke -ixany intr ^c erase 0177\n\
629 kill ^u\n\
630 * [-]decctlq same as [-]ixany\n\
631 ek erase and kill characters to their default values\n\
632 evenp same as parenb -parodd cs7\n\
633 -evenp same as -parenb cs8\n\
634 * [-]lcase same as xcase iuclc olcuc\n\
635 litout same as -parenb -istrip -opost cs8\n\
636 -litout same as parenb istrip opost cs7\n\
637 nl same as -icrnl -onlcr\n\
638 -nl same as icrnl -inlcr -igncr onlcr -ocrnl -onlret\n\
639 oddp same as parenb parodd cs7\n\
640 -oddp same as -parenb cs8\n\
641 [-]parity same as [-]evenp\n\
642 pass8 same as -parenb -istrip cs8\n\
643 -pass8 same as parenb istrip cs7\n\
644 raw same as -ignbrk -brkint -ignpar -parmrk -inpck -istrip\n\
645 -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany\n\
646 -imaxbel -opost -isig -icanon -xcase min 1 time 0\n\
647 -raw same as cooked\n\
648 sane same as cread -ignbrk brkint -inlcr -igncr icrnl\n\
649 -ixoff -iuclc -ixany imaxbel opost -olcuc -ocrnl onlcr\n\
650 -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0\n\
651 isig icanon iexten echo echoe echok -echonl -noflsh\n\
652 -xcase -tostop -echoprt echoctl echoke, all special\n\
653 characters to their default values.\n\
654 "));
655 printf (_("\
657 Handle the tty line connected to standard input. Without arguments,\n\
658 prints baud rate, line discipline, and deviations from stty sane. In\n\
659 settings, CHAR is taken literally, or coded as in ^c, 0x37, 0177 or\n\
660 127; special values ^- or undef used to disable special characters.\n\
661 "));
662 puts (_("\nReport bugs to <bug-sh-utils@gnu.org>."));
664 exit (status);
667 /* Return 1 if the string contains only valid options. */
669 valid_options (char *opt, const char *valid_opts,
670 const char *valid_arg_opts)
672 char ch;
674 if (*opt++ != '-')
675 return 0;
677 while ((ch = *opt))
679 opt++;
680 if (strchr (valid_opts, ch))
681 continue;
682 if (strchr (valid_arg_opts, ch))
683 return 1;
684 return 0;
686 return 1;
690 main (int argc, char **argv)
692 struct termios mode;
693 enum output_type output_type;
694 int optc;
695 int require_set_attr;
696 int speed_was_set;
697 int verbose_output;
698 int recoverable_output;
699 int k;
700 int noargs = 1;
701 char *file_name = NULL;
702 int fd;
703 const char *device_name;
704 const char *posixly_correct = getenv ("POSIXLY_CORRECT");
705 int invalid_long_option = 0;
707 program_name = argv[0];
708 setlocale (LC_ALL, "");
709 bindtextdomain (PACKAGE, LOCALEDIR);
710 textdomain (PACKAGE);
712 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
713 AUTHORS, usage);
715 output_type = changed;
716 verbose_output = 0;
717 recoverable_output = 0;
719 /* Don't print error messages for unrecognized options. */
720 opterr = 0;
722 while ((optc = getopt_long (argc, argv, "agF:", longopts, NULL)) != -1)
724 int unrecognized_option = 0;
725 switch (optc)
727 case 'a':
728 verbose_output = 1;
729 output_type = all;
730 break;
732 case 'g':
733 recoverable_output = 1;
734 output_type = recoverable;
735 break;
737 case 'F':
738 if (file_name)
739 error (2, 0, _("only one device may be specified"));
740 file_name = optarg;
741 break;
743 default:
744 unrecognized_option = 1;
745 break;
748 if (unrecognized_option)
749 break;
752 /* FIXME: what is this?!? */
753 if (invalid_long_option)
754 usage (1);
756 /* Clear out the options that have been parsed. This is really
757 gross, but it's needed because stty SETTINGS look like options to
758 getopt(), so we need to work around things in a really horrible
759 way. If any new options are ever added to stty, the short option
760 MUST NOT be a letter which is the first letter of one of the
761 possible stty settings. If you change anything about how stty
762 parses options, be sure it still works with combinations of
763 short and long options, --, POSIXLY_CORRECT, etc. */
764 for (k = 1; k < argc; k++)
766 size_t len;
767 char *eq;
769 if (argv[k] == NULL)
770 continue;
772 /* Handle --, and reset noargs if there are arguments following it. */
773 if (STREQ (argv[k], "--"))
775 argv[k] = NULL;
776 if (k < argc - 1)
777 noargs = 0;
778 break;
781 /* Handle "--file device" */
782 len = strlen (argv[k]);
783 if (len >= 3 && strstr ("--file", argv[k]))
785 argv[k] = NULL;
786 argv[k + 1] = NULL;
787 continue;
790 /* Handle "--all" and "--save". */
791 if (len >= 3
792 && (strstr ("--all", argv[k])
793 || strstr ("--save", argv[k])))
795 argv[k] = NULL;
796 continue;
799 /* Handle "--file=device". */
800 eq = strchr (argv[k], '=');
801 if (eq && eq - argv[k] >= 3)
803 *eq = '\0';
804 if (strstr ("--file", argv[k]))
806 argv[k] = NULL;
807 continue;
809 /* Put the equals sign back for the error message. */
810 *eq = '=';
813 /* Handle "-a", "-ag", "-aF/dev/foo", "-aF /dev/foo", etc. */
814 if (valid_options (argv[k], "ag", "F"))
816 /* FIXME: this loses when the device name ends in `F'.
817 e.g. `stty -F/dev/BARF nl' would clobber the `nl' argument. */
818 if (argv[k][strlen (argv[k]) - 1] == 'F')
819 argv[k + 1] = NULL;
820 argv[k] = NULL;
822 /* Everything else must be a normal, non-option argument. */
823 else
825 noargs = 0;
826 if (posixly_correct)
827 break;
831 /* Specifying both -a and -g gets an error. */
832 if (verbose_output && recoverable_output)
833 error (2, 0,
834 _("the options for verbose and stty-readable output styles are\n\
835 mutually exclusive"));
837 /* Specifying any other arguments with -a or -g gets an error. */
838 if (!noargs && (verbose_output || recoverable_output))
839 error (2, 0, _("when specifying an output style, modes may not be set"));
841 /* FIXME: it'd be better not to open the file until we've verified
842 that all arguments are valid. Otherwise, we could end up doing
843 only some of the requested operations and then failing, probably
844 leaving things in an undesirable state. */
846 if (file_name)
848 int fdflags;
849 device_name = file_name;
850 fd = open (device_name, O_RDONLY | O_NONBLOCK);
851 if (fd < 0)
852 error (1, errno, "%s", device_name);
853 if ((fdflags = fcntl (fd, F_GETFL)) == -1
854 || fcntl (fd, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
855 error (1, errno, _("%s: couldn't reset non-blocking mode"),
856 device_name);
858 else
860 fd = 0;
861 device_name = _("standard input");
864 /* Initialize to all zeroes so there is no risk memcmp will report a
865 spurious difference in an uninitialized portion of the structure. */
866 memset (&mode, 0, sizeof (mode));
867 if (tcgetattr (fd, &mode))
868 error (1, errno, "%s", device_name);
870 if (verbose_output || recoverable_output || noargs)
872 max_col = screen_columns ();
873 current_col = 0;
874 display_settings (output_type, &mode, fd, device_name);
875 exit (0);
878 speed_was_set = 0;
879 require_set_attr = 0;
880 k = 1;
881 while (k < argc)
883 int match_found = 0;
884 int reversed = 0;
885 int i;
887 if (argv[k] == 0)
889 k++;
890 continue;
893 if (argv[k][0] == '-')
895 ++argv[k];
896 reversed = 1;
898 for (i = 0; mode_info[i].name != NULL; ++i)
900 if (STREQ (argv[k], mode_info[i].name))
902 match_found = set_mode (&mode_info[i], reversed, &mode);
903 require_set_attr = 1;
904 break;
907 if (match_found == 0 && reversed)
909 error (0, 0, _("invalid argument `%s'"), --argv[k]);
910 usage (1);
912 if (match_found == 0)
914 for (i = 0; control_info[i].name != NULL; ++i)
916 if (STREQ (argv[k], control_info[i].name))
918 if (k == argc - 1)
920 error (0, 0, _("missing argument to `%s'"), argv[k]);
921 usage (1);
923 match_found = 1;
924 ++k;
925 set_control_char (&control_info[i], argv[k], &mode);
926 require_set_attr = 1;
927 break;
931 if (match_found == 0)
933 if (STREQ (argv[k], "ispeed"))
935 if (k == argc - 1)
937 error (0, 0, _("missing argument to `%s'"), argv[k]);
938 usage (1);
940 ++k;
941 set_speed (input_speed, argv[k], &mode);
942 speed_was_set = 1;
943 require_set_attr = 1;
945 else if (STREQ (argv[k], "ospeed"))
947 if (k == argc - 1)
949 error (0, 0, _("missing argument to `%s'"), argv[k]);
950 usage (1);
952 ++k;
953 set_speed (output_speed, argv[k], &mode);
954 speed_was_set = 1;
955 require_set_attr = 1;
957 #ifdef TIOCGWINSZ
958 else if (STREQ (argv[k], "rows"))
960 if (k == argc - 1)
962 error (0, 0, _("missing argument to `%s'"), argv[k]);
963 usage (1);
965 ++k;
966 set_window_size ((int) integer_arg (argv[k]), -1,
967 fd, device_name);
969 else if (STREQ (argv[k], "cols")
970 || STREQ (argv[k], "columns"))
972 if (k == argc - 1)
974 error (0, 0, _("missing argument to `%s'"), argv[k]);
975 usage (1);
977 ++k;
978 set_window_size (-1, (int) integer_arg (argv[k]),
979 fd, device_name);
981 else if (STREQ (argv[k], "size"))
983 max_col = screen_columns ();
984 current_col = 0;
985 display_window_size (0, fd, device_name);
987 #endif
988 #ifdef HAVE_C_LINE
989 else if (STREQ (argv[k], "line"))
991 if (k == argc - 1)
993 error (0, 0, _("missing argument to `%s'"), argv[k]);
994 usage (1);
996 ++k;
997 mode.c_line = integer_arg (argv[k]);
998 require_set_attr = 1;
1000 #endif
1001 else if (STREQ (argv[k], "speed"))
1003 max_col = screen_columns ();
1004 display_speed (&mode, 0);
1006 else if (string_to_baud (argv[k]) != (speed_t) -1)
1008 set_speed (both_speeds, argv[k], &mode);
1009 speed_was_set = 1;
1010 require_set_attr = 1;
1012 else
1014 if (recover_mode (argv[k], &mode) == 0)
1016 error (0, 0, _("invalid argument `%s'"), argv[k]);
1017 usage (1);
1019 require_set_attr = 1;
1022 k++;
1025 if (require_set_attr)
1027 struct termios new_mode;
1029 if (tcsetattr (fd, TCSADRAIN, &mode))
1030 error (1, errno, "%s", device_name);
1032 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
1033 it performs *any* of the requested operations. This means it
1034 can report `success' when it has actually failed to perform
1035 some proper subset of the requested operations. To detect
1036 this partial failure, get the current terminal attributes and
1037 compare them to the requested ones. */
1039 /* Initialize to all zeroes so there is no risk memcmp will report a
1040 spurious difference in an uninitialized portion of the structure. */
1041 memset (&new_mode, 0, sizeof (new_mode));
1042 if (tcgetattr (fd, &new_mode))
1043 error (1, errno, "%s", device_name);
1045 /* Normally, one shouldn't use memcmp to compare structures that
1046 may have `holes' containing uninitialized data, but we have been
1047 careful to initialize the storage of these two variables to all
1048 zeroes. One might think it more efficient simply to compare the
1049 modified fields, but that would require enumerating those fields --
1050 and not all systems have the same fields in this structure. */
1052 if (memcmp (&mode, &new_mode, sizeof (mode)) != 0)
1054 #ifdef CIBAUD
1055 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
1056 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
1057 sometimes (m1 != m2). The only difference is in the four bits
1058 of the c_cflag field corresponding to the baud rate. To save
1059 Sun users a little confusion, don't report an error if this
1060 happens. But suppress the error only if we haven't tried to
1061 set the baud rate explicitly -- otherwise we'd never give an
1062 error for a true failure to set the baud rate. */
1064 new_mode.c_cflag &= (~CIBAUD);
1065 if (speed_was_set || memcmp (&mode, &new_mode, sizeof (mode)) != 0)
1066 #endif
1068 error (1, 0,
1069 _("%s: unable to perform all requested operations"),
1070 device_name);
1071 #ifdef TESTING
1073 size_t i;
1074 printf (_("new_mode: mode\n"));
1075 for (i = 0; i < sizeof (new_mode); i++)
1076 printf ("0x%02x: 0x%02x\n",
1077 *(((unsigned char *) &new_mode) + i),
1078 *(((unsigned char *) &mode) + i));
1080 #endif
1085 exit (0);
1088 /* Return 0 if not applied because not reversible; otherwise return 1. */
1090 static int
1091 set_mode (struct mode_info *info, int reversed, struct termios *mode)
1093 tcflag_t *bitsp;
1095 if (reversed && (info->flags & REV) == 0)
1096 return 0;
1098 bitsp = mode_type_flag (info->type, mode);
1100 if (bitsp == NULL)
1102 /* Combination mode. */
1103 if (STREQ (info->name, "evenp") || STREQ (info->name, "parity"))
1105 if (reversed)
1106 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1107 else
1108 mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
1110 else if (STREQ (info->name, "oddp"))
1112 if (reversed)
1113 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1114 else
1115 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
1117 else if (STREQ (info->name, "nl"))
1119 if (reversed)
1121 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
1122 mode->c_oflag = (mode->c_oflag
1123 #ifdef ONLCR
1124 | ONLCR
1125 #endif
1127 #ifdef OCRNL
1128 & ~OCRNL
1129 #endif
1130 #ifdef ONLRET
1131 & ~ONLRET
1132 #endif
1135 else
1137 mode->c_iflag = mode->c_iflag & ~ICRNL;
1138 #ifdef ONLCR
1139 mode->c_oflag = mode->c_oflag & ~ONLCR;
1140 #endif
1143 else if (STREQ (info->name, "ek"))
1145 mode->c_cc[VERASE] = CERASE;
1146 mode->c_cc[VKILL] = CKILL;
1148 else if (STREQ (info->name, "sane"))
1149 sane_mode (mode);
1150 else if (STREQ (info->name, "cbreak"))
1152 if (reversed)
1153 mode->c_lflag |= ICANON;
1154 else
1155 mode->c_lflag &= ~ICANON;
1157 else if (STREQ (info->name, "pass8"))
1159 if (reversed)
1161 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1162 mode->c_iflag |= ISTRIP;
1164 else
1166 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1167 mode->c_iflag &= ~ISTRIP;
1170 else if (STREQ (info->name, "litout"))
1172 if (reversed)
1174 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1175 mode->c_iflag |= ISTRIP;
1176 mode->c_oflag |= OPOST;
1178 else
1180 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1181 mode->c_iflag &= ~ISTRIP;
1182 mode->c_oflag &= ~OPOST;
1185 else if (STREQ (info->name, "raw") || STREQ (info->name, "cooked"))
1187 if ((info->name[0] == 'r' && reversed)
1188 || (info->name[0] == 'c' && !reversed))
1190 /* Cooked mode. */
1191 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1192 mode->c_oflag |= OPOST;
1193 mode->c_lflag |= ISIG | ICANON;
1194 #if VMIN == VEOF
1195 mode->c_cc[VEOF] = CEOF;
1196 #endif
1197 #if VTIME == VEOL
1198 mode->c_cc[VEOL] = CEOL;
1199 #endif
1201 else
1203 /* Raw mode. */
1204 mode->c_iflag = 0;
1205 mode->c_oflag &= ~OPOST;
1206 mode->c_lflag &= ~(ISIG | ICANON
1207 #ifdef XCASE
1208 | XCASE
1209 #endif
1211 mode->c_cc[VMIN] = 1;
1212 mode->c_cc[VTIME] = 0;
1215 #ifdef IXANY
1216 else if (STREQ (info->name, "decctlq"))
1218 if (reversed)
1219 mode->c_iflag |= IXANY;
1220 else
1221 mode->c_iflag &= ~IXANY;
1223 #endif
1224 #ifdef TABDLY
1225 else if (STREQ (info->name, "tabs"))
1227 if (reversed)
1228 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1229 else
1230 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1232 #else
1233 # ifdef OXTABS
1234 else if (STREQ (info->name, "tabs"))
1236 if (reversed)
1237 mode->c_oflag = mode->c_oflag | OXTABS;
1238 else
1239 mode->c_oflag = mode->c_oflag & ~OXTABS;
1241 # endif
1242 #endif
1243 #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
1244 else if (STREQ (info->name, "lcase")
1245 || STREQ (info->name, "LCASE"))
1247 if (reversed)
1249 mode->c_lflag &= ~XCASE;
1250 mode->c_iflag &= ~IUCLC;
1251 mode->c_oflag &= ~OLCUC;
1253 else
1255 mode->c_lflag |= XCASE;
1256 mode->c_iflag |= IUCLC;
1257 mode->c_oflag |= OLCUC;
1260 #endif
1261 else if (STREQ (info->name, "crt"))
1262 mode->c_lflag |= ECHOE
1263 #ifdef ECHOCTL
1264 | ECHOCTL
1265 #endif
1266 #ifdef ECHOKE
1267 | ECHOKE
1268 #endif
1270 else if (STREQ (info->name, "dec"))
1272 mode->c_cc[VINTR] = 3; /* ^C */
1273 mode->c_cc[VERASE] = 127; /* DEL */
1274 mode->c_cc[VKILL] = 21; /* ^U */
1275 mode->c_lflag |= ECHOE
1276 #ifdef ECHOCTL
1277 | ECHOCTL
1278 #endif
1279 #ifdef ECHOKE
1280 | ECHOKE
1281 #endif
1283 #ifdef IXANY
1284 mode->c_iflag &= ~IXANY;
1285 #endif
1288 else if (reversed)
1289 *bitsp = *bitsp & ~info->mask & ~info->bits;
1290 else
1291 *bitsp = (*bitsp & ~info->mask) | info->bits;
1293 return 1;
1296 static void
1297 set_control_char (struct control_info *info, const char *arg,
1298 struct termios *mode)
1300 unsigned char value;
1302 if (STREQ (info->name, "min") || STREQ (info->name, "time"))
1303 value = integer_arg (arg);
1304 else if (arg[0] == '\0' || arg[1] == '\0')
1305 value = arg[0];
1306 else if (STREQ (arg, "^-") || STREQ (arg, "undef"))
1307 value = _POSIX_VDISABLE;
1308 else if (arg[0] == '^' && arg[1] != '\0') /* Ignore any trailing junk. */
1310 if (arg[1] == '?')
1311 value = 127;
1312 else
1313 value = arg[1] & ~0140; /* Non-letters get weird results. */
1315 else
1316 value = integer_arg (arg);
1317 mode->c_cc[info->offset] = value;
1320 static void
1321 set_speed (enum speed_setting type, const char *arg, struct termios *mode)
1323 speed_t baud;
1325 baud = string_to_baud (arg);
1326 if (type == input_speed || type == both_speeds)
1327 cfsetispeed (mode, baud);
1328 if (type == output_speed || type == both_speeds)
1329 cfsetospeed (mode, baud);
1332 #ifdef TIOCGWINSZ
1334 static int
1335 get_win_size (int fd, struct winsize *win)
1337 int err = ioctl (fd, TIOCGWINSZ, (char *) win);
1338 return err;
1341 static void
1342 set_window_size (int rows, int cols, int fd, const char *device_name)
1344 struct winsize win;
1346 if (get_win_size (fd, &win))
1348 if (errno != EINVAL)
1349 error (1, errno, "%s", device_name);
1350 memset (&win, 0, sizeof (win));
1353 if (rows >= 0)
1354 win.ws_row = rows;
1355 if (cols >= 0)
1356 win.ws_col = cols;
1358 # ifdef TIOCSSIZE
1359 /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
1360 The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
1361 This comment from sys/ttold.h describes Sun's twisted logic - a better
1362 test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
1363 At any rate, the problem is gone in Solaris 2.x.
1365 Unfortunately, the old TIOCSSIZE code does collide with TIOCSWINSZ,
1366 but they can be disambiguated by checking whether a "struct ttysize"
1367 structure's "ts_lines" field is greater than 64K or not. If so,
1368 it's almost certainly a "struct winsize" instead.
1370 At any rate, the bug manifests itself when ws_row == 0; the symptom is
1371 that ws_row is set to ws_col, and ws_col is set to (ws_xpixel<<16) +
1372 ws_ypixel. Since GNU stty sets rows and columns separately, this bug
1373 caused "stty rows 0 cols 0" to set rows to cols and cols to 0, while
1374 "stty cols 0 rows 0" would do the right thing. On a little-endian
1375 machine like the sun386i, the problem is the same, but for ws_col == 0.
1377 The workaround is to do the ioctl once with row and col = 1 to set the
1378 pixel info, and then do it again using a TIOCSSIZE to set rows/cols. */
1380 if (win.ws_row == 0 || win.ws_col == 0)
1382 struct ttysize ttysz;
1384 ttysz.ts_lines = win.ws_row;
1385 ttysz.ts_cols = win.ws_col;
1387 win.ws_row = 1;
1388 win.ws_col = 1;
1390 if (ioctl (fd, TIOCSWINSZ, (char *) &win))
1391 error (1, errno, "%s", device_name);
1393 if (ioctl (fd, TIOCSSIZE, (char *) &ttysz))
1394 error (1, errno, "%s", device_name);
1395 return;
1397 # endif
1399 if (ioctl (fd, TIOCSWINSZ, (char *) &win))
1400 error (1, errno, "%s", device_name);
1403 static void
1404 display_window_size (int fancy, int fd, const char *device_name)
1406 struct winsize win;
1408 if (get_win_size (fd, &win))
1410 if (errno != EINVAL)
1411 error (1, errno, "%s", device_name);
1412 if (!fancy)
1413 error (1, 0, _("%s: no size information for this device"), device_name);
1415 else
1417 wrapf (fancy ? "rows %d; columns %d;" : "%d %d\n",
1418 win.ws_row, win.ws_col);
1419 if (!fancy)
1420 current_col = 0;
1423 #endif
1425 static int
1426 screen_columns (void)
1428 #ifdef TIOCGWINSZ
1429 struct winsize win;
1431 /* With Solaris 2.[123], this ioctl fails and errno is set to
1432 EINVAL for telnet (but not rlogin) sessions.
1433 On ISC 3.0, it fails for the console and the serial port
1434 (but it works for ptys).
1435 It can also fail on any system when stdout isn't a tty.
1436 In case of any failure, just use the default. */
1437 if (get_win_size (STDOUT_FILENO, &win) == 0 && win.ws_col > 0)
1438 return win.ws_col;
1439 #endif
1440 /* FIXME: use xstrtol */
1441 if (getenv ("COLUMNS"))
1442 return atoi (getenv ("COLUMNS"));
1443 return 80;
1446 static tcflag_t *
1447 mode_type_flag (enum mode_type type, struct termios *mode)
1449 switch (type)
1451 case control:
1452 return &mode->c_cflag;
1454 case input:
1455 return &mode->c_iflag;
1457 case output:
1458 return &mode->c_oflag;
1460 case local:
1461 return &mode->c_lflag;
1463 case combination:
1464 return NULL;
1466 default:
1467 abort ();
1471 static void
1472 display_settings (enum output_type output_type, struct termios *mode,
1473 int fd, const char *device_name)
1475 switch (output_type)
1477 case changed:
1478 display_changed (mode);
1479 break;
1481 case all:
1482 display_all (mode, fd, device_name);
1483 break;
1485 case recoverable:
1486 display_recoverable (mode);
1487 break;
1491 static void
1492 display_changed (struct termios *mode)
1494 int i;
1495 int empty_line;
1496 tcflag_t *bitsp;
1497 unsigned long mask;
1498 enum mode_type prev_type = control;
1500 display_speed (mode, 1);
1501 #ifdef HAVE_C_LINE
1502 wrapf ("line = %d;", mode->c_line);
1503 #endif
1504 putchar ('\n');
1505 current_col = 0;
1507 empty_line = 1;
1508 for (i = 0; !STREQ (control_info[i].name, "min"); ++i)
1510 if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
1511 continue;
1512 /* If swtch is the same as susp, don't print both. */
1513 #if VSWTCH == VSUSP
1514 if (STREQ (control_info[i].name, "swtch"))
1515 continue;
1516 #endif
1517 /* If eof uses the same slot as min, only print whichever applies. */
1518 #if VEOF == VMIN
1519 if ((mode->c_lflag & ICANON) == 0
1520 && (STREQ (control_info[i].name, "eof")
1521 || STREQ (control_info[i].name, "eol")))
1522 continue;
1523 #endif
1525 empty_line = 0;
1526 wrapf ("%s = %s;", control_info[i].name,
1527 visible (mode->c_cc[control_info[i].offset]));
1529 if ((mode->c_lflag & ICANON) == 0)
1531 wrapf ("min = %d; time = %d;\n", (int) mode->c_cc[VMIN],
1532 (int) mode->c_cc[VTIME]);
1534 else if (empty_line == 0)
1535 putchar ('\n');
1536 current_col = 0;
1538 empty_line = 1;
1539 for (i = 0; mode_info[i].name != NULL; ++i)
1541 if (mode_info[i].flags & OMIT)
1542 continue;
1543 if (mode_info[i].type != prev_type)
1545 if (empty_line == 0)
1547 putchar ('\n');
1548 current_col = 0;
1549 empty_line = 1;
1551 prev_type = mode_info[i].type;
1554 bitsp = mode_type_flag (mode_info[i].type, mode);
1555 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1556 if ((*bitsp & mask) == mode_info[i].bits)
1558 if (mode_info[i].flags & SANE_UNSET)
1560 wrapf ("%s", mode_info[i].name);
1561 empty_line = 0;
1564 else if ((mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
1566 wrapf ("-%s", mode_info[i].name);
1567 empty_line = 0;
1570 if (empty_line == 0)
1571 putchar ('\n');
1572 current_col = 0;
1575 static void
1576 display_all (struct termios *mode, int fd, const char *device_name)
1578 int i;
1579 tcflag_t *bitsp;
1580 unsigned long mask;
1581 enum mode_type prev_type = control;
1583 display_speed (mode, 1);
1584 #ifdef TIOCGWINSZ
1585 display_window_size (1, fd, device_name);
1586 #endif
1587 #ifdef HAVE_C_LINE
1588 wrapf ("line = %d;", mode->c_line);
1589 #endif
1590 putchar ('\n');
1591 current_col = 0;
1593 for (i = 0; ! STREQ (control_info[i].name, "min"); ++i)
1595 /* If swtch is the same as susp, don't print both. */
1596 #if VSWTCH == VSUSP
1597 if (STREQ (control_info[i].name, "swtch"))
1598 continue;
1599 #endif
1600 /* If eof uses the same slot as min, only print whichever applies. */
1601 #if VEOF == VMIN
1602 if ((mode->c_lflag & ICANON) == 0
1603 && (STREQ (control_info[i].name, "eof")
1604 || STREQ (control_info[i].name, "eol")))
1605 continue;
1606 #endif
1607 wrapf ("%s = %s;", control_info[i].name,
1608 visible (mode->c_cc[control_info[i].offset]));
1610 #if VEOF == VMIN
1611 if ((mode->c_lflag & ICANON) == 0)
1612 #endif
1613 wrapf ("min = %d; time = %d;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
1614 if (current_col != 0)
1615 putchar ('\n');
1616 current_col = 0;
1618 for (i = 0; mode_info[i].name != NULL; ++i)
1620 if (mode_info[i].flags & OMIT)
1621 continue;
1622 if (mode_info[i].type != prev_type)
1624 putchar ('\n');
1625 current_col = 0;
1626 prev_type = mode_info[i].type;
1629 bitsp = mode_type_flag (mode_info[i].type, mode);
1630 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1631 if ((*bitsp & mask) == mode_info[i].bits)
1632 wrapf ("%s", mode_info[i].name);
1633 else if (mode_info[i].flags & REV)
1634 wrapf ("-%s", mode_info[i].name);
1636 putchar ('\n');
1637 current_col = 0;
1640 static void
1641 display_speed (struct termios *mode, int fancy)
1643 if (cfgetispeed (mode) == 0 || cfgetispeed (mode) == cfgetospeed (mode))
1644 wrapf (fancy ? "speed %lu baud;" : "%lu\n",
1645 baud_to_value (cfgetospeed (mode)));
1646 else
1647 wrapf (fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n",
1648 baud_to_value (cfgetispeed (mode)),
1649 baud_to_value (cfgetospeed (mode)));
1650 if (!fancy)
1651 current_col = 0;
1654 static void
1655 display_recoverable (struct termios *mode)
1657 int i;
1659 printf ("%lx:%lx:%lx:%lx",
1660 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
1661 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
1662 for (i = 0; i < NCCS; ++i)
1663 printf (":%x", (unsigned int) mode->c_cc[i]);
1664 putchar ('\n');
1667 static int
1668 recover_mode (char *arg, struct termios *mode)
1670 int i, n;
1671 unsigned int chr;
1672 unsigned long iflag, oflag, cflag, lflag;
1674 /* Scan into temporaries since it is too much trouble to figure out
1675 the right format for `tcflag_t'. */
1676 if (sscanf (arg, "%lx:%lx:%lx:%lx%n",
1677 &iflag, &oflag, &cflag, &lflag, &n) != 4)
1678 return 0;
1679 mode->c_iflag = iflag;
1680 mode->c_oflag = oflag;
1681 mode->c_cflag = cflag;
1682 mode->c_lflag = lflag;
1683 arg += n;
1684 for (i = 0; i < NCCS; ++i)
1686 if (sscanf (arg, ":%x%n", &chr, &n) != 1)
1687 return 0;
1688 mode->c_cc[i] = chr;
1689 arg += n;
1692 /* Fail if there are too many fields. */
1693 if (*arg != '\0')
1694 return 0;
1696 return 1;
1699 struct speed_map
1701 const char *string; /* ASCII representation. */
1702 speed_t speed; /* Internal form. */
1703 unsigned long value; /* Numeric value. */
1706 struct speed_map speeds[] =
1708 {"0", B0, 0},
1709 {"50", B50, 50},
1710 {"75", B75, 75},
1711 {"110", B110, 110},
1712 {"134", B134, 134},
1713 {"134.5", B134, 134},
1714 {"150", B150, 150},
1715 {"200", B200, 200},
1716 {"300", B300, 300},
1717 {"600", B600, 600},
1718 {"1200", B1200, 1200},
1719 {"1800", B1800, 1800},
1720 {"2400", B2400, 2400},
1721 {"4800", B4800, 4800},
1722 {"9600", B9600, 9600},
1723 {"19200", B19200, 19200},
1724 {"38400", B38400, 38400},
1725 {"exta", B19200, 19200},
1726 {"extb", B38400, 38400},
1727 #ifdef B57600
1728 {"57600", B57600, 57600},
1729 #endif
1730 #ifdef B115200
1731 {"115200", B115200, 115200},
1732 #endif
1733 #ifdef B230400
1734 {"230400", B230400, 230400},
1735 #endif
1736 #ifdef B460800
1737 {"460800", B460800, 460800},
1738 #endif
1739 {NULL, 0, 0}
1742 static speed_t
1743 string_to_baud (const char *arg)
1745 int i;
1747 for (i = 0; speeds[i].string != NULL; ++i)
1748 if (STREQ (arg, speeds[i].string))
1749 return speeds[i].speed;
1750 return (speed_t) -1;
1753 static unsigned long
1754 baud_to_value (speed_t speed)
1756 int i;
1758 for (i = 0; speeds[i].string != NULL; ++i)
1759 if (speed == speeds[i].speed)
1760 return speeds[i].value;
1761 return 0;
1764 static void
1765 sane_mode (struct termios *mode)
1767 int i;
1768 tcflag_t *bitsp;
1770 for (i = 0; control_info[i].name; ++i)
1772 #if VMIN == VEOF
1773 if (STREQ (control_info[i].name, "min"))
1774 break;
1775 #endif
1776 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1779 for (i = 0; mode_info[i].name != NULL; ++i)
1781 if (mode_info[i].flags & SANE_SET)
1783 bitsp = mode_type_flag (mode_info[i].type, mode);
1784 *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits;
1786 else if (mode_info[i].flags & SANE_UNSET)
1788 bitsp = mode_type_flag (mode_info[i].type, mode);
1789 *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits;
1794 /* Return a string that is the printable representation of character CH. */
1795 /* Adapted from `cat' by Torbjorn Granlund. */
1797 static const char *
1798 visible (unsigned int ch)
1800 static char buf[10];
1801 char *bpout = buf;
1803 if (ch == _POSIX_VDISABLE)
1804 return _("<undef>");
1806 if (ch >= 32)
1808 if (ch < 127)
1809 *bpout++ = ch;
1810 else if (ch == 127)
1812 *bpout++ = '^';
1813 *bpout++ = '?';
1815 else
1817 *bpout++ = 'M',
1818 *bpout++ = '-';
1819 if (ch >= 128 + 32)
1821 if (ch < 128 + 127)
1822 *bpout++ = ch - 128;
1823 else
1825 *bpout++ = '^';
1826 *bpout++ = '?';
1829 else
1831 *bpout++ = '^';
1832 *bpout++ = ch - 128 + 64;
1836 else
1838 *bpout++ = '^';
1839 *bpout++ = ch + 64;
1841 *bpout = '\0';
1842 return (const char *) buf;
1845 /* Parse string S as an integer, using decimal radix by default,
1846 but allowing octal and hex numbers as in C. */
1847 /* From `od' by Richard Stallman. */
1849 static long
1850 integer_arg (const char *s)
1852 long value;
1853 if (xstrtol (s, NULL, 0, &value, "bB") != LONGINT_OK)
1855 error (0, 0, _("invalid integer argument `%s'"), s);
1856 usage (1);
1858 return value;