Line data Source code
1 : /* stty -- change and print terminal line settings
2 : Copyright (C) 1990-2005, 2007 Free Software Foundation, Inc.
3 :
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.
8 :
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.
13 :
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/>. */
16 :
17 : /* Usage: stty [-ag] [--all] [--save] [-F device] [--file=device] [setting...]
18 :
19 : Options:
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
23 :
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.
27 :
28 : David MacKenzie <djm@gnu.ai.mit.edu> */
29 :
30 : #include <config.h>
31 :
32 : #ifdef TERMIOS_NEEDS_XOPEN_SOURCE
33 : # define _XOPEN_SOURCE
34 : #endif
35 :
36 : #include <stdio.h>
37 : #include <sys/types.h>
38 :
39 : #if HAVE_TERMIOS_H
40 : # include <termios.h>
41 : #endif
42 : #if HAVE_STROPTS_H
43 : # include <stropts.h>
44 : #endif
45 : #ifdef HAVE_SYS_IOCTL_H
46 : # include <sys/ioctl.h>
47 : #endif
48 :
49 : #ifdef WINSIZE_IN_PTEM
50 : # include <sys/stream.h>
51 : # include <sys/ptem.h>
52 : #endif
53 : #ifdef GWINSZ_IN_SYS_PTY
54 : # include <sys/tty.h>
55 : # include <sys/pty.h>
56 : #endif
57 : #include <getopt.h>
58 : #include <stdarg.h>
59 :
60 : #include "system.h"
61 : #include "error.h"
62 : #include "fd-reopen.h"
63 : #include "quote.h"
64 : #include "xstrtol.h"
65 :
66 : /* The official name of this program (e.g., no `g' prefix). */
67 : #define PROGRAM_NAME "stty"
68 :
69 : #define AUTHORS "David MacKenzie"
70 :
71 : #ifndef _POSIX_VDISABLE
72 : # define _POSIX_VDISABLE 0
73 : #endif
74 :
75 : #define Control(c) ((c) & 0x1f)
76 : /* Canonical values for control characters. */
77 : #ifndef CINTR
78 : # define CINTR Control ('c')
79 : #endif
80 : #ifndef CQUIT
81 : # define CQUIT 28
82 : #endif
83 : #ifndef CERASE
84 : # define CERASE 127
85 : #endif
86 : #ifndef CKILL
87 : # define CKILL Control ('u')
88 : #endif
89 : #ifndef CEOF
90 : # define CEOF Control ('d')
91 : #endif
92 : #ifndef CEOL
93 : # define CEOL _POSIX_VDISABLE
94 : #endif
95 : #ifndef CSTART
96 : # define CSTART Control ('q')
97 : #endif
98 : #ifndef CSTOP
99 : # define CSTOP Control ('s')
100 : #endif
101 : #ifndef CSUSP
102 : # define CSUSP Control ('z')
103 : #endif
104 : #if defined VEOL2 && !defined CEOL2
105 : # define CEOL2 _POSIX_VDISABLE
106 : #endif
107 : /* Some platforms have VSWTC, others VSWTCH. In both cases, this control
108 : character is initialized by CSWTCH, if present. */
109 : #if defined VSWTC && !defined VSWTCH
110 : # define VSWTCH VSWTC
111 : #endif
112 : /* ISC renamed swtch to susp for termios, but we'll accept either name. */
113 : #if defined VSUSP && !defined VSWTCH
114 : # define VSWTCH VSUSP
115 : # if defined CSUSP && !defined CSWTCH
116 : # define CSWTCH CSUSP
117 : # endif
118 : #endif
119 : #if defined VSWTCH && !defined CSWTCH
120 : # define CSWTCH _POSIX_VDISABLE
121 : #endif
122 :
123 : /* SunOS 5.3 loses (^Z doesn't work) if `swtch' is the same as `susp'.
124 : So the default is to disable `swtch.' */
125 : #if defined __sparc__ && defined __svr4__
126 : # undef CSWTCH
127 : # define CSWTCH _POSIX_VDISABLE
128 : #endif
129 :
130 : #if defined VWERSE && !defined VWERASE /* AIX-3.2.5 */
131 : # define VWERASE VWERSE
132 : #endif
133 : #if defined VDSUSP && !defined CDSUSP
134 : # define CDSUSP Control ('y')
135 : #endif
136 : #if !defined VREPRINT && defined VRPRNT /* Irix 4.0.5 */
137 : # define VREPRINT VRPRNT
138 : #endif
139 : #if defined VREPRINT && !defined CRPRNT
140 : # define CRPRNT Control ('r')
141 : #endif
142 : #if defined CREPRINT && !defined CRPRNT
143 : # define CRPRNT Control ('r')
144 : #endif
145 : #if defined VWERASE && !defined CWERASE
146 : # define CWERASE Control ('w')
147 : #endif
148 : #if defined VLNEXT && !defined CLNEXT
149 : # define CLNEXT Control ('v')
150 : #endif
151 : #if defined VDISCARD && !defined VFLUSHO
152 : # define VFLUSHO VDISCARD
153 : #endif
154 : #if defined VFLUSH && !defined VFLUSHO /* Ultrix 4.2 */
155 : # define VFLUSHO VFLUSH
156 : #endif
157 : #if defined CTLECH && !defined ECHOCTL /* Ultrix 4.3 */
158 : # define ECHOCTL CTLECH
159 : #endif
160 : #if defined TCTLECH && !defined ECHOCTL /* Ultrix 4.2 */
161 : # define ECHOCTL TCTLECH
162 : #endif
163 : #if defined CRTKIL && !defined ECHOKE /* Ultrix 4.2 and 4.3 */
164 : # define ECHOKE CRTKIL
165 : #endif
166 : #if defined VFLUSHO && !defined CFLUSHO
167 : # define CFLUSHO Control ('o')
168 : #endif
169 : #if defined VSTATUS && !defined CSTATUS
170 : # define CSTATUS Control ('t')
171 : #endif
172 :
173 : /* Which speeds to set. */
174 : enum speed_setting
175 : {
176 : input_speed, output_speed, both_speeds
177 : };
178 :
179 : /* What to output and how. */
180 : enum output_type
181 : {
182 : changed, all, recoverable /* Default, -a, -g. */
183 : };
184 :
185 : /* Which member(s) of `struct termios' a mode uses. */
186 : enum mode_type
187 : {
188 : control, input, output, local, combination
189 : };
190 :
191 : /* Flags for `struct mode_info'. */
192 : #define SANE_SET 1 /* Set in `sane' mode. */
193 : #define SANE_UNSET 2 /* Unset in `sane' mode. */
194 : #define REV 4 /* Can be turned off by prepending `-'. */
195 : #define OMIT 8 /* Don't display value. */
196 :
197 : /* Each mode. */
198 : struct mode_info
199 : {
200 : const char *name; /* Name given on command line. */
201 : enum mode_type type; /* Which structure element to change. */
202 : char flags; /* Setting and display options. */
203 : unsigned long bits; /* Bits to set for this mode. */
204 : unsigned long mask; /* Other bits to turn off for this mode. */
205 : };
206 :
207 : static struct mode_info mode_info[] =
208 : {
209 : {"parenb", control, REV, PARENB, 0},
210 : {"parodd", control, REV, PARODD, 0},
211 : {"cs5", control, 0, CS5, CSIZE},
212 : {"cs6", control, 0, CS6, CSIZE},
213 : {"cs7", control, 0, CS7, CSIZE},
214 : {"cs8", control, 0, CS8, CSIZE},
215 : {"hupcl", control, REV, HUPCL, 0},
216 : {"hup", control, REV | OMIT, HUPCL, 0},
217 : {"cstopb", control, REV, CSTOPB, 0},
218 : {"cread", control, SANE_SET | REV, CREAD, 0},
219 : {"clocal", control, REV, CLOCAL, 0},
220 : #ifdef CRTSCTS
221 : {"crtscts", control, REV, CRTSCTS, 0},
222 : #endif
223 :
224 : {"ignbrk", input, SANE_UNSET | REV, IGNBRK, 0},
225 : {"brkint", input, SANE_SET | REV, BRKINT, 0},
226 : {"ignpar", input, REV, IGNPAR, 0},
227 : {"parmrk", input, REV, PARMRK, 0},
228 : {"inpck", input, REV, INPCK, 0},
229 : {"istrip", input, REV, ISTRIP, 0},
230 : {"inlcr", input, SANE_UNSET | REV, INLCR, 0},
231 : {"igncr", input, SANE_UNSET | REV, IGNCR, 0},
232 : {"icrnl", input, SANE_SET | REV, ICRNL, 0},
233 : {"ixon", input, REV, IXON, 0},
234 : {"ixoff", input, SANE_UNSET | REV, IXOFF, 0},
235 : {"tandem", input, REV | OMIT, IXOFF, 0},
236 : #ifdef IUCLC
237 : {"iuclc", input, SANE_UNSET | REV, IUCLC, 0},
238 : #endif
239 : #ifdef IXANY
240 : {"ixany", input, SANE_UNSET | REV, IXANY, 0},
241 : #endif
242 : #ifdef IMAXBEL
243 : {"imaxbel", input, SANE_SET | REV, IMAXBEL, 0},
244 : #endif
245 : #ifdef IUTF8
246 : {"iutf8", input, SANE_UNSET | REV, IUTF8, 0},
247 : #endif
248 :
249 : {"opost", output, SANE_SET | REV, OPOST, 0},
250 : #ifdef OLCUC
251 : {"olcuc", output, SANE_UNSET | REV, OLCUC, 0},
252 : #endif
253 : #ifdef OCRNL
254 : {"ocrnl", output, SANE_UNSET | REV, OCRNL, 0},
255 : #endif
256 : #ifdef ONLCR
257 : {"onlcr", output, SANE_SET | REV, ONLCR, 0},
258 : #endif
259 : #ifdef ONOCR
260 : {"onocr", output, SANE_UNSET | REV, ONOCR, 0},
261 : #endif
262 : #ifdef ONLRET
263 : {"onlret", output, SANE_UNSET | REV, ONLRET, 0},
264 : #endif
265 : #ifdef OFILL
266 : {"ofill", output, SANE_UNSET | REV, OFILL, 0},
267 : #endif
268 : #ifdef OFDEL
269 : {"ofdel", output, SANE_UNSET | REV, OFDEL, 0},
270 : #endif
271 : #ifdef NLDLY
272 : {"nl1", output, SANE_UNSET, NL1, NLDLY},
273 : {"nl0", output, SANE_SET, NL0, NLDLY},
274 : #endif
275 : #ifdef CRDLY
276 : {"cr3", output, SANE_UNSET, CR3, CRDLY},
277 : {"cr2", output, SANE_UNSET, CR2, CRDLY},
278 : {"cr1", output, SANE_UNSET, CR1, CRDLY},
279 : {"cr0", output, SANE_SET, CR0, CRDLY},
280 : #endif
281 : #ifdef TABDLY
282 : {"tab3", output, SANE_UNSET, TAB3, TABDLY},
283 : {"tab2", output, SANE_UNSET, TAB2, TABDLY},
284 : {"tab1", output, SANE_UNSET, TAB1, TABDLY},
285 : {"tab0", output, SANE_SET, TAB0, TABDLY},
286 : #else
287 : # ifdef OXTABS
288 : {"tab3", output, SANE_UNSET, OXTABS, 0},
289 : # endif
290 : #endif
291 : #ifdef BSDLY
292 : {"bs1", output, SANE_UNSET, BS1, BSDLY},
293 : {"bs0", output, SANE_SET, BS0, BSDLY},
294 : #endif
295 : #ifdef VTDLY
296 : {"vt1", output, SANE_UNSET, VT1, VTDLY},
297 : {"vt0", output, SANE_SET, VT0, VTDLY},
298 : #endif
299 : #ifdef FFDLY
300 : {"ff1", output, SANE_UNSET, FF1, FFDLY},
301 : {"ff0", output, SANE_SET, FF0, FFDLY},
302 : #endif
303 :
304 : {"isig", local, SANE_SET | REV, ISIG, 0},
305 : {"icanon", local, SANE_SET | REV, ICANON, 0},
306 : #ifdef IEXTEN
307 : {"iexten", local, SANE_SET | REV, IEXTEN, 0},
308 : #endif
309 : {"echo", local, SANE_SET | REV, ECHO, 0},
310 : {"echoe", local, SANE_SET | REV, ECHOE, 0},
311 : {"crterase", local, REV | OMIT, ECHOE, 0},
312 : {"echok", local, SANE_SET | REV, ECHOK, 0},
313 : {"echonl", local, SANE_UNSET | REV, ECHONL, 0},
314 : {"noflsh", local, SANE_UNSET | REV, NOFLSH, 0},
315 : #ifdef XCASE
316 : {"xcase", local, SANE_UNSET | REV, XCASE, 0},
317 : #endif
318 : #ifdef TOSTOP
319 : {"tostop", local, SANE_UNSET | REV, TOSTOP, 0},
320 : #endif
321 : #ifdef ECHOPRT
322 : {"echoprt", local, SANE_UNSET | REV, ECHOPRT, 0},
323 : {"prterase", local, REV | OMIT, ECHOPRT, 0},
324 : #endif
325 : #ifdef ECHOCTL
326 : {"echoctl", local, SANE_SET | REV, ECHOCTL, 0},
327 : {"ctlecho", local, REV | OMIT, ECHOCTL, 0},
328 : #endif
329 : #ifdef ECHOKE
330 : {"echoke", local, SANE_SET | REV, ECHOKE, 0},
331 : {"crtkill", local, REV | OMIT, ECHOKE, 0},
332 : #endif
333 :
334 : {"evenp", combination, REV | OMIT, 0, 0},
335 : {"parity", combination, REV | OMIT, 0, 0},
336 : {"oddp", combination, REV | OMIT, 0, 0},
337 : {"nl", combination, REV | OMIT, 0, 0},
338 : {"ek", combination, OMIT, 0, 0},
339 : {"sane", combination, OMIT, 0, 0},
340 : {"cooked", combination, REV | OMIT, 0, 0},
341 : {"raw", combination, REV | OMIT, 0, 0},
342 : {"pass8", combination, REV | OMIT, 0, 0},
343 : {"litout", combination, REV | OMIT, 0, 0},
344 : {"cbreak", combination, REV | OMIT, 0, 0},
345 : #ifdef IXANY
346 : {"decctlq", combination, REV | OMIT, 0, 0},
347 : #endif
348 : #if defined TABDLY || defined OXTABS
349 : {"tabs", combination, REV | OMIT, 0, 0},
350 : #endif
351 : #if defined XCASE && defined IUCLC && defined OLCUC
352 : {"lcase", combination, REV | OMIT, 0, 0},
353 : {"LCASE", combination, REV | OMIT, 0, 0},
354 : #endif
355 : {"crt", combination, OMIT, 0, 0},
356 : {"dec", combination, OMIT, 0, 0},
357 :
358 : {NULL, control, 0, 0, 0}
359 : };
360 :
361 : /* Control character settings. */
362 : struct control_info
363 : {
364 : const char *name; /* Name given on command line. */
365 : cc_t saneval; /* Value to set for `stty sane'. */
366 : size_t offset; /* Offset in c_cc. */
367 : };
368 :
369 : /* Control characters. */
370 :
371 : static struct control_info control_info[] =
372 : {
373 : {"intr", CINTR, VINTR},
374 : {"quit", CQUIT, VQUIT},
375 : {"erase", CERASE, VERASE},
376 : {"kill", CKILL, VKILL},
377 : {"eof", CEOF, VEOF},
378 : {"eol", CEOL, VEOL},
379 : #ifdef VEOL2
380 : {"eol2", CEOL2, VEOL2},
381 : #endif
382 : #ifdef VSWTCH
383 : {"swtch", CSWTCH, VSWTCH},
384 : #endif
385 : {"start", CSTART, VSTART},
386 : {"stop", CSTOP, VSTOP},
387 : {"susp", CSUSP, VSUSP},
388 : #ifdef VDSUSP
389 : {"dsusp", CDSUSP, VDSUSP},
390 : #endif
391 : #ifdef VREPRINT
392 : {"rprnt", CRPRNT, VREPRINT},
393 : #else
394 : # ifdef CREPRINT /* HPUX 10.20 needs this */
395 : {"rprnt", CRPRNT, CREPRINT},
396 : # endif
397 : #endif
398 : #ifdef VWERASE
399 : {"werase", CWERASE, VWERASE},
400 : #endif
401 : #ifdef VLNEXT
402 : {"lnext", CLNEXT, VLNEXT},
403 : #endif
404 : #ifdef VFLUSHO
405 : {"flush", CFLUSHO, VFLUSHO},
406 : #endif
407 : #ifdef VSTATUS
408 : {"status", CSTATUS, VSTATUS},
409 : #endif
410 :
411 : /* These must be last because of the display routines. */
412 : {"min", 1, VMIN},
413 : {"time", 0, VTIME},
414 : {NULL, 0, 0}
415 : };
416 :
417 : static char const *visible (cc_t ch);
418 : static unsigned long int baud_to_value (speed_t speed);
419 : static bool recover_mode (char const *arg, struct termios *mode);
420 : static int screen_columns (void);
421 : static bool set_mode (struct mode_info *info, bool reversed,
422 : struct termios *mode);
423 : static unsigned long int integer_arg (const char *s, unsigned long int max);
424 : static speed_t string_to_baud (const char *arg);
425 : static tcflag_t *mode_type_flag (enum mode_type type, struct termios *mode);
426 : static void display_all (struct termios *mode, char const *device_name);
427 : static void display_changed (struct termios *mode);
428 : static void display_recoverable (struct termios *mode);
429 : static void display_settings (enum output_type output_type,
430 : struct termios *mode,
431 : const char *device_name);
432 : static void display_speed (struct termios *mode, bool fancy);
433 : static void display_window_size (bool fancy, char const *device_name);
434 : static void sane_mode (struct termios *mode);
435 : static void set_control_char (struct control_info *info,
436 : const char *arg,
437 : struct termios *mode);
438 : static void set_speed (enum speed_setting type, const char *arg,
439 : struct termios *mode);
440 : static void set_window_size (int rows, int cols, char const *device_name);
441 :
442 : /* The width of the screen, for output wrapping. */
443 : static int max_col;
444 :
445 : /* Current position, to know when to wrap. */
446 : static int current_col;
447 :
448 : static struct option longopts[] =
449 : {
450 : {"all", no_argument, NULL, 'a'},
451 : {"save", no_argument, NULL, 'g'},
452 : {"file", required_argument, NULL, 'F'},
453 : {GETOPT_HELP_OPTION_DECL},
454 : {GETOPT_VERSION_OPTION_DECL},
455 : {NULL, 0, NULL, 0}
456 : };
457 :
458 : /* The name this program was run with. */
459 : char *program_name;
460 :
461 : static void wrapf (const char *message, ...)
462 : __attribute__ ((__format__ (__printf__, 1, 2)));
463 :
464 : /* Print format string MESSAGE and optional args.
465 : Wrap to next line first if it won't fit.
466 : Print a space first unless MESSAGE will start a new line. */
467 :
468 : static void
469 597 : wrapf (const char *message,...)
470 : {
471 : va_list args;
472 : char *buf;
473 : int buflen;
474 :
475 597 : va_start (args, message);
476 597 : buflen = vasprintf (&buf, message, args);
477 597 : va_end (args);
478 :
479 597 : if (buflen < 0)
480 0 : xalloc_die ();
481 :
482 597 : if (0 < current_col)
483 : {
484 525 : if (max_col - current_col < buflen)
485 : {
486 28 : putchar ('\n');
487 28 : current_col = 0;
488 : }
489 : else
490 : {
491 497 : putchar (' ');
492 497 : current_col++;
493 : }
494 : }
495 :
496 597 : fputs (buf, stdout);
497 597 : free (buf);
498 597 : current_col += buflen;
499 597 : }
500 :
501 : void
502 45 : usage (int status)
503 : {
504 45 : if (status != EXIT_SUCCESS)
505 44 : fprintf (stderr, _("Try `%s --help' for more information.\n"),
506 : program_name);
507 : else
508 : {
509 1 : printf (_("\
510 : Usage: %s [-F DEVICE] [--file=DEVICE] [SETTING]...\n\
511 : or: %s [-F DEVICE] [--file=DEVICE] [-a|--all]\n\
512 : or: %s [-F DEVICE] [--file=DEVICE] [-g|--save]\n\
513 : "),
514 : program_name, program_name, program_name);
515 1 : fputs (_("\
516 : Print or change terminal characteristics.\n\
517 : \n\
518 : -a, --all print all current settings in human-readable form\n\
519 : -g, --save print all current settings in a stty-readable form\n\
520 : -F, --file=DEVICE open and use the specified DEVICE instead of stdin\n\
521 : "), stdout);
522 1 : fputs (HELP_OPTION_DESCRIPTION, stdout);
523 1 : fputs (VERSION_OPTION_DESCRIPTION, stdout);
524 1 : fputs (_("\
525 : \n\
526 : Optional - before SETTING indicates negation. An * marks non-POSIX\n\
527 : settings. The underlying system defines which settings are available.\n\
528 : "), stdout);
529 1 : fputs (_("\
530 : \n\
531 : Special characters:\n\
532 : * dsusp CHAR CHAR will send a terminal stop signal once input flushed\n\
533 : eof CHAR CHAR will send an end of file (terminate the input)\n\
534 : eol CHAR CHAR will end the line\n\
535 : "), stdout);
536 1 : fputs (_("\
537 : * eol2 CHAR alternate CHAR for ending the line\n\
538 : erase CHAR CHAR will erase the last character typed\n\
539 : intr CHAR CHAR will send an interrupt signal\n\
540 : kill CHAR CHAR will erase the current line\n\
541 : "), stdout);
542 1 : fputs (_("\
543 : * lnext CHAR CHAR will enter the next character quoted\n\
544 : quit CHAR CHAR will send a quit signal\n\
545 : * rprnt CHAR CHAR will redraw the current line\n\
546 : start CHAR CHAR will restart the output after stopping it\n\
547 : "), stdout);
548 1 : fputs (_("\
549 : stop CHAR CHAR will stop the output\n\
550 : susp CHAR CHAR will send a terminal stop signal\n\
551 : * swtch CHAR CHAR will switch to a different shell layer\n\
552 : * werase CHAR CHAR will erase the last word typed\n\
553 : "), stdout);
554 1 : fputs (_("\
555 : \n\
556 : Special settings:\n\
557 : N set the input and output speeds to N bauds\n\
558 : * cols N tell the kernel that the terminal has N columns\n\
559 : * columns N same as cols N\n\
560 : "), stdout);
561 1 : fputs (_("\
562 : ispeed N set the input speed to N\n\
563 : * line N use line discipline N\n\
564 : min N with -icanon, set N characters minimum for a completed read\n\
565 : ospeed N set the output speed to N\n\
566 : "), stdout);
567 1 : fputs (_("\
568 : * rows N tell the kernel that the terminal has N rows\n\
569 : * size print the number of rows and columns according to the kernel\n\
570 : speed print the terminal speed\n\
571 : time N with -icanon, set read timeout of N tenths of a second\n\
572 : "), stdout);
573 1 : fputs (_("\
574 : \n\
575 : Control settings:\n\
576 : [-]clocal disable modem control signals\n\
577 : [-]cread allow input to be received\n\
578 : * [-]crtscts enable RTS/CTS handshaking\n\
579 : csN set character size to N bits, N in [5..8]\n\
580 : "), stdout);
581 1 : fputs (_("\
582 : [-]cstopb use two stop bits per character (one with `-')\n\
583 : [-]hup send a hangup signal when the last process closes the tty\n\
584 : [-]hupcl same as [-]hup\n\
585 : [-]parenb generate parity bit in output and expect parity bit in input\n\
586 : [-]parodd set odd parity (even with `-')\n\
587 : "), stdout);
588 1 : fputs (_("\
589 : \n\
590 : Input settings:\n\
591 : [-]brkint breaks cause an interrupt signal\n\
592 : [-]icrnl translate carriage return to newline\n\
593 : [-]ignbrk ignore break characters\n\
594 : [-]igncr ignore carriage return\n\
595 : "), stdout);
596 1 : fputs (_("\
597 : [-]ignpar ignore characters with parity errors\n\
598 : * [-]imaxbel beep and do not flush a full input buffer on a character\n\
599 : [-]inlcr translate newline to carriage return\n\
600 : [-]inpck enable input parity checking\n\
601 : [-]istrip clear high (8th) bit of input characters\n\
602 : "), stdout);
603 1 : fputs (_("\
604 : * [-]iutf8 assume input characters are UTF-8 encoded\n\
605 : "), stdout);
606 1 : fputs (_("\
607 : * [-]iuclc translate uppercase characters to lowercase\n\
608 : * [-]ixany let any character restart output, not only start character\n\
609 : [-]ixoff enable sending of start/stop characters\n\
610 : [-]ixon enable XON/XOFF flow control\n\
611 : [-]parmrk mark parity errors (with a 255-0-character sequence)\n\
612 : [-]tandem same as [-]ixoff\n\
613 : "), stdout);
614 1 : fputs (_("\
615 : \n\
616 : Output settings:\n\
617 : * bsN backspace delay style, N in [0..1]\n\
618 : * crN carriage return delay style, N in [0..3]\n\
619 : * ffN form feed delay style, N in [0..1]\n\
620 : * nlN newline delay style, N in [0..1]\n\
621 : "), stdout);
622 1 : fputs (_("\
623 : * [-]ocrnl translate carriage return to newline\n\
624 : * [-]ofdel use delete characters for fill instead of null characters\n\
625 : * [-]ofill use fill (padding) characters instead of timing for delays\n\
626 : * [-]olcuc translate lowercase characters to uppercase\n\
627 : * [-]onlcr translate newline to carriage return-newline\n\
628 : * [-]onlret newline performs a carriage return\n\
629 : "), stdout);
630 1 : fputs (_("\
631 : * [-]onocr do not print carriage returns in the first column\n\
632 : [-]opost postprocess output\n\
633 : * tabN horizontal tab delay style, N in [0..3]\n\
634 : * tabs same as tab0\n\
635 : * -tabs same as tab3\n\
636 : * vtN vertical tab delay style, N in [0..1]\n\
637 : "), stdout);
638 1 : fputs (_("\
639 : \n\
640 : Local settings:\n\
641 : [-]crterase echo erase characters as backspace-space-backspace\n\
642 : * crtkill kill all line by obeying the echoprt and echoe settings\n\
643 : * -crtkill kill all line by obeying the echoctl and echok settings\n\
644 : "), stdout);
645 1 : fputs (_("\
646 : * [-]ctlecho echo control characters in hat notation (`^c')\n\
647 : [-]echo echo input characters\n\
648 : * [-]echoctl same as [-]ctlecho\n\
649 : [-]echoe same as [-]crterase\n\
650 : [-]echok echo a newline after a kill character\n\
651 : "), stdout);
652 1 : fputs (_("\
653 : * [-]echoke same as [-]crtkill\n\
654 : [-]echonl echo newline even if not echoing other characters\n\
655 : * [-]echoprt echo erased characters backward, between `\\' and '/'\n\
656 : [-]icanon enable erase, kill, werase, and rprnt special characters\n\
657 : [-]iexten enable non-POSIX special characters\n\
658 : "), stdout);
659 1 : fputs (_("\
660 : [-]isig enable interrupt, quit, and suspend special characters\n\
661 : [-]noflsh disable flushing after interrupt and quit special characters\n\
662 : * [-]prterase same as [-]echoprt\n\
663 : * [-]tostop stop background jobs that try to write to the terminal\n\
664 : * [-]xcase with icanon, escape with `\\' for uppercase characters\n\
665 : "), stdout);
666 1 : fputs (_("\
667 : \n\
668 : Combination settings:\n\
669 : * [-]LCASE same as [-]lcase\n\
670 : cbreak same as -icanon\n\
671 : -cbreak same as icanon\n\
672 : "), stdout);
673 1 : fputs (_("\
674 : cooked same as brkint ignpar istrip icrnl ixon opost isig\n\
675 : icanon, eof and eol characters to their default values\n\
676 : -cooked same as raw\n\
677 : crt same as echoe echoctl echoke\n\
678 : "), stdout);
679 1 : fputs (_("\
680 : dec same as echoe echoctl echoke -ixany intr ^c erase 0177\n\
681 : kill ^u\n\
682 : * [-]decctlq same as [-]ixany\n\
683 : ek erase and kill characters to their default values\n\
684 : evenp same as parenb -parodd cs7\n\
685 : "), stdout);
686 1 : fputs (_("\
687 : -evenp same as -parenb cs8\n\
688 : * [-]lcase same as xcase iuclc olcuc\n\
689 : litout same as -parenb -istrip -opost cs8\n\
690 : -litout same as parenb istrip opost cs7\n\
691 : nl same as -icrnl -onlcr\n\
692 : -nl same as icrnl -inlcr -igncr onlcr -ocrnl -onlret\n\
693 : "), stdout);
694 1 : fputs (_("\
695 : oddp same as parenb parodd cs7\n\
696 : -oddp same as -parenb cs8\n\
697 : [-]parity same as [-]evenp\n\
698 : pass8 same as -parenb -istrip cs8\n\
699 : -pass8 same as parenb istrip cs7\n\
700 : "), stdout);
701 1 : fputs (_("\
702 : raw same as -ignbrk -brkint -ignpar -parmrk -inpck -istrip\n\
703 : -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany\n\
704 : -imaxbel -opost -isig -icanon -xcase min 1 time 0\n\
705 : -raw same as cooked\n\
706 : "), stdout);
707 1 : fputs (_("\
708 : sane same as cread -ignbrk brkint -inlcr -igncr icrnl -iutf8\n\
709 : -ixoff -iuclc -ixany imaxbel opost -olcuc -ocrnl onlcr\n\
710 : -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0\n\
711 : isig icanon iexten echo echoe echok -echonl -noflsh\n\
712 : -xcase -tostop -echoprt echoctl echoke, all special\n\
713 : characters to their default values.\n\
714 : "), stdout);
715 1 : fputs (_("\
716 : \n\
717 : Handle the tty line connected to standard input. Without arguments,\n\
718 : prints baud rate, line discipline, and deviations from stty sane. In\n\
719 : settings, CHAR is taken literally, or coded as in ^c, 0x37, 0177 or\n\
720 : 127; special values ^- or undef used to disable special characters.\n\
721 : "), stdout);
722 1 : emit_bug_reporting_address ();
723 : }
724 45 : exit (status);
725 : }
726 :
727 : int
728 97 : main (int argc, char **argv)
729 : {
730 : /* Initialize to all zeroes so there is no risk memcmp will report a
731 : spurious difference in an uninitialized portion of the structure. */
732 97 : struct termios mode = { 0, };
733 :
734 : enum output_type output_type;
735 : int optc;
736 97 : int argi = 0;
737 97 : int opti = 1;
738 : bool require_set_attr;
739 : bool speed_was_set;
740 : bool verbose_output;
741 : bool recoverable_output;
742 : int k;
743 97 : bool noargs = true;
744 97 : char *file_name = NULL;
745 : const char *device_name;
746 :
747 : initialize_main (&argc, &argv);
748 97 : program_name = argv[0];
749 97 : setlocale (LC_ALL, "");
750 : bindtextdomain (PACKAGE, LOCALEDIR);
751 : textdomain (PACKAGE);
752 :
753 97 : atexit (close_stdout);
754 :
755 97 : output_type = changed;
756 97 : verbose_output = false;
757 97 : recoverable_output = false;
758 :
759 : /* Don't print error messages for unrecognized options. */
760 97 : opterr = 0;
761 :
762 : /* If any new options are ever added to stty, the short options MUST
763 : NOT allow any ambiguity with the stty settings. For example, the
764 : stty setting "-gagFork" would not be feasible, since it will be
765 : parsed as "-g -a -g -F ork". If you change anything about how
766 : stty parses options, be sure it still works with combinations of
767 : short and long options, --, POSIXLY_CORRECT, etc. */
768 :
769 306 : while ((optc = getopt_long (argc - argi, argv + argi, "-agF:",
770 : longopts, NULL))
771 : != -1)
772 : {
773 115 : switch (optc)
774 : {
775 11 : case 'a':
776 11 : verbose_output = true;
777 11 : output_type = all;
778 11 : break;
779 :
780 4 : case 'g':
781 4 : recoverable_output = true;
782 4 : output_type = recoverable;
783 4 : break;
784 :
785 11 : case 'F':
786 11 : if (file_name)
787 1 : error (EXIT_FAILURE, 0, _("only one device may be specified"));
788 10 : file_name = optarg;
789 10 : break;
790 :
791 1 : case_GETOPT_HELP_CHAR;
792 :
793 1 : case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
794 :
795 87 : default:
796 87 : noargs = false;
797 :
798 : /* Skip the argument containing this unrecognized option;
799 : the 2nd pass will analyze it. */
800 87 : argi += opti;
801 :
802 : /* Restart getopt_long from the first unskipped argument. */
803 87 : opti = 1;
804 87 : optind = 0;
805 :
806 87 : break;
807 : }
808 :
809 : /* Clear fully-parsed arguments, so they don't confuse the 2nd pass. */
810 252 : while (opti < optind)
811 28 : argv[argi + opti++] = NULL;
812 : }
813 :
814 : /* Specifying both -a and -g gets an error. */
815 94 : if (verbose_output & recoverable_output)
816 1 : error (EXIT_FAILURE, 0,
817 : _("the options for verbose and stty-readable output styles are\n"
818 : "mutually exclusive"));
819 :
820 : /* Specifying any other arguments with -a or -g gets an error. */
821 93 : if (!noargs & (verbose_output | recoverable_output))
822 2 : error (EXIT_FAILURE, 0,
823 : _("when specifying an output style, modes may not be set"));
824 :
825 : /* FIXME: it'd be better not to open the file until we've verified
826 : that all arguments are valid. Otherwise, we could end up doing
827 : only some of the requested operations and then failing, probably
828 : leaving things in an undesirable state. */
829 :
830 91 : if (file_name)
831 : {
832 : int fdflags;
833 9 : device_name = file_name;
834 9 : if (fd_reopen (STDIN_FILENO, device_name, O_RDONLY | O_NONBLOCK, 0) < 0)
835 4 : error (EXIT_FAILURE, errno, "%s", device_name);
836 5 : if ((fdflags = fcntl (STDIN_FILENO, F_GETFL)) == -1
837 5 : || fcntl (STDIN_FILENO, F_SETFL, fdflags & ~O_NONBLOCK) < 0)
838 0 : error (EXIT_FAILURE, errno, _("%s: couldn't reset non-blocking mode"),
839 : device_name);
840 : }
841 : else
842 82 : device_name = _("standard input");
843 :
844 87 : if (tcgetattr (STDIN_FILENO, &mode))
845 8 : error (EXIT_FAILURE, errno, "%s", device_name);
846 :
847 79 : if (verbose_output | recoverable_output | noargs)
848 : {
849 16 : max_col = screen_columns ();
850 16 : current_col = 0;
851 16 : display_settings (output_type, &mode, device_name);
852 16 : exit (EXIT_SUCCESS);
853 : }
854 :
855 63 : speed_was_set = false;
856 63 : require_set_attr = false;
857 92 : for (k = 1; k < argc; k++)
858 : {
859 73 : char const *arg = argv[k];
860 73 : bool match_found = false;
861 73 : bool reversed = false;
862 : int i;
863 :
864 73 : if (! arg)
865 0 : continue;
866 :
867 73 : if (arg[0] == '-')
868 : {
869 17 : ++arg;
870 17 : reversed = true;
871 : }
872 5748 : for (i = 0; mode_info[i].name != NULL; ++i)
873 : {
874 5695 : if (STREQ (arg, mode_info[i].name))
875 : {
876 20 : match_found = set_mode (&mode_info[i], reversed, &mode);
877 20 : require_set_attr = true;
878 20 : break;
879 : }
880 : }
881 73 : if (!match_found & reversed)
882 : {
883 12 : error (0, 0, _("invalid argument %s"), quote (arg - 1));
884 12 : usage (EXIT_FAILURE);
885 : }
886 61 : if (!match_found)
887 : {
888 702 : for (i = 0; control_info[i].name != NULL; ++i)
889 : {
890 666 : if (STREQ (arg, control_info[i].name))
891 : {
892 6 : if (k == argc - 1)
893 : {
894 1 : error (0, 0, _("missing argument to %s"), quote (arg));
895 1 : usage (EXIT_FAILURE);
896 : }
897 5 : match_found = true;
898 5 : ++k;
899 5 : set_control_char (&control_info[i], argv[k], &mode);
900 3 : require_set_attr = true;
901 3 : break;
902 : }
903 : }
904 : }
905 58 : if (!match_found)
906 : {
907 36 : if (STREQ (arg, "ispeed"))
908 : {
909 2 : if (k == argc - 1)
910 : {
911 1 : error (0, 0, _("missing argument to %s"), quote (arg));
912 1 : usage (EXIT_FAILURE);
913 : }
914 1 : ++k;
915 1 : set_speed (input_speed, argv[k], &mode);
916 1 : speed_was_set = true;
917 1 : require_set_attr = true;
918 : }
919 34 : else if (STREQ (arg, "ospeed"))
920 : {
921 0 : if (k == argc - 1)
922 : {
923 0 : error (0, 0, _("missing argument to %s"), quote (arg));
924 0 : usage (EXIT_FAILURE);
925 : }
926 0 : ++k;
927 0 : set_speed (output_speed, argv[k], &mode);
928 0 : speed_was_set = true;
929 0 : require_set_attr = true;
930 : }
931 : #ifdef TIOCGWINSZ
932 34 : else if (STREQ (arg, "rows"))
933 : {
934 0 : if (k == argc - 1)
935 : {
936 0 : error (0, 0, _("missing argument to %s"), quote (arg));
937 0 : usage (EXIT_FAILURE);
938 : }
939 0 : ++k;
940 0 : set_window_size (integer_arg (argv[k], INT_MAX), -1,
941 : device_name);
942 : }
943 34 : else if (STREQ (arg, "cols")
944 28 : || STREQ (arg, "columns"))
945 : {
946 8 : if (k == argc - 1)
947 : {
948 1 : error (0, 0, _("missing argument to %s"), quote (arg));
949 1 : usage (EXIT_FAILURE);
950 : }
951 7 : ++k;
952 7 : set_window_size (-1, integer_arg (argv[k], INT_MAX),
953 : device_name);
954 : }
955 26 : else if (STREQ (arg, "size"))
956 : {
957 0 : max_col = screen_columns ();
958 0 : current_col = 0;
959 0 : display_window_size (false, device_name);
960 : }
961 : #endif
962 : #ifdef HAVE_C_LINE
963 26 : else if (STREQ (arg, "line"))
964 : {
965 : unsigned long int value;
966 0 : if (k == argc - 1)
967 : {
968 0 : error (0, 0, _("missing argument to %s"), quote (arg));
969 0 : usage (EXIT_FAILURE);
970 : }
971 0 : ++k;
972 0 : mode.c_line = value = integer_arg (argv[k], ULONG_MAX);
973 0 : if (mode.c_line != value)
974 0 : error (0, 0, _("invalid line discipline %s"), quote (argv[k]));
975 0 : require_set_attr = true;
976 : }
977 : #endif
978 26 : else if (STREQ (arg, "speed"))
979 : {
980 0 : max_col = screen_columns ();
981 0 : display_speed (&mode, false);
982 : }
983 26 : else if (string_to_baud (arg) != (speed_t) -1)
984 : {
985 2 : set_speed (both_speeds, arg, &mode);
986 2 : speed_was_set = true;
987 2 : require_set_attr = true;
988 : }
989 : else
990 : {
991 24 : if (! recover_mode (arg, &mode))
992 : {
993 24 : error (0, 0, _("invalid argument %s"), quote (arg));
994 24 : usage (EXIT_FAILURE);
995 : }
996 0 : require_set_attr = true;
997 : }
998 : }
999 : }
1000 :
1001 19 : if (require_set_attr)
1002 : {
1003 : /* Initialize to all zeroes so there is no risk memcmp will report a
1004 : spurious difference in an uninitialized portion of the structure. */
1005 19 : struct termios new_mode = { 0, };
1006 :
1007 19 : if (tcsetattr (STDIN_FILENO, TCSADRAIN, &mode))
1008 3 : error (EXIT_FAILURE, errno, "%s", device_name);
1009 :
1010 : /* POSIX (according to Zlotnick's book) tcsetattr returns zero if
1011 : it performs *any* of the requested operations. This means it
1012 : can report `success' when it has actually failed to perform
1013 : some proper subset of the requested operations. To detect
1014 : this partial failure, get the current terminal attributes and
1015 : compare them to the requested ones. */
1016 :
1017 16 : if (tcgetattr (STDIN_FILENO, &new_mode))
1018 0 : error (EXIT_FAILURE, errno, "%s", device_name);
1019 :
1020 : /* Normally, one shouldn't use memcmp to compare structures that
1021 : may have `holes' containing uninitialized data, but we have been
1022 : careful to initialize the storage of these two variables to all
1023 : zeroes. One might think it more efficient simply to compare the
1024 : modified fields, but that would require enumerating those fields --
1025 : and not all systems have the same fields in this structure. */
1026 :
1027 16 : if (memcmp (&mode, &new_mode, sizeof (mode)) != 0)
1028 : {
1029 : #ifdef CIBAUD
1030 : /* SunOS 4.1.3 (at least) has the problem that after this sequence,
1031 : tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2);
1032 : sometimes (m1 != m2). The only difference is in the four bits
1033 : of the c_cflag field corresponding to the baud rate. To save
1034 : Sun users a little confusion, don't report an error if this
1035 : happens. But suppress the error only if we haven't tried to
1036 : set the baud rate explicitly -- otherwise we'd never give an
1037 : error for a true failure to set the baud rate. */
1038 :
1039 3 : new_mode.c_cflag &= (~CIBAUD);
1040 3 : if (speed_was_set || memcmp (&mode, &new_mode, sizeof (mode)) != 0)
1041 : #endif
1042 : {
1043 3 : error (EXIT_FAILURE, 0,
1044 : _("%s: unable to perform all requested operations"),
1045 : device_name);
1046 : #ifdef TESTING
1047 : {
1048 : size_t i;
1049 : printf (_("new_mode: mode\n"));
1050 : for (i = 0; i < sizeof (new_mode); i++)
1051 : printf ("0x%02x: 0x%02x\n",
1052 : *(((unsigned char *) &new_mode) + i),
1053 : *(((unsigned char *) &mode) + i));
1054 : }
1055 : #endif
1056 : }
1057 : }
1058 : }
1059 :
1060 13 : exit (EXIT_SUCCESS);
1061 : }
1062 :
1063 : /* Return false if not applied because not reversible; otherwise
1064 : return true. */
1065 :
1066 : static bool
1067 20 : set_mode (struct mode_info *info, bool reversed, struct termios *mode)
1068 : {
1069 : tcflag_t *bitsp;
1070 :
1071 20 : if (reversed && (info->flags & REV) == 0)
1072 1 : return false;
1073 :
1074 19 : bitsp = mode_type_flag (info->type, mode);
1075 :
1076 19 : if (bitsp == NULL)
1077 : {
1078 : /* Combination mode. */
1079 14 : if (STREQ (info->name, "evenp") || STREQ (info->name, "parity"))
1080 : {
1081 6 : if (reversed)
1082 1 : mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1083 : else
1084 2 : mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7;
1085 : }
1086 11 : else if (STREQ (info->name, "oddp"))
1087 : {
1088 1 : if (reversed)
1089 0 : mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1090 : else
1091 1 : mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB;
1092 : }
1093 10 : else if (STREQ (info->name, "nl"))
1094 : {
1095 1 : if (reversed)
1096 : {
1097 0 : mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
1098 0 : mode->c_oflag = (mode->c_oflag
1099 : #ifdef ONLCR
1100 : | ONLCR
1101 : #endif
1102 : )
1103 : #ifdef OCRNL
1104 : & ~OCRNL
1105 : #endif
1106 : #ifdef ONLRET
1107 0 : & ~ONLRET
1108 : #endif
1109 : ;
1110 : }
1111 : else
1112 : {
1113 1 : mode->c_iflag = mode->c_iflag & ~ICRNL;
1114 : #ifdef ONLCR
1115 1 : mode->c_oflag = mode->c_oflag & ~ONLCR;
1116 : #endif
1117 : }
1118 : }
1119 9 : else if (STREQ (info->name, "ek"))
1120 : {
1121 1 : mode->c_cc[VERASE] = CERASE;
1122 1 : mode->c_cc[VKILL] = CKILL;
1123 : }
1124 8 : else if (STREQ (info->name, "sane"))
1125 1 : sane_mode (mode);
1126 7 : else if (STREQ (info->name, "cbreak"))
1127 : {
1128 2 : if (reversed)
1129 1 : mode->c_lflag |= ICANON;
1130 : else
1131 1 : mode->c_lflag &= ~ICANON;
1132 : }
1133 5 : else if (STREQ (info->name, "pass8"))
1134 : {
1135 2 : if (reversed)
1136 : {
1137 1 : mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1138 1 : mode->c_iflag |= ISTRIP;
1139 : }
1140 : else
1141 : {
1142 1 : mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1143 1 : mode->c_iflag &= ~ISTRIP;
1144 : }
1145 : }
1146 3 : else if (STREQ (info->name, "litout"))
1147 : {
1148 0 : if (reversed)
1149 : {
1150 0 : mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB;
1151 0 : mode->c_iflag |= ISTRIP;
1152 0 : mode->c_oflag |= OPOST;
1153 : }
1154 : else
1155 : {
1156 0 : mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8;
1157 0 : mode->c_iflag &= ~ISTRIP;
1158 0 : mode->c_oflag &= ~OPOST;
1159 : }
1160 : }
1161 3 : else if (STREQ (info->name, "raw") || STREQ (info->name, "cooked"))
1162 : {
1163 4 : if ((info->name[0] == 'r' && reversed)
1164 2 : || (info->name[0] == 'c' && !reversed))
1165 : {
1166 : /* Cooked mode. */
1167 1 : mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON;
1168 1 : mode->c_oflag |= OPOST;
1169 1 : mode->c_lflag |= ISIG | ICANON;
1170 : #if VMIN == VEOF
1171 : mode->c_cc[VEOF] = CEOF;
1172 : #endif
1173 : #if VTIME == VEOL
1174 : mode->c_cc[VEOL] = CEOL;
1175 : #endif
1176 : }
1177 : else
1178 : {
1179 : /* Raw mode. */
1180 1 : mode->c_iflag = 0;
1181 1 : mode->c_oflag &= ~OPOST;
1182 1 : mode->c_lflag &= ~(ISIG | ICANON
1183 : #ifdef XCASE
1184 : | XCASE
1185 : #endif
1186 : );
1187 1 : mode->c_cc[VMIN] = 1;
1188 1 : mode->c_cc[VTIME] = 0;
1189 : }
1190 : }
1191 : #ifdef IXANY
1192 1 : else if (STREQ (info->name, "decctlq"))
1193 : {
1194 0 : if (reversed)
1195 0 : mode->c_iflag |= IXANY;
1196 : else
1197 0 : mode->c_iflag &= ~IXANY;
1198 : }
1199 : #endif
1200 : #ifdef TABDLY
1201 1 : else if (STREQ (info->name, "tabs"))
1202 : {
1203 0 : if (reversed)
1204 0 : mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3;
1205 : else
1206 0 : mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0;
1207 : }
1208 : #else
1209 : # ifdef OXTABS
1210 : else if (STREQ (info->name, "tabs"))
1211 : {
1212 : if (reversed)
1213 : mode->c_oflag = mode->c_oflag | OXTABS;
1214 : else
1215 : mode->c_oflag = mode->c_oflag & ~OXTABS;
1216 : }
1217 : # endif
1218 : #endif
1219 : #if defined XCASE && defined IUCLC && defined OLCUC
1220 1 : else if (STREQ (info->name, "lcase")
1221 1 : || STREQ (info->name, "LCASE"))
1222 : {
1223 0 : if (reversed)
1224 : {
1225 0 : mode->c_lflag &= ~XCASE;
1226 0 : mode->c_iflag &= ~IUCLC;
1227 0 : mode->c_oflag &= ~OLCUC;
1228 : }
1229 : else
1230 : {
1231 0 : mode->c_lflag |= XCASE;
1232 0 : mode->c_iflag |= IUCLC;
1233 0 : mode->c_oflag |= OLCUC;
1234 : }
1235 : }
1236 : #endif
1237 1 : else if (STREQ (info->name, "crt"))
1238 1 : mode->c_lflag |= ECHOE
1239 : #ifdef ECHOCTL
1240 : | ECHOCTL
1241 : #endif
1242 : #ifdef ECHOKE
1243 : | ECHOKE
1244 : #endif
1245 : ;
1246 0 : else if (STREQ (info->name, "dec"))
1247 : {
1248 0 : mode->c_cc[VINTR] = 3; /* ^C */
1249 0 : mode->c_cc[VERASE] = 127; /* DEL */
1250 0 : mode->c_cc[VKILL] = 21; /* ^U */
1251 0 : mode->c_lflag |= ECHOE
1252 : #ifdef ECHOCTL
1253 : | ECHOCTL
1254 : #endif
1255 : #ifdef ECHOKE
1256 : | ECHOKE
1257 : #endif
1258 : ;
1259 : #ifdef IXANY
1260 0 : mode->c_iflag &= ~IXANY;
1261 : #endif
1262 : }
1263 : }
1264 5 : else if (reversed)
1265 1 : *bitsp = *bitsp & ~info->mask & ~info->bits;
1266 : else
1267 4 : *bitsp = (*bitsp & ~info->mask) | info->bits;
1268 :
1269 19 : return true;
1270 : }
1271 :
1272 : static void
1273 5 : set_control_char (struct control_info *info, const char *arg,
1274 : struct termios *mode)
1275 : {
1276 : unsigned long int value;
1277 :
1278 5 : if (STREQ (info->name, "min") || STREQ (info->name, "time"))
1279 2 : value = integer_arg (arg, TYPE_MAXIMUM (cc_t));
1280 3 : else if (arg[0] == '\0' || arg[1] == '\0')
1281 2 : value = to_uchar (arg[0]);
1282 1 : else if (STREQ (arg, "^-") || STREQ (arg, "undef"))
1283 0 : value = _POSIX_VDISABLE;
1284 1 : else if (arg[0] == '^' && arg[1] != '\0') /* Ignore any trailing junk. */
1285 : {
1286 0 : if (arg[1] == '?')
1287 0 : value = 127;
1288 : else
1289 0 : value = to_uchar (arg[1]) & ~0140; /* Non-letters get weird results. */
1290 : }
1291 : else
1292 1 : value = integer_arg (arg, TYPE_MAXIMUM (cc_t));
1293 3 : mode->c_cc[info->offset] = value;
1294 3 : }
1295 :
1296 : static void
1297 3 : set_speed (enum speed_setting type, const char *arg, struct termios *mode)
1298 : {
1299 : speed_t baud;
1300 :
1301 3 : baud = string_to_baud (arg);
1302 3 : if (type == input_speed || type == both_speeds)
1303 3 : cfsetispeed (mode, baud);
1304 3 : if (type == output_speed || type == both_speeds)
1305 2 : cfsetospeed (mode, baud);
1306 3 : }
1307 :
1308 : #ifdef TIOCGWINSZ
1309 :
1310 : static int
1311 27 : get_win_size (int fd, struct winsize *win)
1312 : {
1313 27 : int err = ioctl (fd, TIOCGWINSZ, (char *) win);
1314 27 : return err;
1315 : }
1316 :
1317 : static void
1318 4 : set_window_size (int rows, int cols, char const *device_name)
1319 : {
1320 : struct winsize win;
1321 :
1322 4 : if (get_win_size (STDIN_FILENO, &win))
1323 : {
1324 0 : if (errno != EINVAL)
1325 0 : error (EXIT_FAILURE, errno, "%s", device_name);
1326 0 : memset (&win, 0, sizeof (win));
1327 : }
1328 :
1329 4 : if (rows >= 0)
1330 0 : win.ws_row = rows;
1331 4 : if (cols >= 0)
1332 4 : win.ws_col = cols;
1333 :
1334 : # ifdef TIOCSSIZE
1335 : /* Alexander Dupuy <dupuy@cs.columbia.edu> wrote:
1336 : The following code deals with a bug in the SunOS 4.x (and 3.x?) kernel.
1337 : This comment from sys/ttold.h describes Sun's twisted logic - a better
1338 : test would have been (ts_lines > 64k || ts_cols > 64k || ts_cols == 0).
1339 : At any rate, the problem is gone in Solaris 2.x.
1340 :
1341 : Unfortunately, the old TIOCSSIZE code does collide with TIOCSWINSZ,
1342 : but they can be disambiguated by checking whether a "struct ttysize"
1343 : structure's "ts_lines" field is greater than 64K or not. If so,
1344 : it's almost certainly a "struct winsize" instead.
1345 :
1346 : At any rate, the bug manifests itself when ws_row == 0; the symptom is
1347 : that ws_row is set to ws_col, and ws_col is set to (ws_xpixel<<16) +
1348 : ws_ypixel. Since GNU stty sets rows and columns separately, this bug
1349 : caused "stty rows 0 cols 0" to set rows to cols and cols to 0, while
1350 : "stty cols 0 rows 0" would do the right thing. On a little-endian
1351 : machine like the sun386i, the problem is the same, but for ws_col == 0.
1352 :
1353 : The workaround is to do the ioctl once with row and col = 1 to set the
1354 : pixel info, and then do it again using a TIOCSSIZE to set rows/cols. */
1355 :
1356 : if (win.ws_row == 0 || win.ws_col == 0)
1357 : {
1358 : struct ttysize ttysz;
1359 :
1360 : ttysz.ts_lines = win.ws_row;
1361 : ttysz.ts_cols = win.ws_col;
1362 :
1363 : win.ws_row = 1;
1364 : win.ws_col = 1;
1365 :
1366 : if (ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win))
1367 : error (EXIT_FAILURE, errno, "%s", device_name);
1368 :
1369 : if (ioctl (STDIN_FILENO, TIOCSSIZE, (char *) &ttysz))
1370 : error (EXIT_FAILURE, errno, "%s", device_name);
1371 : return;
1372 : }
1373 : # endif
1374 :
1375 4 : if (ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win))
1376 0 : error (EXIT_FAILURE, errno, "%s", device_name);
1377 4 : }
1378 :
1379 : static void
1380 7 : display_window_size (bool fancy, char const *device_name)
1381 : {
1382 : struct winsize win;
1383 :
1384 7 : if (get_win_size (STDIN_FILENO, &win))
1385 : {
1386 0 : if (errno != EINVAL)
1387 0 : error (EXIT_FAILURE, errno, "%s", device_name);
1388 0 : if (!fancy)
1389 0 : error (EXIT_FAILURE, 0,
1390 : _("%s: no size information for this device"), device_name);
1391 : }
1392 : else
1393 : {
1394 14 : wrapf (fancy ? "rows %d; columns %d;" : "%d %d\n",
1395 14 : win.ws_row, win.ws_col);
1396 7 : if (!fancy)
1397 0 : current_col = 0;
1398 : }
1399 7 : }
1400 : #endif
1401 :
1402 : static int
1403 16 : screen_columns (void)
1404 : {
1405 : #ifdef TIOCGWINSZ
1406 : struct winsize win;
1407 :
1408 : /* With Solaris 2.[123], this ioctl fails and errno is set to
1409 : EINVAL for telnet (but not rlogin) sessions.
1410 : On ISC 3.0, it fails for the console and the serial port
1411 : (but it works for ptys).
1412 : It can also fail on any system when stdout isn't a tty.
1413 : In case of any failure, just use the default. */
1414 16 : if (get_win_size (STDOUT_FILENO, &win) == 0 && 0 < win.ws_col)
1415 13 : return win.ws_col;
1416 : #endif
1417 : {
1418 : /* Use $COLUMNS if it's in [1..INT_MAX]. */
1419 3 : char *col_string = getenv ("COLUMNS");
1420 : long int n_columns;
1421 3 : if (!(col_string != NULL
1422 0 : && xstrtol (col_string, NULL, 0, &n_columns, "") == LONGINT_OK
1423 0 : && 0 < n_columns
1424 0 : && n_columns <= INT_MAX))
1425 3 : n_columns = 80;
1426 3 : return n_columns;
1427 : }
1428 : }
1429 :
1430 : static tcflag_t *
1431 886 : mode_type_flag (enum mode_type type, struct termios *mode)
1432 : {
1433 886 : switch (type)
1434 : {
1435 148 : case control:
1436 148 : return &mode->c_cflag;
1437 :
1438 205 : case input:
1439 205 : return &mode->c_iflag;
1440 :
1441 336 : case output:
1442 336 : return &mode->c_oflag;
1443 :
1444 183 : case local:
1445 183 : return &mode->c_lflag;
1446 :
1447 14 : case combination:
1448 14 : return NULL;
1449 :
1450 0 : default:
1451 0 : abort ();
1452 : }
1453 : }
1454 :
1455 : static void
1456 16 : display_settings (enum output_type output_type, struct termios *mode,
1457 : char const *device_name)
1458 : {
1459 16 : switch (output_type)
1460 : {
1461 6 : case changed:
1462 6 : display_changed (mode);
1463 6 : break;
1464 :
1465 7 : case all:
1466 7 : display_all (mode, device_name);
1467 7 : break;
1468 :
1469 3 : case recoverable:
1470 3 : display_recoverable (mode);
1471 3 : break;
1472 : }
1473 16 : }
1474 :
1475 : static void
1476 6 : display_changed (struct termios *mode)
1477 : {
1478 : int i;
1479 : bool empty_line;
1480 : tcflag_t *bitsp;
1481 : unsigned long mask;
1482 6 : enum mode_type prev_type = control;
1483 :
1484 6 : display_speed (mode, true);
1485 : #ifdef HAVE_C_LINE
1486 6 : wrapf ("line = %d;", mode->c_line);
1487 : #endif
1488 6 : putchar ('\n');
1489 6 : current_col = 0;
1490 :
1491 6 : empty_line = true;
1492 96 : for (i = 0; !STREQ (control_info[i].name, "min"); ++i)
1493 : {
1494 90 : if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
1495 72 : continue;
1496 : /* If swtch is the same as susp, don't print both. */
1497 : #if VSWTCH == VSUSP
1498 : if (STREQ (control_info[i].name, "swtch"))
1499 : continue;
1500 : #endif
1501 : /* If eof uses the same slot as min, only print whichever applies. */
1502 : #if VEOF == VMIN
1503 : if ((mode->c_lflag & ICANON) == 0
1504 : && (STREQ (control_info[i].name, "eof")
1505 : || STREQ (control_info[i].name, "eol")))
1506 : continue;
1507 : #endif
1508 :
1509 18 : empty_line = false;
1510 18 : wrapf ("%s = %s;", control_info[i].name,
1511 18 : visible (mode->c_cc[control_info[i].offset]));
1512 : }
1513 6 : if ((mode->c_lflag & ICANON) == 0)
1514 : {
1515 12 : wrapf ("min = %lu; time = %lu;\n",
1516 6 : (unsigned long int) mode->c_cc[VMIN],
1517 6 : (unsigned long int) mode->c_cc[VTIME]);
1518 : }
1519 0 : else if (!empty_line)
1520 0 : putchar ('\n');
1521 6 : current_col = 0;
1522 :
1523 6 : empty_line = true;
1524 522 : for (i = 0; mode_info[i].name != NULL; ++i)
1525 : {
1526 516 : if (mode_info[i].flags & OMIT)
1527 138 : continue;
1528 378 : if (mode_info[i].type != prev_type)
1529 : {
1530 18 : if (!empty_line)
1531 : {
1532 12 : putchar ('\n');
1533 12 : current_col = 0;
1534 12 : empty_line = true;
1535 : }
1536 18 : prev_type = mode_info[i].type;
1537 : }
1538 :
1539 378 : bitsp = mode_type_flag (mode_info[i].type, mode);
1540 378 : mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1541 378 : if ((*bitsp & mask) == mode_info[i].bits)
1542 : {
1543 66 : if (mode_info[i].flags & SANE_UNSET)
1544 : {
1545 6 : wrapf ("%s", mode_info[i].name);
1546 6 : empty_line = false;
1547 : }
1548 : }
1549 312 : else if ((mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
1550 : {
1551 72 : wrapf ("-%s", mode_info[i].name);
1552 72 : empty_line = false;
1553 : }
1554 : }
1555 6 : if (!empty_line)
1556 6 : putchar ('\n');
1557 6 : current_col = 0;
1558 6 : }
1559 :
1560 : static void
1561 7 : display_all (struct termios *mode, char const *device_name)
1562 : {
1563 : int i;
1564 : tcflag_t *bitsp;
1565 : unsigned long mask;
1566 7 : enum mode_type prev_type = control;
1567 :
1568 7 : display_speed (mode, true);
1569 : #ifdef TIOCGWINSZ
1570 7 : display_window_size (true, device_name);
1571 : #endif
1572 : #ifdef HAVE_C_LINE
1573 7 : wrapf ("line = %d;", mode->c_line);
1574 : #endif
1575 7 : putchar ('\n');
1576 7 : current_col = 0;
1577 :
1578 112 : for (i = 0; ! STREQ (control_info[i].name, "min"); ++i)
1579 : {
1580 : /* If swtch is the same as susp, don't print both. */
1581 : #if VSWTCH == VSUSP
1582 : if (STREQ (control_info[i].name, "swtch"))
1583 : continue;
1584 : #endif
1585 : /* If eof uses the same slot as min, only print whichever applies. */
1586 : #if VEOF == VMIN
1587 : if ((mode->c_lflag & ICANON) == 0
1588 : && (STREQ (control_info[i].name, "eof")
1589 : || STREQ (control_info[i].name, "eol")))
1590 : continue;
1591 : #endif
1592 105 : wrapf ("%s = %s;", control_info[i].name,
1593 105 : visible (mode->c_cc[control_info[i].offset]));
1594 : }
1595 : #if VEOF == VMIN
1596 : if ((mode->c_lflag & ICANON) == 0)
1597 : #endif
1598 14 : wrapf ("min = %lu; time = %lu;",
1599 7 : (unsigned long int) mode->c_cc[VMIN],
1600 7 : (unsigned long int) mode->c_cc[VTIME]);
1601 7 : if (current_col != 0)
1602 7 : putchar ('\n');
1603 7 : current_col = 0;
1604 :
1605 609 : for (i = 0; mode_info[i].name != NULL; ++i)
1606 : {
1607 602 : if (mode_info[i].flags & OMIT)
1608 161 : continue;
1609 441 : if (mode_info[i].type != prev_type)
1610 : {
1611 21 : putchar ('\n');
1612 21 : current_col = 0;
1613 21 : prev_type = mode_info[i].type;
1614 : }
1615 :
1616 441 : bitsp = mode_type_flag (mode_info[i].type, mode);
1617 441 : mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
1618 441 : if ((*bitsp & mask) == mode_info[i].bits)
1619 77 : wrapf ("%s", mode_info[i].name);
1620 364 : else if (mode_info[i].flags & REV)
1621 273 : wrapf ("-%s", mode_info[i].name);
1622 : }
1623 7 : putchar ('\n');
1624 7 : current_col = 0;
1625 7 : }
1626 :
1627 : static void
1628 13 : display_speed (struct termios *mode, bool fancy)
1629 : {
1630 13 : if (cfgetispeed (mode) == 0 || cfgetispeed (mode) == cfgetospeed (mode))
1631 13 : wrapf (fancy ? "speed %lu baud;" : "%lu\n",
1632 : baud_to_value (cfgetospeed (mode)));
1633 : else
1634 0 : wrapf (fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n",
1635 : baud_to_value (cfgetispeed (mode)),
1636 : baud_to_value (cfgetospeed (mode)));
1637 13 : if (!fancy)
1638 0 : current_col = 0;
1639 13 : }
1640 :
1641 : static void
1642 3 : display_recoverable (struct termios *mode)
1643 : {
1644 : size_t i;
1645 :
1646 12 : printf ("%lx:%lx:%lx:%lx",
1647 3 : (unsigned long int) mode->c_iflag,
1648 3 : (unsigned long int) mode->c_oflag,
1649 3 : (unsigned long int) mode->c_cflag,
1650 3 : (unsigned long int) mode->c_lflag);
1651 99 : for (i = 0; i < NCCS; ++i)
1652 96 : printf (":%lx", (unsigned long int) mode->c_cc[i]);
1653 3 : putchar ('\n');
1654 3 : }
1655 :
1656 : /* NOTE: identical to below, modulo use of tcflag_t */
1657 : static int
1658 25 : strtoul_tcflag_t (char const *s, int base, char **p, tcflag_t *result,
1659 : char delim)
1660 : {
1661 : unsigned long ul;
1662 25 : errno = 0;
1663 25 : ul = strtoul (s, p, base);
1664 25 : if (errno || **p != delim || *p == s || (tcflag_t) ul != ul)
1665 24 : return -1;
1666 1 : *result = ul;
1667 1 : return 0;
1668 : }
1669 :
1670 : /* NOTE: identical to above, modulo use of cc_t */
1671 : static int
1672 0 : strtoul_cc_t (char const *s, int base, char **p, cc_t *result, char delim)
1673 : {
1674 : unsigned long ul;
1675 0 : errno = 0;
1676 0 : ul = strtoul (s, p, base);
1677 0 : if (errno || **p != delim || *p == s || (cc_t) ul != ul)
1678 0 : return -1;
1679 0 : *result = ul;
1680 0 : return 0;
1681 : }
1682 :
1683 : /* Parse the output of display_recoverable.
1684 : Return false if any part of it is invalid. */
1685 : static bool
1686 24 : recover_mode (char const *arg, struct termios *mode)
1687 : {
1688 : tcflag_t flag[4];
1689 24 : char const *s = arg;
1690 : size_t i;
1691 25 : for (i = 0; i < 4; i++)
1692 : {
1693 : char *p;
1694 25 : if (strtoul_tcflag_t (s, 16, &p, flag + i, ':') != 0)
1695 24 : return false;
1696 1 : s = p + 1;
1697 : }
1698 0 : mode->c_iflag = flag[0];
1699 0 : mode->c_oflag = flag[1];
1700 0 : mode->c_cflag = flag[2];
1701 0 : mode->c_lflag = flag[3];
1702 :
1703 0 : for (i = 0; i < NCCS; ++i)
1704 : {
1705 : char *p;
1706 0 : char delim = i < NCCS - 1 ? ':' : '\0';
1707 0 : if (strtoul_cc_t (s, 16, &p, mode->c_cc + i, delim) != 0)
1708 0 : return false;
1709 0 : s = p + 1;
1710 : }
1711 :
1712 0 : return true;
1713 : }
1714 :
1715 : struct speed_map
1716 : {
1717 : const char *string; /* ASCII representation. */
1718 : speed_t speed; /* Internal form. */
1719 : unsigned long int value; /* Numeric value. */
1720 : };
1721 :
1722 : static struct speed_map speeds[] =
1723 : {
1724 : {"0", B0, 0},
1725 : {"50", B50, 50},
1726 : {"75", B75, 75},
1727 : {"110", B110, 110},
1728 : {"134", B134, 134},
1729 : {"134.5", B134, 134},
1730 : {"150", B150, 150},
1731 : {"200", B200, 200},
1732 : {"300", B300, 300},
1733 : {"600", B600, 600},
1734 : {"1200", B1200, 1200},
1735 : {"1800", B1800, 1800},
1736 : {"2400", B2400, 2400},
1737 : {"4800", B4800, 4800},
1738 : {"9600", B9600, 9600},
1739 : {"19200", B19200, 19200},
1740 : {"38400", B38400, 38400},
1741 : {"exta", B19200, 19200},
1742 : {"extb", B38400, 38400},
1743 : #ifdef B57600
1744 : {"57600", B57600, 57600},
1745 : #endif
1746 : #ifdef B115200
1747 : {"115200", B115200, 115200},
1748 : #endif
1749 : #ifdef B230400
1750 : {"230400", B230400, 230400},
1751 : #endif
1752 : #ifdef B460800
1753 : {"460800", B460800, 460800},
1754 : #endif
1755 : #ifdef B500000
1756 : {"500000", B500000, 500000},
1757 : #endif
1758 : #ifdef B576000
1759 : {"576000", B576000, 576000},
1760 : #endif
1761 : #ifdef B921600
1762 : {"921600", B921600, 921600},
1763 : #endif
1764 : #ifdef B1000000
1765 : {"1000000", B1000000, 1000000},
1766 : #endif
1767 : #ifdef B1152000
1768 : {"1152000", B1152000, 1152000},
1769 : #endif
1770 : #ifdef B1500000
1771 : {"1500000", B1500000, 1500000},
1772 : #endif
1773 : #ifdef B2000000
1774 : {"2000000", B2000000, 2000000},
1775 : #endif
1776 : #ifdef B2500000
1777 : {"2500000", B2500000, 2500000},
1778 : #endif
1779 : #ifdef B3000000
1780 : {"3000000", B3000000, 3000000},
1781 : #endif
1782 : #ifdef B3500000
1783 : {"3500000", B3500000, 3500000},
1784 : #endif
1785 : #ifdef B4000000
1786 : {"4000000", B4000000, 4000000},
1787 : #endif
1788 : {NULL, 0, 0}
1789 : };
1790 :
1791 : static speed_t
1792 29 : string_to_baud (const char *arg)
1793 : {
1794 : int i;
1795 :
1796 881 : for (i = 0; speeds[i].string != NULL; ++i)
1797 856 : if (STREQ (arg, speeds[i].string))
1798 4 : return speeds[i].speed;
1799 25 : return (speed_t) -1;
1800 : }
1801 :
1802 : static unsigned long int
1803 13 : baud_to_value (speed_t speed)
1804 : {
1805 : int i;
1806 :
1807 221 : for (i = 0; speeds[i].string != NULL; ++i)
1808 221 : if (speed == speeds[i].speed)
1809 13 : return speeds[i].value;
1810 0 : return 0;
1811 : }
1812 :
1813 : static void
1814 1 : sane_mode (struct termios *mode)
1815 : {
1816 : int i;
1817 : tcflag_t *bitsp;
1818 :
1819 18 : for (i = 0; control_info[i].name; ++i)
1820 : {
1821 : #if VMIN == VEOF
1822 : if (STREQ (control_info[i].name, "min"))
1823 : break;
1824 : #endif
1825 17 : mode->c_cc[control_info[i].offset] = control_info[i].saneval;
1826 : }
1827 :
1828 87 : for (i = 0; mode_info[i].name != NULL; ++i)
1829 : {
1830 86 : if (mode_info[i].flags & SANE_SET)
1831 : {
1832 20 : bitsp = mode_type_flag (mode_info[i].type, mode);
1833 20 : *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits;
1834 : }
1835 66 : else if (mode_info[i].flags & SANE_UNSET)
1836 : {
1837 28 : bitsp = mode_type_flag (mode_info[i].type, mode);
1838 28 : *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits;
1839 : }
1840 : }
1841 1 : }
1842 :
1843 : /* Return a string that is the printable representation of character CH. */
1844 : /* Adapted from `cat' by Torbjorn Granlund. */
1845 :
1846 : static const char *
1847 123 : visible (cc_t ch)
1848 : {
1849 : static char buf[10];
1850 123 : char *bpout = buf;
1851 :
1852 123 : if (ch == _POSIX_VDISABLE)
1853 0 : return "<undef>";
1854 :
1855 123 : if (ch >= 32)
1856 : {
1857 46 : if (ch < 127)
1858 0 : *bpout++ = ch;
1859 46 : else if (ch == 127)
1860 : {
1861 7 : *bpout++ = '^';
1862 7 : *bpout++ = '?';
1863 : }
1864 : else
1865 : {
1866 39 : *bpout++ = 'M';
1867 39 : *bpout++ = '-';
1868 39 : if (ch >= 128 + 32)
1869 : {
1870 39 : if (ch < 128 + 127)
1871 0 : *bpout++ = ch - 128;
1872 : else
1873 : {
1874 39 : *bpout++ = '^';
1875 39 : *bpout++ = '?';
1876 : }
1877 : }
1878 : else
1879 : {
1880 0 : *bpout++ = '^';
1881 0 : *bpout++ = ch - 128 + 64;
1882 : }
1883 : }
1884 : }
1885 : else
1886 : {
1887 77 : *bpout++ = '^';
1888 77 : *bpout++ = ch + 64;
1889 : }
1890 123 : *bpout = '\0';
1891 123 : return (const char *) buf;
1892 : }
1893 :
1894 : /* Parse string S as an integer, using decimal radix by default,
1895 : but allowing octal and hex numbers as in C. Reject values
1896 : larger than MAXVAL. */
1897 :
1898 : static unsigned long int
1899 10 : integer_arg (const char *s, unsigned long int maxval)
1900 : {
1901 : unsigned long int value;
1902 10 : if (xstrtoul (s, NULL, 0, &value, "bB") != LONGINT_OK || maxval < value)
1903 : {
1904 5 : error (0, 0, _("invalid integer argument %s"), quote (s));
1905 5 : usage (EXIT_FAILURE);
1906 : }
1907 5 : return value;
1908 : }
|