Implement more tty flags for better portability from other systems:
authortholo <tholo@openbsd.org>
Mon, 16 Dec 1996 20:04:39 +0000 (20:04 +0000)
committertholo <tholo@openbsd.org>
Mon, 16 Dec 1996 20:04:39 +0000 (20:04 +0000)
XCASE - canonical input/output processing
IUCLC - translate uppercase to lowercase on input
OLCUC - translate lowercase to uppercase on output
OCRNL - translate carriage return to newline on output
ONOCR - do not output carriage return at column 0
ONLRET - newline performs carriage return function

In addition the tty compatibility interface supports LCASE properly.

Look at termios(4) for a more complete description of the above flags.

bin/stty/key.c
bin/stty/modes.c
bin/stty/stty.1
libexec/getty/subr.c
share/man/man4/termios.4
sys/compat/common/tty_43.c
sys/kern/tty.c
sys/sys/termios.h
usr.sbin/lpr/lpd/modes.c
usr.sbin/lpr/lpd/ttcompat.c

index 1ab7f30..4b9f40f 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: key.c,v 1.4 1996/08/02 12:10:21 deraadt Exp $ */
+/*     $OpenBSD: key.c,v 1.5 1996/12/16 20:04:39 tholo Exp $   */
 /*     $NetBSD: key.c,v 1.11 1995/09/07 06:57:11 jtc Exp $     */
 
 /*-
@@ -38,7 +38,7 @@
 #if 0
 static char sccsid[] = "@(#)key.c      8.4 (Berkeley) 2/20/95";
 #else
-static char rcsid[] = "$OpenBSD: key.c,v 1.4 1996/08/02 12:10:21 deraadt Exp $";
+static char rcsid[] = "$OpenBSD: key.c,v 1.5 1996/12/16 20:04:39 tholo Exp $";
 #endif
 #endif /* not lint */
 
@@ -61,6 +61,7 @@ void  f_dec __P((struct info *));
 void   f_everything __P((struct info *));
 void   f_extproc __P((struct info *));
 void   f_ispeed __P((struct info *));
+void   f_lcase __P((struct info *));
 void   f_nl __P((struct info *));
 void   f_ospeed __P((struct info *));
 void   f_raw __P((struct info *));
@@ -89,6 +90,7 @@ static struct key {
        { "everything", f_everything,   0 },
        { "extproc",    f_extproc,      F_OFFOK },
        { "ispeed",     f_ispeed,       F_NEEDARG },
+       { "lcase",      f_lcase,        0 },
        { "new",        f_tty,          0 },
        { "nl",         f_nl,           F_OFFOK },
        { "old",        f_tty,          0 },
@@ -220,6 +222,22 @@ f_ispeed(ip)
        ip->set = 1;
 }
 
+void
+f_lcase(ip)
+       struct info *ip;
+{
+       if (ip->off) {
+               ip.t_iflag &= ~IUCLC;
+               ip.t_oflag &= ~OLCUC;
+               ip.t_lflag &= ~XCASE;
+       } else {
+               ip.t_iflag |= IUCLC;
+               ip.t_oflag |= OLCUC;
+               ip.t_lflag |= XCASE;
+       }
+       ip->set = 1;
+}
+
 void
 f_nl(ip)
        struct info *ip;
index 1c4cc17..4807ac5 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: modes.c,v 1.3 1996/06/23 14:21:51 deraadt Exp $       */
+/*     $OpenBSD: modes.c,v 1.4 1996/12/16 20:04:41 tholo Exp $ */
 /*     $NetBSD: modes.c,v 1.9 1996/05/07 18:20:09 jtc Exp $    */
 
 /*-
@@ -38,7 +38,7 @@
 #if 0
 static char sccsid[] = "@(#)modes.c    8.3 (Berkeley) 4/2/94";
 #else
-static char rcsid[] = "$OpenBSD: modes.c,v 1.3 1996/06/23 14:21:51 deraadt Exp $";
+static char rcsid[] = "$OpenBSD: modes.c,v 1.4 1996/12/16 20:04:41 tholo Exp $";
 #endif
 #endif /* not lint */
 
