diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-01-20 10:55:18 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2016-01-20 10:55:18 +0000 |
commit | 70e9163c9c18e995515598085cb824e554eb7ae7 (patch) | |
tree | a42dc8b2a6c031354bf31472de888bfc8a060132 /src/stty.c | |
parent | cbf5993c43f49281173f185863577d86bfac6eae (diff) | |
download | coreutils-tarball-master.tar.gz |
coreutils-8.25HEADcoreutils-8.25master
Diffstat (limited to 'src/stty.c')
-rw-r--r-- | src/stty.c | 1579 |
1 files changed, 997 insertions, 582 deletions
@@ -1,10 +1,10 @@ /* stty -- change and print terminal line settings - Copyright (C) 1990-2005 Free Software Foundation, Inc. + Copyright (C) 1990-2016 Free Software Foundation, Inc. - This program is free software; you can redistribute it and/or modify + This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by - the Free Software Foundation; either version 2, or (at your option) - any later version. + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of @@ -12,8 +12,7 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License - along with this program; if not, write to the Free Software Foundation, - Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ + along with this program. If not, see <http://www.gnu.org/licenses/>. */ /* Usage: stty [-ag] [--all] [--save] [-F device] [--file=device] [setting...] @@ -37,15 +36,11 @@ #include <stdio.h> #include <sys/types.h> -#if HAVE_TERMIOS_H -# include <termios.h> -#endif +#include <termios.h> #if HAVE_STROPTS_H # include <stropts.h> #endif -#ifdef HAVE_SYS_IOCTL_H -# include <sys/ioctl.h> -#endif +#include <sys/ioctl.h> #ifdef WINSIZE_IN_PTEM # include <sys/stream.h> @@ -57,18 +52,19 @@ #endif #include <getopt.h> #include <stdarg.h> +#include <assert.h> #include "system.h" #include "error.h" #include "fd-reopen.h" #include "quote.h" -#include "vasprintf.h" +#include "xdectoint.h" #include "xstrtol.h" -/* The official name of this program (e.g., no `g' prefix). */ +/* The official name of this program (e.g., no 'g' prefix). */ #define PROGRAM_NAME "stty" -#define AUTHORS "David MacKenzie" +#define AUTHORS proper_name ("David MacKenzie") #ifndef _POSIX_VDISABLE # define _POSIX_VDISABLE 0 @@ -122,8 +118,8 @@ # define CSWTCH _POSIX_VDISABLE #endif -/* SunOS 5.3 loses (^Z doesn't work) if `swtch' is the same as `susp'. - So the default is to disable `swtch.' */ +/* SunOS 5.3 loses (^Z doesn't work) if 'swtch' is the same as 'susp'. + So the default is to disable 'swtch.' */ #if defined __sparc__ && defined __svr4__ # undef CSWTCH # define CSWTCH _POSIX_VDISABLE @@ -184,17 +180,18 @@ enum output_type changed, all, recoverable /* Default, -a, -g. */ }; -/* Which member(s) of `struct termios' a mode uses. */ +/* Which member(s) of 'struct termios' a mode uses. */ enum mode_type { control, input, output, local, combination }; -/* Flags for `struct mode_info'. */ -#define SANE_SET 1 /* Set in `sane' mode. */ -#define SANE_UNSET 2 /* Unset in `sane' mode. */ -#define REV 4 /* Can be turned off by prepending `-'. */ +/* Flags for 'struct mode_info'. */ +#define SANE_SET 1 /* Set in 'sane' mode. */ +#define SANE_UNSET 2 /* Unset in 'sane' mode. */ +#define REV 4 /* Can be turned off by prepending '-'. */ #define OMIT 8 /* Don't display value. */ +#define NO_SETATTR 16 /* tcsetattr not used to set mode bits. */ /* Each mode. */ struct mode_info @@ -206,10 +203,13 @@ struct mode_info unsigned long mask; /* Other bits to turn off for this mode. */ }; -static struct mode_info mode_info[] = +static struct mode_info const mode_info[] = { {"parenb", control, REV, PARENB, 0}, {"parodd", control, REV, PARODD, 0}, +#ifdef CMSPAR + {"cmspar", control, REV, CMSPAR, 0}, +#endif {"cs5", control, 0, CS5, CSIZE}, {"cs6", control, 0, CS6, CSIZE}, {"cs7", control, 0, CS7, CSIZE}, @@ -222,6 +222,9 @@ static struct mode_info mode_info[] = #ifdef CRTSCTS {"crtscts", control, REV, CRTSCTS, 0}, #endif +#ifdef CDTRDSR + {"cdtrdsr", control, REV, CDTRDSR, 0}, +#endif {"ignbrk", input, SANE_UNSET | REV, IGNBRK, 0}, {"brkint", input, SANE_SET | REV, BRKINT, 0}, @@ -281,10 +284,18 @@ static struct mode_info mode_info[] = {"cr0", output, SANE_SET, CR0, CRDLY}, #endif #ifdef TABDLY +# ifdef TAB3 {"tab3", output, SANE_UNSET, TAB3, TABDLY}, +# endif +# ifdef TAB2 {"tab2", output, SANE_UNSET, TAB2, TABDLY}, +# endif +# ifdef TAB1 {"tab1", output, SANE_UNSET, TAB1, TABDLY}, +# endif +# ifdef TAB0 {"tab0", output, SANE_SET, TAB0, TABDLY}, +# endif #else # ifdef OXTABS {"tab3", output, SANE_UNSET, OXTABS, 0}, @@ -332,6 +343,14 @@ static struct mode_info mode_info[] = {"echoke", local, SANE_SET | REV, ECHOKE, 0}, {"crtkill", local, REV | OMIT, ECHOKE, 0}, #endif +#ifdef FLUSHO + {"flusho", local, SANE_UNSET | REV, FLUSHO, 0}, +#endif +#if defined TIOCEXT + {"extproc", local, SANE_UNSET | REV | NO_SETATTR, EXTPROC, 0}, +#elif defined EXTPROC + {"extproc", local, SANE_UNSET | REV, EXTPROC, 0}, +#endif {"evenp", combination, REV | OMIT, 0, 0}, {"parity", combination, REV | OMIT, 0, 0}, @@ -364,13 +383,13 @@ static struct mode_info mode_info[] = struct control_info { const char *name; /* Name given on command line. */ - cc_t saneval; /* Value to set for `stty sane'. */ + cc_t saneval; /* Value to set for 'stty sane'. */ size_t offset; /* Offset in c_cc. */ }; /* Control characters. */ -static struct control_info control_info[] = +static struct control_info const control_info[] = { {"intr", CINTR, VINTR}, {"quit", CQUIT, VQUIT}, @@ -404,7 +423,8 @@ static struct control_info control_info[] = {"lnext", CLNEXT, VLNEXT}, #endif #ifdef VFLUSHO - {"flush", CFLUSHO, VFLUSHO}, + {"flush", CFLUSHO, VFLUSHO}, /* deprecated compat option. */ + {"discard", CFLUSHO, VFLUSHO}, #endif #ifdef VSTATUS {"status", CSTATUS, VSTATUS}, @@ -420,8 +440,8 @@ static char const *visible (cc_t ch); static unsigned long int baud_to_value (speed_t speed); static bool recover_mode (char const *arg, struct termios *mode); static int screen_columns (void); -static bool set_mode (struct mode_info *info, bool reversed, - struct termios *mode); +static bool set_mode (struct mode_info const *info, bool reversed, + struct termios *mode); static unsigned long int integer_arg (const char *s, unsigned long int max); static speed_t string_to_baud (const char *arg); static tcflag_t *mode_type_flag (enum mode_type type, struct termios *mode); @@ -429,16 +449,16 @@ static void display_all (struct termios *mode, char const *device_name); static void display_changed (struct termios *mode); static void display_recoverable (struct termios *mode); static void display_settings (enum output_type output_type, - struct termios *mode, - const char *device_name); + struct termios *mode, + const char *device_name); static void display_speed (struct termios *mode, bool fancy); static void display_window_size (bool fancy, char const *device_name); static void sane_mode (struct termios *mode); -static void set_control_char (struct control_info *info, - const char *arg, - struct termios *mode); +static void set_control_char (struct control_info const *info, + const char *arg, + struct termios *mode); static void set_speed (enum speed_setting type, const char *arg, - struct termios *mode); + struct termios *mode); static void set_window_size (int rows, int cols, char const *device_name); /* The width of the screen, for output wrapping. */ @@ -447,7 +467,10 @@ static int max_col; /* Current position, to know when to wrap. */ static int current_col; -static struct option longopts[] = +/* Default "drain" mode for tcsetattr. */ +static int tcsetattr_options = TCSADRAIN; + +static struct option const longopts[] = { {"all", no_argument, NULL, 'a'}, {"save", no_argument, NULL, 'g'}, @@ -457,9 +480,6 @@ static struct option longopts[] = {NULL, 0, NULL, 0} }; -/* The name this program was run with. */ -char *program_name; - static void wrapf (const char *message, ...) __attribute__ ((__format__ (__printf__, 1, 2))); @@ -484,15 +504,15 @@ wrapf (const char *message,...) if (0 < current_col) { if (max_col - current_col < buflen) - { - putchar ('\n'); - current_col = 0; - } + { + putchar ('\n'); + current_col = 0; + } else - { - putchar (' '); - current_col++; - } + { + putchar (' '); + current_col++; + } } fputs (buf, stdout); @@ -504,19 +524,22 @@ void usage (int status) { if (status != EXIT_SUCCESS) - fprintf (stderr, _("Try `%s --help' for more information.\n"), - program_name); + emit_try_help (); else { printf (_("\ -Usage: %s [-F DEVICE] [--file=DEVICE] [SETTING]...\n\ - or: %s [-F DEVICE] [--file=DEVICE] [-a|--all]\n\ - or: %s [-F DEVICE] [--file=DEVICE] [-g|--save]\n\ +Usage: %s [-F DEVICE | --file=DEVICE] [SETTING]...\n\ + or: %s [-F DEVICE | --file=DEVICE] [-a|--all]\n\ + or: %s [-F DEVICE | --file=DEVICE] [-g|--save]\n\ "), - program_name, program_name, program_name); + program_name, program_name, program_name); fputs (_("\ Print or change terminal characteristics.\n\ -\n\ +"), stdout); + + emit_mandatory_arg_note (); + + fputs (_("\ -a, --all print all current settings in human-readable form\n\ -g, --save print all current settings in a stty-readable form\n\ -F, --file=DEVICE open and use the specified DEVICE instead of stdin\n\ @@ -530,45 +553,97 @@ settings. The underlying system defines which settings are available.\n\ "), stdout); fputs (_("\ \n\ -Special characters:\n\ +Special characters:\n"), stdout); +#ifdef VFLUSHO + fputs (_("\ + * discard CHAR CHAR will toggle discarding of output\n\ +"), stdout); +#endif +#ifdef VDSUSP + fputs (_("\ * dsusp CHAR CHAR will send a terminal stop signal once input flushed\n\ +"), stdout); +#endif + fputs (_("\ eof CHAR CHAR will send an end of file (terminate the input)\n\ eol CHAR CHAR will end the line\n\ "), stdout); +#ifdef VEOL2 fputs (_("\ * eol2 CHAR alternate CHAR for ending the line\n\ +"), stdout); +#endif + fputs (_("\ erase CHAR CHAR will erase the last character typed\n\ intr CHAR CHAR will send an interrupt signal\n\ kill CHAR CHAR will erase the current line\n\ "), stdout); +#ifdef VLNEXT fputs (_("\ * lnext CHAR CHAR will enter the next character quoted\n\ +"), stdout); +#endif +#ifdef VSTATUS + fputs (_("\ + * status CHAR CHAR will send an info signal\n\ +"), stdout); +#endif + fputs (_("\ quit CHAR CHAR will send a quit signal\n\ +"), stdout); +#if defined CREPRINT || defined VREPRINT + fputs (_("\ * rprnt CHAR CHAR will redraw the current line\n\ - start CHAR CHAR will restart the output after stopping it\n\ "), stdout); +#endif fputs (_("\ + start CHAR CHAR will restart the output after stopping it\n\ stop CHAR CHAR will stop the output\n\ susp CHAR CHAR will send a terminal stop signal\n\ +"), stdout); +#ifdef VSWTCH + fputs (_("\ * swtch CHAR CHAR will switch to a different shell layer\n\ +"), stdout); +#endif +#ifdef VWERASE + fputs (_("\ * werase CHAR CHAR will erase the last word typed\n\ "), stdout); +#endif fputs (_("\ \n\ Special settings:\n\ - N set the input and output speeds to N bauds\n\ + N set the input and output speeds to N bauds\n\ +"), stdout); +#ifdef TIOCGWINSZ + fputs (_("\ * cols N tell the kernel that the terminal has N columns\n\ * columns N same as cols N\n\ "), stdout); +#endif + printf (_("\ + * [-]drain wait for transmission before applying settings (%s by default)\ +\n"), tcsetattr_options == TCSADRAIN ? _("on") : _("off")); fputs (_("\ ispeed N set the input speed to N\n\ +"), stdout); +#ifdef HAVE_C_LINE + fputs (_("\ * line N use line discipline N\n\ +"), stdout); +#endif + fputs (_("\ min N with -icanon, set N characters minimum for a completed read\n\ ospeed N set the output speed to N\n\ "), stdout); +#ifdef TIOCGWINSZ fputs (_("\ * rows N tell the kernel that the terminal has N rows\n\ * size print the number of rows and columns according to the kernel\n\ +"), stdout); +#endif + fputs (_("\ speed print the terminal speed\n\ time N with -icanon, set read timeout of N tenths of a second\n\ "), stdout); @@ -577,16 +652,32 @@ Special settings:\n\ Control settings:\n\ [-]clocal disable modem control signals\n\ [-]cread allow input to be received\n\ +"), stdout); +#ifdef CRTSCTS + fputs (_("\ * [-]crtscts enable RTS/CTS handshaking\n\ +"), stdout); +#endif +#ifdef CDTRDSR + fputs (_("\ + * [-]cdtrdsr enable DTR/DSR handshaking\n\ +"), stdout); +#endif + fputs (_("\ csN set character size to N bits, N in [5..8]\n\ "), stdout); fputs (_("\ - [-]cstopb use two stop bits per character (one with `-')\n\ + [-]cstopb use two stop bits per character (one with '-')\n\ [-]hup send a hangup signal when the last process closes the tty\n\ [-]hupcl same as [-]hup\n\ [-]parenb generate parity bit in output and expect parity bit in input\n\ - [-]parodd set odd parity (even with `-')\n\ + [-]parodd set odd parity (or even parity with '-')\n\ +"), stdout); +#ifdef CMSPAR + fputs (_("\ + * [-]cmspar use \"stick\" (mark/space) parity\n\ "), stdout); +#endif fputs (_("\ \n\ Input settings:\n\ @@ -594,20 +685,34 @@ Input settings:\n\ [-]icrnl translate carriage return to newline\n\ [-]ignbrk ignore break characters\n\ [-]igncr ignore carriage return\n\ + [-]ignpar ignore characters with parity errors\n\ "), stdout); +#ifdef IMAXBEL fputs (_("\ - [-]ignpar ignore characters with parity errors\n\ * [-]imaxbel beep and do not flush a full input buffer on a character\n\ +"), stdout); +#endif + fputs (_("\ [-]inlcr translate newline to carriage return\n\ [-]inpck enable input parity checking\n\ [-]istrip clear high (8th) bit of input characters\n\ "), stdout); +#ifdef IUTF8 fputs (_("\ * [-]iutf8 assume input characters are UTF-8 encoded\n\ "), stdout); +#endif +#ifdef IUCLC fputs (_("\ * [-]iuclc translate uppercase characters to lowercase\n\ +"), stdout); +#endif +#ifdef IXANY + fputs (_("\ * [-]ixany let any character restart output, not only start character\n\ +"), stdout); +#endif + fputs (_("\ [-]ixoff enable sending of start/stop characters\n\ [-]ixon enable XON/XOFF flow control\n\ [-]parmrk mark parity errors (with a 255-0-character sequence)\n\ @@ -616,59 +721,168 @@ Input settings:\n\ fputs (_("\ \n\ Output settings:\n\ +"), stdout); +#ifdef BSDLY + fputs (_("\ * bsN backspace delay style, N in [0..1]\n\ +"), stdout); +#endif +#ifdef CRDLY + fputs (_("\ * crN carriage return delay style, N in [0..3]\n\ +"), stdout); +#endif +#ifdef FFDLY + fputs (_("\ * ffN form feed delay style, N in [0..1]\n\ +"), stdout); +#endif +#ifdef NLDLY + fputs (_("\ * nlN newline delay style, N in [0..1]\n\ "), stdout); +#endif +#ifdef OCRNL fputs (_("\ * [-]ocrnl translate carriage return to newline\n\ - * [-]ofdel use delete characters for fill instead of null characters\n\ +"), stdout); +#endif +#ifdef OFDEL + fputs (_("\ + * [-]ofdel use delete characters for fill instead of NUL characters\n\ +"), stdout); +#endif +#ifdef OFILL + fputs (_("\ * [-]ofill use fill (padding) characters instead of timing for delays\n\ +"), stdout); +#endif +#ifdef OLCUC + fputs (_("\ * [-]olcuc translate lowercase characters to uppercase\n\ +"), stdout); +#endif +#ifdef ONLCR + fputs (_("\ * [-]onlcr translate newline to carriage return-newline\n\ +"), stdout); +#endif +#ifdef ONLRET + fputs (_("\ * [-]onlret newline performs a carriage return\n\ "), stdout); +#endif +#ifdef ONOCR fputs (_("\ * [-]onocr do not print carriage returns in the first column\n\ +"), stdout); +#endif + fputs (_("\ [-]opost postprocess output\n\ +"), stdout); +#if defined TABDLY || defined OXTABS + fputs (_("\ * tabN horizontal tab delay style, N in [0..3]\n\ * tabs same as tab0\n\ * -tabs same as tab3\n\ +"), stdout); +#endif +#ifdef VTDLY + fputs (_("\ * vtN vertical tab delay style, N in [0..1]\n\ "), stdout); +#endif fputs (_("\ \n\ Local settings:\n\ [-]crterase echo erase characters as backspace-space-backspace\n\ +"), stdout); +#ifdef ECHOKE + fputs (_("\ * crtkill kill all line by obeying the echoprt and echoe settings\n\ * -crtkill kill all line by obeying the echoctl and echok settings\n\ "), stdout); +#endif +#ifdef ECHOCTL + fputs (_("\ + * [-]ctlecho echo control characters in hat notation ('^c')\n\ +"), stdout); +#endif fputs (_("\ - * [-]ctlecho echo control characters in hat notation (`^c')\n\ [-]echo echo input characters\n\ +"), stdout); +#ifdef ECHOCTL + fputs (_("\ * [-]echoctl same as [-]ctlecho\n\ +"), stdout); +#endif + fputs (_("\ [-]echoe same as [-]crterase\n\ [-]echok echo a newline after a kill character\n\ "), stdout); +#ifdef ECHOKE fputs (_("\ * [-]echoke same as [-]crtkill\n\ +"), stdout); +#endif + fputs (_("\ [-]echonl echo newline even if not echoing other characters\n\ - * [-]echoprt echo erased characters backward, between `\\' and '/'\n\ - [-]icanon enable erase, kill, werase, and rprnt special characters\n\ - [-]iexten enable non-POSIX special characters\n\ "), stdout); +#ifdef ECHOPRT + fputs (_("\ + * [-]echoprt echo erased characters backward, between '\\' and '/'\n\ +"), stdout); +#endif +#if defined EXTPROC || defined TIOCEXT + fputs (_("\ + * [-]extproc enable \"LINEMODE\"; useful with high latency links\n\ +"), stdout); +#endif +#if defined FLUSHO + fputs (_("\ + * [-]flusho discard output\n\ +"), stdout); +#endif + printf (_("\ + [-]icanon enable special characters: %s\n\ + [-]iexten enable non-POSIX special characters\n\ +"), "erase, kill" +#ifdef VWERASE + ", werase" +#endif +#if defined CREPRINT || defined VREPRINT + ", rprnt" +#endif +); fputs (_("\ [-]isig enable interrupt, quit, and suspend special characters\n\ [-]noflsh disable flushing after interrupt and quit special characters\n\ +"), stdout); +#ifdef ECHOPRT + fputs (_("\ * [-]prterase same as [-]echoprt\n\ +"), stdout); +#endif +#ifdef TOSTOP + fputs (_("\ * [-]tostop stop background jobs that try to write to the terminal\n\ - * [-]xcase with icanon, escape with `\\' for uppercase characters\n\ "), stdout); +#endif +#ifdef XCASE + fputs (_("\ + * [-]xcase with icanon, escape with '\\' for uppercase characters\n\ +"), stdout); +#endif fputs (_("\ \n\ Combination settings:\n\ +"), stdout); +#if defined XCASE && defined IUCLC && defined OLCUC + fputs (_("\ * [-]LCASE same as [-]lcase\n\ +"), stdout); +#endif + fputs (_("\ cbreak same as -icanon\n\ -cbreak same as icanon\n\ "), stdout); @@ -676,22 +890,69 @@ Combination settings:\n\ cooked same as brkint ignpar istrip icrnl ixon opost isig\n\ icanon, eof and eol characters to their default values\n\ -cooked same as raw\n\ - crt same as echoe echoctl echoke\n\ "), stdout); - fputs (_("\ - dec same as echoe echoctl echoke -ixany intr ^c erase 0177\n\ + printf (_("\ + crt same as %s\n\ +"), "echoe" +#ifdef ECHOCTL + " echoctl" +#endif +#ifdef ECHOKE + " echoke" +#endif +); + printf (_("\ + dec same as %s intr ^c erase 0177\n\ kill ^u\n\ +"), "echoe" +#ifdef ECHOCTL + " echoctl" +#endif +#ifdef ECHOKE + " echoke" +#endif +#ifdef IXANY + " -ixany" +#endif +); +#ifdef IXANY + fputs (_("\ * [-]decctlq same as [-]ixany\n\ +"), stdout); +#endif + fputs (_("\ ek erase and kill characters to their default values\n\ evenp same as parenb -parodd cs7\n\ + -evenp same as -parenb cs8\n\ "), stdout); +#if defined XCASE && defined IUCLC && defined OLCUC fputs (_("\ - -evenp same as -parenb cs8\n\ * [-]lcase same as xcase iuclc olcuc\n\ +"), stdout); +#endif + fputs (_("\ litout same as -parenb -istrip -opost cs8\n\ -litout same as parenb istrip opost cs7\n\ - nl same as -icrnl -onlcr\n\ - -nl same as icrnl -inlcr -igncr onlcr -ocrnl -onlret\n\ +"), stdout); + printf (_("\ + nl same as %s\n\ + -nl same as %s\n\ +"), "-icrnl" +#ifdef ONLCR + " -onlcr" +#endif + , "icrnl -inlcr -igncr" +#ifdef ONLCR + " onlcr" +#endif +#ifdef OCRNL + " -ocrnl" +#endif +#ifdef ONLRET + " -onlret" +#endif +); + fputs (_("\ "), stdout); fputs (_("\ oddp same as parenb parodd cs7\n\ @@ -700,20 +961,111 @@ Combination settings:\n\ pass8 same as -parenb -istrip cs8\n\ -pass8 same as parenb istrip cs7\n\ "), stdout); - fputs (_("\ + printf (_("\ raw same as -ignbrk -brkint -ignpar -parmrk -inpck -istrip\n\ - -inlcr -igncr -icrnl -ixon -ixoff -iuclc -ixany\n\ - -imaxbel -opost -isig -icanon -xcase min 1 time 0\n\ + -inlcr -igncr -icrnl -ixon -ixoff -icanon -opost\n\ + -isig%s min 1 time 0\n\ -raw same as cooked\n\ -"), stdout); - fputs (_("\ - sane same as cread -ignbrk brkint -inlcr -igncr icrnl -iutf8\n\ - -ixoff -iuclc -ixany imaxbel opost -olcuc -ocrnl onlcr\n\ - -onocr -onlret -ofill -ofdel nl0 cr0 tab0 bs0 vt0 ff0\n\ - isig icanon iexten echo echoe echok -echonl -noflsh\n\ - -xcase -tostop -echoprt echoctl echoke, all special\n\ - characters to their default values.\n\ -"), stdout); +"), +#ifdef IUCLC + " -iuclc" +#endif +#ifdef IXANY + " -ixany" +#endif +#ifdef IMAXBEL + " -imaxbel" +#endif +#ifdef XCASE + " -xcase" +#endif +); + printf (_("\ + sane same as cread -ignbrk brkint -inlcr -igncr icrnl\n\ + icanon iexten echo echoe echok -echonl -noflsh\n\ + %s\n\ + %s\n\ + %s,\n\ + all special characters to their default values\n\ +"), + "-ixoff" +#ifdef IUTF8 + " -iutf8" +#endif +#ifdef IUCLC + " -iuclc" +#endif +#ifdef IXANY + " -ixany" +#endif +#ifdef IMAXBEL + " imaxbel" +#endif +#ifdef XCASE + " -xcase" +#endif +#ifdef OLCUC + " -olcuc" +#endif +#ifdef OCRNL + " -ocrnl" +#endif + + , "opost" +#ifdef OFILL + " -ofill" +#endif +#ifdef ONLCR + " onlcr" +#endif +#ifdef ONOCR + " -onocr" +#endif +#ifdef ONLRET + " -onlret" +#endif +#ifdef NLDLY + " nl0" +#endif +#ifdef CRDLY + " cr0" +#endif +#ifdef TAB0 + " tab0" +#endif +#ifdef BSDLY + " bs0" +#endif +#ifdef VTDLY + " vt0" +#endif +#ifdef FFDLY + " ff0" +#endif + + , "isig" +#ifdef TOSTOP + " -tostop" +#endif +#ifdef OFDEL + " -ofdel" +#endif +#ifdef ECHOPRT + " -echoprt" +#endif +#ifdef ECHOCTL + " echoctl" +#endif +#ifdef ECHOKE + " echoke" +#endif +#ifdef EXTPROC + " -extproc" +#endif +#ifdef FLUSHO + " -flusho" +#endif +); fputs (_("\ \n\ Handle the tty line connected to standard input. Without arguments,\n\ @@ -721,7 +1073,7 @@ prints baud rate, line discipline, and deviations from stty sane. In\n\ settings, CHAR is taken literally, or coded as in ^c, 0x37, 0177 or\n\ 127; special values ^- or undef used to disable special characters.\n\ "), stdout); - printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT); + emit_ancillary_info (PROGRAM_NAME); } exit (status); } @@ -731,14 +1083,14 @@ main (int argc, char **argv) { /* Initialize to all zeroes so there is no risk memcmp will report a spurious difference in an uninitialized portion of the structure. */ - struct termios mode = { 0, }; + static struct termios mode; enum output_type output_type; int optc; int argi = 0; int opti = 1; bool require_set_attr; - bool speed_was_set; + bool speed_was_set _GL_UNUSED; bool verbose_output; bool recoverable_output; int k; @@ -747,7 +1099,7 @@ main (int argc, char **argv) const char *device_name; initialize_main (&argc, &argv); - program_name = argv[0]; + set_program_name (argv[0]); setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); @@ -769,60 +1121,64 @@ main (int argc, char **argv) short and long options, --, POSIXLY_CORRECT, etc. */ while ((optc = getopt_long (argc - argi, argv + argi, "-agF:", - longopts, NULL)) - != -1) + longopts, NULL)) + != -1) { switch (optc) - { - case 'a': - verbose_output = true; - output_type = all; - break; + { + case 'a': + verbose_output = true; + output_type = all; + break; - case 'g': - recoverable_output = true; - output_type = recoverable; - break; + case 'g': + recoverable_output = true; + output_type = recoverable; + break; - case 'F': - if (file_name) - error (EXIT_FAILURE, 0, _("only one device may be specified")); - file_name = optarg; - break; + case 'F': + if (file_name) + error (EXIT_FAILURE, 0, _("only one device may be specified")); + file_name = optarg; + break; - case_GETOPT_HELP_CHAR; + case_GETOPT_HELP_CHAR; - case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); + case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); - default: - noargs = false; + default: + /* Consider "drain" as an option rather than a setting, + to support: alias stty='stty -drain' etc. */ + if (! STREQ (argv[argi + opti], "-drain") + && ! STREQ (argv[argi + opti], "drain")) + noargs = false; - /* Skip the argument containing this unrecognized option; - the 2nd pass will analyze it. */ - argi += opti; + /* Skip the argument containing this unrecognized option; + the 2nd pass will analyze it. */ + argi += opti; - /* Restart getopt_long from the first unskipped argument. */ - opti = 1; - optind = 0; + /* Restart getopt_long from the first unskipped argument. */ + opti = 1; + optind = 0; - break; - } + break; + } /* Clear fully-parsed arguments, so they don't confuse the 2nd pass. */ while (opti < optind) - argv[argi + opti++] = NULL; + argv[argi + opti++] = NULL; } /* Specifying both -a and -g gets an error. */ - if (verbose_output & recoverable_output) + if (verbose_output && recoverable_output) error (EXIT_FAILURE, 0, - _("the options for verbose and stty-readable output styles are\n" - "mutually exclusive")); + _("the options for verbose and stty-readable output styles are\n" + "mutually exclusive")); /* Specifying any other arguments with -a or -g gets an error. */ - if (!noargs & (verbose_output | recoverable_output)) + if (!noargs && (verbose_output || recoverable_output)) error (EXIT_FAILURE, 0, - _("when specifying an output style, modes may not be set")); + _("when specifying an output style, modes may not be set")); /* FIXME: it'd be better not to open the file until we've verified that all arguments are valid. Otherwise, we could end up doing @@ -834,24 +1190,24 @@ main (int argc, char **argv) int fdflags; device_name = file_name; if (fd_reopen (STDIN_FILENO, device_name, O_RDONLY | O_NONBLOCK, 0) < 0) - error (EXIT_FAILURE, errno, "%s", device_name); + error (EXIT_FAILURE, errno, "%s", quotef (device_name)); if ((fdflags = fcntl (STDIN_FILENO, F_GETFL)) == -1 - || fcntl (STDIN_FILENO, F_SETFL, fdflags & ~O_NONBLOCK) < 0) - error (EXIT_FAILURE, errno, _("%s: couldn't reset non-blocking mode"), - device_name); + || fcntl (STDIN_FILENO, F_SETFL, fdflags & ~O_NONBLOCK) < 0) + error (EXIT_FAILURE, errno, _("%s: couldn't reset non-blocking mode"), + quotef (device_name)); } else device_name = _("standard input"); if (tcgetattr (STDIN_FILENO, &mode)) - error (EXIT_FAILURE, errno, "%s", device_name); + error (EXIT_FAILURE, errno, "%s", quotef (device_name)); - if (verbose_output | recoverable_output | noargs) + if (verbose_output || recoverable_output || noargs) { max_col = screen_columns (); current_col = 0; display_settings (output_type, &mode, device_name); - exit (EXIT_SUCCESS); + return EXIT_SUCCESS; } speed_was_set = false; @@ -860,213 +1216,238 @@ main (int argc, char **argv) { char const *arg = argv[k]; bool match_found = false; + bool not_set_attr = false; bool reversed = false; int i; if (! arg) - continue; + continue; if (arg[0] == '-') - { - ++arg; - reversed = true; - } + { + ++arg; + reversed = true; + } + if (STREQ (arg, "drain")) + { + tcsetattr_options = reversed ? TCSANOW : TCSADRAIN; + continue; + } for (i = 0; mode_info[i].name != NULL; ++i) - { - if (STREQ (arg, mode_info[i].name)) - { - match_found = set_mode (&mode_info[i], reversed, &mode); - require_set_attr = true; - break; - } - } - if (!match_found & reversed) - { - error (0, 0, _("invalid argument %s"), quote (arg - 1)); - usage (EXIT_FAILURE); - } - if (!match_found) - { - for (i = 0; control_info[i].name != NULL; ++i) - { - if (STREQ (arg, control_info[i].name)) - { - if (k == argc - 1) - { - error (0, 0, _("missing argument to %s"), quote (arg)); - usage (EXIT_FAILURE); - } - match_found = true; - ++k; - set_control_char (&control_info[i], argv[k], &mode); - require_set_attr = true; - break; - } - } - } + { + if (STREQ (arg, mode_info[i].name)) + { + if ((mode_info[i].flags & NO_SETATTR) == 0) + { + match_found = set_mode (&mode_info[i], reversed, &mode); + require_set_attr = true; + } + else + match_found = not_set_attr = true; + break; + } + } + if (!match_found && reversed) + { + error (0, 0, _("invalid argument %s"), quote (arg - 1)); + usage (EXIT_FAILURE); + } if (!match_found) - { - if (STREQ (arg, "ispeed")) - { - if (k == argc - 1) - { - error (0, 0, _("missing argument to %s"), quote (arg)); - usage (EXIT_FAILURE); - } - ++k; - set_speed (input_speed, argv[k], &mode); - speed_was_set = true; - require_set_attr = true; - } - else if (STREQ (arg, "ospeed")) - { - if (k == argc - 1) - { - error (0, 0, _("missing argument to %s"), quote (arg)); - usage (EXIT_FAILURE); - } - ++k; - set_speed (output_speed, argv[k], &mode); - speed_was_set = true; - require_set_attr = true; - } + { + for (i = 0; control_info[i].name != NULL; ++i) + { + if (STREQ (arg, control_info[i].name)) + { + if (k == argc - 1) + { + error (0, 0, _("missing argument to %s"), quote (arg)); + usage (EXIT_FAILURE); + } + match_found = true; + ++k; + set_control_char (&control_info[i], argv[k], &mode); + require_set_attr = true; + break; + } + } + } + if (!match_found || not_set_attr) + { + if (STREQ (arg, "ispeed")) + { + if (k == argc - 1) + { + error (0, 0, _("missing argument to %s"), quote (arg)); + usage (EXIT_FAILURE); + } + ++k; + set_speed (input_speed, argv[k], &mode); + speed_was_set = true; + require_set_attr = true; + } + else if (STREQ (arg, "ospeed")) + { + if (k == argc - 1) + { + error (0, 0, _("missing argument to %s"), quote (arg)); + usage (EXIT_FAILURE); + } + ++k; + set_speed (output_speed, argv[k], &mode); + speed_was_set = true; + require_set_attr = true; + } +#ifdef TIOCEXT + /* This is the BSD interface to "extproc". + Even though it's an lflag, an ioctl is used to set it. */ + else if (STREQ (arg, "extproc")) + { + int val = ! reversed; + + if (ioctl (STDIN_FILENO, TIOCEXT, &val) != 0) + { + error (EXIT_FAILURE, errno, _("%s: error setting %s"), + quotef_n (0, device_name), quote_n (1, arg)); + } + } +#endif #ifdef TIOCGWINSZ - else if (STREQ (arg, "rows")) - { - if (k == argc - 1) - { - error (0, 0, _("missing argument to %s"), quote (arg)); - usage (EXIT_FAILURE); - } - ++k; - set_window_size (integer_arg (argv[k], INT_MAX), -1, - device_name); - } - else if (STREQ (arg, "cols") - || STREQ (arg, "columns")) - { - if (k == argc - 1) - { - error (0, 0, _("missing argument to %s"), quote (arg)); - usage (EXIT_FAILURE); - } - ++k; - set_window_size (-1, integer_arg (argv[k], INT_MAX), - device_name); - } - else if (STREQ (arg, "size")) - { - max_col = screen_columns (); - current_col = 0; - display_window_size (false, device_name); - } + else if (STREQ (arg, "rows")) + { + if (k == argc - 1) + { + error (0, 0, _("missing argument to %s"), quote (arg)); + usage (EXIT_FAILURE); + } + ++k; + set_window_size (integer_arg (argv[k], INT_MAX), -1, + device_name); + } + else if (STREQ (arg, "cols") + || STREQ (arg, "columns")) + { + if (k == argc - 1) + { + error (0, 0, _("missing argument to %s"), quote (arg)); + usage (EXIT_FAILURE); + } + ++k; + set_window_size (-1, integer_arg (argv[k], INT_MAX), + device_name); + } + else if (STREQ (arg, "size")) + { + max_col = screen_columns (); + current_col = 0; + display_window_size (false, device_name); + } #endif #ifdef HAVE_C_LINE - else if (STREQ (arg, "line")) - { - unsigned long int value; - if (k == argc - 1) - { - error (0, 0, _("missing argument to %s"), quote (arg)); - usage (EXIT_FAILURE); - } - ++k; - mode.c_line = value = integer_arg (argv[k], ULONG_MAX); - if (mode.c_line != value) - error (0, 0, _("invalid line discipline %s"), quote (argv[k])); - require_set_attr = true; - } -#endif - else if (STREQ (arg, "speed")) - { - max_col = screen_columns (); - display_speed (&mode, false); - } - else if (string_to_baud (arg) != (speed_t) -1) - { - set_speed (both_speeds, arg, &mode); - speed_was_set = true; - require_set_attr = true; - } - else - { - if (! recover_mode (arg, &mode)) - { - error (0, 0, _("invalid argument %s"), quote (arg)); - usage (EXIT_FAILURE); - } - require_set_attr = true; - } - } + else if (STREQ (arg, "line")) + { + unsigned long int value; + if (k == argc - 1) + { + error (0, 0, _("missing argument to %s"), quote (arg)); + usage (EXIT_FAILURE); + } + ++k; + mode.c_line = value = integer_arg (argv[k], ULONG_MAX); + if (mode.c_line != value) + error (0, 0, _("invalid line discipline %s"), quote (argv[k])); + require_set_attr = true; + } +#endif + else if (STREQ (arg, "speed")) + { + max_col = screen_columns (); + display_speed (&mode, false); + } + else if (string_to_baud (arg) != (speed_t) -1) + { + set_speed (both_speeds, arg, &mode); + speed_was_set = true; + require_set_attr = true; + } + else + { + if (! recover_mode (arg, &mode)) + { + error (0, 0, _("invalid argument %s"), quote (arg)); + usage (EXIT_FAILURE); + } + require_set_attr = true; + } + } } if (require_set_attr) { /* Initialize to all zeroes so there is no risk memcmp will report a - spurious difference in an uninitialized portion of the structure. */ - struct termios new_mode = { 0, }; + spurious difference in an uninitialized portion of the structure. */ + static struct termios new_mode; - if (tcsetattr (STDIN_FILENO, TCSADRAIN, &mode)) - error (EXIT_FAILURE, errno, "%s", device_name); + if (tcsetattr (STDIN_FILENO, tcsetattr_options, &mode)) + error (EXIT_FAILURE, errno, "%s", quotef (device_name)); /* POSIX (according to Zlotnick's book) tcsetattr returns zero if - it performs *any* of the requested operations. This means it - can report `success' when it has actually failed to perform - some proper subset of the requested operations. To detect - this partial failure, get the current terminal attributes and - compare them to the requested ones. */ + it performs *any* of the requested operations. This means it + can report 'success' when it has actually failed to perform + some proper subset of the requested operations. To detect + this partial failure, get the current terminal attributes and + compare them to the requested ones. */ if (tcgetattr (STDIN_FILENO, &new_mode)) - error (EXIT_FAILURE, errno, "%s", device_name); + error (EXIT_FAILURE, errno, "%s", quotef (device_name)); /* Normally, one shouldn't use memcmp to compare structures that - may have `holes' containing uninitialized data, but we have been - careful to initialize the storage of these two variables to all - zeroes. One might think it more efficient simply to compare the - modified fields, but that would require enumerating those fields -- - and not all systems have the same fields in this structure. */ + may have 'holes' containing uninitialized data, but we have been + careful to initialize the storage of these two variables to all + zeroes. One might think it more efficient simply to compare the + modified fields, but that would require enumerating those fields -- + and not all systems have the same fields in this structure. */ if (memcmp (&mode, &new_mode, sizeof (mode)) != 0) - { + { #ifdef CIBAUD - /* SunOS 4.1.3 (at least) has the problem that after this sequence, - tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2); - sometimes (m1 != m2). The only difference is in the four bits - of the c_cflag field corresponding to the baud rate. To save - Sun users a little confusion, don't report an error if this - happens. But suppress the error only if we haven't tried to - set the baud rate explicitly -- otherwise we'd never give an - error for a true failure to set the baud rate. */ - - new_mode.c_cflag &= (~CIBAUD); - if (speed_was_set || memcmp (&mode, &new_mode, sizeof (mode)) != 0) -#endif - { - error (EXIT_FAILURE, 0, - _("%s: unable to perform all requested operations"), - device_name); + /* SunOS 4.1.3 (at least) has the problem that after this sequence, + tcgetattr (&m1); tcsetattr (&m1); tcgetattr (&m2); + sometimes (m1 != m2). The only difference is in the four bits + of the c_cflag field corresponding to the baud rate. To save + Sun users a little confusion, don't report an error if this + happens. But suppress the error only if we haven't tried to + set the baud rate explicitly -- otherwise we'd never give an + error for a true failure to set the baud rate. */ + + new_mode.c_cflag &= (~CIBAUD); + if (speed_was_set || memcmp (&mode, &new_mode, sizeof (mode)) != 0) +#endif + { + error (EXIT_FAILURE, 0, + _("%s: unable to perform all requested operations"), + quotef (device_name)); #ifdef TESTING - { - size_t i; - printf (_("new_mode: mode\n")); - for (i = 0; i < sizeof (new_mode); i++) - printf ("0x%02x: 0x%02x\n", - *(((unsigned char *) &new_mode) + i), - *(((unsigned char *) &mode) + i)); - } -#endif - } - } + { + size_t i; + printf ("new_mode: mode\n"); + for (i = 0; i < sizeof (new_mode); i++) + printf ("0x%02x: 0x%02x\n", + *(((unsigned char *) &new_mode) + i), + *(((unsigned char *) &mode) + i)); + } +#endif + } + } } - exit (EXIT_SUCCESS); + return EXIT_SUCCESS; } /* Return false if not applied because not reversible; otherwise return true. */ static bool -set_mode (struct mode_info *info, bool reversed, struct termios *mode) +set_mode (struct mode_info const *info, bool reversed, struct termios *mode) { tcflag_t *bitsp; @@ -1079,189 +1460,189 @@ set_mode (struct mode_info *info, bool reversed, struct termios *mode) { /* Combination mode. */ if (STREQ (info->name, "evenp") || STREQ (info->name, "parity")) - { - if (reversed) - mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; - else - mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7; - } + { + if (reversed) + mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; + else + mode->c_cflag = (mode->c_cflag & ~PARODD & ~CSIZE) | PARENB | CS7; + } else if (STREQ (info->name, "oddp")) - { - if (reversed) - mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; - else - mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB; - } + { + if (reversed) + mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; + else + mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARODD | PARENB; + } else if (STREQ (info->name, "nl")) - { - if (reversed) - { - mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR; - mode->c_oflag = (mode->c_oflag + { + if (reversed) + { + mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR; + mode->c_oflag = (mode->c_oflag #ifdef ONLCR - | ONLCR + | ONLCR #endif - ) + ) #ifdef OCRNL - & ~OCRNL + & ~OCRNL #endif #ifdef ONLRET - & ~ONLRET + & ~ONLRET #endif - ; - } - else - { - mode->c_iflag = mode->c_iflag & ~ICRNL; + ; + } + else + { + mode->c_iflag = mode->c_iflag & ~ICRNL; #ifdef ONLCR - mode->c_oflag = mode->c_oflag & ~ONLCR; + mode->c_oflag = mode->c_oflag & ~ONLCR; #endif - } - } + } + } else if (STREQ (info->name, "ek")) - { - mode->c_cc[VERASE] = CERASE; - mode->c_cc[VKILL] = CKILL; - } + { + mode->c_cc[VERASE] = CERASE; + mode->c_cc[VKILL] = CKILL; + } else if (STREQ (info->name, "sane")) - sane_mode (mode); + sane_mode (mode); else if (STREQ (info->name, "cbreak")) - { - if (reversed) - mode->c_lflag |= ICANON; - else - mode->c_lflag &= ~ICANON; - } + { + if (reversed) + mode->c_lflag |= ICANON; + else + mode->c_lflag &= ~ICANON; + } else if (STREQ (info->name, "pass8")) - { - if (reversed) - { - mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB; - mode->c_iflag |= ISTRIP; - } - else - { - mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; - mode->c_iflag &= ~ISTRIP; - } - } + { + if (reversed) + { + mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB; + mode->c_iflag |= ISTRIP; + } + else + { + mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; + mode->c_iflag &= ~ISTRIP; + } + } else if (STREQ (info->name, "litout")) - { - if (reversed) - { - mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB; - mode->c_iflag |= ISTRIP; - mode->c_oflag |= OPOST; - } - else - { - mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; - mode->c_iflag &= ~ISTRIP; - mode->c_oflag &= ~OPOST; - } - } + { + if (reversed) + { + mode->c_cflag = (mode->c_cflag & ~CSIZE) | CS7 | PARENB; + mode->c_iflag |= ISTRIP; + mode->c_oflag |= OPOST; + } + else + { + mode->c_cflag = (mode->c_cflag & ~PARENB & ~CSIZE) | CS8; + mode->c_iflag &= ~ISTRIP; + mode->c_oflag &= ~OPOST; + } + } else if (STREQ (info->name, "raw") || STREQ (info->name, "cooked")) - { - if ((info->name[0] == 'r' && reversed) - || (info->name[0] == 'c' && !reversed)) - { - /* Cooked mode. */ - mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON; - mode->c_oflag |= OPOST; - mode->c_lflag |= ISIG | ICANON; + { + if ((info->name[0] == 'r' && reversed) + || (info->name[0] == 'c' && !reversed)) + { + /* Cooked mode. */ + mode->c_iflag |= BRKINT | IGNPAR | ISTRIP | ICRNL | IXON; + mode->c_oflag |= OPOST; + mode->c_lflag |= ISIG | ICANON; #if VMIN == VEOF - mode->c_cc[VEOF] = CEOF; + mode->c_cc[VEOF] = CEOF; #endif #if VTIME == VEOL - mode->c_cc[VEOL] = CEOL; -#endif - } - else - { - /* Raw mode. */ - mode->c_iflag = 0; - mode->c_oflag &= ~OPOST; - mode->c_lflag &= ~(ISIG | ICANON + mode->c_cc[VEOL] = CEOL; +#endif + } + else + { + /* Raw mode. */ + mode->c_iflag = 0; + mode->c_oflag &= ~OPOST; + mode->c_lflag &= ~(ISIG | ICANON #ifdef XCASE - | XCASE + | XCASE #endif - ); - mode->c_cc[VMIN] = 1; - mode->c_cc[VTIME] = 0; - } - } + ); + mode->c_cc[VMIN] = 1; + mode->c_cc[VTIME] = 0; + } + } #ifdef IXANY else if (STREQ (info->name, "decctlq")) - { - if (reversed) - mode->c_iflag |= IXANY; - else - mode->c_iflag &= ~IXANY; - } + { + if (reversed) + mode->c_iflag |= IXANY; + else + mode->c_iflag &= ~IXANY; + } #endif #ifdef TABDLY else if (STREQ (info->name, "tabs")) - { - if (reversed) - mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3; - else - mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0; - } + { + if (reversed) + mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB3; + else + mode->c_oflag = (mode->c_oflag & ~TABDLY) | TAB0; + } #else # ifdef OXTABS else if (STREQ (info->name, "tabs")) - { - if (reversed) - mode->c_oflag = mode->c_oflag | OXTABS; - else - mode->c_oflag = mode->c_oflag & ~OXTABS; - } + { + if (reversed) + mode->c_oflag = mode->c_oflag | OXTABS; + else + mode->c_oflag = mode->c_oflag & ~OXTABS; + } # endif #endif #if defined XCASE && defined IUCLC && defined OLCUC else if (STREQ (info->name, "lcase") - || STREQ (info->name, "LCASE")) - { - if (reversed) - { - mode->c_lflag &= ~XCASE; - mode->c_iflag &= ~IUCLC; - mode->c_oflag &= ~OLCUC; - } - else - { - mode->c_lflag |= XCASE; - mode->c_iflag |= IUCLC; - mode->c_oflag |= OLCUC; - } - } + || STREQ (info->name, "LCASE")) + { + if (reversed) + { + mode->c_lflag &= ~XCASE; + mode->c_iflag &= ~IUCLC; + mode->c_oflag &= ~OLCUC; + } + else + { + mode->c_lflag |= XCASE; + mode->c_iflag |= IUCLC; + mode->c_oflag |= OLCUC; + } + } #endif else if (STREQ (info->name, "crt")) - mode->c_lflag |= ECHOE + mode->c_lflag |= ECHOE #ifdef ECHOCTL - | ECHOCTL + | ECHOCTL #endif #ifdef ECHOKE - | ECHOKE + | ECHOKE #endif - ; + ; else if (STREQ (info->name, "dec")) - { - mode->c_cc[VINTR] = 3; /* ^C */ - mode->c_cc[VERASE] = 127; /* DEL */ - mode->c_cc[VKILL] = 21; /* ^U */ - mode->c_lflag |= ECHOE + { + mode->c_cc[VINTR] = 3; /* ^C */ + mode->c_cc[VERASE] = 127; /* DEL */ + mode->c_cc[VKILL] = 21; /* ^U */ + mode->c_lflag |= ECHOE #ifdef ECHOCTL - | ECHOCTL + | ECHOCTL #endif #ifdef ECHOKE - | ECHOKE + | ECHOKE #endif - ; + ; #ifdef IXANY - mode->c_iflag &= ~IXANY; + mode->c_iflag &= ~IXANY; #endif - } + } } else if (reversed) *bitsp = *bitsp & ~info->mask & ~info->bits; @@ -1272,8 +1653,8 @@ set_mode (struct mode_info *info, bool reversed, struct termios *mode) } static void -set_control_char (struct control_info *info, const char *arg, - struct termios *mode) +set_control_char (struct control_info const *info, const char *arg, + struct termios *mode) { unsigned long int value; @@ -1286,9 +1667,9 @@ set_control_char (struct control_info *info, const char *arg, else if (arg[0] == '^' && arg[1] != '\0') /* Ignore any trailing junk. */ { if (arg[1] == '?') - value = 127; + value = 127; else - value = to_uchar (arg[1]) & ~0140; /* Non-letters get weird results. */ + value = to_uchar (arg[1]) & ~0140; /* Non-letters get weird results. */ } else value = integer_arg (arg, TYPE_MAXIMUM (cc_t)); @@ -1324,7 +1705,7 @@ set_window_size (int rows, int cols, char const *device_name) if (get_win_size (STDIN_FILENO, &win)) { if (errno != EINVAL) - error (EXIT_FAILURE, errno, "%s", device_name); + error (EXIT_FAILURE, errno, "%s", quotef (device_name)); memset (&win, 0, sizeof (win)); } @@ -1346,8 +1727,8 @@ set_window_size (int rows, int cols, char const *device_name) it's almost certainly a "struct winsize" instead. At any rate, the bug manifests itself when ws_row == 0; the symptom is - that ws_row is set to ws_col, and ws_col is set to (ws_xpixel<<16) + - ws_ypixel. Since GNU stty sets rows and columns separately, this bug + that ws_row is set to ws_col, and ws_col is set to (ws_xpixel<<16) + + ws_ypixel. Since GNU stty sets rows and columns separately, this bug caused "stty rows 0 cols 0" to set rows to cols and cols to 0, while "stty cols 0 rows 0" would do the right thing. On a little-endian machine like the sun386i, the problem is the same, but for ws_col == 0. @@ -1366,16 +1747,16 @@ set_window_size (int rows, int cols, char const *device_name) win.ws_col = 1; if (ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win)) - error (EXIT_FAILURE, errno, "%s", device_name); + error (EXIT_FAILURE, errno, "%s", quotef (device_name)); if (ioctl (STDIN_FILENO, TIOCSSIZE, (char *) &ttysz)) - error (EXIT_FAILURE, errno, "%s", device_name); + error (EXIT_FAILURE, errno, "%s", quotef (device_name)); return; } # endif if (ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win)) - error (EXIT_FAILURE, errno, "%s", device_name); + error (EXIT_FAILURE, errno, "%s", quotef (device_name)); } static void @@ -1386,17 +1767,18 @@ display_window_size (bool fancy, char const *device_name) if (get_win_size (STDIN_FILENO, &win)) { if (errno != EINVAL) - error (EXIT_FAILURE, errno, "%s", device_name); + error (EXIT_FAILURE, errno, "%s", quotef (device_name)); if (!fancy) - error (EXIT_FAILURE, 0, - _("%s: no size information for this device"), device_name); + error (EXIT_FAILURE, 0, + _("%s: no size information for this device"), + quotef (device_name)); } else { wrapf (fancy ? "rows %d; columns %d;" : "%d %d\n", - win.ws_row, win.ws_col); + win.ws_row, win.ws_col); if (!fancy) - current_col = 0; + current_col = 0; } } #endif @@ -1421,15 +1803,15 @@ screen_columns (void) char *col_string = getenv ("COLUMNS"); long int n_columns; if (!(col_string != NULL - && xstrtol (col_string, NULL, 0, &n_columns, "") == LONGINT_OK - && 0 < n_columns - && n_columns <= INT_MAX)) + && xstrtol (col_string, NULL, 0, &n_columns, "") == LONGINT_OK + && 0 < n_columns + && n_columns <= INT_MAX)) n_columns = 80; return n_columns; } } -static tcflag_t * +static tcflag_t * _GL_ATTRIBUTE_PURE mode_type_flag (enum mode_type type, struct termios *mode) { switch (type) @@ -1456,7 +1838,7 @@ mode_type_flag (enum mode_type type, struct termios *mode) static void display_settings (enum output_type output_type, struct termios *mode, - char const *device_name) + char const *device_name) { switch (output_type) { @@ -1494,29 +1876,35 @@ display_changed (struct termios *mode) for (i = 0; !STREQ (control_info[i].name, "min"); ++i) { if (mode->c_cc[control_info[i].offset] == control_info[i].saneval) - continue; + continue; + +#ifdef VFLUSHO + /* 'flush' is the deprecated equivalent of 'discard'. */ + if (STREQ (control_info[i].name, "flush")) + continue; +#endif /* If swtch is the same as susp, don't print both. */ #if VSWTCH == VSUSP if (STREQ (control_info[i].name, "swtch")) - continue; + continue; #endif /* If eof uses the same slot as min, only print whichever applies. */ #if VEOF == VMIN if ((mode->c_lflag & ICANON) == 0 - && (STREQ (control_info[i].name, "eof") - || STREQ (control_info[i].name, "eol"))) - continue; + && (STREQ (control_info[i].name, "eof") + || STREQ (control_info[i].name, "eol"))) + continue; #endif empty_line = false; wrapf ("%s = %s;", control_info[i].name, - visible (mode->c_cc[control_info[i].offset])); + visible (mode->c_cc[control_info[i].offset])); } if ((mode->c_lflag & ICANON) == 0) { wrapf ("min = %lu; time = %lu;\n", - (unsigned long int) mode->c_cc[VMIN], - (unsigned long int) mode->c_cc[VTIME]); + (unsigned long int) mode->c_cc[VMIN], + (unsigned long int) mode->c_cc[VTIME]); } else if (!empty_line) putchar ('\n'); @@ -1526,33 +1914,39 @@ display_changed (struct termios *mode) for (i = 0; mode_info[i].name != NULL; ++i) { if (mode_info[i].flags & OMIT) - continue; + continue; if (mode_info[i].type != prev_type) - { - if (!empty_line) - { - putchar ('\n'); - current_col = 0; - empty_line = true; - } - prev_type = mode_info[i].type; - } + { + if (!empty_line) + { + putchar ('\n'); + current_col = 0; + empty_line = true; + } + prev_type = mode_info[i].type; + } bitsp = mode_type_flag (mode_info[i].type, mode); mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits; + + /* bitsp would be NULL only for "combination" modes, yet those + are filtered out above via the OMIT flag. Tell static analysis + tools that it's ok to dereference bitsp here. */ + assert (bitsp); + if ((*bitsp & mask) == mode_info[i].bits) - { - if (mode_info[i].flags & SANE_UNSET) - { - wrapf ("%s", mode_info[i].name); - empty_line = false; - } - } + { + if (mode_info[i].flags & SANE_UNSET) + { + wrapf ("%s", mode_info[i].name); + empty_line = false; + } + } else if ((mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV)) - { - wrapf ("-%s", mode_info[i].name); - empty_line = false; - } + { + wrapf ("-%s", mode_info[i].name); + empty_line = false; + } } if (!empty_line) putchar ('\n'); @@ -1579,27 +1973,32 @@ display_all (struct termios *mode, char const *device_name) for (i = 0; ! STREQ (control_info[i].name, "min"); ++i) { +#ifdef VFLUSHO + /* 'flush' is the deprecated equivalent of 'discard'. */ + if (STREQ (control_info[i].name, "flush")) + continue; +#endif /* If swtch is the same as susp, don't print both. */ #if VSWTCH == VSUSP if (STREQ (control_info[i].name, "swtch")) - continue; + continue; #endif /* If eof uses the same slot as min, only print whichever applies. */ #if VEOF == VMIN if ((mode->c_lflag & ICANON) == 0 - && (STREQ (control_info[i].name, "eof") - || STREQ (control_info[i].name, "eol"))) - continue; + && (STREQ (control_info[i].name, "eof") + || STREQ (control_info[i].name, "eol"))) + continue; #endif wrapf ("%s = %s;", control_info[i].name, - visible (mode->c_cc[control_info[i].offset])); + visible (mode->c_cc[control_info[i].offset])); } #if VEOF == VMIN if ((mode->c_lflag & ICANON) == 0) #endif wrapf ("min = %lu; time = %lu;", - (unsigned long int) mode->c_cc[VMIN], - (unsigned long int) mode->c_cc[VTIME]); + (unsigned long int) mode->c_cc[VMIN], + (unsigned long int) mode->c_cc[VTIME]); if (current_col != 0) putchar ('\n'); current_col = 0; @@ -1607,20 +2006,21 @@ display_all (struct termios *mode, char const *device_name) for (i = 0; mode_info[i].name != NULL; ++i) { if (mode_info[i].flags & OMIT) - continue; + continue; if (mode_info[i].type != prev_type) - { - putchar ('\n'); - current_col = 0; - prev_type = mode_info[i].type; - } + { + putchar ('\n'); + current_col = 0; + prev_type = mode_info[i].type; + } bitsp = mode_type_flag (mode_info[i].type, mode); mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits; + assert (bitsp); /* See the identical assertion and comment above. */ if ((*bitsp & mask) == mode_info[i].bits) - wrapf ("%s", mode_info[i].name); + wrapf ("%s", mode_info[i].name); else if (mode_info[i].flags & REV) - wrapf ("-%s", mode_info[i].name); + wrapf ("-%s", mode_info[i].name); } putchar ('\n'); current_col = 0; @@ -1631,11 +2031,11 @@ display_speed (struct termios *mode, bool fancy) { if (cfgetispeed (mode) == 0 || cfgetispeed (mode) == cfgetospeed (mode)) wrapf (fancy ? "speed %lu baud;" : "%lu\n", - baud_to_value (cfgetospeed (mode))); + baud_to_value (cfgetospeed (mode))); else wrapf (fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n", - baud_to_value (cfgetispeed (mode)), - baud_to_value (cfgetospeed (mode))); + baud_to_value (cfgetispeed (mode)), + baud_to_value (cfgetospeed (mode))); if (!fancy) current_col = 0; } @@ -1646,51 +2046,70 @@ display_recoverable (struct termios *mode) size_t i; printf ("%lx:%lx:%lx:%lx", - (unsigned long int) mode->c_iflag, - (unsigned long int) mode->c_oflag, - (unsigned long int) mode->c_cflag, - (unsigned long int) mode->c_lflag); + (unsigned long int) mode->c_iflag, + (unsigned long int) mode->c_oflag, + (unsigned long int) mode->c_cflag, + (unsigned long int) mode->c_lflag); for (i = 0; i < NCCS; ++i) printf (":%lx", (unsigned long int) mode->c_cc[i]); putchar ('\n'); } +/* NOTE: identical to below, modulo use of tcflag_t */ +static int +strtoul_tcflag_t (char const *s, int base, char **p, tcflag_t *result, + char delim) +{ + unsigned long ul; + errno = 0; + ul = strtoul (s, p, base); + if (errno || **p != delim || *p == s || (tcflag_t) ul != ul) + return -1; + *result = ul; + return 0; +} + +/* NOTE: identical to above, modulo use of cc_t */ +static int +strtoul_cc_t (char const *s, int base, char **p, cc_t *result, char delim) +{ + unsigned long ul; + errno = 0; + ul = strtoul (s, p, base); + if (errno || **p != delim || *p == s || (cc_t) ul != ul) + return -1; + *result = ul; + return 0; +} + +/* Parse the output of display_recoverable. + Return false if any part of it is invalid. */ static bool recover_mode (char const *arg, struct termios *mode) { + tcflag_t flag[4]; + char const *s = arg; size_t i; - int n; - unsigned long int chr; - unsigned long int iflag, oflag, cflag, lflag; - - /* Scan into temporaries since it is too much trouble to figure out - the right format for `tcflag_t'. */ - if (sscanf (arg, "%lx:%lx:%lx:%lx%n", - &iflag, &oflag, &cflag, &lflag, &n) != 4) - return false; - mode->c_iflag = iflag; - mode->c_oflag = oflag; - mode->c_cflag = cflag; - mode->c_lflag = lflag; - if (mode->c_iflag != iflag - || mode->c_oflag != oflag - || mode->c_cflag != cflag - || mode->c_lflag != lflag) - return false; - arg += n; - for (i = 0; i < NCCS; ++i) + for (i = 0; i < 4; i++) { - if (sscanf (arg, ":%lx%n", &chr, &n) != 1) - return false; - mode->c_cc[i] = chr; - if (mode->c_cc[i] != chr) - return false; - arg += n; + char *p; + if (strtoul_tcflag_t (s, 16, &p, flag + i, ':') != 0) + return false; + s = p + 1; } + mode->c_iflag = flag[0]; + mode->c_oflag = flag[1]; + mode->c_cflag = flag[2]; + mode->c_lflag = flag[3]; - /* Fail if there are too many fields. */ - if (*arg != '\0') - return false; + for (i = 0; i < NCCS; ++i) + { + char *p; + char delim = i < NCCS - 1 ? ':' : '\0'; + if (strtoul_cc_t (s, 16, &p, mode->c_cc + i, delim) != 0) + return false; + s = p + 1; + } return true; } @@ -1702,7 +2121,7 @@ struct speed_map unsigned long int value; /* Numeric value. */ }; -static struct speed_map speeds[] = +static struct speed_map const speeds[] = { {"0", B0, 0}, {"50", B50, 50}, @@ -1771,7 +2190,7 @@ static struct speed_map speeds[] = {NULL, 0, 0} }; -static speed_t +static speed_t _GL_ATTRIBUTE_PURE string_to_baud (const char *arg) { int i; @@ -1782,7 +2201,7 @@ string_to_baud (const char *arg) return (speed_t) -1; } -static unsigned long int +static unsigned long int _GL_ATTRIBUTE_PURE baud_to_value (speed_t speed) { int i; @@ -1803,28 +2222,31 @@ sane_mode (struct termios *mode) { #if VMIN == VEOF if (STREQ (control_info[i].name, "min")) - break; + break; #endif mode->c_cc[control_info[i].offset] = control_info[i].saneval; } for (i = 0; mode_info[i].name != NULL; ++i) { + if (mode_info[i].flags & NO_SETATTR) + continue; + if (mode_info[i].flags & SANE_SET) - { - bitsp = mode_type_flag (mode_info[i].type, mode); - *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits; - } + { + bitsp = mode_type_flag (mode_info[i].type, mode); + *bitsp = (*bitsp & ~mode_info[i].mask) | mode_info[i].bits; + } else if (mode_info[i].flags & SANE_UNSET) - { - bitsp = mode_type_flag (mode_info[i].type, mode); - *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits; - } + { + bitsp = mode_type_flag (mode_info[i].type, mode); + *bitsp = *bitsp & ~mode_info[i].mask & ~mode_info[i].bits; + } } } /* Return a string that is the printable representation of character CH. */ -/* Adapted from `cat' by Torbjorn Granlund. */ +/* Adapted from 'cat' by Torbjorn Granlund. */ static const char * visible (cc_t ch) @@ -1838,32 +2260,32 @@ visible (cc_t ch) if (ch >= 32) { if (ch < 127) - *bpout++ = ch; + *bpout++ = ch; else if (ch == 127) - { - *bpout++ = '^'; - *bpout++ = '?'; - } + { + *bpout++ = '^'; + *bpout++ = '?'; + } else - { - *bpout++ = 'M', - *bpout++ = '-'; - if (ch >= 128 + 32) - { - if (ch < 128 + 127) - *bpout++ = ch - 128; - else - { - *bpout++ = '^'; - *bpout++ = '?'; - } - } - else - { - *bpout++ = '^'; - *bpout++ = ch - 128 + 64; - } - } + { + *bpout++ = 'M'; + *bpout++ = '-'; + if (ch >= 128 + 32) + { + if (ch < 128 + 127) + *bpout++ = ch - 128; + else + { + *bpout++ = '^'; + *bpout++ = '?'; + } + } + else + { + *bpout++ = '^'; + *bpout++ = ch - 128 + 64; + } + } } else { @@ -1881,12 +2303,5 @@ visible (cc_t ch) static unsigned long int integer_arg (const char *s, unsigned long int maxval) { - unsigned long int value; - if (xstrtoul (s, NULL, 0, &value, "bB") != LONGINT_OK - || maxval < value) - { - error (0, 0, _("invalid integer argument %s"), quote (s)); - usage (EXIT_FAILURE); - } - return value; + return xnumtoumax (s, 0, 0, maxval, "bB", _("invalid integer argument"), 0); } |