*** empty log message ***
[coreutils.git] / src / stty.c
blob3fe28c0e2faf750c89726727e63ee987d606f0e2
1 /* stty -- change and print terminal line settings
2 Copyright (C) 1990-2001 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"
67 #include "closeout.h"
69 /* The official name of this program (e.g., no `g' prefix). */
70 #define PROGRAM_NAME "stty"
72 #define AUTHORS "David MacKenzie"
74 #ifndef _POSIX_VDISABLE
75 # define _POSIX_VDISABLE ((unsigned char) 0)
76 #endif
78 #define Control(c) ((c) & 0x1f)
79 /* Canonical values for control characters. */
80 #ifndef CINTR
81 # define CINTR Control ('c')
82 #endif
83 #ifndef CQUIT
84 # define CQUIT 28
85 #endif
86 #ifndef CERASE
87 # define CERASE 127
88 #endif
89 #ifndef CKILL
90 # define CKILL Control ('u')
91 #endif
92 #ifndef CEOF
93 # define CEOF Control ('d')
94 #endif
95 #ifndef CEOL
96 # define CEOL _POSIX_VDISABLE
97 #endif
98 #ifndef CSTART
99 # define CSTART Control ('q')
100 #endif
101 #ifndef CSTOP
102 # define CSTOP Control ('s')
103 #endif
104 #ifndef CSUSP
105 # define CSUSP Control ('z')
106 #endif
107 #if defined(VEOL2) && !defined(CEOL2)
108 # define CEOL2 _POSIX_VDISABLE
109 #endif
110 /* ISC renamed swtch to susp for termios, but we'll accept either name. */
111 #if defined(VSUSP) && !defined(VSWTCH)
112 # define VSWTCH VSUSP
113 # define CSWTCH CSUSP
114 #endif
115 #if defined(VSWTCH) && !defined(CSWTCH)
116 # define CSWTCH _POSIX_VDISABLE
117 #endif
119 /* SunOS 5.3 loses (^Z doesn't work) if `swtch' is the same as `susp'.
120 So the default is to disable `swtch.' */
121 #if defined (__sparc__) && defined (__svr4__)
122 # undef CSWTCH
123 # define CSWTCH _POSIX_VDISABLE
124 #endif
126 #if defined(VWERSE) && !defined (VWERASE) /* AIX-3.2.5 */
127 # define VWERASE VWERSE
128 #endif
129 #if defined(VDSUSP) && !defined (CDSUSP)
130 # define CDSUSP Control ('y')
131 #endif
132 #if !defined(VREPRINT) && defined(VRPRNT) /* Irix 4.0.5 */
133 # define VREPRINT VRPRNT
134 #endif
135 #if defined(VREPRINT) && !defined(CRPRNT)
136 # define CRPRNT Control ('r')
137 #endif
138 #if defined(CREPRINT) && !defined(CRPRNT)
139 # define CRPRNT Control ('r')
140 #endif
141 #if defined(VWERASE) && !defined(CWERASE)
142 # define CWERASE Control ('w')
143 #endif
144 #if defined(VLNEXT) && !defined(CLNEXT)
145 # define CLNEXT Control ('v')
146 #endif
147 #if defined(VDISCARD) && !defined(VFLUSHO)
148 # define VFLUSHO VDISCARD
149 #endif
150 #if defined(VFLUSH) && !defined(VFLUSHO) /* Ultrix 4.2 */
151 # define VFLUSHO VFLUSH
152 #endif
153 #if defined(CTLECH) && !defined(ECHOCTL) /* Ultrix 4.3 */
154 # define ECHOCTL CTLECH
155 #endif
156 #if defined(TCTLECH) && !defined(ECHOCTL) /* Ultrix 4.2 */
157 # define ECHOCTL TCTLECH
158 #endif
159 #if defined(CRTKIL) && !defined(ECHOKE) /* Ultrix 4.2 and 4.3 */
160 # define ECHOKE CRTKIL
161 #endif
162 #if defined(VFLUSHO) && !defined(CFLUSHO)
163 # define CFLUSHO Control ('o')
164 #endif
165 #if defined(VSTATUS) && !defined(CSTATUS)
166 # define CSTATUS Control ('t')
167 #endif
169 /* Which speeds to set. */
170 enum speed_setting
172 input_speed, output_speed, both_speeds
175 /* What to output and how. */
176 enum output_type
178 changed, all, recoverable /* Default, -a, -g. */
181 /* Which member(s) of `struct termios' a mode uses. */
182 enum mode_type
184 control, input, output, local, combination
187 /* Flags for `struct mode_info'. */
188 #define SANE_SET 1 /* Set in `sane' mode. */
189 #define SANE_UNSET 2 /* Unset in `sane' mode. */
190 #define REV 4 /* Can be turned off by prepending `-'. */
191 #define OMIT 8 /* Don't display value. */
193 /* Each mode. */
194 struct mode_info
196 const char *name; /* Name given on command line. */
197 enum mode_type type; /* Which structure element to change. */
198 char flags; /* Setting and display options. */
199 unsigned long bits; /* Bits to set for this mode. */
200 unsigned long mask; /* Other bits to turn off for this mode. */
203 static struct mode_info mode_info[] =
205 {"parenb", control, REV, PARENB, 0},
206 {"parodd", control, REV, PARODD, 0},
207 {"cs5", control, 0, CS5, CSIZE},
208 {"cs6", control, 0, CS6, CSIZE},
209 {"cs7", control, 0, CS7, CSIZE},
210 {"cs8", control, 0, CS8, CSIZE},
211 {"hupcl", control, REV, HUPCL, 0},
212 {"hup", control, REV | OMIT, HUPCL, 0},
213 {"cstopb", control, REV, CSTOPB, 0},
214 {"cread", control, SANE_SET | REV, CREAD, 0},
215 {"clocal", control, REV, CLOCAL, 0},
216 #ifdef CRTSCTS
217 {"crtscts", control, REV, CRTSCTS, 0},
218 #endif
220 {"ignbrk", input, SANE_UNSET | REV, IGNBRK, 0},
221 {"brkint", input, SANE_SET | REV, BRKINT, 0},
222 {"ignpar", input, REV, IGNPAR, 0},
223 {"parmrk", input, REV, PARMRK, 0},
224 {"inpck", input, REV, INPCK, 0},
225 {"istrip", input, REV, ISTRIP, 0},
226 {"inlcr", input, SANE_UNSET | REV, INLCR, 0},
227 {"igncr", input, SANE_UNSET | REV, IGNCR, 0},
228 {"icrnl", input, SANE_SET | REV, ICRNL, 0},
229 {"ixon", input, REV, IXON, 0},
230 {"ixoff", input, SANE_UNSET | REV, IXOFF, 0},
231 {"tandem", input, REV | OMIT, IXOFF, 0},
232 #ifdef IUCLC
233 {"iuclc", input, SANE_UNSET | REV, IUCLC, 0},
234 #endif
235 #ifdef IXANY
236 {"ixany", input, SANE_UNSET | REV, IXANY, 0},
237 #endif
238 #ifdef IMAXBEL
239 {"imaxbel", input, SANE_SET | REV, IMAXBEL, 0},
240 #endif
242 {"opost", output, SANE_SET | REV, OPOST, 0},
243 #ifdef OLCUC
244 {"olcuc", output, SANE_UNSET | REV, OLCUC, 0},
245 #endif
246 #ifdef OCRNL
247 {"ocrnl", output, SANE_UNSET | REV, OCRNL, 0},
248 #endif
249 #ifdef ONLCR
250 {"onlcr", output, SANE_SET | REV, ONLCR, 0},
251 #endif
252 #ifdef ONOCR
253 {"onocr", output, SANE_UNSET | REV, ONOCR, 0},
254 #endif
255 #ifdef ONLRET
256 {"onlret", output, SANE_UNSET | REV, ONLRET, 0},
257 #endif
258 #ifdef OFILL
259 {"ofill", output, SANE_UNSET | REV, OFILL, 0},
260 #endif
261 #ifdef OFDEL
262 {"ofdel", output, SANE_UNSET | REV, OFDEL, 0},
263 #endif
264 #ifdef NLDLY
265 {"nl1", output, SANE_UNSET, NL1, NLDLY},
266 {"nl0", output, SANE_SET, NL0, NLDLY},
267 #endif
268 #ifdef CRDLY
269 {"cr3", output, SANE_UNSET, CR3, CRDLY},
270 {"cr2", output, SANE_UNSET, CR2, CRDLY},
271 {"cr1", output, SANE_UNSET, CR1, CRDLY},
272 {"cr0", output, SANE_SET, CR0, CRDLY},
273 #endif
274 #ifdef TABDLY
275 {"tab3", output, SANE_UNSET, TAB3, TABDLY},
276 {"tab2", output, SANE_UNSET, TAB2, TABDLY},
277 {"tab1", output, SANE_UNSET, TAB1, TABDLY},
278 {"tab0", output, SANE_SET, TAB0, TABDLY},
279 #else
280 # ifdef OXTABS
281 {"tab3", output, SANE_UNSET, OXTABS, 0},
282 # endif
283 #endif
284 #ifdef BSDLY
285 {"bs1", output, SANE_UNSET, BS1, BSDLY},
286 {"bs0", output, SANE_SET, BS0, BSDLY},
287 #endif
288 #ifdef VTDLY
289 {"vt1", output, SANE_UNSET, VT1, VTDLY},
290 {"vt0", output, SANE_SET, VT0, VTDLY},
291 #endif
292 #ifdef FFDLY
293 {"ff1", output, SANE_UNSET, FF1, FFDLY},
294 {"ff0", output, SANE_SET, FF0, FFDLY},
295 #endif
297 {"isig", local, SANE_SET | REV, ISIG, 0},
298 {"icanon", local, SANE_SET | REV, ICANON, 0},
299 #ifdef IEXTEN
300 {"iexten", local, SANE_SET | REV, IEXTEN, 0},
301 #endif
302 {"echo", local, SANE_SET | REV, ECHO, 0},
303 {"echoe", local, SANE_SET | REV, ECHOE, 0},
304 {"crterase", local, REV | OMIT, ECHOE, 0},
305 {"echok", local, SANE_SET | REV, ECHOK, 0},
306 {"echonl", local, SANE_UNSET | REV, ECHONL, 0},
307 {"noflsh", local, SANE_UNSET | REV, NOFLSH, 0},
308 #ifdef XCASE
309 {"xcase", local, SANE_UNSET | REV, XCASE, 0},
310 #endif
311 #ifdef TOSTOP
312 {"tostop", local, SANE_UNSET | REV, TOSTOP, 0},
313 #endif
314 #ifdef ECHOPRT
315 {"echoprt", local, SANE_UNSET | REV, ECHOPRT, 0},
316 {"prterase", local, REV | OMIT, ECHOPRT, 0},
317 #endif
318 #ifdef ECHOCTL
319 {"echoctl", local, SANE_SET | REV, ECHOCTL, 0},
320 {"ctlecho", local, REV | OMIT, ECHOCTL, 0},
321 #endif
322 #ifdef ECHOKE
323 {"echoke", local, SANE_SET | REV, ECHOKE, 0},
324 {"crtkill", local, REV | OMIT, ECHOKE, 0},
325 #endif
327 {"evenp", combination, REV | OMIT, 0, 0},
328 {"parity", combination, REV | OMIT, 0, 0},
329 {"oddp", combination, REV | OMIT, 0, 0},
330 {"nl", combination, REV | OMIT, 0, 0},
331 {"ek", combination, OMIT, 0, 0},
332 {"sane", combination, OMIT, 0, 0},
333 {"cooked", combination, REV | OMIT, 0, 0},
334 {"raw", combination, REV | OMIT, 0, 0},
335 {"pass8", combination, REV | OMIT, 0, 0},
336 {"litout", combination, REV | OMIT, 0, 0},
337 {"cbreak", combination, REV | OMIT, 0, 0},
338 #ifdef IXANY
339 {"decctlq", combination, REV | OMIT, 0, 0},
340 #endif
341 #if defined (TABDLY) || defined (OXTABS)
342 {"tabs", combination, REV | OMIT, 0, 0},
343 #endif
344 #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
345 {"lcase", combination, REV | OMIT, 0, 0},
346 {"LCASE", combination, REV | OMIT, 0, 0},
347 #endif
348 {"crt", combination, OMIT, 0, 0},
349 {"dec", combination, OMIT, 0, 0},
351 {NULL, control, 0, 0, 0}
354 /* Control character settings. */
355 struct control_info
357 const char *name; /* Name given on command line. */
358 unsigned char saneval; /* Value to set for `stty sane'. */
359 int offset; /* Offset in c_cc. */
362 /* Control characters. */
364 static struct control_info control_info[] =
366 {"intr", CINTR, VINTR},
367 {"quit", CQUIT, VQUIT},
368 {"erase", CERASE, VERASE},
369 {"kill", CKILL, VKILL},
370 {"eof", CEOF, VEOF},
371 {"eol", CEOL, VEOL},
372 #ifdef VEOL2
373 {"eol2", CEOL2, VEOL2},
374 #endif
375 #ifdef VSWTCH
376 {"swtch", CSWTCH, VSWTCH},
377 #endif
378 {"start", CSTART, VSTART},
379 {"stop", CSTOP, VSTOP},
380 {"susp", CSUSP, VSUSP},
381 #ifdef VDSUSP
382 {"dsusp", CDSUSP, VDSUSP},
383 #endif
384 #ifdef VREPRINT
385 {"rprnt", CRPRNT, VREPRINT},
386 #else
387 # ifdef CREPRINT /* HPUX 10.20 needs this */
388 {"rprnt", CRPRNT, CREPRINT},
389 # endif
390 #endif
391 #ifdef VWERASE
392 {"werase", CWERASE, VWERASE},
393 #endif
394 #ifdef VLNEXT
395 {"lnext", CLNEXT, VLNEXT},
396 #endif
397 #ifdef VFLUSHO
398 {"flush", CFLUSHO, VFLUSHO},
399 #endif
400 #ifdef VSTATUS
401 {"status", CSTATUS, VSTATUS},
402 #endif
404 /* These must be last because of the display routines. */
405 {"min", 1, VMIN},
406 {"time", 0, VTIME},
407 {NULL, 0, 0}
410 static const char *visible PARAMS ((unsigned int ch));
411 static unsigned long baud_to_value PARAMS ((speed_t speed));
412 static int recover_mode PARAMS ((char *arg, struct termios *mode));
413 static int screen_columns PARAMS ((void));
414 static int set_mode PARAMS ((struct mode_info *info, int reversed,
415 struct termios *mode));
416 static long integer_arg PARAMS ((const char *s));
417 static speed_t string_to_baud PARAMS ((const char *arg));
418 static tcflag_t *mode_type_flag PARAMS ((enum mode_type type,
419 struct termios *mode));
420 static void display_all PARAMS ((struct termios *mode, int fd,
421 const char *device_name));
422 static void display_changed PARAMS ((struct termios *mode));
423 static void display_recoverable PARAMS ((struct termios *mode));
424 static void display_settings PARAMS ((enum output_type output_type,
425 struct termios *mode, int fd,
426 const char *device_name));
427 static void display_speed PARAMS ((struct termios *mode, int fancy));
428 static void display_window_size PARAMS ((int fancy, int fd,
429 const char *device_name));
430 static void sane_mode PARAMS ((struct termios *mode));
431 static void set_control_char PARAMS ((struct control_info *info,
432 const char *arg,
433 struct termios *mode));
434 static void set_speed PARAMS ((enum speed_setting type, const char *arg,
435 struct termios *mode));
436 static void set_window_size PARAMS ((int rows, int cols, int fd,
437 const char *device_name));
439 /* The width of the screen, for output wrapping. */
440 static int max_col;
442 /* Current position, to know when to wrap. */
443 static int current_col;
445 static struct option longopts[] =
447 {"all", no_argument, NULL, 'a'},
448 {"save", no_argument, NULL, 'g'},
449 {"file", required_argument, NULL, 'F'},
450 {NULL, 0, NULL, 0}
453 /* The name this program was run with. */
454 char *program_name;
456 /* Print format string MESSAGE and optional args.
457 Wrap to next line first if it won't fit.
458 Print a space first unless MESSAGE will start a new line. */
460 /* VARARGS */
461 static void
462 #if PROTOTYPES
463 wrapf (const char *message,...)
464 #else
465 wrapf (message, va_alist)
466 const char *message;
467 va_dcl
468 #endif
470 va_list args;
471 char buf[1024]; /* Plenty long for our needs. */
472 int buflen;
474 VA_START (args, message);
475 vsprintf (buf, message, args);
476 va_end (args);
477 buflen = strlen (buf);
478 if (0 < current_col
479 && max_col <= current_col + (0 < current_col) + buflen)
481 putchar ('\n');
482 current_col = 0;
484 if (0 < current_col)
486 putchar (' ');
487 current_col++;
489 fputs (buf, stdout);
490 current_col += buflen;
493 void
494 usage (int status)
496 if (status != 0)
497 fprintf (stderr, _("Try `%s --help' for more information.\n"),
498 program_name);
499 else
501 printf (_("\
502 Usage: %s [-F DEVICE] [--file=DEVICE] [SETTING]...\n\
503 or: %s [-F DEVICE] [--file=DEVICE] [-a|--all]\n\
504 or: %s [-F DEVICE] [--file=DEVICE] [-g|--save]\n\
506 program_name, program_name, program_name);
507 fputs (_("\
508 Print or change terminal characteristics.\n\
510 -a, --all print all current settings in human-readable form\n\
511 -g, --save print all current settings in a stty-readable form\n\
512 -F, --file=DEVICE open and use the specified DEVICE instead of stdin\n\
513 "), stdout);
514 fputs (HELP_OPTION_DESCRIPTION, stdout);
515 fputs (VERSION_OPTION_DESCRIPTION, stdout);
516 fputs (_("\
518 Optional - before SETTING indicates negation. An * marks non-POSIX\n\
519 settings. The underlying system defines which settings are available.\n\
520 "), stdout);
521 fputs (_("\
523 Special characters:\n\
524 * dsusp CHAR CHAR will send a terminal stop signal once input flushed\n\
525 eof CHAR CHAR will send an end of file (terminate the input)\n\
526 eol CHAR CHAR will end the line\n\
527 "), stdout);
528 fputs (_("\
529 * eol2 CHAR alternate CHAR for ending the line\n\
530 erase CHAR CHAR will erase the last character typed\n\
531 intr CHAR CHAR will send an interrupt signal\n\
532 kill CHAR CHAR will erase the current line\n\
533 "), stdout);
534 fputs (_("\
535 * lnext CHAR CHAR will enter the next character quoted\n\
536 quit CHAR CHAR will send a quit signal\n\
537 * rprnt CHAR CHAR will redraw the current line\n\
538 start CHAR CHAR will restart the output after stopping it\n\
539 "), stdout);
540 fputs (_("\
541 stop CHAR CHAR will stop the output\n\
542 susp CHAR CHAR will send a terminal stop signal\n\
543 * swtch CHAR CHAR will switch to a different shell layer\n\
544 * werase CHAR CHAR will erase the last word typed\n\
545 "), stdout);
546 fputs (_("\
548 Special settings:\n\
549 N set the input and output speeds to N bauds\n\
550 * cols N tell the kernel that the terminal has N columns\n\
551 * columns N same as cols N\n\
552 "), stdout);
553 fputs (_("\
554 ispeed N set the input speed to N\n\
555 * line N use line discipline N\n\
556 min N with -icanon, set N characters minimum for a completed read\n\
557 ospeed N set the output speed to N\n\
558 "), stdout);
559 fputs (_("\
560 * rows N tell the kernel that the terminal has N rows\n\
561 * size print the number of rows and columns according to the kernel\n\
562 speed print the terminal speed\n\
563 time N with -icanon, set read timeout of N tenths of a second\n\
564 "), stdout);
565 fputs (_("\
567 Control settings:\n\
568 [-]clocal disable modem control signals\n\
569 [-]cread allow input to be received\n\
570 * [-]crtscts enable RTS/CTS handshaking\n\
571 csN set character size to N bits, N in [5..8]\n\
572 "), stdout);
573 fputs (_("\
574 [-]cstopb use two stop bits per character (one with `-')\n\
575 [-]hup send a hangup signal when the last process closes the tty\n\
576 [-]hupcl same as [-]hup\n\
577 [-]parenb generate parity bit in output and expect parity bit in input\n\
578 [-]parodd set odd parity (even with `-')\n\
579 "), stdout);
580 fputs (_("\
582 Input settings:\n\
583 [-]brkint breaks cause an interrupt signal\n\
584 [-]icrnl translate carriage return to newline\n\
585 [-]ignbrk ignore break characters\n\
586 [-]igncr ignore carriage return\n\
587 "), stdout);
588 fputs (_("\
589 [-]ignpar ignore characters with parity errors\n\
590 * [-]imaxbel beep and do not flush a full input buffer on a character\n\
591 [-]inlcr translate newline to carriage return\n\
592 [-]inpck enable input parity checking\n\
593 [-]istrip clear high (8th) bit of input characters\n\
594 "), stdout);
595 fputs (_("\
596 * [-]iuclc translate uppercase characters to lowercase\n\
597 * [-]ixany let any character restart output, not only start character\n\
598 [-]ixoff enable sending of start/stop characters\n\
599 [-]ixon enable XON/XOFF flow control\n\
600 [-]parmrk mark parity errors (with a 255-0-character sequence)\n\
601 [-]tandem same as [-]ixoff\n\
602 "), stdout);
603 fputs (_("\
605 Output settings:\n\
606 * bsN backspace delay style, N in [0..1]\n\
607 * crN carriage return delay style, N in [0..3]\n\
608 * ffN form feed delay style, N in [0..1]\n\
609 * nlN newline delay style, N in [0..1]\n\
610 "), stdout);
611 fputs (_("\
612 * [-]ocrnl translate carriage return to newline\n\
613 * [-]ofdel use delete characters for fill instead of null characters\n\
614 * [-]ofill use fill (padding) characters instead of timing for delays\n\
615 * [-]olcuc translate lowercase characters to uppercase\n\
616 * [-]onlcr translate newline to carriage return-newline\n\
617 * [-]onlret newline performs a carriage return\n\
618 "), stdout);
619 fputs (_("\
620 * [-]onocr do not print carriage returns in the first column\n\
621 [-]opost postprocess output\n\
622 * tabN horizontal tab delay style, N in [0..3]\n\
623 * tabs same as tab0\n\
624 * -tabs same as tab3\n\
625 * vtN vertical tab delay style, N in [0..1]\n\
626 "), stdout);
627 fputs (_("\
629 Local settings:\n\
630 [-]crterase echo erase characters as backspace-space-backspace\n\
631 * crtkill kill all line by obeying the echoprt and echoe settings\n\
632 * -crtkill kill all line by obeying the echoctl and echok settings\n\
633 "), stdout);
634 fputs (_("\
635 * [-]ctlecho echo control characters in hat notation (`^c')\n\
636 [-]echo echo input characters\n\
637 * [-]echoctl same as [-]ctlecho\n\
638 [-]echoe same as [-]crterase\n\
639 [-]echok echo a newline after a kill character\n\
640 "), stdout);
641 fputs (_("\
642 * [-]echoke same as [-]crtkill\n\
643 [-]echonl echo newline even if not echoing other characters\n\
644 * [-]echoprt echo erased characters backward, between `\\' and '/'\n\
645 [-]icanon enable erase, kill, werase, and rprnt special characters\n\
646 [-]iexten enable non-POSIX special characters\n\
647 "), stdout);
648 fputs (_("\
649 [-]isig enable interrupt, quit, and suspend special characters\n\
650 [-]noflsh disable flushing after interrupt and quit special characters\n\
651 * [-]prterase same as [-]echoprt\n\
652 * [-]tostop stop background jobs that try to write to the terminal\n\
653 * [-]xcase with icanon, escape with `\\' for uppercase characters\n\
654 "), stdout);
655 fputs (_("\
657 Combination settings:\n\
658 * [-]LCASE same as [-]lcase\n\
659 cbreak same as -icanon\n\
660 -cbreak same as icanon\n\
661 "), stdout);
662 fputs (_("\
663 cooked same as brkint ignpar istrip icrnl ixon opost isig\n\
664 icanon, eof and eol characters to their default values\n\
665 -cooked same as raw\n\
666 crt same as echoe echoctl echoke\n\
667 "), stdout);
668 fputs (_("\
669 dec same as echoe echoctl echoke -ixany intr ^c erase 0177\n\
670 kill ^u\n\
671 * [-]decctlq same as [-]ixany\n\
672 ek erase and kill characters to their default values\n\
673 evenp same as parenb -parodd cs7\n\
674 "), stdout);
675 fputs (_("\
676 -evenp same as -parenb cs8\n\
677 * [-]lcase same as xcase iuclc olcuc\n\
678 litout same as -parenb -istrip -opost cs8\n\
679 -litout same as parenb istrip opost cs7\n\
680 nl same as -icrnl -onlcr\n\
681 -nl same as icrnl -inlcr -igncr onlcr -ocrnl -onlret\n\
682 "), stdout);
683 fputs (_("\
684 oddp same as parenb parodd cs7\n\
685 -oddp same as -parenb cs8\n\
686 [-]parity same as [-]evenp\n\
687 pass8 same as -parenb -istrip cs8\n\
688 -pass8 same as parenb istrip cs7\n\
689 "), stdout);
690 fputs (_("\
691 raw same as -ignbrk -brkint -ignpar -parmrk -inpck -istrip\n\
692 -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany\n\
693 -imaxbel -opost -isig -icanon -xcase min 1 time 0\n\
694 -raw same as cooked\n\
695 "), stdout);
696 fputs (_("\
697 sane same as cread -ignbrk brkint -inlcr -igncr icrnl\n\
698 -ixoff -iuclc -ixany imaxbel opost -olcuc -ocrnl onlcr\n\
699 -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0\n\
700 isig icanon iexten echo echoe echok -echonl -noflsh\n\
701 -xcase -tostop -echoprt echoctl echoke, all special\n\
702 characters to their default values.\n\
703 "), stdout);
704 fputs (_("\
706 Handle the tty line connected to standard input. Without arguments,\n\
707 prints baud rate, line discipline, and deviations from stty sane. In\n\
708 settings, CHAR is taken literally, or coded as in ^c, 0x37, 0177 or\n\
709 127; special values ^- or undef used to disable special characters.\n\
710 "), stdout);
711 printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
713 exit (status);
716 /* Return 1 if the string contains only valid options. */
718 valid_options (char *opt, const char *valid_opts,
719 const char *valid_arg_opts)
721 char ch;
723 if (*opt++ != '-' || *opt == 0)
724 return 0;
726 while ((ch = *opt))
728 opt++;
729 if (strchr (valid_opts, ch))
730 continue;
731 if (strchr (valid_arg_opts, ch))
732 return 1;
733 return 0;
735 return 1;
739 main (int argc, char **argv)
741 struct termios mode;
742 enum output_type output_type;
743 int optc;
744 int require_set_attr;
745 int speed_was_set;
746 int verbose_output;
747 int recoverable_output;
748 int k;
749 int noargs = 1;
750 char *file_name = NULL;
751 int fd;
752 const char *device_name;
753 const char *posixly_correct = getenv ("POSIXLY_CORRECT");
754 int invalid_long_option = 0;
756 program_name = argv[0];
757 setlocale (LC_ALL, "");
758 bindtextdomain (PACKAGE, LOCALEDIR);
759 textdomain (PACKAGE);
761 atexit (close_stdout);
763 parse_long_options (argc, argv, PROGRAM_NAME, GNU_PACKAGE, VERSION,
764 AUTHORS, usage);
766 output_type = changed;
767 verbose_output = 0;
768 recoverable_output = 0;
770 /* Don't print error messages for unrecognized options. */
771 opterr = 0;
773 while ((optc = getopt_long (argc, argv, "agF:", longopts, NULL)) != -1)
775 int unrecognized_option = 0;
776 switch (optc)
778 case 'a':
779 verbose_output = 1;
780 output_type = all;
781 break;
783 case 'g':
784 recoverable_output = 1;
785 output_type = recoverable;
786 break;
788 case 'F':
789 if (file_name)
790 error (2, 0, _("only one device may be specified"));
791 file_name = optarg;
792 break;
794 default:
795 unrecognized_option = 1;
796 break;
799 if (unrecognized_option)
800 break;
803 /* FIXME: what is this?!? */
804 if (invalid_long_option)
805 usage (1);
807 /* Clear out the options that have been parsed. This is really
808 gross, but it's needed because stty SETTINGS look like options to
809 getopt(), so we need to work around things in a really horrible
810 way. If any new options are ever added to stty, the short option
811 MUST NOT be a letter which is the first letter of one of the
812 possible stty settings. If you change anything about how stty
813 parses options, be sure it still works with combinations of
814 short and long options, --, POSIXLY_CORRECT, etc. */
815 for (k = 1; k < argc; k++)
817 size_t len;
818 char *eq;
820 if (argv[k] == NULL)
821 continue;
823 /* Handle --, and reset noargs if there are arguments following it. */
824 if (STREQ (argv[k], "--"))
826 argv[k] = NULL;
827 if (k < argc - 1)
828 noargs = 0;
829 break;
832 /* Handle "--file device" */
833 len = strlen (argv[k]);
834 if (len >= 3 && strstr ("--file", argv[k]))
836 argv[k] = NULL;
837 argv[k + 1] = NULL;
838 continue;
841 /* Handle "--all" and "--save". */
842 if (len >= 3
843 && (strstr ("--all", argv[k])
844 || strstr ("--save", argv[k])))
846 argv[k] = NULL;
847 continue;
850 /* Handle "--file=device". */
851 eq = strchr (argv[k], '=');
852 if (eq && eq - argv[k] >= 3)
854 *eq = '\0';
855 if (strstr ("--file", argv[k]))
857 argv[k] = NULL;
858 continue;
860 /* Put the equals sign back for the error message. */
861 *eq = '=';
864 /* Handle "-a", "-ag", "-aF/dev/foo", "-aF /dev/foo", etc. */
865 if (valid_options (argv[k], "ag", "F"))
867 /* FIXME: this loses when the device name ends in `F'.
868 e.g. `stty -F/dev/BARF nl' would clobber the `nl' argument. */
869 if (argv[k][strlen (argv[k]) - 1] == 'F')
870 argv[k + 1] = NULL;
871 argv[k] = NULL;
873 /* Everything else must be a normal, non-option argument. */
874 else
876 noargs = 0;
877 if (posixly_correct)
878 break;
882 /* Specifying both -a and -g gets an error. */
883 if (verbose_output && recoverable_output)
884 error (2, 0,
885 _("the options for verbose and stty-readable output styles are\n\
886 mutually exclusive"));
888 /* Specifying any other arguments with -a or -g gets an error. */
889 if (!noargs && (verbose_output || recoverable_output))
890 error (2, 0, _("when specifying an output style, modes may not be set"));
892 /* FIXME: it'd be better not to open the file until we've verified
893 that all arguments are valid. Otherwise, we could end up doing
894 only some of the requested operations and then failing, probably
895 leaving things in an undesirable state. */
897 if (file_name)
899 int fdflags;
900 device_name = file_name;
901 fd = open (device_name, O_RDONLY | O_NONBLOCK);
902 if (fd < 0)
903 error (1, errno, "%s", device_name);
904 if ((fdflags = fcntl (fd, F_GETFL)) == -1
905 || fcntl (fd, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
906 error (1, errno, _("%s: couldn't reset non-blocking mode"),
907 device_name);
909 else
911 fd = 0;
912 device_name = _("standard input");
915 /* Initialize to all zeroes so there is no risk memcmp will report a
916 spurious difference in an uninitialized portion of the structure. */
917 memset (&mode, 0, sizeof (mode));
918 if (tcgetattr (fd, &mode))
919 error (1, errno, "%s", device_name);
921 if (verbose_output || recoverable_output || noargs)
923 max_col = screen_columns ();
924 current_col = 0;
925 display_settings (output_type, &mode, fd, device_name);
926 exit (0);
929 speed_was_set = 0;
930 require_set_attr = 0;
931 k = 1;
932 while (k < argc)
934 int match_found = 0;
935 int reversed = 0;
936 int i;
938 if (argv[k] == 0)
940 k++;
941 continue;
944 if (argv[k][0] == '-')
946 ++argv[k];
947 reversed = 1;
949 for (i = 0; mode_info[i].name != NULL; ++i)
951 if (STREQ (argv[k], mode_info[i].name))
953 match_found = set_mode (&mode_info[i], reversed, &mode);
954 require_set_attr = 1;
955 break;
958 if (match_found == 0 && reversed)
960 error (0, 0, _("invalid argument `%s'"), --argv[k]);
961 usage (1);
963 if (match_found == 0)
965 for (i = 0; control_info[i].name != NULL; ++i)
967 if (STREQ (argv[k], control_info[i].name))
969 if (k == argc - 1)
971 error (0, 0, _("missing argument to `%s'"), argv[k]);
972 usage (1);
974 match_found = 1;
975 ++k;
976 set_control_char (&control_info[i], argv[k], &mode);
977 require_set_attr = 1;
978 break;
982 if (match_found == 0)
984 if (STREQ (argv[k], "ispeed"))
986 if (k == argc - 1)
988 error (0, 0, _("missing argument to `%s'"), argv[k]);
989 usage (1);
991 ++k;
992 set_speed (input_speed, argv[k], &mode);
993 speed_was_set = 1;
994 require_set_attr = 1;
996 else if (STREQ (argv[k], "ospeed"))
998 if (k == argc - 1)
1000 error (0, 0, _("missing argument to `%s'"), argv[k]);
1001 usage (1);
1003 ++k;
1004 set_speed (output_speed, argv[k], &mode);
1005 speed_was_set = 1;
1006 require_set_attr = 1;
1008 #ifdef TIOCGWINSZ
1009 else if (STREQ (argv[k], "rows"))
1011 if (k == argc - 1)
1013 error (0, 0, _("missing argument to `%s'"), argv[k]);
1014 usage (1);
1016 ++k;
1017 set_window_size ((int) integer_arg (argv[k]), -1,
1018 fd, device_name);
1020 else if (STREQ (argv[k], "cols")
1021 || STREQ (argv[k], "columns"))
1023 if (k == argc - 1)
1025 error (0, 0, _("missing argument to `%s'"), argv[k]);
1026 usage (1);
1028 ++k;
1029 set_window_size (-1, (int) integer_arg (argv[k]),
1030 fd, device_name);
1032 else if (STREQ (argv[k], "size"))
1034 max_col = screen_columns ();
1035 current_col = 0;
1036 display_window_size (0, fd, device_name);
1038 #endif
1039 #ifdef HAVE_C_LINE
1040 else if (STREQ (argv[k], "line"))
1042 if (k == argc - 1)
1044 error (0, 0, _("missing argument to `%s'"), argv[k]);
1045 usage (1);
1047 ++k;
1048 mode.c_line = integer_arg (argv[k]);
1049 require_set_attr = 1;
1051 #endif
1052 else if (STREQ (argv[k], "speed"))
1054 max_col = screen_columns ();
1055 display_speed (&mode, 0);
1057 else if (string_to_baud (argv[k]) != (speed_t) -1)
1059 set_speed (both_speeds, argv[k], &mode);
1060 speed_was_set = 1;
1061 require_set_attr = 1;
1063 else
1065 if (recover_mode (argv[k], &mode) == 0)
1067 error (0, 0, _("invalid argument `%s'"), argv[k]);
1068 usage (1);
1070 require_set_attr = 1;
1073 k++;
1076 if (require_set_attr)
1078 struct termios new_mode;
1080 if (tcsetattr (fd, TCSADRAIN, &mode))
1081 error (1, errno, "%s", device_name);
1083 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
1084 it performs *any* of the requested operations. This means it
1085 can report `success' when it has actually failed to perform
1086 some proper subset of the requested operations. To detect
1087 this partial failure, get the current terminal attributes and
1088 compare them to the requested ones. */
1090 /* Initialize to all zeroes so there is no risk memcmp will report a
1091 spurious difference in an uninitialized portion of the structure. */
1092 memset (&new_mode, 0, sizeof (new_mode));
1093 if (tcgetattr (fd, &new_mode))
1094 error (1, errno, "%s", device_name);
1096 /* Normally, one shouldn't use memcmp to compare structures that
1097 may have `holes' containing uninitialized data, but we have been
1098 careful to initialize the storage of these two variables to all
1099 zeroes. One might think it more efficient simply to compare the
1100 modified fields, but that would require enumerating those fields --
1101 and not all systems have the same fields in this structure. */
1103 if (memcmp (&mode, &new_mode, sizeof (mode)) != 0)
1105 #ifdef CIBAUD
1106 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
1107 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
1108 sometimes (m1 != m2). The only difference is in the four bits
1109 of the c_cflag field corresponding to the baud rate. To save
1110 Sun users a little confusion, don't report an error if this
1111 happens. But suppress the error only if we haven't tried to
1112 set the baud rate explicitly -- otherwise we'd never give an
1113 error for a true failure to set the baud rate. */
1115 new_mode.c_cflag &= (~CIBAUD);
1116 if (speed_was_set || memcmp (&mode, &new_mode, sizeof (mode)) != 0)
1117 #endif
1119 error (1, 0,
1120 _("%s: unable to perform all requested operations"),
1121 device_name);
1122 #ifdef TESTING
1124 size_t i;
1125 printf (_("new_mode: mode\n"));
1126 for (i = 0; i < sizeof (new_mode); i++)
1127 printf ("0x%02x: 0x%02x\n",
1128 *(((unsigned char *) &new_mode) + i),
1129 *(((unsigned char *) &mode) + i));
1131 #endif
1136 exit (0);
1139 /* Return 0 if not applied because not reversible; otherwise return 1. */
1141 static int
1142 set_mode (struct mode_info *info, int reversed, struct termios *mode)
1144 tcflag_t *bitsp;
1146 if (reversed && (info->flags & REV) == 0)
1147 return 0;
1149 bitsp = mode_type_flag (info->type, mode);
1151 if (bitsp == NULL)
1153 /* Combination mode. */
1154 if (STREQ (info->name, "evenp") || STREQ (info->name, "parity"))
1156 if (reversed)
1157 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1158 else
1159 mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
1161 else if (STREQ (info->name, "oddp"))
1163 if (reversed)
1164 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1165 else
1166 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
1168 else if (STREQ (info->name, "nl"))
1170 if (reversed)
1172 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
1173 mode->c_oflag = (mode->c_oflag
1174 #ifdef ONLCR
1175 | ONLCR
1176 #endif
1178 #ifdef OCRNL
1179 & ~OCRNL
1180 #endif
1181 #ifdef ONLRET
1182 & ~ONLRET
1183 #endif
1186 else
1188 mode->c_iflag = mode->c_iflag & ~ICRNL;
1189 #ifdef ONLCR
1190 mode->c_oflag = mode->c_oflag & ~ONLCR;
1191 #endif
1194 else if (STREQ (info->name, "ek"))
1196 mode->c_cc[VERASE] = CERASE;
1197 mode->c_cc[VKILL] = CKILL;
1199 else if (STREQ (info->name, "sane"))
1200 sane_mode (mode);
1201 else if (STREQ (info->name, "cbreak"))
1203 if (reversed)
1204 mode->c_lflag |= ICANON;
1205 else
1206 mode->c_lflag &= ~ICANON;
1208 else if (STREQ (info->name, "pass8"))
1210 if (reversed)
1212 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1213 mode->c_iflag |= ISTRIP;
1215 else
1217 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1218 mode->c_iflag &= ~ISTRIP;
1221 else if (STREQ (info->name, "litout"))
1223 if (reversed)
1225 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1226 mode->c_iflag |= ISTRIP;
1227 mode->c_oflag |= OPOST;
1229 else
1231 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1232 mode->c_iflag &= ~ISTRIP;
1233 mode->c_oflag &= ~OPOST;
1236 else if (STREQ (info->name, "raw") || STREQ (info->name, "cooked"))
1238 if ((info->name[0] == 'r' && reversed)
1239 || (info->name[0] == 'c' && !reversed))
1241 /* Cooked mode. */
1242 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1243 mode->c_oflag |= OPOST;
1244 mode->c_lflag |= ISIG | ICANON;
1245 #if VMIN == VEOF
1246 mode->c_cc[VEOF] = CEOF;
1247 #endif
1248 #if VTIME == VEOL
1249 mode->c_cc[VEOL] = CEOL;
1250 #endif
1252 else
1254 /* Raw mode. */
1255 mode->c_iflag = 0;
1256 mode->c_oflag &= ~OPOST;
1257 mode->c_lflag &= ~(ISIG | ICANON
1258 #ifdef XCASE
1259 | XCASE
1260 #endif
1262 mode->c_cc[VMIN] = 1;
1263 mode->c_cc[VTIME] = 0;
1266 #ifdef IXANY
1267 else if (STREQ (info->name, "decctlq"))
1269 if (reversed)
1270 mode->c_iflag |= IXANY;
1271 else
1272 mode->c_iflag &= ~IXANY;
1274 #endif
1275 #ifdef TABDLY
1276 else if (STREQ (info->name, "tabs"))
1278 if (reversed)
1279 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1280 else
1281 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1283 #else
1284 # ifdef OXTABS
1285 else if (STREQ (info->name, "tabs"))
1287 if (reversed)
1288 mode->c_oflag = mode->c_oflag | OXTABS;
1289 else
1290 mode->c_oflag = mode->c_oflag & ~OXTABS;
1292 # endif
1293 #endif
1294 #if defined(XCASE) && defined(IUCLC) && defined(OLCUC)
1295 else if (STREQ (info->name, "lcase")
1296 || STREQ (info->name, "LCASE"))
1298 if (reversed)
1300 mode->c_lflag &= ~XCASE;
1301 mode->c_iflag &= ~IUCLC;
1302 mode->c_oflag &= ~OLCUC;
1304 else
1306 mode->c_lflag |= XCASE;
1307 mode->c_iflag |= IUCLC;
1308 mode->c_oflag |= OLCUC;
1311 #endif
1312 else if (STREQ (info->name, "crt"))
1313 mode->c_lflag |= ECHOE
1314 #ifdef ECHOCTL
1315 | ECHOCTL
1316 #endif
1317 #ifdef ECHOKE
1318 | ECHOKE
1319 #endif
1321 else if (STREQ (info->name, "dec"))
1323 mode->c_cc[VINTR] = 3; /* ^C */
1324 mode->c_cc[VERASE] = 127; /* DEL */
1325 mode->c_cc[VKILL] = 21; /* ^U */
1326 mode->c_lflag |= ECHOE
1327 #ifdef ECHOCTL
1328 | ECHOCTL
1329 #endif
1330 #ifdef ECHOKE
1331 | ECHOKE
1332 #endif
1334 #ifdef IXANY
1335 mode->c_iflag &= ~IXANY;
1336 #endif
1339 else if (reversed)
1340 *bitsp = *bitsp & ~info->mask & ~info->bits;
1341 else
1342 *bitsp = (*bitsp & ~info->mask) | info->bits;
1344 return 1;
1347 static void
1348 set_control_char (struct control_info *info, const char *arg,
1349 struct termios *mode)
1351 unsigned char value;
1353 if (STREQ (info->name, "min") || STREQ (info->name, "time"))
1354 value = integer_arg (arg);
1355 else if (arg[0] == '\0' || arg[1] == '\0')
1356 value = arg[0];
1357 else if (STREQ (arg, "^-") || STREQ (arg, "undef"))
1358 value = _POSIX_VDISABLE;
1359 else if (arg[0] == '^' && arg[1] != '\0') /* Ignore any trailing junk. */
1361 if (arg[1] == '?')
1362 value = 127;
1363 else
1364 value = arg[1] & ~0140; /* Non-letters get weird results. */
1366 else
1367 value = integer_arg (arg);
1368 mode->c_cc[info->offset] = value;
1371 static void
1372 set_speed (enum speed_setting type, const char *arg, struct termios *mode)
1374 speed_t baud;
1376 baud = string_to_baud (arg);
1377 if (type == input_speed || type == both_speeds)
1378 cfsetispeed (mode, baud);
1379 if (type == output_speed || type == both_speeds)
1380 cfsetospeed (mode, baud);
1383 #ifdef TIOCGWINSZ
1385 static int
1386 get_win_size (int fd, struct winsize *win)
1388 int err = ioctl (fd, TIOCGWINSZ, (char *) win);
1389 return err;
1392 static void
1393 set_window_size (int rows, int cols, int fd, const char *device_name)
1395 struct winsize win;
1397 if (get_win_size (fd, &win))
1399 if (errno != EINVAL)
1400 error (1, errno, "%s", device_name);
1401 memset (&win, 0, sizeof (win));
1404 if (rows >= 0)
1405 win.ws_row = rows;
1406 if (cols >= 0)
1407 win.ws_col = cols;
1409 # ifdef TIOCSSIZE
1410 /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
1411 The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
1412 This comment from sys/ttold.h describes Sun's twisted logic - a better
1413 test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
1414 At any rate, the problem is gone in Solaris 2.x.
1416 Unfortunately, the old TIOCSSIZE code does collide with TIOCSWINSZ,
1417 but they can be disambiguated by checking whether a "struct ttysize"
1418 structure's "ts_lines" field is greater than 64K or not. If so,
1419 it's almost certainly a "struct winsize" instead.
1421 At any rate, the bug manifests itself when ws_row == 0; the symptom is
1422 that ws_row is set to ws_col, and ws_col is set to (ws_xpixel<<16) +
1423 ws_ypixel. Since GNU stty sets rows and columns separately, this bug
1424 caused "stty rows 0 cols 0" to set rows to cols and cols to 0, while
1425 "stty cols 0 rows 0" would do the right thing. On a little-endian
1426 machine like the sun386i, the problem is the same, but for ws_col == 0.
1428 The workaround is to do the ioctl once with row and col = 1 to set the
1429 pixel info, and then do it again using a TIOCSSIZE to set rows/cols. */
1431 if (win.ws_row == 0 || win.ws_col == 0)
1433 struct ttysize ttysz;
1435 ttysz.ts_lines = win.ws_row;
1436 ttysz.ts_cols = win.ws_col;
1438 win.ws_row = 1;
1439 win.ws_col = 1;
1441 if (ioctl (fd, TIOCSWINSZ, (char *) &win))
1442 error (1, errno, "%s", device_name);
1444 if (ioctl (fd, TIOCSSIZE, (char *) &ttysz))
1445 error (1, errno, "%s", device_name);
1446 return;
1448 # endif
1450 if (ioctl (fd, TIOCSWINSZ, (char *) &win))
1451 error (1, errno, "%s", device_name);
1454 static void
1455 display_window_size (int fancy, int fd, const char *device_name)
1457 struct winsize win;
1459 if (get_win_size (fd, &win))
1461 if (errno != EINVAL)
1462 error (1, errno, "%s", device_name);
1463 if (!fancy)
1464 error (1, 0, _("%s: no size information for this device"), device_name);
1466 else
1468 wrapf (fancy ? "rows %d; columns %d;" : "%d %d\n",
1469 win.ws_row, win.ws_col);
1470 if (!fancy)
1471 current_col = 0;
1474 #endif
1476 static int
1477 screen_columns (void)
1479 #ifdef TIOCGWINSZ
1480 struct winsize win;
1482 /* With Solaris 2.[123], this ioctl fails and errno is set to
1483 EINVAL for telnet (but not rlogin) sessions.
1484 On ISC 3.0, it fails for the console and the serial port
1485 (but it works for ptys).
1486 It can also fail on any system when stdout isn't a tty.
1487 In case of any failure, just use the default. */
1488 if (get_win_size (STDOUT_FILENO, &win) == 0 && 0 < win.ws_col)
1489 return win.ws_col;
1490 #endif
1492 /* Use $COLUMNS if it's in [1..INT_MAX-1]. */
1493 char *col_string = getenv ("COLUMNS");
1494 long n_columns;
1495 if (!(col_string != NULL
1496 && xstrtol (col_string, NULL, 0, &n_columns, "") == LONGINT_OK
1497 && 0 < n_columns
1498 && n_columns < INT_MAX))
1499 n_columns = 80;
1500 return n_columns;
1504 static tcflag_t *
1505 mode_type_flag (enum mode_type type, struct termios *mode)
1507 switch (type)
1509 case control:
1510 return &mode->c_cflag;
1512 case input:
1513 return &mode->c_iflag;
1515 case output:
1516 return &mode->c_oflag;
1518 case local:
1519 return &mode->c_lflag;
1521 case combination:
1522 return NULL;
1524 default:
1525 abort ();
1529 static void
1530 display_settings (enum output_type output_type, struct termios *mode,
1531 int fd, const char *device_name)
1533 switch (output_type)
1535 case changed:
1536 display_changed (mode);
1537 break;
1539 case all:
1540 display_all (mode, fd, device_name);
1541 break;
1543 case recoverable:
1544 display_recoverable (mode);
1545 break;
1549 static void
1550 display_changed (struct termios *mode)
1552 int i;
1553 int empty_line;
1554 tcflag_t *bitsp;
1555 unsigned long mask;
1556 enum mode_type prev_type = control;
1558 display_speed (mode, 1);
1559 #ifdef HAVE_C_LINE
1560 wrapf ("line = %d;", mode->c_line);
1561 #endif
1562 putchar ('\n');
1563 current_col = 0;
1565 empty_line = 1;
1566 for (i = 0; !STREQ (control_info[i].name, "min"); ++i)
1568 if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
1569 continue;
1570 /* If swtch is the same as susp, don't print both. */
1571 #if VSWTCH == VSUSP
1572 if (STREQ (control_info[i].name, "swtch"))
1573 continue;
1574 #endif
1575 /* If eof uses the same slot as min, only print whichever applies. */
1576 #if VEOF == VMIN
1577 if ((mode->c_lflag & ICANON) == 0
1578 && (STREQ (control_info[i].name, "eof")
1579 || STREQ (control_info[i].name, "eol")))
1580 continue;
1581 #endif
1583 empty_line = 0;
1584 wrapf ("%s = %s;", control_info[i].name,
1585 visible (mode->c_cc[control_info[i].offset]));
1587 if ((mode->c_lflag & ICANON) == 0)
1589 wrapf ("min = %d; time = %d;\n", (int) mode->c_cc[VMIN],
1590 (int) mode->c_cc[VTIME]);
1592 else if (empty_line == 0)
1593 putchar ('\n');
1594 current_col = 0;
1596 empty_line = 1;
1597 for (i = 0; mode_info[i].name != NULL; ++i)
1599 if (mode_info[i].flags & OMIT)
1600 continue;
1601 if (mode_info[i].type != prev_type)
1603 if (empty_line == 0)
1605 putchar ('\n');
1606 current_col = 0;
1607 empty_line = 1;
1609 prev_type = mode_info[i].type;
1612 bitsp = mode_type_flag (mode_info[i].type, mode);
1613 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1614 if ((*bitsp & mask) == mode_info[i].bits)
1616 if (mode_info[i].flags & SANE_UNSET)
1618 wrapf ("%s", mode_info[i].name);
1619 empty_line = 0;
1622 else if ((mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
1624 wrapf ("-%s", mode_info[i].name);
1625 empty_line = 0;
1628 if (empty_line == 0)
1629 putchar ('\n');
1630 current_col = 0;
1633 static void
1634 display_all (struct termios *mode, int fd, const char *device_name)
1636 int i;
1637 tcflag_t *bitsp;
1638 unsigned long mask;
1639 enum mode_type prev_type = control;
1641 display_speed (mode, 1);
1642 #ifdef TIOCGWINSZ
1643 display_window_size (1, fd, device_name);
1644 #endif
1645 #ifdef HAVE_C_LINE
1646 wrapf ("line = %d;", mode->c_line);
1647 #endif
1648 putchar ('\n');
1649 current_col = 0;
1651 for (i = 0; ! STREQ (control_info[i].name, "min"); ++i)
1653 /* If swtch is the same as susp, don't print both. */
1654 #if VSWTCH == VSUSP
1655 if (STREQ (control_info[i].name, "swtch"))
1656 continue;
1657 #endif
1658 /* If eof uses the same slot as min, only print whichever applies. */
1659 #if VEOF == VMIN
1660 if ((mode->c_lflag & ICANON) == 0
1661 && (STREQ (control_info[i].name, "eof")
1662 || STREQ (control_info[i].name, "eol")))
1663 continue;
1664 #endif
1665 wrapf ("%s = %s;", control_info[i].name,
1666 visible (mode->c_cc[control_info[i].offset]));
1668 #if VEOF == VMIN
1669 if ((mode->c_lflag & ICANON) == 0)
1670 #endif
1671 wrapf ("min = %d; time = %d;", mode->c_cc[VMIN], mode->c_cc[VTIME]);
1672 if (current_col != 0)
1673 putchar ('\n');
1674 current_col = 0;
1676 for (i = 0; mode_info[i].name != NULL; ++i)
1678 if (mode_info[i].flags & OMIT)
1679 continue;
1680 if (mode_info[i].type != prev_type)
1682 putchar ('\n');
1683 current_col = 0;
1684 prev_type = mode_info[i].type;
1687 bitsp = mode_type_flag (mode_info[i].type, mode);
1688 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1689 if ((*bitsp & mask) == mode_info[i].bits)
1690 wrapf ("%s", mode_info[i].name);
1691 else if (mode_info[i].flags & REV)
1692 wrapf ("-%s", mode_info[i].name);
1694 putchar ('\n');
1695 current_col = 0;
1698 static void
1699 display_speed (struct termios *mode, int fancy)
1701 if (cfgetispeed (mode) == 0 || cfgetispeed (mode) == cfgetospeed (mode))
1702 wrapf (fancy ? "speed %lu baud;" : "%lu\n",
1703 baud_to_value (cfgetospeed (mode)));
1704 else
1705 wrapf (fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n",
1706 baud_to_value (cfgetispeed (mode)),
1707 baud_to_value (cfgetospeed (mode)));
1708 if (!fancy)
1709 current_col = 0;
1712 static void
1713 display_recoverable (struct termios *mode)
1715 int i;
1717 printf ("%lx:%lx:%lx:%lx",
1718 (unsigned long) mode->c_iflag, (unsigned long) mode->c_oflag,
1719 (unsigned long) mode->c_cflag, (unsigned long) mode->c_lflag);
1720 for (i = 0; i < NCCS; ++i)
1721 printf (":%x", (unsigned int) mode->c_cc[i]);
1722 putchar ('\n');
1725 static int
1726 recover_mode (char *arg, struct termios *mode)
1728 int i, n;
1729 unsigned int chr;
1730 unsigned long iflag, oflag, cflag, lflag;
1732 /* Scan into temporaries since it is too much trouble to figure out
1733 the right format for `tcflag_t'. */
1734 if (sscanf (arg, "%lx:%lx:%lx:%lx%n",
1735 &iflag, &oflag, &cflag, &lflag, &n) != 4)
1736 return 0;
1737 mode->c_iflag = iflag;
1738 mode->c_oflag = oflag;
1739 mode->c_cflag = cflag;
1740 mode->c_lflag = lflag;
1741 arg += n;
1742 for (i = 0; i < NCCS; ++i)
1744 if (sscanf (arg, ":%x%n", &chr, &n) != 1)
1745 return 0;
1746 mode->c_cc[i] = chr;
1747 arg += n;
1750 /* Fail if there are too many fields. */
1751 if (*arg != '\0')
1752 return 0;
1754 return 1;
1757 struct speed_map
1759 const char *string; /* ASCII representation. */
1760 speed_t speed; /* Internal form. */
1761 unsigned long value; /* Numeric value. */
1764 struct speed_map speeds[] =
1766 {"0", B0, 0},
1767 {"50", B50, 50},
1768 {"75", B75, 75},
1769 {"110", B110, 110},
1770 {"134", B134, 134},
1771 {"134.5", B134, 134},
1772 {"150", B150, 150},
1773 {"200", B200, 200},
1774 {"300", B300, 300},
1775 {"600", B600, 600},
1776 {"1200", B1200, 1200},
1777 {"1800", B1800, 1800},
1778 {"2400", B2400, 2400},
1779 {"4800", B4800, 4800},
1780 {"9600", B9600, 9600},
1781 {"19200", B19200, 19200},
1782 {"38400", B38400, 38400},
1783 {"exta", B19200, 19200},
1784 {"extb", B38400, 38400},
1785 #ifdef B57600
1786 {"57600", B57600, 57600},
1787 #endif
1788 #ifdef B115200
1789 {"115200", B115200, 115200},
1790 #endif
1791 #ifdef B230400
1792 {"230400", B230400, 230400},
1793 #endif
1794 #ifdef B460800
1795 {"460800", B460800, 460800},
1796 #endif
1797 {NULL, 0, 0}
1800 static speed_t
1801 string_to_baud (const char *arg)
1803 int i;
1805 for (i = 0; speeds[i].string != NULL; ++i)
1806 if (STREQ (arg, speeds[i].string))
1807 return speeds[i].speed;
1808 return (speed_t) -1;
1811 static unsigned long
1812 baud_to_value (speed_t speed)
1814 int i;
1816 for (i = 0; speeds[i].string != NULL; ++i)
1817 if (speed == speeds[i].speed)
1818 return speeds[i].value;
1819 return 0;
1822 static void
1823 sane_mode (struct termios *mode)
1825 int i;
1826 tcflag_t *bitsp;
1828 for (i = 0; control_info[i].name; ++i)
1830 #if VMIN == VEOF
1831 if (STREQ (control_info[i].name, "min"))
1832 break;
1833 #endif
1834 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1837 for (i = 0; mode_info[i].name != NULL; ++i)
1839 if (mode_info[i].flags & SANE_SET)
1841 bitsp = mode_type_flag (mode_info[i].type, mode);
1842 *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits;
1844 else if (mode_info[i].flags & SANE_UNSET)
1846 bitsp = mode_type_flag (mode_info[i].type, mode);
1847 *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits;
1852 /* Return a string that is the printable representation of character CH. */
1853 /* Adapted from `cat' by Torbjorn Granlund. */
1855 static const char *
1856 visible (unsigned int ch)
1858 static char buf[10];
1859 char *bpout = buf;
1861 if (ch == _POSIX_VDISABLE)
1862 return "<undef>";
1864 if (ch >= 32)
1866 if (ch < 127)
1867 *bpout++ = ch;
1868 else if (ch == 127)
1870 *bpout++ = '^';
1871 *bpout++ = '?';
1873 else
1875 *bpout++ = 'M',
1876 *bpout++ = '-';
1877 if (ch >= 128 + 32)
1879 if (ch < 128 + 127)
1880 *bpout++ = ch - 128;
1881 else
1883 *bpout++ = '^';
1884 *bpout++ = '?';
1887 else
1889 *bpout++ = '^';
1890 *bpout++ = ch - 128 + 64;
1894 else
1896 *bpout++ = '^';
1897 *bpout++ = ch + 64;
1899 *bpout = '\0';
1900 return (const char *) buf;
1903 /* Parse string S as an integer, using decimal radix by default,
1904 but allowing octal and hex numbers as in C. */
1905 /* From `od' by Richard Stallman. */
1907 static long
1908 integer_arg (const char *s)
1910 long value;
1911 if (xstrtol (s, NULL, 0, &value, "bB") != LONGINT_OK)
1913 error (0, 0, _("invalid integer argument `%s'"), s);
1914 usage (1);
1916 return value;