BSD 4_4_Lite1 release
[unix-history] / usr / src / bin / stty / stty.c
index f279c7c..4a840c2 100644 (file)
-/*
- * Copyright (c) 1980, 1989 Regents of the University of California.
- * All rights reserved.  The Berkeley software License Agreement
- * specifies the terms and conditions for redistribution.
+/*-
+ * Copyright (c) 1989, 1991, 1993, 1994
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-char copyright[] =
-"@(#) Copyright (c) 1980, 1989 Regents of the University of California.\n\
- All rights reserved.\n";
-#endif not lint
+static char copyright[] =
+"@(#) Copyright (c) 1989, 1991, 1993, 1994\n\
      The Regents of the University of California.  All rights reserved.\n";
+#endif /* not lint */
 
 #ifndef lint
 
 #ifndef lint
-static char sccsid[] = "@(#)stty.c     5.11 (Berkeley) %G%";
-#endif not lint
-
-/*
- * set teletype modes
- */
+static char sccsid[] = "@(#)stty.c     8.3 (Berkeley) 4/2/94";
+#endif /* not lint */
 
 #include <sys/types.h>
 
 #include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/syslog.h>
-#define KERNEL
-#include <sys/tty.h>
-#undef KERNEL
-#include <sys/termios.h>
-#include <sys/file.h>
-#include <errno.h>
+
 #include <ctype.h>
 #include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <fcntl.h>
 #include <stdio.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
 
 
