src/stty.c - coreutils-8.23
Global variables defined
Data types defined
Functions defined
Macros defined
Source code
#include <config.h>
#ifdef TERMIOS_NEEDS_XOPEN_SOURCE
# define _XOPEN_SOURCE
#endif
#include <stdio.h>
#include <sys/types.h>
#include <termios.h>
#if HAVE_STROPTS_H
# include <stropts.h>
#endif
#include <sys/ioctl.h>
#ifdef WINSIZE_IN_PTEM
# include <sys/stream.h>
# include <sys/ptem.h>
#endif
#ifdef GWINSZ_IN_SYS_PTY
# include <sys/tty.h>
# include <sys/pty.h>
#endif
#include <getopt.h>
#include <stdarg.h>
#include <assert.h>
#include "system.h"
#include "error.h"
#include "fd-reopen.h"
#include "quote.h"
#include "xstrtol.h"
#define PROGRAM_NAME "stty"
#define AUTHORS proper_name ("David MacKenzie")
#ifndef _POSIX_VDISABLE
# define _POSIX_VDISABLE 0
#endif
#define Control(c) ((c) & 0x1f)
#ifndef CINTR
# define CINTR Control ('c')
#endif
#ifndef CQUIT
# define CQUIT 28
#endif
#ifndef CERASE
# define CERASE 127
#endif
#ifndef CKILL
# define CKILL Control ('u')
#endif
#ifndef CEOF
# define CEOF Control ('d')
#endif
#ifndef CEOL
# define CEOL _POSIX_VDISABLE
#endif
#ifndef CSTART
# define CSTART Control ('q')
#endif
#ifndef CSTOP
# define CSTOP Control ('s')
#endif
#ifndef CSUSP
# define CSUSP Control ('z')
#endif
#if defined VEOL2 && !defined CEOL2
# define CEOL2 _POSIX_VDISABLE
#endif
#if defined VSWTC && !defined VSWTCH
# define VSWTCH VSWTC
#endif
#if defined VSUSP && !defined VSWTCH
# define VSWTCH VSUSP
# if defined CSUSP && !defined CSWTCH
# define CSWTCH CSUSP
# endif
#endif
#if defined VSWTCH && !defined CSWTCH
# define CSWTCH _POSIX_VDISABLE
#endif
#if defined __sparc__ && defined __svr4__
# undef CSWTCH
# define CSWTCH _POSIX_VDISABLE
#endif
#if defined VWERSE && !defined VWERASE # define VWERASE VWERSE
#endif
#if defined VDSUSP && !defined CDSUSP
# define CDSUSP Control ('y')
#endif
#if !defined VREPRINT && defined VRPRNT # define VREPRINT VRPRNT
#endif
#if defined VREPRINT && !defined CRPRNT
# define CRPRNT Control ('r')
#endif
#if defined CREPRINT && !defined CRPRNT
# define CRPRNT Control ('r')
#endif
#if defined VWERASE && !defined CWERASE
# define CWERASE Control ('w')
#endif
#if defined VLNEXT && !defined CLNEXT
# define CLNEXT Control ('v')
#endif
#if defined VDISCARD && !defined VFLUSHO
# define VFLUSHO VDISCARD
#endif
#if defined VFLUSH && !defined VFLUSHO # define VFLUSHO VFLUSH
#endif
#if defined CTLECH && !defined ECHOCTL # define ECHOCTL CTLECH
#endif
#if defined TCTLECH && !defined ECHOCTL # define ECHOCTL TCTLECH
#endif
#if defined CRTKIL && !defined ECHOKE # define ECHOKE CRTKIL
#endif
#if defined VFLUSHO && !defined CFLUSHO
# define CFLUSHO Control ('o')
#endif
#if defined VSTATUS && !defined CSTATUS
# define CSTATUS Control ('t')
#endif
enum speed_setting
{
input_speed, output_speed, both_speeds
};
enum output_type
{
changed, all, recoverable };
enum mode_type
{
control, input, output, local, combination
};
#define SANE_SET 1 #define SANE_UNSET 2 #define REV 4 #define OMIT 8
struct mode_info
{
const char *name; enum mode_type type; char flags; unsigned long bits; unsigned long mask; };
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},
{"cs8", control, 0, CS8, CSIZE},
{"hupcl", control, REV, HUPCL, 0},
{"hup", control, REV | OMIT, HUPCL, 0},
{"cstopb", control, REV, CSTOPB, 0},
{"cread", control, SANE_SET | REV, CREAD, 0},
{"clocal", control, REV, CLOCAL, 0},
#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},
{"ignpar", input, REV, IGNPAR, 0},
{"parmrk", input, REV, PARMRK, 0},
{"inpck", input, REV, INPCK, 0},
{"istrip", input, REV, ISTRIP, 0},
{"inlcr", input, SANE_UNSET | REV, INLCR, 0},
{"igncr", input, SANE_UNSET | REV, IGNCR, 0},
{"icrnl", input, SANE_SET | REV, ICRNL, 0},
{"ixon", input, REV, IXON, 0},
{"ixoff", input, SANE_UNSET | REV, IXOFF, 0},
{"tandem", input, REV | OMIT, IXOFF, 0},
#ifdef IUCLC
{"iuclc", input, SANE_UNSET | REV, IUCLC, 0},
#endif
#ifdef IXANY
{"ixany", input, SANE_UNSET | REV, IXANY, 0},
#endif
#ifdef IMAXBEL
{"imaxbel", input, SANE_SET | REV, IMAXBEL, 0},
#endif
#ifdef IUTF8
{"iutf8", input, SANE_UNSET | REV, IUTF8, 0},
#endif
{"opost", output, SANE_SET | REV, OPOST, 0},
#ifdef OLCUC
{"olcuc", output, SANE_UNSET | REV, OLCUC, 0},
#endif
#ifdef OCRNL
{"ocrnl", output, SANE_UNSET | REV, OCRNL, 0},
#endif
#ifdef ONLCR
{"onlcr", output, SANE_SET | REV, ONLCR, 0},
#endif
#ifdef ONOCR
{"onocr", output, SANE_UNSET | REV, ONOCR, 0},
#endif
#ifdef ONLRET
{"onlret", output, SANE_UNSET | REV, ONLRET, 0},
#endif
#ifdef OFILL
{"ofill", output, SANE_UNSET | REV, OFILL, 0},
#endif
#ifdef OFDEL
{"ofdel", output, SANE_UNSET | REV, OFDEL, 0},
#endif
#ifdef NLDLY
{"nl1", output, SANE_UNSET, NL1, NLDLY},
{"nl0", output, SANE_SET, NL0, NLDLY},
#endif
#ifdef CRDLY
{"cr3", output, SANE_UNSET, CR3, CRDLY},
{"cr2", output, SANE_UNSET, CR2, CRDLY},
{"cr1", output, SANE_UNSET, CR1, CRDLY},
{"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},
# endif
#endif
#ifdef BSDLY
{"bs1", output, SANE_UNSET, BS1, BSDLY},
{"bs0", output, SANE_SET, BS0, BSDLY},
#endif
#ifdef VTDLY
{"vt1", output, SANE_UNSET, VT1, VTDLY},
{"vt0", output, SANE_SET, VT0, VTDLY},
#endif
#ifdef FFDLY
{"ff1", output, SANE_UNSET, FF1, FFDLY},
{"ff0", output, SANE_SET, FF0, FFDLY},
#endif
{"isig", local, SANE_SET | REV, ISIG, 0},
{"icanon", local, SANE_SET | REV, ICANON, 0},
#ifdef IEXTEN
{"iexten", local, SANE_SET | REV, IEXTEN, 0},
#endif
{"echo", local, SANE_SET | REV, ECHO, 0},
{"echoe", local, SANE_SET | REV, ECHOE, 0},
{"crterase", local, REV | OMIT, ECHOE, 0},
{"echok", local, SANE_SET | REV, ECHOK, 0},
{"echonl", local, SANE_UNSET | REV, ECHONL, 0},
{"noflsh", local, SANE_UNSET | REV, NOFLSH, 0},
#ifdef XCASE
{"xcase", local, SANE_UNSET | REV, XCASE, 0},
#endif
#ifdef TOSTOP
{"tostop", local, SANE_UNSET | REV, TOSTOP, 0},
#endif
#ifdef ECHOPRT
{"echoprt", local, SANE_UNSET | REV, ECHOPRT, 0},
{"prterase", local, REV | OMIT, ECHOPRT, 0},
#endif
#ifdef ECHOCTL
{"echoctl", local, SANE_SET | REV, ECHOCTL, 0},
{"ctlecho", local, REV | OMIT, ECHOCTL, 0},
#endif
#ifdef ECHOKE
{"echoke", local, SANE_SET | REV, ECHOKE, 0},
{"crtkill", local, REV | OMIT, ECHOKE, 0},
#endif
{"evenp", combination, REV | OMIT, 0, 0},
{"parity", combination, REV | OMIT, 0, 0},
{"oddp", combination, REV | OMIT, 0, 0},
{"nl", combination, REV | OMIT, 0, 0},
{"ek", combination, OMIT, 0, 0},
{"sane", combination, OMIT, 0, 0},
{"cooked", combination, REV | OMIT, 0, 0},
{"raw", combination, REV | OMIT, 0, 0},
{"pass8", combination, REV | OMIT, 0, 0},
{"litout", combination, REV | OMIT, 0, 0},
{"cbreak", combination, REV | OMIT, 0, 0},
#ifdef IXANY
{"decctlq", combination, REV | OMIT, 0, 0},
#endif
#if defined TABDLY || defined OXTABS
{"tabs", combination, REV | OMIT, 0, 0},
#endif
#if defined XCASE && defined IUCLC && defined OLCUC
{"lcase", combination, REV | OMIT, 0, 0},
{"LCASE", combination, REV | OMIT, 0, 0},
#endif
{"crt", combination, OMIT, 0, 0},
{"dec", combination, OMIT, 0, 0},
{NULL, control, 0, 0, 0}
};
struct control_info
{
const char *name; cc_t saneval; size_t offset; };
static struct control_info const control_info[] =
{
{"intr", CINTR, VINTR},
{"quit", CQUIT, VQUIT},
{"erase", CERASE, VERASE},
{"kill", CKILL, VKILL},
{"eof", CEOF, VEOF},
{"eol", CEOL, VEOL},
#ifdef VEOL2
{"eol2", CEOL2, VEOL2},
#endif
#ifdef VSWTCH
{"swtch", CSWTCH, VSWTCH},
#endif
{"start", CSTART, VSTART},
{"stop", CSTOP, VSTOP},
{"susp", CSUSP, VSUSP},
#ifdef VDSUSP
{"dsusp", CDSUSP, VDSUSP},
#endif
#ifdef VREPRINT
{"rprnt", CRPRNT, VREPRINT},
#else
# ifdef CREPRINT {"rprnt", CRPRNT, CREPRINT},
# endif
#endif
#ifdef VWERASE
{"werase", CWERASE, VWERASE},
#endif
#ifdef VLNEXT
{"lnext", CLNEXT, VLNEXT},
#endif
#ifdef VFLUSHO
{"flush", CFLUSHO, VFLUSHO},
#endif
#ifdef VSTATUS
{"status", CSTATUS, VSTATUS},
#endif
{"min", 1, VMIN},
{"time", 0, VTIME},
{NULL, 0, 0}
};
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 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);
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);
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 const *info,
const char *arg,
struct termios *mode);
static void set_speed (enum speed_setting type, const char *arg,
struct termios *mode);
static void set_window_size (int rows, int cols, char const *device_name);
static int max_col;
static int current_col;
static struct option const longopts[] =
{
{"all", no_argument, NULL, 'a'},
{"save", no_argument, NULL, 'g'},
{"file", required_argument, NULL, 'F'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
};
static void wrapf (const char *message, ...)
__attribute__ ((__format__ (__printf__, 1, 2)));
static void
wrapf (const char *message,...)
{
va_list args;
char *buf;
int buflen;
va_start (args, message);
buflen = vasprintf (&buf, message, args);
va_end (args);
if (buflen < 0)
xalloc_die ();
if (0 < current_col)
{
if (max_col - current_col < buflen)
{
putchar ('\n');
current_col = 0;
}
else
{
putchar (' ');
current_col++;
}
}
fputs (buf, stdout);
free (buf);
current_col += buflen;
}
void
usage (int status)
{
if (status != EXIT_SUCCESS)
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\
"),
program_name, program_name, program_name);
fputs (_("\
Print or change terminal characteristics.\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\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\
\n\
Optional - before SETTING indicates negation. An * marks non-POSIX\n\
settings. The underlying system defines which settings are available.\n\
"), stdout);
fputs (_("\
\n\
Special characters:\n\
* dsusp CHAR CHAR will send a terminal stop signal once input flushed\n\
eof CHAR CHAR will send an end of file (terminate the input)\n\
eol CHAR CHAR will end the line\n\
"), stdout);
fputs (_("\
* eol2 CHAR alternate CHAR for ending the line\n\
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);
fputs (_("\
* lnext CHAR CHAR will enter the next character quoted\n\
quit CHAR CHAR will send a quit signal\n\
* rprnt CHAR CHAR will redraw the current line\n\
start CHAR CHAR will restart the output after stopping it\n\
"), stdout);
fputs (_("\
stop CHAR CHAR will stop the output\n\
susp CHAR CHAR will send a terminal stop signal\n\
* swtch CHAR CHAR will switch to a different shell layer\n\
* werase CHAR CHAR will erase the last word typed\n\
"), stdout);
fputs (_("\
\n\
Special settings:\n\
N set the input and output speeds to N bauds\n\
* cols N tell the kernel that the terminal has N columns\n\
* columns N same as cols N\n\
"), stdout);
fputs (_("\
ispeed N set the input speed to N\n\
* line N use line discipline N\n\
min N with -icanon, set N characters minimum for a completed read\n\
ospeed N set the output speed to N\n\
"), stdout);
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\
speed print the terminal speed\n\
time N with -icanon, set read timeout of N tenths of a second\n\
"), stdout);
fputs (_("\
\n\
Control settings:\n\
[-]clocal disable modem control signals\n\
[-]cread allow input to be received\n\
* [-]crtscts enable RTS/CTS handshaking\n\
* [-]cdtrdsr enable DTR/DSR handshaking\n\
csN set character size to N bits, N in [5..8]\n\
"), stdout);
fputs (_("\
[-]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 (or even parity with '-')\n\
* [-]cmspar use \"stick\" (mark/space) parity\n\
"), stdout);
fputs (_("\
\n\
Input settings:\n\
[-]brkint breaks cause an interrupt signal\n\
[-]icrnl translate carriage return to newline\n\
[-]ignbrk ignore break characters\n\
[-]igncr ignore carriage return\n\
"), stdout);
fputs (_("\
[-]ignpar ignore characters with parity errors\n\
* [-]imaxbel beep and do not flush a full input buffer on a character\n\
[-]inlcr translate newline to carriage return\n\
[-]inpck enable input parity checking\n\
[-]istrip clear high (8th) bit of input characters\n\
"), stdout);
fputs (_("\
* [-]iutf8 assume input characters are UTF-8 encoded\n\
"), stdout);
fputs (_("\
* [-]iuclc translate uppercase characters to lowercase\n\
* [-]ixany let any character restart output, not only start character\n\
[-]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\
[-]tandem same as [-]ixoff\n\
"), stdout);
fputs (_("\
\n\
Output settings:\n\
* bsN backspace delay style, N in [0..1]\n\
* crN carriage return delay style, N in [0..3]\n\
* ffN form feed delay style, N in [0..1]\n\
* nlN newline delay style, N in [0..1]\n\
"), stdout);
fputs (_("\
* [-]ocrnl translate carriage return to newline\n\
* [-]ofdel use delete characters for fill instead of NUL characters\n\
* [-]ofill use fill (padding) characters instead of timing for delays\n\
* [-]olcuc translate lowercase characters to uppercase\n\
* [-]onlcr translate newline to carriage return-newline\n\
* [-]onlret newline performs a carriage return\n\
"), stdout);
fputs (_("\
* [-]onocr do not print carriage returns in the first column\n\
[-]opost postprocess output\n\
* tabN horizontal tab delay style, N in [0..3]\n\
* tabs same as tab0\n\
* -tabs same as tab3\n\
* vtN vertical tab delay style, N in [0..1]\n\
"), stdout);
fputs (_("\
\n\
Local settings:\n\
[-]crterase echo erase characters as backspace-space-backspace\n\
* 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);
fputs (_("\
* [-]ctlecho echo control characters in hat notation ('^c')\n\
[-]echo echo input characters\n\
* [-]echoctl same as [-]ctlecho\n\
[-]echoe same as [-]crterase\n\
[-]echok echo a newline after a kill character\n\
"), stdout);
fputs (_("\
* [-]echoke same as [-]crtkill\n\
[-]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);
fputs (_("\
[-]isig enable interrupt, quit, and suspend special characters\n\
[-]noflsh disable flushing after interrupt and quit special characters\n\
* [-]prterase same as [-]echoprt\n\
* [-]tostop stop background jobs that try to write to the terminal\n\
* [-]xcase with icanon, escape with '\\' for uppercase characters\n\
"), stdout);
fputs (_("\
\n\
Combination settings:\n\
* [-]LCASE same as [-]lcase\n\
cbreak same as -icanon\n\
-cbreak same as icanon\n\
"), stdout);
fputs (_("\
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\
kill ^u\n\
* [-]decctlq same as [-]ixany\n\
ek erase and kill characters to their default values\n\
evenp same as parenb -parodd cs7\n\
"), stdout);
fputs (_("\
-evenp same as -parenb cs8\n\
* [-]lcase same as xcase iuclc olcuc\n\
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);
fputs (_("\
oddp same as parenb parodd cs7\n\
-oddp same as -parenb cs8\n\
[-]parity same as [-]evenp\n\
pass8 same as -parenb -istrip cs8\n\
-pass8 same as parenb istrip cs7\n\
"), stdout);
fputs (_("\
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\
-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);
fputs (_("\
\n\
Handle the tty line connected to standard input. Without arguments,\n\
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);
emit_ancillary_info ();
}
exit (status);
}
int
main (int argc, char **argv)
{
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 _GL_UNUSED;
bool verbose_output;
bool recoverable_output;
int k;
bool noargs = true;
char *file_name = NULL;
const char *device_name;
initialize_main (&argc, &argv);
set_program_name (argv[0]);
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
output_type = changed;
verbose_output = false;
recoverable_output = false;
opterr = 0;
while ((optc = getopt_long (argc - argi, argv + argi, "-agF:",
longopts, NULL))
!= -1)
{
switch (optc)
{
case 'a':
verbose_output = true;
output_type = all;
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_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
noargs = false;
argi += opti;
opti = 1;
optind = 0;
break;
}
while (opti < optind)
argv[argi + opti++] = NULL;
}
if (verbose_output && recoverable_output)
error (EXIT_FAILURE, 0,
_("the options for verbose and stty-readable output styles are\n"
"mutually exclusive"));
if (!noargs && (verbose_output || recoverable_output))
error (EXIT_FAILURE, 0,
_("when specifying an output style, modes may not be set"));
FIXME
if (file_name)
{
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);
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);
}
else
device_name = _("standard input");
if (tcgetattr (STDIN_FILENO, &mode))
error (EXIT_FAILURE, errno, "%s", device_name);
if (verbose_output || recoverable_output || noargs)
{
max_col = screen_columns ();
current_col = 0;
display_settings (output_type, &mode, device_name);
exit (EXIT_SUCCESS);
}
speed_was_set = false;
require_set_attr = false;
for (k = 1; k < argc; k++)
{
char const *arg = argv[k];
bool match_found = false;
bool reversed = false;
int i;
if (! arg)
continue;
if (arg[0] == '-')
{
++arg;
reversed = true;
}
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 (!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;
}
#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);
}
#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;
}
}
}
if (require_set_attr)
{
static struct termios new_mode;
if (tcsetattr (STDIN_FILENO, TCSADRAIN, &mode))
error (EXIT_FAILURE, errno, "%s", device_name);
if (tcgetattr (STDIN_FILENO, &new_mode))
error (EXIT_FAILURE, errno, "%s", device_name);
if (memcmp (&mode, &new_mode, sizeof (mode)) != 0)
{
#ifdef CIBAUD
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);
#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
}
}
}
exit (EXIT_SUCCESS);
}
static bool
set_mode (struct mode_info const *info, bool reversed, struct termios *mode)
{
tcflag_t *bitsp;
if (reversed && (info->flags & REV) == 0)
return false;
bitsp = mode_type_flag (info->type, mode);
if (bitsp == NULL)
{
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;
}
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;
}
else if (STREQ (info->name, "nl"))
{
if (reversed)
{
mode->c_iflag = (mode->c_iflag | ICRNL) & ~INLCR & ~IGNCR;
mode->c_oflag = (mode->c_oflag
#ifdef ONLCR
| ONLCR
#endif
)
#ifdef OCRNL
& ~OCRNL
#endif
#ifdef ONLRET
& ~ONLRET
#endif
;
}
else
{
mode->c_iflag = mode->c_iflag & ~ICRNL;
#ifdef 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;
}
else if (STREQ (info->name, "sane"))
sane_mode (mode);
else if (STREQ (info->name, "cbreak"))
{
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;
}
}
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;
}
}
else if (STREQ (info->name, "raw") || STREQ (info->name, "cooked"))
{
if ((info->name[0] == 'r' && reversed)
|| (info->name[0] == 'c' && !reversed))
{
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;
#endif
#if VTIME == VEOL
mode->c_cc[VEOL] = CEOL;
#endif
}
else
{
mode->c_iflag = 0;
mode->c_oflag &= ~OPOST;
mode->c_lflag &= ~(ISIG | ICANON
#ifdef XCASE
| XCASE
#endif
);
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;
}
#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;
}
#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;
}
# 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;
}
}
#endif
else if (STREQ (info->name, "crt"))
mode->c_lflag |= ECHOE
#ifdef ECHOCTL
| ECHOCTL
#endif
#ifdef ECHOKE
| ECHOKE
#endif
;
else if (STREQ (info->name, "dec"))
{
mode->c_cc[VINTR] = 3; mode->c_cc[VERASE] = 127; mode->c_cc[VKILL] = 21; mode->c_lflag |= ECHOE
#ifdef ECHOCTL
| ECHOCTL
#endif
#ifdef ECHOKE
| ECHOKE
#endif
;
#ifdef IXANY
mode->c_iflag &= ~IXANY;
#endif
}
}
else if (reversed)
*bitsp = *bitsp & ~info->mask & ~info->bits;
else
*bitsp = (*bitsp & ~info->mask) | info->bits;
return true;
}
static void
set_control_char (struct control_info const *info, const char *arg,
struct termios *mode)
{
unsigned long int value;
if (STREQ (info->name, "min") || STREQ (info->name, "time"))
value = integer_arg (arg, TYPE_MAXIMUM (cc_t));
else if (arg[0] == '\0' || arg[1] == '\0')
value = to_uchar (arg[0]);
else if (STREQ (arg, "^-") || STREQ (arg, "undef"))
value = _POSIX_VDISABLE;
else if (arg[0] == '^' && arg[1] != '\0') {
if (arg[1] == '?')
value = 127;
else
value = to_uchar (arg[1]) & ~0140; }
else
value = integer_arg (arg, TYPE_MAXIMUM (cc_t));
mode->c_cc[info->offset] = value;
}
static void
set_speed (enum speed_setting type, const char *arg, struct termios *mode)
{
speed_t baud;
baud = string_to_baud (arg);
if (type == input_speed || type == both_speeds)
cfsetispeed (mode, baud);
if (type == output_speed || type == both_speeds)
cfsetospeed (mode, baud);
}
#ifdef TIOCGWINSZ
static int
get_win_size (int fd, struct winsize *win)
{
int err = ioctl (fd, TIOCGWINSZ, (char *) win);
return err;
}
static void
set_window_size (int rows, int cols, char const *device_name)
{
struct winsize win;
if (get_win_size (STDIN_FILENO, &win))
{
if (errno != EINVAL)
error (EXIT_FAILURE, errno, "%s", device_name);
memset (&win, 0, sizeof (win));
}
if (rows >= 0)
win.ws_row = rows;
if (cols >= 0)
win.ws_col = cols;
# ifdef TIOCSSIZE
if (win.ws_row == 0 || win.ws_col == 0)
{
struct ttysize ttysz;
ttysz.ts_lines = win.ws_row;
ttysz.ts_cols = win.ws_col;
win.ws_row = 1;
win.ws_col = 1;
if (ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win))
error (EXIT_FAILURE, errno, "%s", device_name);
if (ioctl (STDIN_FILENO, TIOCSSIZE, (char *) &ttysz))
error (EXIT_FAILURE, errno, "%s", device_name);
return;
}
# endif
if (ioctl (STDIN_FILENO, TIOCSWINSZ, (char *) &win))
error (EXIT_FAILURE, errno, "%s", device_name);
}
static void
display_window_size (bool fancy, char const *device_name)
{
struct winsize win;
if (get_win_size (STDIN_FILENO, &win))
{
if (errno != EINVAL)
error (EXIT_FAILURE, errno, "%s", device_name);
if (!fancy)
error (EXIT_FAILURE, 0,
_("%s: no size information for this device"), device_name);
}
else
{
wrapf (fancy ? "rows %d; columns %d;" : "%d %d\n",
win.ws_row, win.ws_col);
if (!fancy)
current_col = 0;
}
}
#endif
static int
screen_columns (void)
{
#ifdef TIOCGWINSZ
struct winsize win;
if (get_win_size (STDOUT_FILENO, &win) == 0 && 0 < win.ws_col)
return win.ws_col;
#endif
{
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))
n_columns = 80;
return n_columns;
}
}
static tcflag_t * _GL_ATTRIBUTE_PURE
mode_type_flag (enum mode_type type, struct termios *mode)
{
switch (type)
{
case control:
return &mode->c_cflag;
case input:
return &mode->c_iflag;
case output:
return &mode->c_oflag;
case local:
return &mode->c_lflag;
case combination:
return NULL;
default:
abort ();
}
}
static void
display_settings (enum output_type output_type, struct termios *mode,
char const *device_name)
{
switch (output_type)
{
case changed:
display_changed (mode);
break;
case all:
display_all (mode, device_name);
break;
case recoverable:
display_recoverable (mode);
break;
}
}
static void
display_changed (struct termios *mode)
{
int i;
bool empty_line;
tcflag_t *bitsp;
unsigned long mask;
enum mode_type prev_type = control;
display_speed (mode, true);
#ifdef HAVE_C_LINE
wrapf ("line = %d;", mode->c_line);
#endif
putchar ('\n');
current_col = 0;
empty_line = true;
for (i = 0; !STREQ (control_info[i].name, "min"); ++i)
{
if (mode->c_cc[control_info[i].offset] == control_info[i].saneval)
continue;
#if VSWTCH == VSUSP
if (STREQ (control_info[i].name, "swtch"))
continue;
#endif
#if VEOF == VMIN
if ((mode->c_lflag & ICANON) == 0
&& (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]));
}
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]);
}
else if (!empty_line)
putchar ('\n');
current_col = 0;
empty_line = true;
for (i = 0; mode_info[i].name != NULL; ++i)
{
if (mode_info[i].flags & OMIT)
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;
}
bitsp = mode_type_flag (mode_info[i].type, mode);
mask = mode_info[i].mask ? mode_info[i].mask : mode_info[i].bits;
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;
}
}
else if ((mode_info[i].flags & (SANE_SET | REV)) == (SANE_SET | REV))
{
wrapf ("-%s", mode_info[i].name);
empty_line = false;
}
}
if (!empty_line)
putchar ('\n');
current_col = 0;
}
static void
display_all (struct termios *mode, char const *device_name)
{
int i;
tcflag_t *bitsp;
unsigned long mask;
enum mode_type prev_type = control;
display_speed (mode, true);
#ifdef TIOCGWINSZ
display_window_size (true, device_name);
#endif
#ifdef HAVE_C_LINE
wrapf ("line = %d;", mode->c_line);
#endif
putchar ('\n');
current_col = 0;
for (i = 0; ! STREQ (control_info[i].name, "min"); ++i)
{
#if VSWTCH == VSUSP
if (STREQ (control_info[i].name, "swtch"))
continue;
#endif
#if VEOF == VMIN
if ((mode->c_lflag & ICANON) == 0
&& (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]));
}
#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]);
if (current_col != 0)
putchar ('\n');
current_col = 0;
for (i = 0; mode_info[i].name != NULL; ++i)
{
if (mode_info[i].flags & OMIT)
continue;
if (mode_info[i].type != prev_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); if ((*bitsp & mask) == mode_info[i].bits)
wrapf ("%s", mode_info[i].name);
else if (mode_info[i].flags & REV)
wrapf ("-%s", mode_info[i].name);
}
putchar ('\n');
current_col = 0;
}
static void
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)));
else
wrapf (fancy ? "ispeed %lu baud; ospeed %lu baud;" : "%lu %lu\n",
baud_to_value (cfgetispeed (mode)),
baud_to_value (cfgetospeed (mode)));
if (!fancy)
current_col = 0;
}
static void
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);
for (i = 0; i < NCCS; ++i)
printf (":%lx", (unsigned long int) mode->c_cc[i]);
putchar ('\n');
}
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;
}
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;
}
static bool
recover_mode (char const *arg, struct termios *mode)
{
tcflag_t flag[4];
char const *s = arg;
size_t i;
for (i = 0; i < 4; i++)
{
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];
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;
}
struct speed_map
{
const char *string; speed_t speed; unsigned long int value; };
static struct speed_map const speeds[] =
{
{"0", B0, 0},
{"50", B50, 50},
{"75", B75, 75},
{"110", B110, 110},
{"134", B134, 134},
{"134.5", B134, 134},
{"150", B150, 150},
{"200", B200, 200},
{"300", B300, 300},
{"600", B600, 600},
{"1200", B1200, 1200},
{"1800", B1800, 1800},
{"2400", B2400, 2400},
{"4800", B4800, 4800},
{"9600", B9600, 9600},
{"19200", B19200, 19200},
{"38400", B38400, 38400},
{"exta", B19200, 19200},
{"extb", B38400, 38400},
#ifdef B57600
{"57600", B57600, 57600},
#endif
#ifdef B115200
{"115200", B115200, 115200},
#endif
#ifdef B230400
{"230400", B230400, 230400},
#endif
#ifdef B460800
{"460800", B460800, 460800},
#endif
#ifdef B500000
{"500000", B500000, 500000},
#endif
#ifdef B576000
{"576000", B576000, 576000},
#endif
#ifdef B921600
{"921600", B921600, 921600},
#endif
#ifdef B1000000
{"1000000", B1000000, 1000000},
#endif
#ifdef B1152000
{"1152000", B1152000, 1152000},
#endif
#ifdef B1500000
{"1500000", B1500000, 1500000},
#endif
#ifdef B2000000
{"2000000", B2000000, 2000000},
#endif
#ifdef B2500000
{"2500000", B2500000, 2500000},
#endif
#ifdef B3000000
{"3000000", B3000000, 3000000},
#endif
#ifdef B3500000
{"3500000", B3500000, 3500000},
#endif
#ifdef B4000000
{"4000000", B4000000, 4000000},
#endif
{NULL, 0, 0}
};
static speed_t _GL_ATTRIBUTE_PURE
string_to_baud (const char *arg)
{
int i;
for (i = 0; speeds[i].string != NULL; ++i)
if (STREQ (arg, speeds[i].string))
return speeds[i].speed;
return (speed_t) -1;
}
static unsigned long int _GL_ATTRIBUTE_PURE
baud_to_value (speed_t speed)
{
int i;
for (i = 0; speeds[i].string != NULL; ++i)
if (speed == speeds[i].speed)
return speeds[i].value;
return 0;
}
static void
sane_mode (struct termios *mode)
{
int i;
tcflag_t *bitsp;
for (i = 0; control_info[i].name; ++i)
{
#if VMIN == VEOF
if (STREQ (control_info[i].name, "min"))
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 & SANE_SET)
{
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;
}
}
}
static const char *
visible (cc_t ch)
{
static char buf[10];
char *bpout = buf;
if (ch == _POSIX_VDISABLE)
return "<undef>";
if (ch >= 32)
{
if (ch < 127)
*bpout++ = ch;
else if (ch == 127)
{
*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;
}
}
}
else
{
*bpout++ = '^';
*bpout++ = ch + 64;
}
*bpout = '\0';
return (const char *) buf;
}
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;
}