LCOV - code coverage report
Current view: top level - src - stty.c (source / functions) Hit Total Coverage
Test: coreutils.info Lines: 437 543 80.5 %
Date: 2018-01-30 Functions: 23 24 95.8 %

          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             : }

Generated by: LCOV version 1.10