diff options
author | chin <none@none> | 2007-08-17 12:01:52 -0700 |
---|---|---|
committer | chin <none@none> | 2007-08-17 12:01:52 -0700 |
commit | da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968 (patch) | |
tree | 5280d3b78e289fe9551371ab6e7f15ef9944ea14 /usr/src/lib/libcmd/common/stty.c | |
parent | 073dbf9103ef2a2b05d8a16e2d26db04e0374b0e (diff) | |
download | illumos-joyent-da2e3ebdc1edfbc5028edf1354e7dd2fa69a7968.tar.gz |
6437624 RFE: Add ksh93 (as /usr/bin/ksh93) and libshell.so to OS/Net
6505835 AST tools and library (libpp) required for creating l10n messages for ksh93
PSARC/2006/550 Korn Shell 93 Integration
PSARC/2006/587 /etc/ksh.kshrc for ksh93
PSARC/2007/035 ksh93 Amendments
Contributed by Roland Mainz <roland.mainz@nrubsig.org>
--HG--
rename : usr/src/lib/libcmd/common/mapfile-vers => deleted_files/usr/src/lib/libcmd/common/mapfile-vers
rename : usr/src/lib/libcmd/common/placeholder.c => deleted_files/usr/src/lib/libcmd/common/placeholder.c
Diffstat (limited to 'usr/src/lib/libcmd/common/stty.c')
-rw-r--r-- | usr/src/lib/libcmd/common/stty.c | 943 |
1 files changed, 943 insertions, 0 deletions
diff --git a/usr/src/lib/libcmd/common/stty.c b/usr/src/lib/libcmd/common/stty.c new file mode 100644 index 0000000000..ef53c61bf7 --- /dev/null +++ b/usr/src/lib/libcmd/common/stty.c @@ -0,0 +1,943 @@ +/*********************************************************************** +* * +* This software is part of the ast package * +* Copyright (c) 1992-2007 AT&T Knowledge Ventures * +* and is licensed under the * +* Common Public License, Version 1.0 * +* by AT&T Knowledge Ventures * +* * +* A copy of the License is available at * +* http://www.opensource.org/licenses/cpl1.0.txt * +* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) * +* * +* Information and Software Systems Research * +* AT&T Research * +* Florham Park NJ * +* * +* Glenn Fowler <gsf@research.att.com> * +* David Korn <dgk@research.att.com> * +* * +***********************************************************************/ +#pragma prototyped +/* + * stty.c + * Written by David Korn + * Tue Apr 4 10:46:00 EDT 1995 + */ + +static const char usage[] = +"[-?@(#)$Id: stty (AT&T Research) 2006-10-31 $\n]" +USAGE_LICENSE +"[+NAME?stty - set or get terminal modes]" +"[+DESCRIPTION?\bstty\b sets certain terminal I/O modes for the device " + "that is the current standard input; without arguments, it writes " + "the settings of certain modes to standard output.]" + +"[a:all?Writes to standard output all of the mode settings.]" +"[g:save?Writes the current settings to standard output in a form that can " + "be used as an argument to another \bstty\b command. The \brows\b " + "and \bcolumns\b values are not included.]" +"\n" +"\n[mode ...]\n" +"\n" +"[+EXTENDED DESCRIPTION?Modes are specified either as a single name or " + "as a name followed by a value. As indicated below, many of the " + "mode names can be preceded by a \b-\b to negate its meaning. " + "Modes are listed by group corresponding to field in the " + "\btermios\b structure defined in \b<termios.h>\b. Modes " + "in the last group are implemented using options in the previous " + "groups. Note that many combinations of modes make no sense, but " + "no sanity checking is performed. The modes are selected from the " + "following:]{\fabc\f}" + +"[+EXIT STATUS?]{" + "[+0?All modes reported or set successfully.]" + "[+>0?Standard input not a terminaol or one or more modes failed.]" +"}" +"[+SEE ALSO?\btegetattr\b(2), \btcsetattr\b(2), \bioctl\b(2)]" +; + + +#include <cmd.h> +#include <ccode.h> +#include <ctype.h> +#include <ast_tty.h> +#if _sys_ioctl +#include <sys/ioctl.h> +#endif + +#define C(x) ERROR_catalog(x) + +#ifndef _POSIX_VDISABLE +# define _POSIX_VDISABLE 0 +#endif + +#ifndef NCCS +# ifdef NCC +# define NCCS NCC +# else +# define NCCS elementsof(((struct termio*)0)->c_cc) +# endif +#endif + +/* command options */ +#define A_FLAG 1 +#define G_FLAG 2 + +/* termios fields */ +#define C_FLAG 1 +#define C_LINE 2 +#define C_SPEED 3 +#define I_FLAG 4 +#define O_FLAG 5 +#define L_FLAG 6 +#define T_CHAR 7 +#define W_SIZE 8 + +#define BIT 1 +#define BITS 2 +#define NUM 3 +#define CHAR 4 +#define SPEED 5 +#define SIZE 6 +#define MIXED 7 +#define SANE 8 +#define COOKED 9 +#define CASE 10 +#define TABS 11 +#define WIND 12 + +#undef SS /* who co-opted this namespace? */ + +#define IG 0x0001 /* ignore display */ +#define NL 0x0002 /* entry ends line of display */ +#define SS 0x0004 /* set in sane mode */ +#define US 0x0010 /* unset in sane mode */ + +typedef struct tty_s +{ + const char name[8]; + unsigned char type; + unsigned char field; + short flags; + unsigned long mask; + unsigned long val; + const char description[76]; +} Tty_t; + +static const Tty_t Ttable[] = +{ +#ifdef CBAUD +{ "ispeed", NUM, C_SPEED,0, CBAUD, 0, C("\an\a is the input baud rate") }, +{ "ospeed", NUM, C_SPEED,0, CBAUD, 0, C("\an\a is the output baud rate") }, +{ "speed", NUM, C_SPEED,IG, CBAUD }, +#endif +{ "0", SPEED, C_FLAG, 0, B0 }, +{ "50", SPEED, C_FLAG, 0, B50 }, +{ "75", SPEED, C_FLAG, 0, B75 }, +{ "110", SPEED, C_FLAG, 0, B110 }, +{ "134", SPEED, C_FLAG, 0, B134 }, +{ "150", SPEED, C_FLAG, 0, B150 }, +{ "200", SPEED, C_FLAG, 0, B200 }, +{ "300", SPEED, C_FLAG, 0, B300 }, +{ "600", SPEED, C_FLAG, 0, B600 }, +{ "1200", SPEED, C_FLAG, 0, B1200 }, +{ "1800", SPEED, C_FLAG, 0, B1800 }, +{ "2400", SPEED, C_FLAG, 0, B2400 }, +{ "4800", SPEED, C_FLAG, 0, B4800 }, +{ "9600", SPEED, C_FLAG, 0, B9600 }, +{ "19200", SPEED, C_FLAG, 0, B19200 }, +{ "38400", SPEED, C_FLAG, 0, B38400 }, + +#ifdef TIOCSWINSZ +{ "rows", WIND, W_SIZE, IG, 0, 24, C("\an\a is the number of lines for display") }, +{ "cols", WIND, W_SIZE, IG, 1, 80, C("\an\a is the number of columns for display") }, +{ "columns", WIND, W_SIZE, IG, 1, 80, C("Same as \bcols\b") }, +#endif +{ "intr", CHAR, T_CHAR, SS, VINTR, 'C', C("Send an interrupt signal") }, +{ "quit", CHAR, T_CHAR, SS, VQUIT, '|', C("Send a quit signal") }, +{ "erase", CHAR, T_CHAR, SS, VERASE, 'H', C("Erase the last character entered") }, +{ "kill", CHAR, T_CHAR, NL|SS, VKILL, 'U', C("Erase the current line") }, +{ "eof", CHAR, T_CHAR, SS, VEOF, 'D', C("Send an end of file") }, +#ifdef VEOL2 +{ "eol2", CHAR, T_CHAR, US, VEOL2, _POSIX_VDISABLE, C("Alternate character to end the line") }, +#endif /* VEOL2 */ +#ifdef VSWTCH +{ "swtch", CHAR, T_CHAR, US, VSWTCH, _POSIX_VDISABLE, C("Switch to a different shell layer") }, +#endif /* VSWTCH */ +{ "eol", CHAR, T_CHAR, NL|US, VEOL, _POSIX_VDISABLE, C("End the line") }, +#ifdef VSTART +{ "start", CHAR, T_CHAR, SS, VSTART, 'Q', C("Restart the output after stopping it") }, +#endif /* VSTART */ +#ifdef VSTOP +{ "stop", CHAR, T_CHAR, SS, VSTOP, 'S', C("Stop the output") }, +#endif /* VSTOP */ +#ifdef VDSUSP +{ "dsusp", CHAR, T_CHAR, SS, VDSUSP, 'Y', C("Send a terminal stop signal after flushing the input") }, +#endif /* VDSUSP */ +#ifdef VSUSP +{ "susp", CHAR, T_CHAR, NL|SS, VSUSP, 'Z', C("Send a terminal stop signal") }, +#endif /* VSUSP */ +#ifdef VREPRINT +{ "rprnt", CHAR, T_CHAR, SS, VREPRINT, 'R', C("Redraw the current line") }, +#endif /* VREPRINT */ +#ifdef VDISCARD +{ "flush", CHAR, T_CHAR, SS, VDISCARD, 'O', C("Discard output") }, +#endif /* VDISCARD */ +#ifdef VWERASE +{ "werase", CHAR, T_CHAR, SS, VWERASE, 'W', C("Erase the last word entered") }, +#endif /* VWERASE */ +#ifdef VLNEXT +{ "lnext", CHAR, T_CHAR, NL|SS, VLNEXT, 'V', C("Enter the next input character literally") }, +#endif /* VLNEXT */ + +#if _mem_c_line_termios +{ "line", NUM, C_LINE, 0, 0, 0, C("Line discipline number") }, +#endif +{ "min", NUM, T_CHAR, 0, VMIN, 0, C("Mininmum number of characters to read in raw mode") }, +{ "time", NUM, T_CHAR, 0, VTIME, 0, C("Number of .1 second intervals with raw mode") }, + +{ "parenb", BIT, C_FLAG, 0, PARENB, PARENB, C("Enable (disable) parity generation and detection") }, +{ "parodd", BIT, C_FLAG, 0, PARODD, PARODD, C("Use odd (even) parity") }, +#ifdef PAREXT +{ "parext", BIT, C_FLAG, 0, PAREXT, PAREXT }, +#endif /* PAREXT */ +#ifdef CREAD +{ "cread", BIT, C_FLAG, SS, CREAD, CREAD, C("Enable (disable) input") }, +#endif /* CREAD */ +{ "cs5", SIZE, C_FLAG, 0, CSIZE, CS5 , C("Char size 5") }, +{ "cs6", SIZE, C_FLAG, 0, CSIZE, CS6 , C("Char size 6") }, +{ "cs7", SIZE, C_FLAG, 0, CSIZE, CS7 , C("Char size 7") }, +{ "cs8", SIZE, C_FLAG, 0, CSIZE, CS8 , C("Char size 8") }, +{ "hupcl", BIT, C_FLAG, 0, HUPCL, HUPCL, C("Hangup (do not hangup) connection on last close") }, +{ "hup", BIT, C_FLAG, IG, HUPCL, HUPCL, C("Same as \bhupcl\b") }, +{ "cstopb", BIT, C_FLAG, 0, CSTOPB, CSTOPB, C("Use two (one) stop bits") }, +#ifdef CRTSCTS +{ "crtscts", BIT, C_FLAG, 0, CRTSCTS, CRTSCTS, C("Enable (disable) RTS/CTS handshaking") }, +#endif /* CRTSCTS */ +{ "clocal", BIT, C_FLAG, NL, CLOCAL, CLOCAL, C("Disable (enable) modem control signals") }, + +{ "ignbrk", BIT, I_FLAG, US, IGNBRK, IGNBRK, C("Ignore (do not ignore) break characters") }, +{ "brkint", BIT, I_FLAG, SS, BRKINT, BRKINT, C("Generate (do not generate) INTR signal on break") }, +{ "ignpar", BIT, I_FLAG, 0, IGNPAR, IGNPAR, C("Ignore (do not ignore) characters with parity errors") }, +{ "parmrk", BIT, I_FLAG, 0, PARMRK, PARMRK, C("Mark (do not mark) parity errors") }, +{ "inpck", BIT, I_FLAG, 0, INPCK, INPCK, C("Enable (disable) input parity checking") }, +{ "istrip", BIT, I_FLAG, 0, ISTRIP, ISTRIP, C("Clear (do not clear) high bit of input characters") }, +{ "inlcr", BIT, I_FLAG, US, INLCR, INLCR, C("Translate (do not translate) carriage return to newline") }, +{ "igncr", BIT, I_FLAG, US, IGNCR, IGNCR, C("Ignore (do not ignore) carriage return") }, +#ifdef IUCLC +{ "iuclc", BIT, I_FLAG, US, IUCLC, IUCLC, C("Map (do not map) upper-case to lower case") }, +#endif /* IUCLC */ +{ "ixon", BIT, I_FLAG, 0, IXON, IXON, C("Enable (disable) XON/XOFF flow control. \bstop\b character stops output") }, +#ifdef IXANY +{ "ixany", BIT, I_FLAG, US, IXANY, IXANY, C("Any character (only start character) can restart output.") }, +{ "decctlq", BIT, I_FLAG, IG, IXANY, 0, C("Same as \b-ixany\b") }, +#endif /* IXANY */ +{ "ixoff", BIT, I_FLAG, US, IXOFF, IXOFF, C("Disable (enable) XON/XOFF flow control") }, +#ifdef IMAXBEL +{ "imaxbel", BIT, I_FLAG, SS, IMAXBEL, IMAXBEL, C("Beep (do not beep) if a character arrives with full input buffer") }, +#endif /* IMAXBEL */ +{ "icrnl", BIT, I_FLAG, NL|SS, ICRNL, ICRNL, C("Translate (do not translate) carriage return to newline") }, + +{ "isig", BIT, L_FLAG, SS, ISIG, ISIG, C("Enable (disable) \bintr\b, \bquit\b, and \bsusp\b special characters") }, +{ "icanon", BIT, L_FLAG, SS, ICANON, ICANON, C("Enable (disable) \berase\b, \bkill\b, \bwerase\b, and \brprnt\b special characters") }, +{ "icannon", BIT, L_FLAG, SS, ICANON, ICANON }, +#ifdef IEXTEN +{ "iexten", BIT, L_FLAG, SS, IEXTEN, IEXTEN, C("Enable (disable) non-POSIX special characters") }, +#endif /* IEXTEN */ +{ "echo", BIT, L_FLAG, SS, ECHO|ECHONL, ECHO|ECHONL, C("Echo (do not echo) input characters") }, +{ "echoe", BIT, L_FLAG, SS, ECHOE, ECHOE, C("Echo (do not echo) erase characters as backspace-space-backspace") }, +{ "echok", BIT, L_FLAG, SS, ECHOK, ECHOK, C("Echo (do not echo) a newline after a kill character") }, +#ifdef ECHOKE +{ "echoke", BIT, L_FLAG, SS, ECHOKE, ECHOKE, C("Echo (do not echo) a newline after a kill character") }, +#endif +{ "lfkc", BIT, L_FLAG, IG, ECHOK, ECHOK, C("Same as \bechok\b (\b-echok\b); obsolete") }, +{ "echonl", BIT, L_FLAG, SS, ECHONL, ECHONL,"Echo (do not echo) newline even if not echoing other character" }, +#ifdef ECHOCTL +{ "echoctl", BIT, L_FLAG, SS, ECHOCTL, ECHOCTL, C("Echo (do not echo) control characters as \b^\b\ac\a") }, +#else +#define ECHOCTL 0 +#endif /* ECHOCTL */ +#ifdef ECHOPRT +{ "echoprt", BIT, L_FLAG, US, ECHOPRT, ECHOPRT, C("Echo (do not echo) erased characters backward, between '\\' and '/'") }, +#else +#define ECHOPRT 0 +#endif /* ECHOPRT */ +#ifdef XCASE +{ "xcase", BIT, L_FLAG, US, XCASE, XCASE, C("Enable (disable) \bicanon\b uppercase as lowercase with '\\' prefix") }, +#endif /* XCASE */ +#ifdef DEFECHO +{ "defecho", BIT, L_FLAG, 0, DEFECHO, DEFECHO }, +#endif /* DEFECHO */ +#ifdef FLUSHO +{ "flusho", BIT, L_FLAG, 0, FLUSHO, FLUSHO, C("Discard (do not discard) written data. Cleared by subsequent input") }, +#endif /* FLUSHO */ +#ifdef PENDIN +{ "pendin", BIT, L_FLAG, 0, PENDIN, PENDIN, C("Redisplay pending input at next read and then automatically clear \bpendin\b") }, +#endif /* PENDIN */ +{ "noflsh", BIT, L_FLAG, US, NOFLSH, NOFLSH, C("Disable (enable) flushing after \bintr\b and \bquit\b special characters") }, +#ifdef TOSTOP +{ "tostop", BIT, L_FLAG, NL|US, TOSTOP, TOSTOP, C("Stop (do not stop) background jobs that try to write to the terminal") }, +#endif /* TOSTOP */ +#ifdef OLCUC +{ "olcuc", BIT, O_FLAG, US, OLCUC, OLCUC, C("Translate (do not translate) lowercase characters to uppercase") }, +#endif /* OLCUC */ +#ifdef ONLCR +{ "onlcr", BIT, O_FLAG, SS, ONLCR, ONLCR, C("Translate (do not translate) newline to carriage return-newline") }, +#endif /* ONLCR */ +#ifdef ONLRET +{ "onlret", BIT, O_FLAG, US, ONLRET, ONLRET, C("Newline performs (does not perform) a carriage return") }, +#endif /* ONLRET */ +#ifdef OCRNL +{ "ocrnl", BIT, O_FLAG, US, OCRNL, OCRNL, C("Translate (do not translate) carriage return to newline") }, +#endif /* OCRNL */ +#ifdef ONOCR +{ "onocr", BIT, O_FLAG, US, ONOCR, ONOCR, C("Do not (do) print carriage returns in the first column") }, +#endif /* ONOCR */ +#ifdef OFILL +{ "ofill", BIT, O_FLAG, US, OFILL, OFILL, C("Use fill characters (use timing) for delays") }, +#endif /* OFILL */ +#ifdef OFDEL +{ "ofdel", BIT, O_FLAG, US, OFDEL, OFDEL, C("Use DEL (NUL) as fill characters for delays") }, +#endif /* OFDEL */ +{ "opost", BIT, O_FLAG, SS, OPOST, OPOST, C(" Postprocess (do not postprocess) output") }, +#ifdef CRDLY +{ "cr0", BITS, O_FLAG, IG|SS, CRDLY, CR0 }, +{ "cr1", BITS, O_FLAG, US, CRDLY, CR1 }, +{ "cr2", BITS, O_FLAG, US, CRDLY, CR2 }, +{ "cr3", BITS, O_FLAG, US, CRDLY, CR3 }, +#endif +#ifdef NLDLY +{ "nl0", BITS, O_FLAG, IG|US, NLDLY, NL0 }, +{ "nl1", BITS, O_FLAG, US, NLDLY, NL1 }, +#endif +#ifdef TABDLY +{ "tabs", TABS, O_FLAG, IG, TABDLY, TAB3, C("Preserve (expand to spaces) tabs") }, +{ "tab0", BITS, O_FLAG, IG|SS, TABDLY, TAB0 }, +{ "tab1", BITS, O_FLAG, US, TABDLY, TAB1 }, +{ "tab2", BITS, O_FLAG, US, TABDLY, TAB2 }, +{ "tab3", BITS, O_FLAG, US, TABDLY, TAB3 }, +#endif +#ifdef BSDLY +{ "bs0", BITS, O_FLAG, IG|SS, BSDLY, BS0 }, +{ "bs1", BITS, O_FLAG, US, BSDLY, BS1 }, +#endif +#ifdef VTDLY +{ "vt0", BITS, O_FLAG, IG|SS, VTDLY, VT0 }, +{ "vt1", BITS, O_FLAG, US, VTDLY, VT1 }, +#endif +#ifdef FFDLY +{ "ff0", BITS, O_FLAG, IG|SS, FFDLY, FF0 }, +{ "ff1", BITS, O_FLAG, US, FFDLY, FF1 }, +#endif +{ "", MIXED, O_FLAG, NL|IG }, + +{ "evenp", MIXED, C_FLAG, IG, PARENB, 0, C("Same as \bparenb -parodd cs7\b") }, +{ "oddp", MIXED, C_FLAG, IG, PARODD, 0, C("Same as \bparenb parodd cs7\b") }, +{ "parity", MIXED, C_FLAG, IG, 0, 0, C("Same as parenb \b-parodd cs7\b") }, +{ "ek", MIXED, C_FLAG, IG, 0, 0, C("Reset the \berase\b and \bkill\b special characters to their default values") }, +{ "sane", SANE, C_FLAG, IG, 0, 0, C("Reset all modes to some reasonable values") }, +{ "cooked", COOKED, C_FLAG, IG, 0, 0, C("Disable raw input and output") }, +{ "raw", COOKED, C_FLAG, IG, 0, 0, C("Enable raw input and output") }, +{ "lcase", CASE, C_FLAG, IG, 0 , 0, C("Set \bxcase\b, \biuclc\b, and \bolcuc\b") }, +{ "LCASE", CASE, C_FLAG, IG, 0 , 0, C("Same as \blcase\b") } +}; + +#if CC_NATIVE == CC_ASCII +#define cntl(x) (((x)=='?')?0177:((x)&037)) +#else +#define cntl(x) (((x)=='?')?ccmapc(0177,CC_ASCII,CC_NATIVE):ccmapc(ccmapc(x,CC_NATIVE,CC_ASCII)&037,CC_ASCII,CC_NATIVE)) +#endif + +static void sane(register struct termios *sp) +{ + register const Tty_t* tp; + + for (tp = Ttable; tp < &Ttable[elementsof(Ttable)]; tp++) + if (tp->flags & (SS|US)) + switch (tp->type) + { + case BIT: + case BITS: + switch (tp->field) + { + case C_FLAG: + if (tp->flags & SS) + sp->c_cflag |= tp->mask; + else + sp->c_cflag &= ~tp->mask; + break; + case I_FLAG: + if (tp->flags & SS) + sp->c_iflag |= tp->mask; + else + sp->c_iflag &= ~tp->mask; + break; + case O_FLAG: + if (tp->flags & SS) + sp->c_oflag |= tp->mask; + else + sp->c_oflag &= ~tp->mask; + break; + case L_FLAG: + if (tp->flags & SS) + sp->c_lflag |= tp->mask; + else + sp->c_lflag &= ~tp->mask; + break; + } + break; + case CHAR: + sp->c_cc[tp->mask] = cntl(tp->val); + break; + } +} + +static int gin(char *arg,struct termios *sp) +{ + register int i; + if(*arg++ != ':') + return(0); + sp->c_iflag = strtol(arg,&arg,16); + if(*arg++ != ':') + return(0); + sp->c_oflag = strtol(arg,&arg,16); + if(*arg++ != ':') + return(0); + sp->c_cflag = strtol(arg,&arg,16); + if(*arg++ != ':') + return(0); + sp->c_lflag = strtol(arg,&arg,16); + if(*arg++ != ':') + return(0); + for(i=0;i< NCCS; i++) + { + sp->c_cc[i] = strtol(arg,&arg,16); + if(*arg++ != ':') + return(0); + } +#if _mem_c_line_termios + sp->c_line = +#endif + strtol(arg,&arg,16); + if(*arg++ != ':') + return(0); + i = strtol(arg,&arg,16); + if(*arg++ != ':') + return(0); + cfsetispeed(sp, i); + i = strtol(arg,&arg,16); + if(*arg++ != ':') + return(0); + cfsetospeed(sp, i); + if(*arg) + return(0); + return(1); +} + +static void gout(struct termios *sp) +{ + register int i; + sfprintf(sfstdout,":%x",sp->c_iflag); + sfprintf(sfstdout,":%x",sp->c_oflag); + sfprintf(sfstdout,":%x",sp->c_cflag); + sfprintf(sfstdout,":%x",sp->c_lflag); + for(i=0;i< NCCS; i++) + sfprintf(sfstdout,":%x",sp->c_cc[i]); +#if _mem_c_line_termios + sfprintf(sfstdout,":%x", sp->c_line); +#else + sfprintf(sfstdout,":%x", 0); +#endif + sfprintf(sfstdout,":%x",cfgetispeed(sp)); + sfprintf(sfstdout,":%x",cfgetospeed(sp)); + sfprintf(sfstdout,":\n"); +} + +static void output(struct termios *sp, int flags) +{ + const Tty_t *tp; + struct termios tty; + register int delim = ' '; + register int i,off,off2; + char schar[2]; + unsigned int ispeed = cfgetispeed(sp); + unsigned int ospeed = cfgetospeed(sp); + if(flags&G_FLAG) + { + gout(sp); + return; + } + tty = *sp; + sane(&tty); + for(i=0; i < elementsof(Ttable); i++) + { + tp= &Ttable[i]; + if(tp->flags&IG) + { + if(tp->flags&NL) + sfputc(sfstdout,'\n'); + continue; + } + switch(tp->type) + { + case BIT: + case BITS: + off = 1; + switch(tp->field) + { + case C_FLAG: + if(sp->c_cflag&tp->mask) + off = 0; + if(tty.c_cflag&tp->mask) + off2 = 0; + break; + case I_FLAG: + if(sp->c_iflag&tp->mask) + off = 0; + if(tty.c_iflag&tp->mask) + off2 = 0; + break; + case O_FLAG: + if((sp->c_oflag&tp->mask)==tp->val) + off = 0; + if(tty.c_oflag&tp->mask) + off2 = 0; + break; + case L_FLAG: + if(sp->c_lflag&tp->mask) + off = 0; + if(tty.c_lflag&tp->mask) + off2 = 0; + } + if(tp->flags&NL) + delim = '\n'; + if(!flags && off==off2) + continue; + if(!off) + sfprintf(sfstdout,"%s%c",tp->name,delim); + else if(tp->type==BIT) + sfprintf(sfstdout,"-%s%c",tp->name,delim); + delim = ' '; + break; + + case CHAR: + off = sp->c_cc[tp->mask]; + if(tp->flags&NL) + delim = '\n'; + if(!flags && off==(unsigned char)tty.c_cc[tp->mask]) + continue; + if(off==_POSIX_VDISABLE) + sfprintf(sfstdout,"%s = <undef>;%c",tp->name,delim); + else if(isprint(off&0xff)) + sfprintf(sfstdout,"%s = %c;%c",tp->name,off,delim); + else +#if CC_NATIVE == CC_ASCII + sfprintf(sfstdout,"%s = ^%c;%c",tp->name,off==0177?'?':(off^0100),delim); +#else + { + off = ccmapc(off, CC_NATIVE, CC_ASCII); + sfprintf(sfstdout,"%s = ^%c;%c",tp->name,off==0177?'?':ccmapc(off^0100,CC_ASCII,CC_NATIVE),delim); + } +#endif + delim = ' '; + break; + case SIZE: + if((sp->c_cflag&CSIZE)!=tp->mask) + continue; + if(flags || (sp->c_cflag&CSIZE) != (tty.c_cflag&CSIZE)) + sfprintf(sfstdout,"%s ",tp->name); + break; + case SPEED: + if(tp->mask==ispeed) + { + if(ispeed!=ospeed) + schar[0]='i'; + else + schar[0]=0; + } + else if(tp->mask==ospeed) + schar[0]='o'; + else + continue; + schar[1] = 0; +#ifdef TIOCSWINSZ + { + struct winsize win; + off = ioctl(0,TIOCGWINSZ,&win); + if(off>=0) + sfprintf(sfstdout,"%sspeed %s baud; rows %d; columns %d;\n",schar,tp->name,win.ws_row,win.ws_col); + } + if(off<0) +#endif + sfprintf(sfstdout,"%sspeed %s baud;\n",schar,tp->name); + } + } + if(delim=='\n') + sfputc(sfstdout,'\n'); +} + +static const Tty_t *lookup(const char *name) +{ + register int i; + for(i=0; i < elementsof(Ttable); i++) + { + if(strcmp(Ttable[i].name,name)==0) + return(&Ttable[i]); + } + return(0); + +} + +static const Tty_t *getspeed(unsigned long val) +{ + register int i; + for(i=0; i < elementsof(Ttable); i++) + { + if(Ttable[i].type==SPEED && Ttable[i].mask==val) + return(&Ttable[i]); + } + return(0); +} + +static int gettchar(register const char *cp) +{ + if(*cp==0) + return(-1); + if(cp[1]==0) + return((unsigned)cp[0]); + if(*cp=='^' && cp[1] && cp[2]==0) + { + switch(cp[1]) + { + case '-': + return(-1); + default: + return(cntl(cp[1])); + } + } + if(streq(cp,"undef") || streq(cp,"<undef>")) + return(-1); + return(*((unsigned char*)cp)); +} + +static void set(char *argv[], struct termios *sp) +{ + const Tty_t *tp; + register int c,off; + char *cp; + char *ep; + while(cp = *argv++) + { + off = 0; + if(*cp=='-') + { + cp++; + off=1; + } + if(!(tp=lookup(cp)) || (off && (tp->type!=BIT) && (tp->type!=TABS))) + error(ERROR_exit(1),"%s: unknown mode",cp); + switch(tp->type) + { + case CHAR: + if(off) + error(ERROR_exit(1),"%s: unknown mode",cp); + if(!*argv) + error(ERROR_exit(1),"missing argument to %s",cp); + c = gettchar(*argv++); + if(c>=0) + sp->c_cc[tp->mask] = c; + else + sp->c_cc[tp->mask] = _POSIX_VDISABLE; + break; + case BIT: case BITS: + switch(tp->field) + { + case C_FLAG: + if(off) + sp->c_cflag &= ~tp->mask; + else + sp->c_cflag |= tp->mask; + break; + case I_FLAG: + if(off) + sp->c_iflag &= ~tp->mask; + else + sp->c_iflag |= tp->mask; + break; + case O_FLAG: + sp->c_oflag &= ~tp->mask; + sp->c_oflag |= tp->val; + break; + case L_FLAG: + if(off) + sp->c_lflag &= ~tp->mask; + else + sp->c_lflag |= tp->mask; + break; + } + break; + case TABS: + sp->c_oflag &= ~tp->mask; + if(off) + sp->c_oflag |= tp->val; + break; +#ifdef TIOCSWINSZ + case WIND: + { + struct winsize win; + int n; + if(ioctl(0,TIOCGWINSZ,&win)<0) + error(ERROR_system(1),"cannot set %s",tp->name); + if(!(cp= *argv)) + { + sfprintf(sfstdout,"%d\n",tp->mask?win.ws_col:win.ws_row); + break; + } + argv++; + n=strtol(cp,&cp,10); + if(*cp) + error(ERROR_system(1),"%d: invalid number of %s",argv[-1],tp->name); + if(tp->mask) + win.ws_col = n; + else + win.ws_row = n; + if(ioctl(0,TIOCSWINSZ,&win)<0) + error(ERROR_system(1),"cannot set %s",tp->name); + break; + } +#endif + case NUM: + cp = *argv; + if (!cp) + { + if (tp->field == C_SPEED) + { + if (tp = getspeed(*tp->name == 'i' ? cfgetispeed(sp) : cfgetospeed(sp))) + sfprintf(sfstdout, "%s\n", tp->name); + break; + } + error(ERROR_exit(1), "%s: missing numeric argument", tp->name); + } + argv++; + c = (int)strtol(cp, &ep, 10); + if (*ep) + error(ERROR_exit(1), "%s: %s: numeric argument expected", tp->name, cp); + switch (tp->field) + { +#if _mem_c_line_termios + case C_LINE: + sp->c_line = c; + break; +#endif + case C_SPEED: + if(getspeed(c)) + { + if (*tp->name != 'o') + cfsetispeed(sp, c); + if (*tp->name != 'i') + cfsetospeed(sp, c); + } + else + error(ERROR_exit(1), "%s: %s: invalid speed", tp->name, cp); + break; + case T_CHAR: + sp->c_cc[tp->mask] = c; + break; + } + break; + case SPEED: + cfsetospeed(sp, tp->mask); + cfsetispeed(sp, tp->mask); + break; + case SIZE: + sp->c_cflag &= ~CSIZE; + sp->c_cflag |= tp->mask; + break; + case SANE: + sane(sp); + break; +#if defined(OLCUC) && defined(IUCLC) + case CASE: + if(off) + { + sp->c_iflag |= IUCLC; + sp->c_oflag |= OLCUC; + } + else + { + sp->c_iflag &= ~IUCLC; + sp->c_oflag &= ~OLCUC; + } + break; +#endif /* OLCUC && IUCLC */ + } + } +} + + +static void listchars(Sfio_t *sp,int type) +{ + int i,c; + c = (type==CHAR?'c':'n'); + for(i=0; i < elementsof(Ttable); i++) + { + if(Ttable[i].type==type && *Ttable[i].description) + sfprintf(sp,"[+%s \a%c\a?%s.]",Ttable[i].name,c,Ttable[i].description); + } +} + +static void listgroup(Sfio_t *sp,int type, const char *description) +{ + int i; + sfprintf(sp,"[+"); + for(i=0; i < elementsof(Ttable); i++) + { + if(Ttable[i].type==type) + sfprintf(sp,"%s ",Ttable[i].name); + } + sfprintf(sp,"?%s.]",description); +} + +static void listmask(Sfio_t *sp,unsigned int mask,const char *description) +{ + int i; + sfprintf(sp,"[+"); + for(i=0; i < elementsof(Ttable); i++) + { + if(Ttable[i].mask==mask && Ttable[i].type==BITS) + sfprintf(sp,"%s ",Ttable[i].name); + } + sfprintf(sp,"?%s.]",description); +} + +static void listfields(Sfio_t *sp,int field) +{ + int i; + for(i=0; i < elementsof(Ttable); i++) + { + if(Ttable[i].field==field && Ttable[i].type==BIT && *Ttable[i].description) + sfprintf(sp,"[+%s (-%s)?%s.]",Ttable[i].name,Ttable[i].name,Ttable[i].description); + } +} + +static void listmode(Sfio_t *sp,const char *name) +{ + sfprintf(sp,"[+%s?%s.]",name,lookup(name)->description); +} + +static int infof(Opt_t* op, Sfio_t* sp, const char* s, Optdisc_t* dp) +{ + NoP(op); + NoP(s); + NoP(dp); + sfprintf(sp,"[+Control Modes.]{"); + listfields(sp,C_FLAG); + listgroup(sp,SPEED,"Attempt to set input and output baud rate to number given. A value of \b0\b causes immediate hangup"); + listchars(sp,NUM); + listgroup(sp,SIZE,"Number of bits in a character"); + sfprintf(sp,"}[+Input Modes.]{"); + listfields(sp,I_FLAG); + sfprintf(sp,"}[+Output Modes.]{"); + listfields(sp,O_FLAG); +#ifdef CRDLY + listmask(sp,CRDLY,"Carriage return delay style"); +#endif +#ifdef NLDLY + listmask(sp,NLDLY,"Newline delay style"); +#endif +#ifdef TABDLY + listmask(sp,TABDLY,"Horizontal tab delay style"); +#endif +#ifdef BSDLY + listmask(sp,BSDLY,"Backspace delay style"); +#endif +#ifdef FFDLY + listmask(sp,FFDLY,"Form feed delay style"); +#endif +#ifdef VTDLY + listmask(sp,VTDLY,"Vertical tab delay style"); +#endif + sfprintf(sp,"}[+Local Modes.]{"); + listfields(sp,L_FLAG); + sfprintf(sp,"}[+Control Assignments.?If \ac\a is \bundef\b or an empty " + "string then the control assignment is disabled.]{"); + listchars(sp,WIND); + listchars(sp,CHAR); + sfprintf(sp,"}[+Combination Modes.]{"); + listmode(sp,"ek"); + listmode(sp,"evenp"); + listmode(sp,"lcase"); + listmode(sp,"oddp"); + listmode(sp,"parity"); + listmode(sp,"sane"); + listmode(sp,"tabs"); + listmode(sp,"LCASE"); + sfputc(sp,'}'); + return(1); +} + +int +b_stty(int argc, char** argv, void* context) +{ + struct termios tty; + register int n; + register int flags = 0; + const Tty_t* tp; + Optdisc_t disc; + + cmdinit(argc, argv, context, ERROR_CATALOG, ERROR_INTERACTIVE); + if (tcgetattr(0, &tty) < 0) + error(ERROR_system(1),"not a tty"); + memset(&disc, 0, sizeof(disc)); + disc.version = OPT_VERSION; + disc.infof = infof; + opt_info.disc = &disc; + for (;;) + { + switch (n = optget(argv, usage)) + { + case 'a': + case 'g': + if (!opt_info.offset || !argv[opt_info.index][opt_info.offset]) + { + switch (n) + { + case 'a': + flags |= A_FLAG; + break; + case 'g': + flags |= G_FLAG; + break; + } + continue; + } + /*FALLTHROUGH*/ + case ':': + if (!opt_info.offset) + error(2, "%s", opt_info.arg); + else if (!(tp = lookup(argv[opt_info.index]+1)) || (tp->type != BIT && tp->type != TABS)) + error(ERROR_exit(1), "%s: unknown mode", argv[opt_info.index]); + break; + case '?': + error(ERROR_usage(2), "%s", opt_info.arg); + break; + } + break; + } + argv += opt_info.index; + if (error_info.errors || (flags && *argv)) + error(ERROR_usage(2), "%s", optusage(NiL)); + if (*argv) + { + if (!argv[1] && **argv == ':') + gin(*argv, &tty); + else + set(argv, &tty); + if (tcsetattr(0, TCSANOW, &tty) < 0) + error(ERROR_system(1), "cannot set tty"); + } + else + output(&tty, flags); + return error_info.errors; +} |