@@ -110,6 +110,8 @@ const struct modes imodes[] = {
        { "-igncr",     0, IGNCR },
        { "icrnl",      ICRNL, 0 },
        { "-icrnl",     0, ICRNL },
+       { "iuclc",      IUCLC, 0 },
+       { "-iuclc",     0, IUCLC },
        { "ixon",       IXON, 0 },
        { "-ixon",      0, IXON },
        { "flow",       IXON, 0 },
@@ -176,6 +178,8 @@ const struct modes lmodes[] = {
        { "-nokerninfo",0, NOKERNINFO },
        { "kerninfo",   0, NOKERNINFO },
        { "-kerninfo",  NOKERNINFO, 0 },
+       { "xcase",      XCASE, 0 },
+       { "-xcase",     0, XCASE },
        { NULL },
 };
 
@@ -184,8 +188,16 @@ const struct modes omodes[] = {
        { "-opost",     0, OPOST },
        { "litout",     0, OPOST },
        { "-litout",    OPOST, 0 },
+       { "ocrnl",      OCRNL, 0 },
+       { "-ocrnl",     0, OCRNL },
+       { "olcuc",      OLCUC, 0 },
+       { "-olcuc",     0, OLCUC },
        { "onlcr",      ONLCR, 0 },
        { "-onlcr",     0, ONLCR },
+       { "onlret",     ONLRET, 0 },
+       { "-onlret",    0, ONLRET },
+       { "onocr",      ONOCR, 0 },
+       { "-onocr",     0, ONOCR },
        { "tabs",       0, OXTABS },            /* "preserve" tabs */
        { "-tabs",      OXTABS, 0 },
        { "oxtabs",     OXTABS, 0 },
index 1c643d4..6ed8618 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: stty.1,v 1.4 1996/12/10 09:06:01 deraadt Exp $
+.\"    $OpenBSD: stty.1,v 1.5 1996/12/16 20:04:42 tholo Exp $
 .\"    $NetBSD: stty.1,v 1.10 1995/09/07 06:57:14 jtc Exp $
 .\"
 .\" Copyright (c) 1990, 1993, 1994
@@ -189,6 +189,9 @@ Map (do not map)
 to
 .Dv NL
 on input.
+.It Cm iuclc Pq Fl iuclc
+Translate (do not translate) upper case to lower case
+on input.
 .It Cm ixon Pq Fl ixon
 Enable (disable)
 .Dv START/STOP
@@ -241,6 +244,14 @@ Map (do not map)
 to
 .Dv CR-NL
 on output.
+.It Cm ocrnl Pq Fl ocrnl
+Translate (do not translate) carriage return to newline on output.
+.It Cm onocr Pq Fl onocr
+Carriage return is output (is not output) at column 0.
+.It Cm onlret Pq Fl onlret
+Newline performs (does not perform) carriage return on output.
+.It Cm olcuc Pq Fl olcuc
+Translate (do not translate) lower case to upper case on output.
 .It Cm oxtabs Pq Fl oxtabs
 Expand (do not expand) tabs to spaces on output.
 .El
@@ -351,6 +362,12 @@ Indicates output is (is not) being discarded.
 Indicates input is (is not) pending after a switch from non-canonical
 to canonical mode and will be re-input when a read becomes pending
 or more input arrives.
+.It Cm xcase Pq Fl xcase
+Upper and lower case is (is not) handled canonically on input and output
+with
+.Cm iuclc
+and
+.Cm olcuc .
 .El
 .Ss Control Characters:
 .Bl -tag -width Fl
@@ -553,6 +570,12 @@ Same as
 .It Cm prterase Pq Fl prterase
 Same as
 .Cm echoprt .
+.It Cm lcase Pq Fl lcase
+Same as
+.Cm iuclc ,
+.Cm olcuc
+and
+.Cm xcase .
 .It Cm litout Pq Fl litout
 The converse of
 .Cm opost .
index f2c8dc5..14ed2aa 100644 (file)
@@ -33,7 +33,7 @@
 
 #ifndef lint
 /*static char sccsid[] = "from: @(#)subr.c     8.1 (Berkeley) 6/4/93";*/
-static char rcsid[] = "$Id: subr.c,v 1.5 1996/12/16 17:14:03 deraadt Exp $";
+static char rcsid[] = "$Id: subr.c,v 1.6 1996/12/16 20:04:45 tholo Exp $";
 #endif /* not lint */
 
 /*
@@ -388,15 +388,27 @@ register long flags;
                SET(oflag, OXTABS);
        else
                CLR(oflag, OXTABS);
+       if (ISSET(flags, LCASE))
+               SET(iflag, IUCLC);
+               SET(oflag, OLCUC);
+               SET(lflag, XCASE);
+       }
+       else {
+               CLR(iflag, IUCLC);
+               CLR(oflag, OLCUC);
+               CLR(lflag, XCASE);
+       }
 
 
        if (ISSET(flags, RAW)) {
                iflag &= IXOFF;
-               CLR(lflag, ISIG|ICANON|IEXTEN);
+               CLR(lflag, ISIG|ICANON|IEXTEN|XCASE);
                CLR(cflag, PARENB);
        } else {
                SET(iflag, BRKINT|IXON|IMAXBEL);
                SET(lflag, ISIG|IEXTEN);
+               if (ISSET(iflag, IUCLC) && ISSET(oflag, OLCUC))
+                       SET(lflag, XCASE);
                if (ISSET(flags, CBREAK))
                        CLR(lflag, ICANON);
                else
index 8af0997..ed6ee4c 100644 (file)
@@ -793,6 +793,8 @@ following masks:
 /* any char will restart after stop */
 .It Dv IMAXBEL
 /* ring bell on input queue full */
+.It Dv IUCLC
+/* translate upper case to lower case */
 .El
 .Pp
 In the context of asynchronous serial data transmission, a break
@@ -960,6 +962,11 @@ is set and the input queue is full, subsequent input shall cause an
 character to be transmitted to
 the output queue.
 .Pp
+If
+.Dv IUCLC
+is set, characters will be translated from upper to lower case on
+input.
+.Pp
 The initial input control value after open() is implementation defined.
 .Ss Output Modes
 Values of the
@@ -981,6 +988,14 @@ and are composed of the following masks:
 .Dv EOT Ns 's
 .Ql \&^D
 on output) */
+.It Dv OCRNL
+/* map CR to NL */
+.It Dv OLCUC
+/* translate lower case to upper case */
+.It Dv ONOCR
+/* No CR output at column 0 */
+.It Dv ONLRET
+/* NL performs CR function */
 .El
 .Pp
 If
@@ -1003,6 +1018,23 @@ is set,
 .Tn ASCII
 .Dv EOT NS 's
 are discarded on output.
+.Pp
+If
+.Dv OCRNL
+is set, carriage returns are translated to newlines.
+.Pp
+If
+.Dv OLCUC
+is set, lower case is translated to upper case on output.
+.Pp
+If
+.Dv ONOCR
+is set, no CR character is output when at column 0.
+.Pp
+If
+.Dv ONLRET
+is set, NL also performs CR on output, and reset current
+column to 0.
 .Ss Control Modes
 Values of the
 .Fa c_cflag
@@ -1181,6 +1213,8 @@ and
 /* XXX retype pending input (state) */
 .It Dv NOFLSH
 /* don't flush after interrupt */
+.It Dv XCASE
+/* canonical upper/lower case */
 .El
 .Pp
 If
@@ -1336,6 +1370,26 @@ characters
 are not be done.
 .Pp
 If
+.Dv XCASE
+and
+.Dv ICANON
+is set, an upper case character is preserved on input if prefixed by
+a \\ character.  In addition, this prefix is added to upper case
+characters on output.
+.Pp
+In addition, the following special character translations are in effect:
+.Pp
+.Bl -column "for:" "use:" -offset indent -compact
+.It Em "for:    use:"
+.It Dv ` Ta \&\e'
+.It Dv | Ta \&\e!
+.It Dv ~ Ta \&\e^
+.It Dv { Ta \&\e(
+.It Dv } Ta \&\e)
+.It Dv \&\e Ta \&\e\e
+.El
+.Pp
+If
 .Dv TOSTOP
 is set, the signal
 .Dv SIGTTOU
index fd60b69..765a63a 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: tty_43.c,v 1.4 1996/05/23 08:32:23 deraadt Exp $      */
+/*     $OpenBSD: tty_43.c,v 1.5 1996/12/16 20:04:52 tholo Exp $        */
 /*     $NetBSD: tty_43.c,v 1.5 1996/05/20 14:29:17 mark Exp $  */
 
 /*-
@@ -307,6 +307,8 @@ ttcompatgetflags(tp)
                SET(flags, MDMBUF);
        if (!ISSET(cflag, HUPCL))
                SET(flags, NOHANG);
+       if (ISSET(cflag, XCASE) && ISSET(iflag, IUCLC) && ISSET(oflag, OLCUC))
+               SET(flags, LCASE);
        if (ISSET(oflag, OXTABS))
                SET(flags, XTABS);
        if (ISSET(lflag, ECHOE))
@@ -355,10 +357,20 @@ ttcompatsetflags(tp, t)
                SET(oflag, OXTABS);
        else
                CLR(oflag, OXTABS);
+       if (ISSET(flags, LCASE)) {
+               SET(iflag, IUCLC);
+               SET(oflag, OLCUC);
+               SET(cflag, XCASE);
+       }
+       else {
+               CLR(iflag, IUCLC);
+               CLR(oflag, OLCUC);
+               CLR(cflag, XCASE);
+       }
 
 
        if (ISSET(flags, RAW)) {
-               iflag &= IXOFF;
+               iflag &= IXOFF|IXANY;
                CLR(lflag, ISIG|ICANON|IEXTEN);
                CLR(cflag, PARENB);
        } else {
@@ -390,7 +402,7 @@ ttcompatsetflags(tp, t)
        }
 
        if (ISSET(flags, RAW|LITOUT|PASS8)) {
-               CLR(cflag, CSIZE);
+               CLR(cflag, CSIZE|XCASE);
                SET(cflag, CS8);
                if (!ISSET(flags, RAW|PASS8))
                        SET(iflag, ISTRIP);
@@ -403,6 +415,8 @@ ttcompatsetflags(tp, t)
        } else {
                CLR(cflag, CSIZE);
                SET(cflag, CS7);
+               if (ISSET(iflag, IUCLC) && ISSET(oflag, OLCUC))
+                       SET(cflag, XCASE);
                SET(iflag, ISTRIP);
                SET(oflag, OPOST);
        }
@@ -454,6 +468,11 @@ ttcompatsetlflags(tp, t)
                SET(iflag, IXANY);
        else
                CLR(iflag, IXANY);
+       if (ISSET(flags, LCASE)) {
+               SET(oflag, OLCUC);
+               SET(iflag, IUCLC);
+               SET(cflag, XCASE);
+       }
        CLR(lflag, TOSTOP|FLUSHO|PENDIN|NOFLSH);
        SET(lflag, ISSET(flags, TOSTOP|FLUSHO|PENDIN|NOFLSH));
 
@@ -466,13 +485,17 @@ ttcompatsetlflags(tp, t)
                        CLR(iflag, ISTRIP);
                if (!ISSET(flags, RAW|LITOUT))
                        SET(oflag, OPOST);
-               else
+               else {
                        CLR(oflag, OPOST);
+                       CLR(cflag, XCASE);
+               }
        } else {
                CLR(cflag, CSIZE);
                SET(cflag, CS7);
                SET(iflag, ISTRIP);
                SET(oflag, OPOST);
+               if (ISSET(oflag, OLCUC) && ISSET(iflag, IUCLC))
+                       SET(cflag, XCASE);
        }
 
        t->c_iflag = iflag;
index 9d698fc..e00ba6a 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: tty.c,v 1.20 1996/12/08 14:25:48 niklas Exp $ */
+/*     $OpenBSD: tty.c,v 1.21 1996/12/16 20:04:54 tholo Exp $  */
 /*     $NetBSD: tty.c,v 1.68.4.2 1996/06/06 16:04:52 thorpej Exp $     */
 
 /*-
@@ -158,6 +158,12 @@ u_char const char_type[] = {
 #define        CLR(t, f)       (t) &= ~((unsigned)(f))
 #define        ISSET(t, f)     ((t) & (f))
 
+#define        islower(c)      ((c) >= 'a' && (c) <= 'z')
+#define        isupper(c)      ((c) >= 'A' && (c) <= 'Z')
+
+#define        tolower(c)      ((c) - 'A' + 'a')
+#define        toupper(c)      ((c) - 'a' + 'A')
+
 struct ttylist_head ttylist;   /* TAILQ_HEAD */
 int tty_count;
 
@@ -396,6 +402,39 @@ parmrk:                            (void)putc(0377 | TTY_QUOTE, &tp->t_rawq);
                 * From here on down canonical mode character
                 * processing takes place.
                 */
+               /*
+                * upper case or specials with IUCLC and XCASE
+                */
+               if (ISSET(lflag, XCASE) && ISSET(iflag, IUCLC)) {
+                       if (ISSET(tp->t_state, TS_BKSL)) {
+                               CLR(tp->t_state, TS_BKSL);
+                               switch (c) {
+                               case '\'':
+                                       c = '`';
+                                       break;
+                               case '!':
+                                       c = '|';
+                                       break;
+                               case '^':
+                                       c = '~';
+                                       break;
+                               case '(':
+                                       c = '{';
+                                       break;
+                               case ')':
+                                       c = '}';
+                                       break;
+                               }
+                       }
+                       else if (c == '\\') {
+                               SET(tp->t_state, TS_BKSL);
+                               goto endcase;
+                       }
+                       else if (isupper(c))
+                               c = tolower(c);
+               }
+               else if (ISSET(iflag, IUCLC) && isupper(c))
+                       c = tolower(c);
                /*
                 * erase (^H / ^?)
                 */
