1 /* stty -- change and print terminal line settings
2 Copyright (C) 1990-2012 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 3 of the License, or
7 (at your option) 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, see <http://www.gnu.org/licenses/>. */
17 /* Usage: stty [-ag] [--all] [--save] [-F device] [--file=device] [setting...]
20 -a, --all Write all current settings to stdout in human-readable form.
21 -g, --save Write all current settings to stdout in stty-readable form.
22 -F, --file Open and use the specified device instead of stdin
24 If no args are given, write to stdout the baud rate and settings that
25 have been changed from their defaults. Mode reading and changes
26 are done on the specified device, or stdin if none was specified.
28 David MacKenzie <djm@gnu.ai.mit.edu> */
32 #ifdef TERMIOS_NEEDS_XOPEN_SOURCE
33 # define _XOPEN_SOURCE
37 #include <sys/types.h>
43 #include <sys/ioctl.h>
45 #ifdef WINSIZE_IN_PTEM
46 # include <sys/stream.h>
47 # include <sys/ptem.h>
49 #ifdef GWINSZ_IN_SYS_PTY
59 #include "fd-reopen.h"
63 /* The official name of this program (e.g., no 'g' prefix). */
64 #define PROGRAM_NAME "stty"
66 #define AUTHORS proper_name ("David MacKenzie")
68 #ifndef _POSIX_VDISABLE
69 # define _POSIX_VDISABLE 0
72 #define Control(c) ((c) & 0x1f)
73 /* Canonical values for control characters. */
75 # define CINTR Control ('c')
84 # define CKILL Control ('u')
87 # define CEOF Control ('d')
90 # define CEOL _POSIX_VDISABLE
93 # define CSTART Control ('q')
96 # define CSTOP Control ('s')
99 # define CSUSP Control ('z')
101 #if defined VEOL2 && !defined CEOL2
102 # define CEOL2 _POSIX_VDISABLE
104 /* Some platforms have VSWTC, others VSWTCH. In both cases, this control
105 character is initialized by CSWTCH, if present. */
106 #if defined VSWTC && !defined VSWTCH
107 # define VSWTCH VSWTC
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 # if defined CSUSP && !defined CSWTCH
113 # define CSWTCH CSUSP
116 #if defined VSWTCH && !defined CSWTCH
117 # define CSWTCH _POSIX_VDISABLE
120 /* SunOS 5.3 loses (^Z doesn't work) if 'swtch' is the same as 'susp'.
121 So the default is to disable 'swtch.' */
122 #if defined __sparc__ && defined __svr4__
124 # define CSWTCH _POSIX_VDISABLE
127 #if defined VWERSE && !defined VWERASE /* AIX-3.2.5 */
128 # define VWERASE VWERSE
130 #if defined VDSUSP && !defined CDSUSP
131 # define CDSUSP Control ('y')
133 #if !defined VREPRINT && defined VRPRNT /* Irix 4.0.5 */
134 # define VREPRINT VRPRNT
136 #if defined VREPRINT && !defined CRPRNT
137 # define CRPRNT Control ('r')
139 #if defined CREPRINT && !defined CRPRNT
140 # define CRPRNT Control ('r')
142 #if defined VWERASE && !defined CWERASE
143 # define CWERASE Control ('w')
145 #if defined VLNEXT && !defined CLNEXT
146 # define CLNEXT Control ('v')
148 #if defined VDISCARD && !defined VFLUSHO
149 # define VFLUSHO VDISCARD
151 #if defined VFLUSH && !defined VFLUSHO /* Ultrix 4.2 */
152 # define VFLUSHO VFLUSH
154 #if defined CTLECH && !defined ECHOCTL /* Ultrix 4.3 */
155 # define ECHOCTL CTLECH
157 #if defined TCTLECH && !defined ECHOCTL /* Ultrix 4.2 */
158 # define ECHOCTL TCTLECH
160 #if defined CRTKIL && !defined ECHOKE /* Ultrix 4.2 and 4.3 */
161 # define ECHOKE CRTKIL
163 #if defined VFLUSHO && !defined CFLUSHO
164 # define CFLUSHO Control ('o')
166 #if defined VSTATUS && !defined CSTATUS
167 # define CSTATUS Control ('t')
170 /* Which speeds to set. */
173 input_speed, output_speed, both_speeds
176 /* What to output and how. */
179 changed, all, recoverable /* Default, -a, -g. */
182 /* Which member(s) of 'struct termios' a mode uses. */
185 control, input, output, local, combination
188 /* Flags for 'struct mode_info'. */
189 #define SANE_SET 1 /* Set in 'sane' mode. */
190 #define SANE_UNSET 2 /* Unset in 'sane' mode. */
191 #define REV 4 /* Can be turned off by prepending '-'. */
192 #define OMIT 8 /* Don't display value. */
197 const char *name; /* Name given on command line. */
198 enum mode_type type; /* Which structure element to change. */
199 char flags; /* Setting and display options. */
200 unsigned long bits; /* Bits to set for this mode. */
201 unsigned long mask; /* Other bits to turn off for this mode. */
204 static struct mode_info const mode_info[] =
206 {"parenb", control, REV, PARENB, 0},
207 {"parodd", control, REV, PARODD, 0},
208 {"cs5", control, 0, CS5, CSIZE},
209 {"cs6", control, 0, CS6, CSIZE},
210 {"cs7", control, 0, CS7, CSIZE},
211 {"cs8", control, 0, CS8, CSIZE},
212 {"hupcl", control, REV, HUPCL, 0},
213 {"hup", control, REV | OMIT, HUPCL, 0},
214 {"cstopb", control, REV, CSTOPB, 0},
215 {"cread", control, SANE_SET | REV, CREAD, 0},
216 {"clocal", control, REV, CLOCAL, 0},
218 {"crtscts", control, REV, CRTSCTS, 0},
221 {"ignbrk", input, SANE_UNSET | REV, IGNBRK, 0},
222 {"brkint", input, SANE_SET | REV, BRKINT, 0},
223 {"ignpar", input, REV, IGNPAR, 0},
224 {"parmrk", input, REV, PARMRK, 0},
225 {"inpck", input, REV, INPCK, 0},
226 {"istrip", input, REV, ISTRIP, 0},
227 {"inlcr", input, SANE_UNSET | REV, INLCR, 0},
228 {"igncr", input, SANE_UNSET | REV, IGNCR, 0},
229 {"icrnl", input, SANE_SET | REV, ICRNL, 0},
230 {"ixon", input, REV, IXON, 0},
231 {"ixoff", input, SANE_UNSET | REV, IXOFF, 0},
232 {"tandem", input, REV | OMIT, IXOFF, 0},
234 {"iuclc", input, SANE_UNSET | REV, IUCLC, 0},
237 {"ixany", input, SANE_UNSET | REV, IXANY, 0},
240 {"imaxbel", input, SANE_SET | REV, IMAXBEL, 0},
243 {"iutf8", input, SANE_UNSET | REV, IUTF8, 0},
246 {"opost", output, SANE_SET | REV, OPOST, 0},
248 {"olcuc", output, SANE_UNSET | REV, OLCUC, 0},
251 {"ocrnl", output, SANE_UNSET | REV, OCRNL, 0},
254 {"onlcr", output, SANE_SET | REV, ONLCR, 0},
257 {"onocr", output, SANE_UNSET | REV, ONOCR, 0},
260 {"onlret", output, SANE_UNSET | REV, ONLRET, 0},
263 {"ofill", output, SANE_UNSET | REV, OFILL, 0},
266 {"ofdel", output, SANE_UNSET | REV, OFDEL, 0},
269 {"nl1", output, SANE_UNSET, NL1, NLDLY},
270 {"nl0", output, SANE_SET, NL0, NLDLY},
273 {"cr3", output, SANE_UNSET, CR3, CRDLY},
274 {"cr2", output, SANE_UNSET, CR2, CRDLY},
275 {"cr1", output, SANE_UNSET, CR1, CRDLY},
276 {"cr0", output, SANE_SET, CR0, CRDLY},
280 {"tab3", output, SANE_UNSET, TAB3, TABDLY},
283 {"tab2", output, SANE_UNSET, TAB2, TABDLY},
286 {"tab1", output, SANE_UNSET, TAB1, TABDLY},
289 {"tab0", output, SANE_SET, TAB0, TABDLY},
293 {"tab3", output, SANE_UNSET, OXTABS, 0},
297 {"bs1", output, SANE_UNSET, BS1, BSDLY},
298 {"bs0", output, SANE_SET, BS0, BSDLY},
301 {"vt1", output, SANE_UNSET, VT1, VTDLY},
302 {"vt0", output, SANE_SET, VT0, VTDLY},
305 {"ff1", output, SANE_UNSET, FF1, FFDLY},
306 {"ff0", output, SANE_SET, FF0, FFDLY},
309 {"isig", local, SANE_SET | REV, ISIG, 0},
310 {"icanon", local, SANE_SET | REV, ICANON, 0},
312 {"iexten", local, SANE_SET | REV, IEXTEN, 0},
314 {"echo", local, SANE_SET | REV, ECHO, 0},
315 {"echoe", local, SANE_SET | REV, ECHOE, 0},
316 {"crterase", local, REV | OMIT, ECHOE, 0},
317 {"echok", local, SANE_SET | REV, ECHOK, 0},
318 {"echonl", local, SANE_UNSET | REV, ECHONL, 0},
319 {"noflsh", local, SANE_UNSET | REV, NOFLSH, 0},
321 {"xcase", local, SANE_UNSET | REV, XCASE, 0},
324 {"tostop", local, SANE_UNSET | REV, TOSTOP, 0},
327 {"echoprt", local, SANE_UNSET | REV, ECHOPRT, 0},
328 {"prterase", local, REV | OMIT, ECHOPRT, 0},
331 {"echoctl", local, SANE_SET | REV, ECHOCTL, 0},
332 {"ctlecho", local, REV | OMIT, ECHOCTL, 0},
335 {"echoke", local, SANE_SET | REV, ECHOKE, 0},
336 {"crtkill", local, REV | OMIT, ECHOKE, 0},
339 {"evenp", combination, REV | OMIT, 0, 0},
340 {"parity", combination, REV | OMIT, 0, 0},
341 {"oddp", combination, REV | OMIT, 0, 0},
342 {"nl", combination, REV | OMIT, 0, 0},
343 {"ek", combination, OMIT, 0, 0},
344 {"sane", combination, OMIT, 0, 0},
345 {"cooked", combination, REV | OMIT, 0, 0},
346 {"raw", combination, REV | OMIT, 0, 0},
347 {"pass8", combination, REV | OMIT, 0, 0},
348 {"litout", combination, REV | OMIT, 0, 0},
349 {"cbreak", combination, REV | OMIT, 0, 0},
351 {"decctlq", combination, REV | OMIT, 0, 0},
353 #if defined TABDLY || defined OXTABS
354 {"tabs", combination, REV | OMIT, 0, 0},
356 #if defined XCASE && defined IUCLC && defined OLCUC
357 {"lcase", combination, REV | OMIT, 0, 0},
358 {"LCASE", combination, REV | OMIT, 0, 0},
360 {"crt", combination, OMIT, 0, 0},
361 {"dec", combination, OMIT, 0, 0},
363 {NULL, control, 0, 0, 0}
366 /* Control character settings. */
369 const char *name; /* Name given on command line. */
370 cc_t saneval; /* Value to set for 'stty sane'. */
371 size_t offset; /* Offset in c_cc. */
374 /* Control characters. */
376 static struct control_info const control_info[] =
378 {"intr", CINTR, VINTR},
379 {"quit", CQUIT, VQUIT},
380 {"erase", CERASE, VERASE},
381 {"kill", CKILL, VKILL},
385 {"eol2", CEOL2, VEOL2},
388 {"swtch", CSWTCH, VSWTCH},
390 {"start", CSTART, VSTART},
391 {"stop", CSTOP, VSTOP},
392 {"susp", CSUSP, VSUSP},
394 {"dsusp", CDSUSP, VDSUSP},
397 {"rprnt", CRPRNT, VREPRINT},
399 # ifdef CREPRINT /* HPUX 10.20 needs this */
400 {"rprnt", CRPRNT, CREPRINT},
404 {"werase", CWERASE, VWERASE},
407 {"lnext", CLNEXT, VLNEXT},
410 {"flush", CFLUSHO, VFLUSHO},
413 {"status", CSTATUS, VSTATUS},
416 /* These must be last because of the display routines. */
422 static char const *visible (cc_t ch);
423 static unsigned long int baud_to_value (speed_t speed);
424 static bool recover_mode (char const *arg, struct termios *mode);
425 static int screen_columns (void);
426 static bool set_mode (struct mode_info const *info, bool reversed,
427 struct termios *mode);
428 static unsigned long int integer_arg (const char *s, unsigned long int max);
429 static speed_t string_to_baud (const char *arg);
430 static tcflag_t *mode_type_flag (enum mode_type type, struct termios *mode);
431 static void display_all (struct termios *mode, char const *device_name);
432 static void display_changed (struct termios *mode);
433 static void display_recoverable (struct termios *mode);
434 static void display_settings (enum output_type output_type,
435 struct termios *mode,
436 const char *device_name);
437 static void display_speed (struct termios *mode, bool fancy);
438 static void display_window_size (bool fancy, char const *device_name);
439 static void sane_mode (struct termios *mode);
440 static void set_control_char (struct control_info const *info,
442 struct termios *mode);
443 static void set_speed (enum speed_setting type, const char *arg,
444 struct termios *mode);
445 static void set_window_size (int rows, int cols, char const *device_name);
447 /* The width of the screen, for output wrapping. */
450 /* Current position, to know when to wrap. */
451 static int current_col;
453 static struct option const longopts[] =
455 {"all", no_argument, NULL, 'a'},
456 {"save", no_argument, NULL, 'g'},
457 {"file", required_argument, NULL, 'F'},
458 {GETOPT_HELP_OPTION_DECL},
459 {GETOPT_VERSION_OPTION_DECL},
463 static void wrapf (const char *message, ...)
464 __attribute__ ((__format__ (__printf__, 1, 2)));
466 /* Print format string MESSAGE and optional args.
467 Wrap to next line first if it won't fit.
468 Print a space first unless MESSAGE will start a new line. */
471 wrapf (const char *message,...)
477 va_start (args, message);
478 buflen = vasprintf (&buf, message, args);
486 if (max_col - current_col < buflen)
500 current_col += buflen;
506 if (status != EXIT_SUCCESS)
511 Usage: %s [-F DEVICE | --file=DEVICE] [SETTING]...\n\
512 or: %s [-F DEVICE | --file=DEVICE] [-a|--all]\n\
513 or: %s [-F DEVICE | --file=DEVICE] [-g|--save]\n\
515 program_name, program_name, program_name);
517 Print or change terminal characteristics.\n\
519 -a, --all print all current settings in human-readable form\n\
520 -g, --save print all current settings in a stty-readable form\n\
521 -F, --file=DEVICE open and use the specified DEVICE instead of stdin\n\
523 fputs (HELP_OPTION_DESCRIPTION, stdout);
524 fputs (VERSION_OPTION_DESCRIPTION, stdout);
527 Optional - before SETTING indicates negation. An * marks non-POSIX\n\
528 settings. The underlying system defines which settings are available.\n\
532 Special characters:\n\
533 * dsusp CHAR CHAR will send a terminal stop signal once input flushed\n\
534 eof CHAR CHAR will send an end of file (terminate the input)\n\
535 eol CHAR CHAR will end the line\n\
538 * eol2 CHAR alternate CHAR for ending the line\n\
539 erase CHAR CHAR will erase the last character typed\n\
540 intr CHAR CHAR will send an interrupt signal\n\
541 kill CHAR CHAR will erase the current line\n\
544 * lnext CHAR CHAR will enter the next character quoted\n\
545 quit CHAR CHAR will send a quit signal\n\
546 * rprnt CHAR CHAR will redraw the current line\n\
547 start CHAR CHAR will restart the output after stopping it\n\
550 stop CHAR CHAR will stop the output\n\
551 susp CHAR CHAR will send a terminal stop signal\n\
552 * swtch CHAR CHAR will switch to a different shell layer\n\
553 * werase CHAR CHAR will erase the last word typed\n\
558 N set the input and output speeds to N bauds\n\
559 * cols N tell the kernel that the terminal has N columns\n\
560 * columns N same as cols N\n\
563 ispeed N set the input speed to N\n\
564 * line N use line discipline N\n\
565 min N with -icanon, set N characters minimum for a completed read\n\
566 ospeed N set the output speed to N\n\
569 * rows N tell the kernel that the terminal has N rows\n\
570 * size print the number of rows and columns according to the kernel\n\
571 speed print the terminal speed\n\
572 time N with -icanon, set read timeout of N tenths of a second\n\
577 [-]clocal disable modem control signals\n\
578 [-]cread allow input to be received\n\
579 * [-]crtscts enable RTS/CTS handshaking\n\
580 csN set character size to N bits, N in [5..8]\n\
583 [-]cstopb use two stop bits per character (one with '-')\n\
584 [-]hup send a hangup signal when the last process closes the tty\n\
585 [-]hupcl same as [-]hup\n\
586 [-]parenb generate parity bit in output and expect parity bit in input\n\
587 [-]parodd set odd parity (or even parity with '-')\n\
592 [-]brkint breaks cause an interrupt signal\n\
593 [-]icrnl translate carriage return to newline\n\
594 [-]ignbrk ignore break characters\n\
595 [-]igncr ignore carriage return\n\
598 [-]ignpar ignore characters with parity errors\n\
599 * [-]imaxbel beep and do not flush a full input buffer on a character\n\
600 [-]inlcr translate newline to carriage return\n\
601 [-]inpck enable input parity checking\n\
602 [-]istrip clear high (8th) bit of input characters\n\
605 * [-]iutf8 assume input characters are UTF-8 encoded\n\
608 * [-]iuclc translate uppercase characters to lowercase\n\
609 * [-]ixany let any character restart output, not only start character\n\
610 [-]ixoff enable sending of start/stop characters\n\
611 [-]ixon enable XON/XOFF flow control\n\
612 [-]parmrk mark parity errors (with a 255-0-character sequence)\n\
613 [-]tandem same as [-]ixoff\n\
618 * bsN backspace delay style, N in [0..1]\n\
619 * crN carriage return delay style, N in [0..3]\n\
620 * ffN form feed delay style, N in [0..1]\n\
621 * nlN newline delay style, N in [0..1]\n\
624 * [-]ocrnl translate carriage return to newline\n\
625 * [-]ofdel use delete characters for fill instead of null characters\n\
626 * [-]ofill use fill (padding) characters instead of timing for delays\n\
627 * [-]olcuc translate lowercase characters to uppercase\n\
628 * [-]onlcr translate newline to carriage return-newline\n\
629 * [-]onlret newline performs a carriage return\n\
632 * [-]onocr do not print carriage returns in the first column\n\
633 [-]opost postprocess output\n\
634 * tabN horizontal tab delay style, N in [0..3]\n\
635 * tabs same as tab0\n\
636 * -tabs same as tab3\n\
637 * vtN vertical tab delay style, N in [0..1]\n\
642 [-]crterase echo erase characters as backspace-space-backspace\n\
643 * crtkill kill all line by obeying the echoprt and echoe settings\n\
644 * -crtkill kill all line by obeying the echoctl and echok settings\n\
647 * [-]ctlecho echo control characters in hat notation ('^c')\n\
648 [-]echo echo input characters\n\
649 * [-]echoctl same as [-]ctlecho\n\
650 [-]echoe same as [-]crterase\n\
651 [-]echok echo a newline after a kill character\n\
654 * [-]echoke same as [-]crtkill\n\
655 [-]echonl echo newline even if not echoing other characters\n\
656 * [-]echoprt echo erased characters backward, between '\\' and '/'\n\
657 [-]icanon enable erase, kill, werase, and rprnt special characters\n\
658 [-]iexten enable non-POSIX special characters\n\
661 [-]isig enable interrupt, quit, and suspend special characters\n\
662 [-]noflsh disable flushing after interrupt and quit special characters\n\
663 * [-]prterase same as [-]echoprt\n\
664 * [-]tostop stop background jobs that try to write to the terminal\n\
665 * [-]xcase with icanon, escape with '\\' for uppercase characters\n\
669 Combination settings:\n\
670 * [-]LCASE same as [-]lcase\n\
671 cbreak same as -icanon\n\
672 -cbreak same as icanon\n\
675 cooked same as brkint ignpar istrip icrnl ixon opost isig\n\
676 icanon, eof and eol characters to their default values\n\
677 -cooked same as raw\n\
678 crt same as echoe echoctl echoke\n\
681 dec same as echoe echoctl echoke -ixany intr ^c erase 0177\n\
683 * [-]decctlq same as [-]ixany\n\
684 ek erase and kill characters to their default values\n\
685 evenp same as parenb -parodd cs7\n\
688 -evenp same as -parenb cs8\n\
689 * [-]lcase same as xcase iuclc olcuc\n\
690 litout same as -parenb -istrip -opost cs8\n\
691 -litout same as parenb istrip opost cs7\n\
692 nl same as -icrnl -onlcr\n\
693 -nl same as icrnl -inlcr -igncr onlcr -ocrnl -onlret\n\
696 oddp same as parenb parodd cs7\n\
697 -oddp same as -parenb cs8\n\
698 [-]parity same as [-]evenp\n\
699 pass8 same as -parenb -istrip cs8\n\
700 -pass8 same as parenb istrip cs7\n\
703 raw same as -ignbrk -brkint -ignpar -parmrk -inpck -istrip\n\
704 -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany\n\
705 -imaxbel -opost -isig -icanon -xcase min 1 time 0\n\
706 -raw same as cooked\n\
709 sane same as cread -ignbrk brkint -inlcr -igncr icrnl -iutf8\n\
710 -ixoff -iuclc -ixany imaxbel opost -olcuc -ocrnl onlcr\n\
711 -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0\n\
712 isig icanon iexten echo echoe echok -echonl -noflsh\n\
713 -xcase -tostop -echoprt echoctl echoke, all special\n\
714 characters to their default values\n\
718 Handle the tty line connected to standard input. Without arguments,\n\
719 prints baud rate, line discipline, and deviations from stty sane. In\n\
720 settings, CHAR is taken literally, or coded as in ^c, 0x37, 0177 or\n\
721 127; special values ^- or undef used to disable special characters.\n\
723 emit_ancillary_info ();
729 main (int argc, char **argv)
731 /* Initialize to all zeroes so there is no risk memcmp will report a
732 spurious difference in an uninitialized portion of the structure. */
733 static struct termios mode;
735 enum output_type output_type;
739 bool require_set_attr;
740 bool speed_was_set ATTRIBUTE_UNUSED;
742 bool recoverable_output;
745 char *file_name = NULL;
746 const char *device_name;
748 initialize_main (&argc, &argv);
749 set_program_name (argv[0]);
750 setlocale (LC_ALL, "");
751 bindtextdomain (PACKAGE, LOCALEDIR);
752 textdomain (PACKAGE);
754 atexit (close_stdout);
756 output_type = changed;
757 verbose_output = false;
758 recoverable_output = false;
760 /* Don't print error messages for unrecognized options. */
763 /* If any new options are ever added to stty, the short options MUST
764 NOT allow any ambiguity with the stty settings. For example, the
765 stty setting "-gagFork" would not be feasible, since it will be
766 parsed as "-g -a -g -F ork". If you change anything about how
767 stty parses options, be sure it still works with combinations of
768 short and long options, --, POSIXLY_CORRECT, etc. */
770 while ((optc = getopt_long (argc - argi, argv + argi, "-agF:",
777 verbose_output = true;
782 recoverable_output = true;
783 output_type = recoverable;
788 error (EXIT_FAILURE, 0, _("only one device may be specified"));
792 case_GETOPT_HELP_CHAR;
794 case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
799 /* Skip the argument containing this unrecognized option;
800 the 2nd pass will analyze it. */
803 /* Restart getopt_long from the first unskipped argument. */
810 /* Clear fully-parsed arguments, so they don't confuse the 2nd pass. */
811 while (opti < optind)
812 argv[argi + opti++] = NULL;
815 /* Specifying both -a and -g gets an error. */
816 if (verbose_output && recoverable_output)
817 error (EXIT_FAILURE, 0,
818 _("the options for verbose and stty-readable output styles are\n"
819 "mutually exclusive"));
821 /* Specifying any other arguments with -a or -g gets an error. */
822 if (!noargs && (verbose_output || recoverable_output))
823 error (EXIT_FAILURE, 0,
824 _("when specifying an output style, modes may not be set"));
826 /* FIXME: it'd be better not to open the file until we've verified
827 that all arguments are valid. Otherwise, we could end up doing
828 only some of the requested operations and then failing, probably
829 leaving things in an undesirable state. */
834 device_name = file_name;
835 if (fd_reopen (STDIN_FILENO, device_name, O_RDONLY | O_NONBLOCK, 0) < 0)
836 error (EXIT_FAILURE, errno, "%s", device_name);
837 if ((fdflags = fcntl (STDIN_FILENO, F_GETFL)) == -1
838 || fcntl (STDIN_FILENO, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
839 error (EXIT_FAILURE, errno, _("%s: couldn't reset non-blocking mode"),
843 device_name = _("standard input");
845 if (tcgetattr (STDIN_FILENO, &mode))
846 error (EXIT_FAILURE, errno, "%s", device_name);
848 if (verbose_output || recoverable_output || noargs)
850 max_col = screen_columns ();
852 display_settings (output_type, &mode, device_name);
856 speed_was_set = false;
857 require_set_attr = false;
858 for (k = 1; k < argc; k++)
860 char const *arg = argv[k];
861 bool match_found = false;
862 bool reversed = false;
873 for (i = 0; mode_info[i].name != NULL; ++i)
875 if (STREQ (arg, mode_info[i].name))
877 match_found = set_mode (&mode_info[i], reversed, &mode);
878 require_set_attr = true;
882 if (!match_found && reversed)
884 error (0, 0, _("invalid argument %s"), quote (arg - 1));
885 usage (EXIT_FAILURE);
889 for (i = 0; control_info[i].name != NULL; ++i)
891 if (STREQ (arg, control_info[i].name))
895 error (0, 0, _("missing argument to %s"), quote (arg));
896 usage (EXIT_FAILURE);
900 set_control_char (&control_info[i], argv[k], &mode);
901 require_set_attr = true;
908 if (STREQ (arg, "ispeed"))
912 error (0, 0, _("missing argument to %s"), quote (arg));
913 usage (EXIT_FAILURE);
916 set_speed (input_speed, argv[k], &mode);
917 speed_was_set = true;
918 require_set_attr = true;
920 else if (STREQ (arg, "ospeed"))
924 error (0, 0, _("missing argument to %s"), quote (arg));
925 usage (EXIT_FAILURE);
928 set_speed (output_speed, argv[k], &mode);
929 speed_was_set = true;
930 require_set_attr = true;
933 else if (STREQ (arg, "rows"))
937 error (0, 0, _("missing argument to %s"), quote (arg));
938 usage (EXIT_FAILURE);
941 set_window_size (integer_arg (argv[k], INT_MAX), -1,
944 else if (STREQ (arg, "cols")
945 || STREQ (arg, "columns"))
949 error (0, 0, _("missing argument to %s"), quote (arg));
950 usage (EXIT_FAILURE);
953 set_window_size (-1, integer_arg (argv[k], INT_MAX),
956 else if (STREQ (arg, "size"))
958 max_col = screen_columns ();
960 display_window_size (false, device_name);
964 else if (STREQ (arg, "line"))
966 unsigned long int value;
969 error (0, 0, _("missing argument to %s"), quote (arg));
970 usage (EXIT_FAILURE);
973 mode.c_line = value = integer_arg (argv[k], ULONG_MAX);
974 if (mode.c_line != value)
975 error (0, 0, _("invalid line discipline %s"), quote (argv[k]));
976 require_set_attr = true;
979 else if (STREQ (arg, "speed"))
981 max_col = screen_columns ();
982 display_speed (&mode, false);
984 else if (string_to_baud (arg) != (speed_t) -1)
986 set_speed (both_speeds, arg, &mode);
987 speed_was_set = true;
988 require_set_attr = true;
992 if (! recover_mode (arg, &mode))
994 error (0, 0, _("invalid argument %s"), quote (arg));
995 usage (EXIT_FAILURE);
997 require_set_attr = true;
1002 if (require_set_attr)
1004 /* Initialize to all zeroes so there is no risk memcmp will report a
1005 spurious difference in an uninitialized portion of the structure. */
1006 static struct termios new_mode;
1008 if (tcsetattr (STDIN_FILENO, TCSADRAIN, &mode))
1009 error (EXIT_FAILURE, errno, "%s", device_name);
1011 /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
1012 it performs *any* of the requested operations. This means it
1013 can report 'success' when it has actually failed to perform
1014 some proper subset of the requested operations. To detect
1015 this partial failure, get the current terminal attributes and
1016 compare them to the requested ones. */
1018 if (tcgetattr (STDIN_FILENO, &new_mode))
1019 error (EXIT_FAILURE, errno, "%s", device_name);
1021 /* Normally, one shouldn't use memcmp to compare structures that
1022 may have 'holes' containing uninitialized data, but we have been
1023 careful to initialize the storage of these two variables to all
1024 zeroes. One might think it more efficient simply to compare the
1025 modified fields, but that would require enumerating those fields --
1026 and not all systems have the same fields in this structure. */
1028 if (memcmp (&mode, &new_mode, sizeof (mode)) != 0)
1031 /* SunOS 4.1.3 (at least) has the problem that after this sequence,
1032 tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
1033 sometimes (m1 != m2). The only difference is in the four bits
1034 of the c_cflag field corresponding to the baud rate. To save
1035 Sun users a little confusion, don't report an error if this
1036 happens. But suppress the error only if we haven't tried to
1037 set the baud rate explicitly -- otherwise we'd never give an
1038 error for a true failure to set the baud rate. */
1040 new_mode.c_cflag &= (~CIBAUD);
1041 if (speed_was_set || memcmp (&mode, &new_mode, sizeof (mode)) != 0)
1044 error (EXIT_FAILURE, 0,
1045 _("%s: unable to perform all requested operations"),
1050 printf ("new_mode: mode\n");
1051 for (i = 0; i < sizeof (new_mode); i++)
1052 printf ("0x%02x: 0x%02x\n",
1053 *(((unsigned char *) &new_mode) + i),
1054 *(((unsigned char *) &mode) + i));
1061 exit (EXIT_SUCCESS);
1064 /* Return false if not applied because not reversible; otherwise
1068 set_mode (struct mode_info const *info, bool reversed, struct termios *mode)
1072 if (reversed && (info->flags & REV) == 0)
1075 bitsp = mode_type_flag (info->type, mode);
1079 /* Combination mode. */
1080 if (STREQ (info->name, "evenp") || STREQ (info->name, "parity"))
1083 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1085 mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
1087 else if (STREQ (info->name, "oddp"))
1090 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1092 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
1094 else if (STREQ (info->name, "nl"))
1098 mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
1099 mode->c_oflag = (mode->c_oflag
1114 mode->c_iflag = mode->c_iflag & ~ICRNL;
1116 mode->c_oflag = mode->c_oflag & ~ONLCR;
1120 else if (STREQ (info->name, "ek"))
1122 mode->c_cc[VERASE] = CERASE;
1123 mode->c_cc[VKILL] = CKILL;
1125 else if (STREQ (info->name, "sane"))
1127 else if (STREQ (info->name, "cbreak"))
1130 mode->c_lflag |= ICANON;
1132 mode->c_lflag &= ~ICANON;
1134 else if (STREQ (info->name, "pass8"))
1138 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1139 mode->c_iflag |= ISTRIP;
1143 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1144 mode->c_iflag &= ~ISTRIP;
1147 else if (STREQ (info->name, "litout"))
1151 mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1152 mode->c_iflag |= ISTRIP;
1153 mode->c_oflag |= OPOST;
1157 mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1158 mode->c_iflag &= ~ISTRIP;
1159 mode->c_oflag &= ~OPOST;
1162 else if (STREQ (info->name, "raw") || STREQ (info->name, "cooked"))
1164 if ((info->name[0] == 'r' && reversed)
1165 || (info->name[0] == 'c' && !reversed))
1168 mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1169 mode->c_oflag |= OPOST;
1170 mode->c_lflag |= ISIG | ICANON;
1172 mode->c_cc[VEOF] = CEOF;
1175 mode->c_cc[VEOL] = CEOL;
1182 mode->c_oflag &= ~OPOST;
1183 mode->c_lflag &= ~(ISIG | ICANON
1188 mode->c_cc[VMIN] = 1;
1189 mode->c_cc[VTIME] = 0;
1193 else if (STREQ (info->name, "decctlq"))
1196 mode->c_iflag |= IXANY;
1198 mode->c_iflag &= ~IXANY;
1202 else if (STREQ (info->name, "tabs"))
1205 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1207 mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1211 else if (STREQ (info->name, "tabs"))
1214 mode->c_oflag = mode->c_oflag | OXTABS;
1216 mode->c_oflag = mode->c_oflag & ~OXTABS;
1220 #if defined XCASE && defined IUCLC && defined OLCUC
1221 else if (STREQ (info->name, "lcase")
1222 || STREQ (info->name, "LCASE"))
1226 mode->c_lflag &= ~XCASE;
1227 mode->c_iflag &= ~IUCLC;
1228 mode->c_oflag &= ~OLCUC;
1232 mode->c_lflag |= XCASE;
1233 mode->c_iflag |= IUCLC;
1234 mode->c_oflag |= OLCUC;
1238 else if (STREQ (info->name, "crt"))
1239 mode->c_lflag |= ECHOE
1247 else if (STREQ (info->name, "dec"))
1249 mode->c_cc[VINTR] = 3; /* ^C */
1250 mode->c_cc[VERASE] = 127; /* DEL */
1251 mode->c_cc[VKILL] = 21; /* ^U */
1252 mode->c_lflag |= ECHOE
1261 mode->c_iflag &= ~IXANY;
1266 *bitsp = *bitsp & ~info->mask & ~info->bits;
1268 *bitsp = (*bitsp & ~info->mask) | info->bits;
1274 set_control_char (struct control_info const *info, const char *arg,
1275 struct termios *mode)
1277 unsigned long int value;
1279 if (STREQ (info->name, "min") || STREQ (info->name, "time"))
1280 value = integer_arg (arg, TYPE_MAXIMUM (cc_t));
1281 else if (arg[0] == '\0' || arg[1] == '\0')
1282 value = to_uchar (arg[0]);
1283 else if (STREQ (arg, "^-") || STREQ (arg, "undef"))
1284 value = _POSIX_VDISABLE;
1285 else if (arg[0] == '^' && arg[1] != '\0') /* Ignore any trailing junk. */
1290 value = to_uchar (arg[1]) & ~0140; /* Non-letters get weird results. */
1293 value = integer_arg (arg, TYPE_MAXIMUM (cc_t));
1294 mode->c_cc[info->offset] = value;
1298 set_speed (enum speed_setting type, const char *arg, struct termios *mode)
1302 baud = string_to_baud (arg);
1303 if (type == input_speed || type == both_speeds)
1304 cfsetispeed (mode, baud);
1305 if (type == output_speed || type == both_speeds)
1306 cfsetospeed (mode, baud);
1312 get_win_size (int fd, struct winsize *win)
1314 int err = ioctl (fd, TIOCGWINSZ, (char *) win);
1319 set_window_size (int rows, int cols, char const *device_name)
1323 if (get_win_size (STDIN_FILENO, &win))
1325 if (errno != EINVAL)
1326 error (EXIT_FAILURE, errno, "%s", device_name);
1327 memset (&win, 0, sizeof (win));
1336 /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
1337 The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
1338 This comment from sys/ttold.h describes Sun's twisted logic - a better
1339 test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
1340 At any rate, the problem is gone in Solaris 2.x.
1342 Unfortunately, the old TIOCSSIZE code does collide with TIOCSWINSZ,
1343 but they can be disambiguated by checking whether a "struct ttysize"
1344 structure's "ts_lines" field is greater than 64K or not. If so,
1345 it's almost certainly a "struct winsize" instead.
1347 At any rate, the bug manifests itself when ws_row == 0; the symptom is
1348 that ws_row is set to ws_col, and ws_col is set to (ws_xpixel<<16)
1349 + ws_ypixel. Since GNU stty sets rows and columns separately, this bug
1350 caused "stty rows 0 cols 0" to set rows to cols and cols to 0, while
1351 "stty cols 0 rows 0" would do the right thing. On a little-endian
1352 machine like the sun386i, the problem is the same, but for ws_col == 0.
1354 The workaround is to do the ioctl once with row and col = 1 to set the
1355 pixel info, and then do it again using a TIOCSSIZE to set rows/cols. */
1357 if (win.ws_row == 0 || win.ws_col == 0)
1359 struct ttysize ttysz;
1361 ttysz.ts_lines = win.ws_row;
1362 ttysz.ts_cols = win.ws_col;
1367 if (ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win))
1368 error (EXIT_FAILURE, errno, "%s", device_name);
1370 if (ioctl (STDIN_FILENO, TIOCSSIZE, (char *) &ttysz))
1371 error (EXIT_FAILURE, errno, "%s", device_name);
1376 if (ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win))
1377 error (EXIT_FAILURE, errno, "%s", device_name);
1381 display_window_size (bool fancy, char const *device_name)
1385 if (get_win_size (STDIN_FILENO, &win))
1387 if (errno != EINVAL)
1388 error (EXIT_FAILURE, errno, "%s", device_name);
1390 error (EXIT_FAILURE, 0,
1391 _("%s: no size information for this device"), device_name);
1395 wrapf (fancy ? "rows %d; columns %d;" : "%d %d\n",
1396 win.ws_row, win.ws_col);
1404 screen_columns (void)
1409 /* With Solaris 2.[123], this ioctl fails and errno is set to
1410 EINVAL for telnet (but not rlogin) sessions.
1411 On ISC 3.0, it fails for the console and the serial port
1412 (but it works for ptys).
1413 It can also fail on any system when stdout isn't a tty.
1414 In case of any failure, just use the default. */
1415 if (get_win_size (STDOUT_FILENO, &win) == 0 && 0 < win.ws_col)
1419 /* Use $COLUMNS if it's in [1..INT_MAX]. */
1420 char *col_string = getenv ("COLUMNS");
1422 if (!(col_string != NULL
1423 && xstrtol (col_string, NULL, 0, &n_columns, "") == LONGINT_OK
1425 && n_columns <= INT_MAX))
1431 static tcflag_t * _GL_ATTRIBUTE_PURE
1432 mode_type_flag (enum mode_type type, struct termios *mode)
1437 return &mode->c_cflag;
1440 return &mode->c_iflag;
1443 return &mode->c_oflag;
1446 return &mode->c_lflag;
1457 display_settings (enum output_type output_type, struct termios *mode,
1458 char const *device_name)
1460 switch (output_type)
1463 display_changed (mode);
1467 display_all (mode, device_name);
1471 display_recoverable (mode);
1477 display_changed (struct termios *mode)
1483 enum mode_type prev_type = control;
1485 display_speed (mode, true);
1487 wrapf ("line = %d;", mode->c_line);
1493 for (i = 0; !STREQ (control_info[i].name, "min"); ++i)
1495 if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
1497 /* If swtch is the same as susp, don't print both. */
1499 if (STREQ (control_info[i].name, "swtch"))
1502 /* If eof uses the same slot as min, only print whichever applies. */
1504 if ((mode->c_lflag & ICANON) == 0
1505 && (STREQ (control_info[i].name, "eof")
1506 || STREQ (control_info[i].name, "eol")))
1511 wrapf ("%s = %s;", control_info[i].name,
1512 visible (mode->c_cc[control_info[i].offset]));
1514 if ((mode->c_lflag & ICANON) == 0)
1516 wrapf ("min = %lu; time = %lu;\n",
1517 (unsigned long int) mode->c_cc[VMIN],
1518 (unsigned long int) mode->c_cc[VTIME]);
1520 else if (!empty_line)
1525 for (i = 0; mode_info[i].name != NULL; ++i)
1527 if (mode_info[i].flags & OMIT)
1529 if (mode_info[i].type != prev_type)
1537 prev_type = mode_info[i].type;
1540 bitsp = mode_type_flag (mode_info[i].type, mode);
1541 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1543 /* bitsp would be NULL only for "combination" modes, yet those
1544 are filtered out above via the OMIT flag. Tell static analysis
1545 tools that it's ok to dereference bitsp here. */
1548 if ((*bitsp & mask) == mode_info[i].bits)
1550 if (mode_info[i].flags & SANE_UNSET)
1552 wrapf ("%s", mode_info[i].name);
1556 else if ((mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
1558 wrapf ("-%s", mode_info[i].name);
1568 display_all (struct termios *mode, char const *device_name)
1573 enum mode_type prev_type = control;
1575 display_speed (mode, true);
1577 display_window_size (true, device_name);
1580 wrapf ("line = %d;", mode->c_line);
1585 for (i = 0; ! STREQ (control_info[i].name, "min"); ++i)
1587 /* If swtch is the same as susp, don't print both. */
1589 if (STREQ (control_info[i].name, "swtch"))
1592 /* If eof uses the same slot as min, only print whichever applies. */
1594 if ((mode->c_lflag & ICANON) == 0
1595 && (STREQ (control_info[i].name, "eof")
1596 || STREQ (control_info[i].name, "eol")))
1599 wrapf ("%s = %s;", control_info[i].name,
1600 visible (mode->c_cc[control_info[i].offset]));
1603 if ((mode->c_lflag & ICANON) == 0)
1605 wrapf ("min = %lu; time = %lu;",
1606 (unsigned long int) mode->c_cc[VMIN],
1607 (unsigned long int) mode->c_cc[VTIME]);
1608 if (current_col != 0)
1612 for (i = 0; mode_info[i].name != NULL; ++i)
1614 if (mode_info[i].flags & OMIT)
1616 if (mode_info[i].type != prev_type)
1620 prev_type = mode_info[i].type;
1623 bitsp = mode_type_flag (mode_info[i].type, mode);
1624 mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1625 assert (bitsp); /* See the identical assertion and comment above. */
1626 if ((*bitsp & mask) == mode_info[i].bits)
1627 wrapf ("%s", mode_info[i].name);
1628 else if (mode_info[i].flags & REV)
1629 wrapf ("-%s", mode_info[i].name);
1636 display_speed (struct termios *mode, bool fancy)
1638 if (cfgetispeed (mode) == 0 || cfgetispeed (mode) == cfgetospeed (mode))
1639 wrapf (fancy ? "speed %lu baud;" : "%lu\n",
1640 baud_to_value (cfgetospeed (mode)));
1642 wrapf (fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n",
1643 baud_to_value (cfgetispeed (mode)),
1644 baud_to_value (cfgetospeed (mode)));
1650 display_recoverable (struct termios *mode)
1654 printf ("%lx:%lx:%lx:%lx",
1655 (unsigned long int) mode->c_iflag,
1656 (unsigned long int) mode->c_oflag,
1657 (unsigned long int) mode->c_cflag,
1658 (unsigned long int) mode->c_lflag);
1659 for (i = 0; i < NCCS; ++i)
1660 printf (":%lx", (unsigned long int) mode->c_cc[i]);
1664 /* NOTE: identical to below, modulo use of tcflag_t */
1666 strtoul_tcflag_t (char const *s, int base, char **p, tcflag_t *result,
1671 ul = strtoul (s, p, base);
1672 if (errno || **p != delim || *p == s || (tcflag_t) ul != ul)
1678 /* NOTE: identical to above, modulo use of cc_t */
1680 strtoul_cc_t (char const *s, int base, char **p, cc_t *result, char delim)
1684 ul = strtoul (s, p, base);
1685 if (errno || **p != delim || *p == s || (cc_t) ul != ul)
1691 /* Parse the output of display_recoverable.
1692 Return false if any part of it is invalid. */
1694 recover_mode (char const *arg, struct termios *mode)
1697 char const *s = arg;
1699 for (i = 0; i < 4; i++)
1702 if (strtoul_tcflag_t (s, 16, &p, flag + i, ':') != 0)
1706 mode->c_iflag = flag[0];
1707 mode->c_oflag = flag[1];
1708 mode->c_cflag = flag[2];
1709 mode->c_lflag = flag[3];
1711 for (i = 0; i < NCCS; ++i)
1714 char delim = i < NCCS - 1 ? ':' : '\0';
1715 if (strtoul_cc_t (s, 16, &p, mode->c_cc + i, delim) != 0)
1725 const char *string; /* ASCII representation. */
1726 speed_t speed; /* Internal form. */
1727 unsigned long int value; /* Numeric value. */
1730 static struct speed_map const speeds[] =
1737 {"134.5", B134, 134},
1742 {"1200", B1200, 1200},
1743 {"1800", B1800, 1800},
1744 {"2400", B2400, 2400},
1745 {"4800", B4800, 4800},
1746 {"9600", B9600, 9600},
1747 {"19200", B19200, 19200},
1748 {"38400", B38400, 38400},
1749 {"exta", B19200, 19200},
1750 {"extb", B38400, 38400},
1752 {"57600", B57600, 57600},
1755 {"115200", B115200, 115200},
1758 {"230400", B230400, 230400},
1761 {"460800", B460800, 460800},
1764 {"500000", B500000, 500000},
1767 {"576000", B576000, 576000},
1770 {"921600", B921600, 921600},
1773 {"1000000", B1000000, 1000000},
1776 {"1152000", B1152000, 1152000},
1779 {"1500000", B1500000, 1500000},
1782 {"2000000", B2000000, 2000000},
1785 {"2500000", B2500000, 2500000},
1788 {"3000000", B3000000, 3000000},
1791 {"3500000", B3500000, 3500000},
1794 {"4000000", B4000000, 4000000},
1799 static speed_t _GL_ATTRIBUTE_PURE
1800 string_to_baud (const char *arg)
1804 for (i = 0; speeds[i].string != NULL; ++i)
1805 if (STREQ (arg, speeds[i].string))
1806 return speeds[i].speed;
1807 return (speed_t) -1;
1810 static unsigned long int _GL_ATTRIBUTE_PURE
1811 baud_to_value (speed_t speed)
1815 for (i = 0; speeds[i].string != NULL; ++i)
1816 if (speed == speeds[i].speed)
1817 return speeds[i].value;
1822 sane_mode (struct termios *mode)
1827 for (i = 0; control_info[i].name; ++i)
1830 if (STREQ (control_info[i].name, "min"))
1833 mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1836 for (i = 0; mode_info[i].name != NULL; ++i)
1838 if (mode_info[i].flags & SANE_SET)
1840 bitsp = mode_type_flag (mode_info[i].type, mode);
1841 *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits;
1843 else if (mode_info[i].flags & SANE_UNSET)
1845 bitsp = mode_type_flag (mode_info[i].type, mode);
1846 *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits;
1851 /* Return a string that is the printable representation of character CH. */
1852 /* Adapted from 'cat' by Torbjorn Granlund. */
1857 static char buf[10];
1860 if (ch == _POSIX_VDISABLE)
1879 *bpout++ = ch - 128;
1889 *bpout++ = ch - 128 + 64;
1899 return (const char *) buf;
1902 /* Parse string S as an integer, using decimal radix by default,
1903 but allowing octal and hex numbers as in C. Reject values
1904 larger than MAXVAL. */
1906 static unsigned long int
1907 integer_arg (const char *s, unsigned long int maxval)
1909 unsigned long int value;
1910 if (xstrtoul (s, NULL, 0, &value, "bB") != LONGINT_OK || maxval < value)
1912 error (0, 0, _("invalid integer argument %s"), quote (s));
1913 usage (EXIT_FAILURE);