-#define eq(s1, s2)     (strcmp((s1), (s2)) == 0)
-#define WRAPCOL 65
-
-struct modes {
-       char *name;
-       long set;
-       long unset;
-};
-
-struct modes imodes[] = {
-       "ignbrk",       IGNBRK, 0,
-       "-ignbrk",      0, IGNBRK,
-       "brkint",       BRKINT, 0,
-       "-brkint",      0, BRKINT,
-       "ignpar",       IGNPAR, 0,
-       "-ignpar",      0, IGNPAR,
-       "parmrk",       PARMRK, 0,
-       "-parmrk",      0, PARMRK,
-       "inpck",        INPCK, 0,
-       "-inpck",       0, INPCK,
-       "istrip",       ISTRIP, 0,
-       "-istrip",      0, ISTRIP,
-       "inlcr",        INLCR, 0,
-       "-inlcr",       0, INLCR,
-       "igncr",        IGNCR, 0,
-       "-igncr",       0, IGNCR,
-       "icrnl",        ICRNL, 0,
-       "-icrnl",       0, ICRNL,
-       "ixon",         IXON, 0,
-       "-ixon",        0, IXON,
-       "flow",         IXON, 0,
-       "-flow",        0, IXON,
-       "ixoff",        IXOFF, 0,
-       "-ixoff",       0, IXOFF,
-       "tandem",       IXOFF, 0,
-       "-tandem",      0, IXOFF,
-       "ixany",        IXANY, 0,
-       "-ixany",       0, IXANY,
-       "decctlq",      0, IXANY,
-       "-decctlq",     IXANY, 0,
-       "imaxbel",      IMAXBEL, 0,
-       "-imaxbel",     0, IMAXBEL,
-       0
-};
-
-struct modes omodes[] = {
-       "opost",        OPOST, 0,
-       "-opost",       0, OPOST,
-       "-litout",      OPOST, 0,
-       "litout",       0, OPOST,
-       "onlcr",        ONLCR, 0,
-       "-onlcr",       0, ONLCR,
-       "tabs",         0, OXTABS,      /* "preserve" tabs */
-       "-tabs",        OXTABS, 0,
-       "xtabs",        OXTABS, 0,
-       "-xtabs",       0, OXTABS,
-       "oxtabs",       OXTABS, 0,
-       "-oxtabs",      0, OXTABS,
-       0
-};
-
-struct modes cmodes[] = {
-       "cs5",          CS5, CSIZE,
-       "cs6",          CS6, CSIZE,
-       "cs7",          CS7, CSIZE,
-       "cs8",          CS8, CSIZE,
-       "cstopb",       CSTOPB, 0,
-       "-cstopb",      0, CSTOPB,
-       "cread",        CREAD, 0,
-       "-cread",       0, CREAD,
-       "parenb",       PARENB, 0,
-       "-parenb",      0, PARENB,
-       "parodd",       PARODD, 0,
-       "-parodd",      0, PARODD,
-       "parity",       PARENB | CS7, PARODD | CSIZE,
-       "evenp",        PARENB | CS7, PARODD | CSIZE,
-       "oddp",         PARENB | CS7 | PARODD, CSIZE,
-       "-parity",      CS8, PARODD | PARENB | CSIZE,
-       "pass8",        CS8, PARODD | PARENB | CSIZE,
-       "-evenp",       CS8, PARODD | PARENB | CSIZE,
-       "-oddp",        CS8, PARODD | PARENB | CSIZE,
-       "hupcl",        HUPCL, 0,
-       "-hupcl",       0, HUPCL,
-       "hup",          HUPCL, 0,
-       "-hup",         0, HUPCL,
-       "clocal",       CLOCAL, 0,
-       "-clocal",      0, CLOCAL,
-       "crtscts",      CRTSCTS, 0,
-       "-crtscts",     0, CRTSCTS,
-       0
-};
-
-struct modes lmodes[] = {
-       "echo",         ECHO, 0,
-       "-echo",        0, ECHO,
-       "echoe",        ECHOE, 0,
-       "-echoe",       0, ECHOE,
-       "crterase",     ECHOE, 0,
-       "-crterase",    0, ECHOE,
-       "crtbs",        ECHOE, 0,   /* crtbs not supported, close enough */
-       "-crtbs",       0, ECHOE,
-       "echok",        ECHOK, 0,
-       "-echok",       0, ECHOK,
-       "echoke",       ECHOKE, 0,
-       "-echoke",      0, ECHOKE,
-       "crtkill",      ECHOKE, 0,
-       "-crtkill",     0, ECHOKE,
-       "altwerase",    ALTWERASE, 0,
-       "-altwerase",   0, ALTWERASE,
-       "iexten",       IEXTEN, 0,
-       "-iexten",      0, IEXTEN,
-       "echonl",       ECHONL, 0,
-       "-echonl",      0, ECHONL,
-       "echoctl",      ECHOCTL, 0,
-       "-echoctl",     0, ECHOCTL,
-       "ctlecho",      ECHOCTL, 0,
-       "-ctlecho",     0, ECHOCTL,
-       "echoprt",      ECHOPRT, 0,
-       "-echoprt",     0, ECHOPRT,
-       "prterase",     ECHOPRT, 0,
-       "-prterase",    0, ECHOPRT,
-       "isig",         ISIG, 0,
-       "-isig",        0, ISIG,
-       "icanon",       ICANON, 0,
-       "-icanon",      0, ICANON,
-       "noflsh",       NOFLSH, 0,
-       "-noflsh",      0, NOFLSH,
-       "tostop",       TOSTOP, 0,
-       "-tostop",      0, TOSTOP,
-       "mdmbuf",       MDMBUF, 0,
-       "-mdmbuf",      0, MDMBUF,
-       "flusho",       FLUSHO, 0,
-       "-flusho",      0, FLUSHO,
-       "pendin",       PENDIN, 0,
-       "-pendin",      0, PENDIN,
-       "crt",          ECHOE|ECHOKE|ECHOCTL, ECHOK|ECHOPRT,
-       "-crt",         ECHOK, ECHOE|ECHOKE|ECHOCTL,
-       "newcrt",       ECHOE|ECHOKE|ECHOCTL, ECHOK|ECHOPRT,
-       "-newcrt",      ECHOK, ECHOE|ECHOKE|ECHOCTL, 
-       0
-};
-
-/*
- * Special control characters.
- *
- * Each entry has a list of names.  The first is the primary name
- * and is used when printing the control character in the "name = val;"
- * form.  The second is an abbreviation which is guaranteed to be less
- * than or equal to four characters in length and is primarily used
- * when printing the values in columunar form (guarantees all will
- * fit within 80 cols).  The rest are optional aliases.
- * All names are recognized on the command line.
- */
-#define MAXNAMES 3
-struct {
-       char    *names[MAXNAMES+1];
-       int     sub;
-       u_char  def;
-} cchars[] = {
-       { "erase", "era" },             VERASE, CERASE,
-       { "werase", "wera" },           VWERASE, CWERASE,
-       { "kill", "kill" },             VKILL,  CKILL,
-       { "intr", "int" },              VINTR,  CINTR,
-       { "quit", "quit" },             VQUIT,  CQUIT,
-       { "susp", "susp" },             VSUSP,  CSUSP,
-       { "dsusp", "dsus" },            VDSUSP, CDSUSP,
-       { "eof", "eof" },               VEOF,   CEOF,
-       { "eol", "eol", "brk" },        VEOL,   CEOL,
-       { "eol2", "eol2" },             VEOL2,  CEOL,
-       { "stop", "stop", "xoff" },     VSTOP,  CSTOP,
-       { "start", "star", "xon" },     VSTART, CSTART,
-       { "lnext", "lnxt" },            VLNEXT, CLNEXT,
-       { "flusho", "fls", "flush" },   VFLUSHO, CFLUSHO,
-       { "reprint", "rpnt", "rprnt" }, VREPRINT, CREPRINT,
-       { "info", "info" },             VINFO, CINFO,
-       0
-};
-       
-struct winsize win;
-int ldisc;
-int dodisc;
-int debug = 0;
-int trace, dotrace;
-
-#define OUT    stdout          /* informational output stream */
-#define ERR    stderr          /* error message stream */
-#define CTL    0               /* default control descriptor */
-int ctl = CTL;
-
-extern errno;
-
-#define NORMAL 0       /* only print modes differing from defaults */
-#define ALL    1       /* print all modes - POSIX standard format */
-#define ALL_BSD        2       /* print all modes - using BSD shorthand for cc's */
-#define GFMT   3       /* print modes in a form that can be re-input to stty */
-
+#include "stty.h"
+#include "extern.h"
 
 
+int
 main(argc, argv) 
 main(argc, argv) 
