summaryrefslogtreecommitdiff
path: root/src/stty.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/stty.c')
-rw-r--r--src/stty.c1579
1 files changed, 997 insertions, 582 deletions
diff --git a/src/stty.c b/src/stty.c
index 33a821d..30053cc 100644
--- a/src/stty.c
+++ b/src/stty.c
@@ -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);
}