@@ -555,7 +594,7 @@ ttyoutput(c, tp)
        register struct tty *tp;
 {
        register long oflag;
-       register int col, notout, s;
+       register int col, notout, s, c2;
 
        oflag = tp->t_oflag;
        if (!ISSET(oflag, OPOST)) {
@@ -595,7 +634,8 @@ ttyoutput(c, tp)
 
        /*
         * Newline translation: if ONLCR is set,
-        * translate newline into "\r\n".
+        * translate newline into "\r\n".  If OCRNL
+        * is set, translate '\r' into '\n'.
         */
        if (c == '\n' && ISSET(tp->t_oflag, ONLCR)) {
                tk_nout++;
@@ -603,6 +643,41 @@ ttyoutput(c, tp)
                if (putc('\r', &tp->t_outq))
                        return (c);
        }
+       else if (c == '\r' && ISSET(tp->t_oflag, OCRNL))
+               c = '\n';
+
+       if (ISSET(tp->t_oflag, OLCUC) && islower(c))
+               c = toupper(c);
+       else if (ISSET(tp->t_oflag, OLCUC) && ISSET(tp->t_lflag, XCASE)) {
+               c2 = c;
+               switch (c) {
+               case '`':
+                       c2 = '\'';
+                       break;
+               case '|':
+                       c2 = '!';
+                       break;
+               case '~':
+                       c2 = '^';
+                       break;
+               case '{':
+                       c2 = '(';
+                       break;
+               case '}':
+                       c2 = ')';
+                       break;
+               }
+               if (c == '\\' || isupper(c) || c != c2) {
+                       tk_nout++;
+                       tp->t_outcc++;
+                       if (putc('\\', &tp->t_outq))
+                               return (c);
+                       c = c2;
+               }
+       }
+       if (ISSET(tp->t_oflag, ONOCR) && c == '\r' && tp->t_column == 0)
+               return (-1);
+
        tk_nout++;
        tp->t_outcc++;
        if (!ISSET(tp->t_lflag, FLUSHO) && putc(c, &tp->t_outq))
@@ -617,6 +692,9 @@ ttyoutput(c, tp)
        case CONTROL:
                break;
        case NEWLINE:
+               if (ISSET(tp->t_oflag, ONLRET))
+                       col = 0;
+               break;
        case RETURN:
                col = 0;
                break;
index 9e5102f..4639c21 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: termios.h,v 1.5 1996/10/26 06:54:42 tholo Exp $       */
+/*     $OpenBSD: termios.h,v 1.6 1996/12/16 20:04:56 tholo Exp $       */
 /*     $NetBSD: termios.h,v 1.14 1996/04/09 20:55:41 cgd Exp $ */
 
 /*
 #define        IXOFF           0x00000400      /* enable input flow control */
 #ifndef _POSIX_SOURCE
 #define        IXANY           0x00000800      /* any char will restart after stop */
+#define        IUCLC           0x00001000      /* translate upper to lower case */
 #define IMAXBEL                0x00002000      /* ring bell on input queue full */
 #endif  /*_POSIX_SOURCE */
 
 #define ONLCR          0x00000002      /* map NL to CR-NL (ala CRMOD) */
 #define OXTABS         0x00000004      /* expand tabs to spaces */
 #define ONOEOT         0x00000008      /* discard EOT's (^D) on output) */
+#define OCRNL          0x00000010      /* map CR to NL */
+#define OLCUC          0x00000020      /* translate lower case to upper case */
+#define ONOCR          0x00000040      /* No CR output at column 0 */
+#define ONLRET         0x00000080      /* NL performs the CR function */
 #endif  /*_POSIX_SOURCE */
 
 /*
 #define TOSTOP         0x00400000      /* stop background jobs from output */
 #ifndef _POSIX_SOURCE
 #define FLUSHO         0x00800000      /* output being flushed (state) */
+#define XCASE          0x01000000      /* canonical upper/lower case */
 #define        NOKERNINFO      0x02000000      /* no kernel output from VSTATUS */
 #define PENDIN         0x20000000      /* XXX retype pending input (state) */
 #endif  /*_POSIX_SOURCE */
index 7436a9f..9e08017 100644 (file)
@@ -111,6 +111,8 @@ struct modes imodes[] = {
        { "-igncr",     0, IGNCR },
        { "icrnl",      ICRNL, 0 },
        { "-icrnl",     0, ICRNL },
+       { "iuclc",      IUCLC, 0 },
+       { "-iuclc",     0, IUCLC },
        { "ixon",       IXON, 0 },
        { "-ixon",      0, IXON },
        { "flow",       IXON, 0 },
@@ -177,6 +179,8 @@ struct modes lmodes[] = {
        { "-nokerninfo",0, NOKERNINFO },
        { "kerninfo",   0, NOKERNINFO },
        { "-kerninfo",  NOKERNINFO, 0 },
+       { "xcase",      XCASE, 0 },
+       { "-xcase",     0, XCASE },
        { NULL },
 };
 
@@ -185,8 +189,16 @@ struct modes omodes[] = {
        { "-opost",     0, OPOST },
        { "litout",     0, OPOST },
        { "-litout",    OPOST, 0 },
+       { "ocrnl",      OCRNL, 0 },
+       { "-ocrnl",     0, OCRNL },
+       { "olcuc",      OLCUC, 0 },
+       { "-olcuc",     0, OLCUC },
        { "onlcr",      ONLCR, 0 },
        { "-onlcr",     0, ONLCR },
+       { "onlret",     ONLRET, 0 },
+       { "-onlret",    0, ONLRET },
+       { "onocr",      ONOCR, 0 },
+       { "-onocr",     0, ONOCR },
        { "tabs",       0, OXTABS },            /* "preserve" tabs */
        { "-tabs",      OXTABS, 0 },
        { "oxtabs",     OXTABS, 0 },
index a31a0db..f368871 100644 (file)
@@ -82,6 +82,8 @@ sttygetoflags(tp)
                if (!ISSET(oflag, OPOST))
                        SET(flags, LITOUT);
        }
+       if (ISSET(lflag, XCASE))
+               SET(flags, LCASE);
 
        if (!ISSET(lflag, ICANON)) {
                /* fudge */
@@ -107,7 +109,7 @@ sttysetoflags(tp, flags)
 
        if (ISSET(flags, RAW)) {
                iflag &= IXOFF;
-               CLR(lflag, ISIG|ICANON|IEXTEN);
+               CLR(lflag, ISIG|ICANON|IEXTEN|XCASE);
                CLR(cflag, PARENB);
        } else {
                SET(iflag, BRKINT|IXON|IMAXBEL);
@@ -116,6 +118,8 @@ sttysetoflags(tp, flags)
                        CLR(lflag, ICANON);
                else
                        SET(lflag, ICANON);
+               if (ISSET(iflag, IUCLC) && ISSET(oflag, OLCUC))
+                       SET(lflag, XCASE);
                switch (ISSET(flags, ANYP)) {
                case 0:
                        CLR(cflag, PARENB);
@@ -180,6 +184,11 @@ sttyclearflags(tp, flags)
                CLR(iflag, ICRNL);
                CLR(oflag, ONLCR);
        }
+       if (ISSET(flags, LCASE)) {
+               CLR(iflag, IUCLC);
+               CLR(oflag, OLCUC);
+               CLR(lflag, XCASE);
+       }
        if (ISSET(flags, XTABS))
                CLR(oflag, OXTABS);
 
@@ -211,6 +220,11 @@ sttysetflags(tp, flags)
                SET(iflag, ICRNL);
                SET(oflag, ONLCR);
        }
+       if (ISSET(flags, LCASE)) {
+               SET(iflag, IUCLC);
+               SET(oflag, OLCUC);
+               SET(lflag, XCASE);
+       }
        if (ISSET(flags, XTABS))
                SET(oflag, OXTABS);