+       int argc;
        char *argv[];
 {
        char *argv[];
 {
-       struct termios t;
-       int i, fmt = NORMAL;
-       extern char *optarg;
-       extern int optind;
+       struct info i;
+       enum FMT fmt;
        int ch;
 
        int ch;
 
-       argc--, argv++;
-       if (argc > 0 && eq(argv[0], "-a")) {
-               fmt = ALL;
-               argc--, argv++;
-       }
-       if (argc > 0 && eq(argv[0], "-f")) {
-               argc--, argv++;
-               if ((ctl = open(argv[0], O_RDONLY | O_NONBLOCK)) < 0)
-                       syserrexit(*argv);
-               argc--, argv++;
-       }
-       if (ioctl(ctl, TIOCGETD, &ldisc) < 0)
-               syserrexit("TIOCGETD");
-       if (tcgetattr(ctl, &t) < 0)
-               syserrexit("tcgetattr");
-       if (ioctl(ctl, TIOCGWINSZ, &win) < 0)
-               warning("TIOCGWINSZ: %s", strerror(errno));
-       checkredirect();        /* conversion aid */
-
-       if (argc == 0 || fmt) {
-               prmode(&t, ldisc, fmt);
-               exit(0);
-       } else if (argc == 1 && strlen(argv[0]) > 2 && *(argv[0]+2) == ':') {
-               gfmtset(argv[0]);
-               goto setit;
-       }
-       
-       while (*argv) {
-               if (eq("everything", *argv)) {
-                       prmode(&t, ldisc, ALL_BSD);
-                       exit(0);
-               }
-               if (eq("all", *argv)) {
-                       prmode(&t, ldisc, ALL);
-                       exit(0);
-               }
-               if (eq("old", *argv)) {
-                       goto next;
-               }
-               if (eq("new", *argv)) {
-                       goto next;
-               }
-               if (eq("nl", *argv)) {
-                       t.c_iflag &= ~ICRNL;
-                       t.c_oflag &= ~ONLCR;
-                       goto next;
-               }
-               if (eq("-nl", *argv)) {
-                       t.c_iflag |= ICRNL;
-                       t.c_oflag |= ONLCR;
-                       goto next;
-               }
-               if (eq("dec", *argv)){
-                       t.c_cc[VERASE] = (u_char)0177;
-                       t.c_cc[VKILL] = CTRL('u');
-                       t.c_cc[VINTR] = CTRL('c');
-                       t.c_lflag &= ~ECHOPRT;
-                       t.c_lflag |= ECHOE|ECHOKE|ECHOCTL;
-                       t.c_iflag &= ~IXANY;
-                       goto next;
-               }
-               if (eq("raw", *argv)) {
-                       cfmakeraw(&t);
-                       t.c_cflag &= ~(CSIZE|PARENB);
-                       t.c_cflag |= CS8;
-                       goto next;
-               }
-               if (eq("cooked", *argv) || eq("-raw", *argv) ||
-                   eq("sane", *argv)) {
-                       t.c_cflag = TTYDEF_CFLAG | (t.c_cflag & CLOCAL);
-                       t.c_iflag = TTYDEF_IFLAG;
-                       t.c_iflag |= ICRNL;
-                       /* preserve user-preference flags in lflag */
-#define        LKEEP   (ECHOKE|ECHOE|ECHOK|ECHOPRT|ECHOCTL|ALTWERASE|TOSTOP|NOFLSH)
-                       t.c_lflag = TTYDEF_LFLAG | (t.c_lflag & LKEEP);
-                       t.c_oflag = TTYDEF_OFLAG;
-                       goto next;
-               }
-               if (eq("rows", *argv)) {
-                       if (*(argv+1) == 0)
-                               goto setit;
-                       win.ws_row = atoi(*++argv);
-                       goto next;
-               }
-               if (eq("ispeed", *argv)) {
-                       int code;
-                       if (*(argv+1) == 0)
-                               errexit("missing ispeed");
-                       cfsetispeed(&t, atoi(*++argv));
-                       goto next;
-               }
-               if (eq("ospeed", *argv)) {
-                       if (*(argv+1) == 0)
-                               errexit("missing ospeed");
-                       cfsetospeed(&t, atoi(*++argv));
-                       goto next;
-               }
-               if (eq("cols", *argv) || eq("columns", *argv)) {
-                       if (*(argv+1) == 0)
-                               goto setit;
-                       win.ws_col = atoi(*++argv);
-                       goto next;
-               }
-               if (eq("size", *argv)) {
-                       put("%d %d\n", win.ws_row, win.ws_col);
-                       exit(0);
-               }
-               if (eq("speed", *argv)) {
-                       put("%d\n", cfgetospeed(&t));
-                       exit(0);
-               }
-               for (i=0; imodes[i].name; i++)
-                       if (eq(imodes[i].name, *argv)) {
-                               t.c_iflag &= ~imodes[i].unset;
-                               t.c_iflag |= imodes[i].set;
-                               goto next;
-                       }
-               for (i=0; omodes[i].name; i++)
-                       if (eq(omodes[i].name, *argv)) {
-                               t.c_oflag &= ~omodes[i].unset;
-                               t.c_oflag |= omodes[i].set;
-                               goto next;
-                       }
-               for (i=0; cmodes[i].name; i++)
-                       if (eq(cmodes[i].name, *argv)) {
-                               t.c_cflag &= ~cmodes[i].unset;
-                               t.c_cflag |= cmodes[i].set;
-                               goto next;
-                       }
-               for (i=0; lmodes[i].name; i++)
-                       if (eq(lmodes[i].name, *argv)) {
-                               t.c_lflag &= ~lmodes[i].unset;
-                               t.c_lflag |= lmodes[i].set;
-                               goto next;
-                       }
-               for (i=0; *cchars[i].names; i++) {
-                       char **cp = cchars[i].names;
-                       while (*cp) {
-                               if (eq(*cp, *argv)) {
-                                       if (*++argv == 0)
-                                               goto setit;
-                                       if (eq(*argv, "undef") || 
-                                           eq(*argv, "disable"))
-                                               t.c_cc[cchars[i].sub] = 
-                                                  _POSIX_VDISABLE;
-                                       else if (**argv == '^')
-                                               t.c_cc[cchars[i].sub] = 
-                                                   ((*argv)[1] == '?') ? 0177 :
-                                                   ((*argv)[1] == '-') ?
-                                                    _POSIX_VDISABLE :
-                                                    (*argv)[1] & 037;
-                                       else
-                                               t.c_cc[cchars[i].sub] = **argv;
-                                       goto next;
-                               }
-                               cp++;
-                       }
-               }
-               if (isdigit(**argv)) {
-                       cfsetospeed(&t, atoi(*argv));
-                       cfsetispeed(&t, atoi(*argv));
-                       goto next;
-               }
-               /* didn't match anything */
-               errexit("unknown option: %s", *argv);
-               exit(1);
-next:
-               argv++;
-       }
-setit:
-       if (tcsetattr(ctl, 0, &t) < 0)
-               syserrexit("tcsetattr");
-       if (ioctl(ctl, TIOCSWINSZ, &win) < 0)
-               warning("can't set window size");
-
-       exit(0);
-}
-
-gfmtset() {
-}
-
-prmode(tp, ldisc, fmt)
-       struct termios *tp;
-{
-       long    i = tp->c_iflag,
-               o = tp->c_oflag,
-               c = tp->c_cflag,
-               l = tp->c_lflag;
-       u_char  *cc = tp->c_cc;
-       int     ispeed = cfgetispeed(tp),
-               ospeed = cfgetospeed(tp);
-       char    unknown[32],
-               *ld;
-       char *ccval();
-       
+       fmt = NOTSET;
+       i.fd = STDIN_FILENO;
 
 
-       /*
-        * line discipline
-        */
-       if (ldisc != TTYDISC) {
-               switch(ldisc) {
-               case TABLDISC:  
-                       ld = "tablet"; 
+       opterr = 0;
+       while (optind < argc &&
+           strspn(argv[optind], "-aefg") == strlen(argv[optind]) &&
+           (ch = getopt(argc, argv, "aef:g")) != EOF)
+               switch(ch) {
+               case 'a':               /* undocumented: POSIX compatibility */
+                       fmt = POSIX;
                        break;
                        break;
-               case SLIPDISC:  
-                       ld = "slip"; 
+               case 'e':
+                       fmt = BSD;
                        break;
                        break;
-               default:        
-                       sprintf(unknown, "#%d", ldisc);
-                       ld = unknown;
-               }
-               put("%s disc; ", ld);
-       }
-       /*
-        * line speed
-        */
-       if (ispeed != ospeed)
-               put("ispeed %d baud; ospeed %d baud;",
-                    ispeed, ospeed);
-       else
-               put("speed %d baud;", ispeed);
-       if (fmt) 
-               put(" %d rows; %d columns;", win.ws_row, win.ws_col);
-       put("\n");
-
-#define lput(n, f, d) if (fmt || on(f) != d) mdput(n+on(f))
-       /*
-        * "local" flags
-        */
-#define on(f)  ((l&f) != 0)
-       if (debug) mdput("LFLAG: ");
-       lput("-icanon ",ICANON, 1);
-       lput("-isig ", ISIG, 1);
-       lput("-iexten ", IEXTEN, 1);
-       lput("-echo ",ECHO, 1);
-       lput("-echoe ",ECHOE, 0);
-       lput("-echok ",ECHOK, 0);
-       lput("-echoke ",ECHOKE, 0);
-       lput("-echonl ",ECHONL, 0);
-       lput("-echoctl ",ECHOCTL, 0);
-       lput("-echoprt ",ECHOPRT, 0);
-       lput("-altwerase ",ALTWERASE, 0);
-       lput("-noflsh ",NOFLSH, 0);
-       lput("-tostop ",TOSTOP, 0);
-       lput("-mdmbuf ",MDMBUF, 0);
-       lput("-flusho ",FLUSHO, 0);
-       lput("-pendin ",PENDIN, 0);
-       /*
-        * input flags
-        */
-#undef on
-#define on(f)  ((i&f) != 0)
-       mdput(0);
-       if (debug) mdput("IFLAG: ");
-       lput("-istrip ", ISTRIP, 0);
-       lput("-icrnl ", ICRNL, 1);
-       lput("-inlcr ", INLCR, 0);
-       lput("-igncr ", IGNCR, 0);
-       lput("-ixon ", IXON, 1);
-       lput("-ixoff ", IXOFF, 0);
-       lput("-ixany ", IXANY, 1);
-       lput("-imaxbel ", IMAXBEL, 1);
-       lput("-ignbrk ", IGNBRK, 0);
-       lput("-brkint ", BRKINT, 1);
-       lput("-inpck ", INPCK, 0);
-       lput("-ignpar ", IGNPAR, 0);
-       lput("-parmrk ", PARMRK, 0);
-#undef on
-       /*
-        * output flags
-        */
-#define on(f)  ((o&f) != 0)
-       mdput(0);
-       if (debug) mdput("OFLAG: ");
-       lput("-opost ", OPOST, 1);
-       lput("-onlcr ", ONLCR, 1);
-       lput("-oxtabs ", OXTABS, 1);
-#undef on
-       /*
-        * control flags (hardware state)
-        */
-#define on(f)  ((c&f) != 0)
-       mdput(0);
-       if (debug) mdput("CFLAG: ");
-       lput("-cread ", CREAD, 1);
-       switch(c&CSIZE) {
-       case CS5: mdput("cs5 "); break;
-       case CS6: mdput("cs6 "); break;
-       case CS7: mdput("cs7 "); break;
-       case CS8: mdput("cs8 "); break;
-       }
-       mdput("-parenb "+on(PARENB));
-       lput("-parodd ", PARODD, 0);
-       lput("-hupcl ", HUPCL, 1);
-       lput("-clocal ", CLOCAL, 0);
-       lput("-cstopb ", CSTOPB, 0);
-       lput("-crtscts ", CRTSCTS, 0);
-       mdput(0);
-#undef on
-       /*
-        * special control characters
-        */
-       if (debug) mdput("CCHARS: ");
-       if (fmt != 2) {
-               for (i=0; *cchars[i].names; i++) {
-                       char temp[64];
-
-                       if (fmt || cc[cchars[i].sub] != cchars[i].def) {
-                               sprintf(temp, "%s = %s; ", *cchars[i].names,
-                                       ccval(cc[cchars[i].sub]), fmt);
-                               mdput(temp);
-                       }
+               case 'f':
+                       if ((i.fd = open(optarg, O_RDONLY | O_NONBLOCK)) < 0)
+                               err(1, "%s", optarg);
+                       break;
+               case 'g':
+                       fmt = GFLAG;
+                       break;
+               case '?':
+               default:
+                       goto args;
                }
                }
-               mdput(0);
-       } else {
-               for (i=0; *cchars[i].names; i++)
-                       put("%*s", strlen(*(cchars[i].names+1)) + (i>0?1:0),
-                               *(cchars[i].names+1));
-               printf("\n");
-               for (i=0; *cchars[i].names; i++)
-                       put("%*s", strlen(*(cchars[i].names+1)) + (i>0?1:0),
-                               ccval(cc[cchars[i].sub], fmt));
-               printf("\n");
-       }
-}
 
 
-/*
- * gross, but since we're changing the control descriptor
- * from 1 to 0, most users will be probably be doing
- * "stty > /dev/sometty" by accident. If 1 and 2 are both ttys, 
- * but not the same, assume that 1 was incorrectly redirected.
- */
-checkredirect() {
-       struct stat st1, st2;
+args:  argc -= optind;
+       argv += optind;
 
 
-       if (isatty(1) && isatty(2) && fstat(1, &st1) != -1 && 
-           fstat(2, &st2) != -1 && (st1.st_rdev != st2.st_rdev))
-warning("stdout appears redirected, but stdin is the control descriptor");
-}
+       if (ioctl(i.fd, TIOCGETD, &i.ldisc) < 0)
+               err(1, "TIOCGETD");
+       if (tcgetattr(i.fd, &i.t) < 0)
+               err(1, "tcgetattr");
+       if (ioctl(i.fd, TIOCGWINSZ, &i.win) < 0)
+               warn("TIOCGWINSZ: %s\n", strerror(errno));
 
 
-char *
-ccval(c, fmt)
-       unsigned char c;
-{
-       static char buf[128];
-       char *bp;
+       checkredirect();                        /* conversion aid */
 
 
-       *buf = 0, bp = buf;
-       if (c == _POSIX_VDISABLE)
-               if (fmt == 2)
-                       return("<u>");
-               else
-                       return("<undef>");
-       if (c & 0200) {
-               strcat(buf, "M-");
-               *bp++ = 'M';
-               *bp++ = '-';
-               c &= 0177;
-       }
-       if (c == 0177) {
-               *bp++ = '^';
-               *bp++ = '?';
-       }
-       else if (c < 040) {
-               *bp++ = '^';
-               *bp++ = c + '@';
-       }
-       else
-               *bp++ = c;
-       *bp = 0;
-       return(buf);
-}
-
-
-mdput(s)
-       char *s;
-{
-       static int col = 0;
-
-       if (s == (char *)0) {
-               if (col) {
-                       put("\n");
-                       col = 0;
-               }
-               return;
-       }
-       if ((col += strlen(s)) > WRAPCOL) {
-               put("\n");
-               col = strlen(s);
+       switch(fmt) {
+       case NOTSET:
+               if (*argv)
+                       break;
+               /* FALLTHROUGH */
+       case BSD:
+       case POSIX:
+               print(&i.t, &i.win, i.ldisc, fmt);
+               break;
+       case GFLAG:
+               gprint(&i.t, &i.win, i.ldisc);
+               break;
        }
        }
-       put(s);
-}
-
-#include <varargs.h>
-
-put(va_alist)
-       va_dcl
-{
-       char *fmt;
-       va_list ap;
+       
+       for (i.set = i.wset = 0; *argv; ++argv) {
+               if (ksearch(&argv, &i))
+                       continue;
 
 
-       va_start(ap);
-       fmt = va_arg(ap, char *);
-       (void) vfprintf(OUT, fmt, ap);
-       va_end(ap);
-}
+               if (csearch(&argv, &i))
+                       continue;
 
 
+               if (msearch(&argv, &i))
+                       continue;
 
 
-warning(va_alist)
-       va_dcl
-{
-       char *fmt;
-       va_list ap;
+               if (isdigit(**argv)) {
+                       int speed;
 
 
-       fprintf(ERR, "stty: warning: ");
-       va_start(ap);
-       fmt = va_arg(ap, char *);
-       (void) vfprintf(ERR, fmt, ap);
-       va_end(ap);
-       fprintf(ERR, "\n");
-}
+                       speed = atoi(*argv);
+                       cfsetospeed(&i.t, speed);
+                       cfsetispeed(&i.t, speed);
+                       i.set = 1;
+                       continue;
+               }
 
 
+               if (!strncmp(*argv, "gfmt1", sizeof("gfmt1") - 1)) {
+                       gread(&i.t, *argv + sizeof("gfmt1") - 1);
+                       continue;
+               }
 
 
-errexit(va_alist)
-       va_dcl
-{
-       char *fmt;
-       va_list ap;
+               warnx("illegal option -- %s", *argv);
+               usage();
+       }
 
 
-       fprintf(ERR, "stty: ");
-       va_start(ap);
-       fmt = va_arg(ap, char *);
-       (void) vfprintf(ERR, fmt, ap);
-       va_end(ap);
-       fprintf(ERR, "\n");
-       exit(1);
+       if (i.set && tcsetattr(i.fd, 0, &i.t) < 0)
+               err(1, "tcsetattr");
+       if (i.wset && ioctl(i.fd, TIOCSWINSZ, &i.win) < 0)
+               warn("TIOCSWINSZ");
+       exit(0);
 }
 
 }
 
-
-syserrexit(va_alist)
-       va_dcl
+void
+usage()
 {
 {
-       char *fmt;
-       va_list ap;
 
 
-       fprintf(ERR, "stty: ");
-       va_start(ap);
-       fmt = va_arg(ap, char *);
-       (void) vfprintf(ERR, fmt, ap);
-       va_end(ap);
-       fprintf(ERR, ": %s\n", strerror(errno));
-       exit(1);
+       (void)fprintf(stderr, "usage: stty: [-a|-e|-g] [-f file] [options]\n");
+       exit (1);
 }
 }