xref: /titanic_51/usr/src/uts/common/io/ldterm.c (revision 19d32b9ab53d17ac6605971e14c45a5281f8d9bb)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
585bb5f1dSis  * Common Development and Distribution License (the "License").
685bb5f1dSis  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
2285bb5f1dSis  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
24*19d32b9aSRobert Mustacchi  * Copyright (c) 2014, Joyent, Inc.  All rights reserved.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
287c478bd9Sstevel@tonic-gate /* All Rights Reserved					*/
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate /*
317c478bd9Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
327c478bd9Sstevel@tonic-gate  * The Regents of the University of California
337c478bd9Sstevel@tonic-gate  * All Rights Reserved
347c478bd9Sstevel@tonic-gate  *
357c478bd9Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
367c478bd9Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
377c478bd9Sstevel@tonic-gate  * contributors.
387c478bd9Sstevel@tonic-gate  */
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate /*
417c478bd9Sstevel@tonic-gate  * Standard Streams Terminal Line Discipline module.
427c478bd9Sstevel@tonic-gate  */
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate #include <sys/param.h>
457c478bd9Sstevel@tonic-gate #include <sys/types.h>
467c478bd9Sstevel@tonic-gate #include <sys/termio.h>
477c478bd9Sstevel@tonic-gate #include <sys/stream.h>
487c478bd9Sstevel@tonic-gate #include <sys/conf.h>
497c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
507c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
517c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
527c478bd9Sstevel@tonic-gate #include <sys/strtty.h>
537c478bd9Sstevel@tonic-gate #include <sys/signal.h>
547c478bd9Sstevel@tonic-gate #include <sys/file.h>
557c478bd9Sstevel@tonic-gate #include <sys/errno.h>
567c478bd9Sstevel@tonic-gate #include <sys/debug.h>
577c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
587c478bd9Sstevel@tonic-gate #include <sys/euc.h>
597c478bd9Sstevel@tonic-gate #include <sys/eucioctl.h>
607c478bd9Sstevel@tonic-gate #include <sys/csiioctl.h>
617c478bd9Sstevel@tonic-gate #include <sys/ptms.h>
627c478bd9Sstevel@tonic-gate #include <sys/ldterm.h>
637c478bd9Sstevel@tonic-gate #include <sys/cred.h>
647c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
657c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
667c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
677c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate /* Time limit when draining during a close(9E) invoked by exit(2) */
707c478bd9Sstevel@tonic-gate /* Can be set to zero to emulate the old, broken behavior */
717c478bd9Sstevel@tonic-gate int ldterm_drain_limit = 15000000;
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate /*
747c478bd9Sstevel@tonic-gate  * Character types.
757c478bd9Sstevel@tonic-gate  */
767c478bd9Sstevel@tonic-gate #define	ORDINARY	0
777c478bd9Sstevel@tonic-gate #define	CONTROL		1
787c478bd9Sstevel@tonic-gate #define	BACKSPACE	2
797c478bd9Sstevel@tonic-gate #define	NEWLINE		3
807c478bd9Sstevel@tonic-gate #define	TAB		4
817c478bd9Sstevel@tonic-gate #define	VTAB		5
827c478bd9Sstevel@tonic-gate #define	RETURN		6
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate /*
857c478bd9Sstevel@tonic-gate  * The following for EUC handling:
867c478bd9Sstevel@tonic-gate  */
877c478bd9Sstevel@tonic-gate #define	T_SS2		7
887c478bd9Sstevel@tonic-gate #define	T_SS3		8
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate /*
917c478bd9Sstevel@tonic-gate  * Table indicating character classes to tty driver.  In particular,
927c478bd9Sstevel@tonic-gate  * if the class is ORDINARY, then the character needs no special
937c478bd9Sstevel@tonic-gate  * processing on output.
947c478bd9Sstevel@tonic-gate  *
957c478bd9Sstevel@tonic-gate  * Characters in the C1 set are all considered CONTROL; this will
967c478bd9Sstevel@tonic-gate  * work with terminals that properly use the ANSI/ISO extensions,
977c478bd9Sstevel@tonic-gate  * but might cause distress with terminals that put graphics in
987c478bd9Sstevel@tonic-gate  * the range 0200-0237.  On the other hand, characters in that
997c478bd9Sstevel@tonic-gate  * range cause even greater distress to other UNIX terminal drivers....
1007c478bd9Sstevel@tonic-gate  */
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate static char typetab[256] = {
1037c478bd9Sstevel@tonic-gate /* 000 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
1047c478bd9Sstevel@tonic-gate /* 004 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
1057c478bd9Sstevel@tonic-gate /* 010 */	BACKSPACE,	TAB,		NEWLINE,	CONTROL,
1067c478bd9Sstevel@tonic-gate /* 014 */	VTAB,		RETURN,		CONTROL,	CONTROL,
1077c478bd9Sstevel@tonic-gate /* 020 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
1087c478bd9Sstevel@tonic-gate /* 024 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
1097c478bd9Sstevel@tonic-gate /* 030 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
1107c478bd9Sstevel@tonic-gate /* 034 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
1117c478bd9Sstevel@tonic-gate /* 040 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1127c478bd9Sstevel@tonic-gate /* 044 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1137c478bd9Sstevel@tonic-gate /* 050 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1147c478bd9Sstevel@tonic-gate /* 054 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1157c478bd9Sstevel@tonic-gate /* 060 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1167c478bd9Sstevel@tonic-gate /* 064 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1177c478bd9Sstevel@tonic-gate /* 070 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1187c478bd9Sstevel@tonic-gate /* 074 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1197c478bd9Sstevel@tonic-gate /* 100 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1207c478bd9Sstevel@tonic-gate /* 104 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1217c478bd9Sstevel@tonic-gate /* 110 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1227c478bd9Sstevel@tonic-gate /* 114 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1237c478bd9Sstevel@tonic-gate /* 120 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1247c478bd9Sstevel@tonic-gate /* 124 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1257c478bd9Sstevel@tonic-gate /* 130 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1267c478bd9Sstevel@tonic-gate /* 134 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1277c478bd9Sstevel@tonic-gate /* 140 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1287c478bd9Sstevel@tonic-gate /* 144 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1297c478bd9Sstevel@tonic-gate /* 150 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1307c478bd9Sstevel@tonic-gate /* 154 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1317c478bd9Sstevel@tonic-gate /* 160 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1327c478bd9Sstevel@tonic-gate /* 164 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1337c478bd9Sstevel@tonic-gate /* 170 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1347c478bd9Sstevel@tonic-gate /* 174 */	ORDINARY,	ORDINARY,	ORDINARY,	CONTROL,
1357c478bd9Sstevel@tonic-gate /* 200 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
1367c478bd9Sstevel@tonic-gate /* 204 */	CONTROL,	CONTROL,	T_SS2,		T_SS3,
1377c478bd9Sstevel@tonic-gate /* 210 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
1387c478bd9Sstevel@tonic-gate /* 214 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
1397c478bd9Sstevel@tonic-gate /* 220 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
1407c478bd9Sstevel@tonic-gate /* 224 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
1417c478bd9Sstevel@tonic-gate /* 230 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
1427c478bd9Sstevel@tonic-gate /* 234 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
1437c478bd9Sstevel@tonic-gate /* 240 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1447c478bd9Sstevel@tonic-gate /* 244 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1457c478bd9Sstevel@tonic-gate /* 250 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1467c478bd9Sstevel@tonic-gate /* 254 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1477c478bd9Sstevel@tonic-gate /* 260 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1487c478bd9Sstevel@tonic-gate /* 264 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1497c478bd9Sstevel@tonic-gate /* 270 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1507c478bd9Sstevel@tonic-gate /* 274 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1517c478bd9Sstevel@tonic-gate /* 300 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1527c478bd9Sstevel@tonic-gate /* 304 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1537c478bd9Sstevel@tonic-gate /* 310 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1547c478bd9Sstevel@tonic-gate /* 314 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1557c478bd9Sstevel@tonic-gate /* 320 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1567c478bd9Sstevel@tonic-gate /* 324 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1577c478bd9Sstevel@tonic-gate /* 330 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1587c478bd9Sstevel@tonic-gate /* 334 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1597c478bd9Sstevel@tonic-gate /* 340 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1607c478bd9Sstevel@tonic-gate /* 344 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1617c478bd9Sstevel@tonic-gate /* 350 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1627c478bd9Sstevel@tonic-gate /* 354 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1637c478bd9Sstevel@tonic-gate /* 360 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1647c478bd9Sstevel@tonic-gate /* 364 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1657c478bd9Sstevel@tonic-gate /* 370 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1667c478bd9Sstevel@tonic-gate /*
1677c478bd9Sstevel@tonic-gate  * WARNING:  For EUC, 0xFF must be an ordinary character.  It is used with
1687c478bd9Sstevel@tonic-gate  * single-byte EUC in some of the "ISO Latin Alphabet" codesets, and occupies
1697c478bd9Sstevel@tonic-gate  * a screen position; in those ISO sets where that position isn't used, it
1707c478bd9Sstevel@tonic-gate  * shouldn't make any difference.
1717c478bd9Sstevel@tonic-gate  */
1727c478bd9Sstevel@tonic-gate /* 374 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
1737c478bd9Sstevel@tonic-gate };
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate /*
1767c478bd9Sstevel@tonic-gate  * Translation table for output without OLCUC.  All ORDINARY-class characters
1777c478bd9Sstevel@tonic-gate  * translate to themselves.  All other characters have a zero in the table,
1787c478bd9Sstevel@tonic-gate  * which stops the copying.
1797c478bd9Sstevel@tonic-gate  */
1807c478bd9Sstevel@tonic-gate static unsigned char notrantab[256] = {
1817c478bd9Sstevel@tonic-gate /* 000 */	0,	0,	0,	0,	0,	0,	0,	0,
1827c478bd9Sstevel@tonic-gate /* 010 */	0,	0,	0,	0,	0,	0,	0,	0,
1837c478bd9Sstevel@tonic-gate /* 020 */	0,	0,	0,	0,	0,	0,	0,	0,
1847c478bd9Sstevel@tonic-gate /* 030 */	0,	0,	0,	0,	0,	0,	0,	0,
1857c478bd9Sstevel@tonic-gate /* 040 */	' ',	'!',	'"',	'#',	'$',	'%',	'&',	'\'',
1867c478bd9Sstevel@tonic-gate /* 050 */	'(',	')',	'*',	'+',	',',	'-',	'.',	'/',
1877c478bd9Sstevel@tonic-gate /* 060 */	'0',	'1',	'2',	'3',	'4',	'5',	'6',	'7',
1887c478bd9Sstevel@tonic-gate /* 070 */	'8',	'9',	':',	';',	'<',	'=',	'>',	'?',
1897c478bd9Sstevel@tonic-gate /* 100 */	'@',	'A',	'B',	'C',	'D',	'E',	'F',	'G',
1907c478bd9Sstevel@tonic-gate /* 110 */	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
1917c478bd9Sstevel@tonic-gate /* 120 */	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
1927c478bd9Sstevel@tonic-gate /* 130 */	'X',	'Y',	'Z',	'[',	'\\',	']',	'^',	'_',
1937c478bd9Sstevel@tonic-gate /* 140 */	'`',	'a',	'b',	'c',	'd',	'e',	'f',	'g',
1947c478bd9Sstevel@tonic-gate /* 150 */	'h',	'i',	'j',	'k',	'l',	'm',	'n',	'o',
1957c478bd9Sstevel@tonic-gate /* 160 */	'p',	'q',	'r',	's',	't',	'u',	'v',	'w',
1967c478bd9Sstevel@tonic-gate /* 170 */	'x',	'y',	'z',	'{',	'|',	'}',	'~',	0,
1977c478bd9Sstevel@tonic-gate /* 200 */	0,	0,	0,	0,	0,	0,	0,	0,
1987c478bd9Sstevel@tonic-gate /* 210 */	0,	0,	0,	0,	0,	0,	0,	0,
1997c478bd9Sstevel@tonic-gate /* 220 */	0,	0,	0,	0,	0,	0,	0,	0,
2007c478bd9Sstevel@tonic-gate /* 230 */	0,	0,	0,	0,	0,	0,	0,	0,
2017c478bd9Sstevel@tonic-gate /* 240 */	0240,	0241,	0242,	0243,	0244,	0245,	0246,	0247,
2027c478bd9Sstevel@tonic-gate /* 250 */	0250,	0251,	0252,	0253,	0254,	0255,	0256,	0257,
2037c478bd9Sstevel@tonic-gate /* 260 */	0260,	0261,	0262,	0263,	0264,	0265,	0266,	0267,
2047c478bd9Sstevel@tonic-gate /* 270 */	0270,	0271,	0272,	0273,	0274,	0275,	0276,	0277,
2057c478bd9Sstevel@tonic-gate /* 300 */	0300,	0301,	0302,	0303,	0304,	0305,	0306,	0307,
2067c478bd9Sstevel@tonic-gate /* 310 */	0310,	0311,	0312,	0313,	0314,	0315,	0316,	0317,
2077c478bd9Sstevel@tonic-gate /* 320 */	0320,	0321,	0322,	0323,	0324,	0325,	0326,	0327,
2087c478bd9Sstevel@tonic-gate /* 330 */	0330,	0331,	0332,	0333,	0334,	0335,	0336,	0337,
2097c478bd9Sstevel@tonic-gate /* 340 */	0340,	0341,	0342,	0343,	0344,	0345,	0346,	0347,
2107c478bd9Sstevel@tonic-gate /* 350 */	0350,	0351,	0352,	0353,	0354,	0355,	0356,	0357,
2117c478bd9Sstevel@tonic-gate /* 360 */	0360,	0361,	0362,	0363,	0364,	0365,	0366,	0367,
2127c478bd9Sstevel@tonic-gate /*
2137c478bd9Sstevel@tonic-gate  * WARNING: as for above ISO sets, \377 may be used.  Translate it to
2147c478bd9Sstevel@tonic-gate  * itself.
2157c478bd9Sstevel@tonic-gate  */
2167c478bd9Sstevel@tonic-gate /* 370 */	0370,	0371,	0372,	0373,	0374,	0375,	0376,	0377,
2177c478bd9Sstevel@tonic-gate };
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate /*
2207c478bd9Sstevel@tonic-gate  * Translation table for output with OLCUC.  All ORDINARY-class characters
2217c478bd9Sstevel@tonic-gate  * translate to themselves, except for lower-case letters which translate
2227c478bd9Sstevel@tonic-gate  * to their upper-case equivalents.  All other characters have a zero in
2237c478bd9Sstevel@tonic-gate  * the table, which stops the copying.
2247c478bd9Sstevel@tonic-gate  */
2257c478bd9Sstevel@tonic-gate static unsigned char lcuctab[256] = {
2267c478bd9Sstevel@tonic-gate /* 000 */	0,	0,	0,	0,	0,	0,	0,	0,
2277c478bd9Sstevel@tonic-gate /* 010 */	0,	0,	0,	0,	0,	0,	0,	0,
2287c478bd9Sstevel@tonic-gate /* 020 */	0,	0,	0,	0,	0,	0,	0,	0,
2297c478bd9Sstevel@tonic-gate /* 030 */	0,	0,	0,	0,	0,	0,	0,	0,
2307c478bd9Sstevel@tonic-gate /* 040 */	' ',	'!',	'"',	'#',	'$',	'%',	'&',	'\'',
2317c478bd9Sstevel@tonic-gate /* 050 */	'(',	')',	'*',	'+',	',',	'-',	'.',	'/',
2327c478bd9Sstevel@tonic-gate /* 060 */	'0',	'1',	'2',	'3',	'4',	'5',	'6',	'7',
2337c478bd9Sstevel@tonic-gate /* 070 */	'8',	'9',	':',	';',	'<',	'=',	'>',	'?',
2347c478bd9Sstevel@tonic-gate /* 100 */	'@',	'A',	'B',	'C',	'D',	'E',	'F',	'G',
2357c478bd9Sstevel@tonic-gate /* 110 */	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
2367c478bd9Sstevel@tonic-gate /* 120 */	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
2377c478bd9Sstevel@tonic-gate /* 130 */	'X',	'Y',	'Z',	'[',	'\\',	']',	'^',	'_',
2387c478bd9Sstevel@tonic-gate /* 140 */	'`',	'A',	'B',	'C',	'D',	'E',	'F',	'G',
2397c478bd9Sstevel@tonic-gate /* 150 */	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
2407c478bd9Sstevel@tonic-gate /* 160 */	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
2417c478bd9Sstevel@tonic-gate /* 170 */	'X',	'Y',	'Z',	'{',	'|',	'}',	'~',	0,
2427c478bd9Sstevel@tonic-gate /* 200 */	0,	0,	0,	0,	0,	0,	0,	0,
2437c478bd9Sstevel@tonic-gate /* 210 */	0,	0,	0,	0,	0,	0,	0,	0,
2447c478bd9Sstevel@tonic-gate /* 220 */	0,	0,	0,	0,	0,	0,	0,	0,
2457c478bd9Sstevel@tonic-gate /* 230 */	0,	0,	0,	0,	0,	0,	0,	0,
2467c478bd9Sstevel@tonic-gate /* 240 */	0240,	0241,	0242,	0243,	0244,	0245,	0246,	0247,
2477c478bd9Sstevel@tonic-gate /* 250 */	0250,	0251,	0252,	0253,	0254,	0255,	0256,	0257,
2487c478bd9Sstevel@tonic-gate /* 260 */	0260,	0261,	0262,	0263,	0264,	0265,	0266,	0267,
2497c478bd9Sstevel@tonic-gate /* 270 */	0270,	0271,	0272,	0273,	0274,	0275,	0276,	0277,
2507c478bd9Sstevel@tonic-gate /* 300 */	0300,	0301,	0302,	0303,	0304,	0305,	0306,	0307,
2517c478bd9Sstevel@tonic-gate /* 310 */	0310,	0311,	0312,	0313,	0314,	0315,	0316,	0317,
2527c478bd9Sstevel@tonic-gate /* 320 */	0320,	0321,	0322,	0323,	0324,	0325,	0326,	0327,
2537c478bd9Sstevel@tonic-gate /* 330 */	0330,	0331,	0332,	0333,	0334,	0335,	0336,	0337,
2547c478bd9Sstevel@tonic-gate /* 340 */	0340,	0341,	0342,	0343,	0344,	0345,	0346,	0347,
2557c478bd9Sstevel@tonic-gate /* 350 */	0350,	0351,	0352,	0353,	0354,	0355,	0356,	0357,
2567c478bd9Sstevel@tonic-gate /* 360 */	0360,	0361,	0362,	0363,	0364,	0365,	0366,	0367,
2577c478bd9Sstevel@tonic-gate /*
2587c478bd9Sstevel@tonic-gate  * WARNING: as for above ISO sets, \377 may be used.  Translate it to
2597c478bd9Sstevel@tonic-gate  * itself.
2607c478bd9Sstevel@tonic-gate  */
2617c478bd9Sstevel@tonic-gate /* 370 */	0370,	0371,	0372,	0373,	0374,	0375,	0376,	0377,
2627c478bd9Sstevel@tonic-gate };
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate /*
2657c478bd9Sstevel@tonic-gate  * Input mapping table -- if an entry is non-zero, and XCASE is set,
2667c478bd9Sstevel@tonic-gate  * when the corresponding character is typed preceded by "\" the escape
2677c478bd9Sstevel@tonic-gate  * sequence is replaced by the table value.  Mostly used for
2687c478bd9Sstevel@tonic-gate  * upper-case only terminals.
2697c478bd9Sstevel@tonic-gate  */
2707c478bd9Sstevel@tonic-gate static char	imaptab[256] = {
2717c478bd9Sstevel@tonic-gate /* 000 */	0,	0,	0,	0,	0,	0,	0,	0,
2727c478bd9Sstevel@tonic-gate /* 010 */	0,	0,	0,	0,	0,	0,	0,	0,
2737c478bd9Sstevel@tonic-gate /* 020 */	0,	0,	0,	0,	0,	0,	0,	0,
2747c478bd9Sstevel@tonic-gate /* 030 */	0,	0,	0,	0,	0,	0,	0,	0,
2757c478bd9Sstevel@tonic-gate /* 040 */	0,	'|',	0,	0,	0,	0,	0,	'`',
2767c478bd9Sstevel@tonic-gate /* 050 */	'{',	'}',	0,	0,	0,	0,	0,	0,
2777c478bd9Sstevel@tonic-gate /* 060 */	0,	0,	0,	0,	0,	0,	0,	0,
2787c478bd9Sstevel@tonic-gate /* 070 */	0,	0,	0,	0,	0,	0,	0,	0,
2797c478bd9Sstevel@tonic-gate /* 100 */	0,	0,	0,	0,	0,	0,	0,	0,
2807c478bd9Sstevel@tonic-gate /* 110 */	0,	0,	0,	0,	0,	0,	0,	0,
2817c478bd9Sstevel@tonic-gate /* 120 */	0,	0,	0,	0,	0,	0,	0,	0,
2827c478bd9Sstevel@tonic-gate /* 130 */	0,	0,	0,	0,	'\\',	0,	'~',	0,
2837c478bd9Sstevel@tonic-gate /* 140 */	0,	'A',	'B',	'C',	'D',	'E',	'F',	'G',
2847c478bd9Sstevel@tonic-gate /* 150 */	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
2857c478bd9Sstevel@tonic-gate /* 160 */	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
2867c478bd9Sstevel@tonic-gate /* 170 */	'X',	'Y',	'Z',	0,	0,	0,	0,	0,
2877c478bd9Sstevel@tonic-gate /* 200-377 aren't mapped */
2887c478bd9Sstevel@tonic-gate };
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate /*
2917c478bd9Sstevel@tonic-gate  * Output mapping table -- if an entry is non-zero, and XCASE is set,
2927c478bd9Sstevel@tonic-gate  * the corresponding character is printed as "\" followed by the table
2937c478bd9Sstevel@tonic-gate  * value.  Mostly used for upper-case only terminals.
2947c478bd9Sstevel@tonic-gate  */
2957c478bd9Sstevel@tonic-gate static char	omaptab[256] = {
2967c478bd9Sstevel@tonic-gate /* 000 */	0,	0,	0,	0,	0,	0,	0,	0,
2977c478bd9Sstevel@tonic-gate /* 010 */	0,	0,	0,	0,	0,	0,	0,	0,
2987c478bd9Sstevel@tonic-gate /* 020 */	0,	0,	0,	0,	0,	0,	0,	0,
2997c478bd9Sstevel@tonic-gate /* 030 */	0,	0,	0,	0,	0,	0,	0,	0,
3007c478bd9Sstevel@tonic-gate /* 040 */	0,	0,	0,	0,	0,	0,	0,	0,
3017c478bd9Sstevel@tonic-gate /* 050 */	0,	0,	0,	0,	0,	0,	0,	0,
3027c478bd9Sstevel@tonic-gate /* 060 */	0,	0,	0,	0,	0,	0,	0,	0,
3037c478bd9Sstevel@tonic-gate /* 070 */	0,	0,	0,	0,	0,	0,	0,	0,
3047c478bd9Sstevel@tonic-gate /* 100 */	0,	'A',	'B',	'C',	'D',	'E',	'F',	'G',
3057c478bd9Sstevel@tonic-gate /* 110 */	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
3067c478bd9Sstevel@tonic-gate /* 120 */	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
3077c478bd9Sstevel@tonic-gate /* 130 */	'X',	'Y',	'Z',	0,	0,	0,	0,	0,
3087c478bd9Sstevel@tonic-gate /* 140 */	'\'',	0,	0,	0,	0,	0,	0,	0,
3097c478bd9Sstevel@tonic-gate /* 150 */	0,	0,	0,	0,	0,	0,	0,	0,
3107c478bd9Sstevel@tonic-gate /* 160 */	0,	0,	0,	0,	0,	0,	0,	0,
3117c478bd9Sstevel@tonic-gate /* 170 */	0,	0,	0,	'(',	'!',	')',	'^',	0,
3127c478bd9Sstevel@tonic-gate /* 200-377 aren't mapped */
3137c478bd9Sstevel@tonic-gate };
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate /*
3167c478bd9Sstevel@tonic-gate  * Translation table for TS_MEUC output without OLCUC.  All printing ASCII
3177c478bd9Sstevel@tonic-gate  * characters translate to themselves.  All other _bytes_ have a zero in
3187c478bd9Sstevel@tonic-gate  * the table, which stops the copying.  This and the following table exist
3197c478bd9Sstevel@tonic-gate  * only so we can use the existing movtuc processing with or without OLCUC.
3207c478bd9Sstevel@tonic-gate  * Maybe it speeds up something...because we can copy a block of characters
3217c478bd9Sstevel@tonic-gate  * by only looking for zeros in the table.
3227c478bd9Sstevel@tonic-gate  *
3237c478bd9Sstevel@tonic-gate  * If we took the simple expedient of DISALLOWING "olcuc" with multi-byte
3247c478bd9Sstevel@tonic-gate  * processing, we could rid ourselves of both these tables and save 512 bytes;
3257c478bd9Sstevel@tonic-gate  * seriously, it doesn't make much sense to use olcuc with multi-byte, and
3267c478bd9Sstevel@tonic-gate  * it will probably never be used.  Consideration should be given to disallowing
3277c478bd9Sstevel@tonic-gate  * the combination TS_MEUC & OLCUC.
3287c478bd9Sstevel@tonic-gate  */
3297c478bd9Sstevel@tonic-gate static unsigned char enotrantab[256] = {
3307c478bd9Sstevel@tonic-gate /* 000 */	0,	0,	0,	0,	0,	0,	0,	0,
3317c478bd9Sstevel@tonic-gate /* 010 */	0,	0,	0,	0,	0,	0,	0,	0,
3327c478bd9Sstevel@tonic-gate /* 020 */	0,	0,	0,	0,	0,	0,	0,	0,
3337c478bd9Sstevel@tonic-gate /* 030 */	0,	0,	0,	0,	0,	0,	0,	0,
3347c478bd9Sstevel@tonic-gate /* 040 */	' ',	'!',	'"',	'#',	'$',	'%',	'&',	'\'',
3357c478bd9Sstevel@tonic-gate /* 050 */	'(',	')',	'*',	'+',	',',	'-',	'.',	'/',
3367c478bd9Sstevel@tonic-gate /* 060 */	'0',	'1',	'2',	'3',	'4',	'5',	'6',	'7',
3377c478bd9Sstevel@tonic-gate /* 070 */	'8',	'9',	':',	';',	'<',	'=',	'>',	'?',
3387c478bd9Sstevel@tonic-gate /* 100 */	'@',	'A',	'B',	'C',	'D',	'E',	'F',	'G',
3397c478bd9Sstevel@tonic-gate /* 110 */	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
3407c478bd9Sstevel@tonic-gate /* 120 */	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
3417c478bd9Sstevel@tonic-gate /* 130 */	'X',	'Y',	'Z',	'[',	'\\',	']',	'^',	'_',
3427c478bd9Sstevel@tonic-gate /* 140 */	'`',	'a',	'b',	'c',	'd',	'e',	'f',	'g',
3437c478bd9Sstevel@tonic-gate /* 150 */	'h',	'i',	'j',	'k',	'l',	'm',	'n',	'o',
3447c478bd9Sstevel@tonic-gate /* 160 */	'p',	'q',	'r',	's',	't',	'u',	'v',	'w',
3457c478bd9Sstevel@tonic-gate /* 170 */	'x',	'y',	'z',	'{',	'|',	'}',	'~',	0,
3467c478bd9Sstevel@tonic-gate /* 200 - 377 aren't mapped (they're stoppers). */
3477c478bd9Sstevel@tonic-gate };
3487c478bd9Sstevel@tonic-gate 
3497c478bd9Sstevel@tonic-gate /*
3507c478bd9Sstevel@tonic-gate  * Translation table for TS_MEUC output with OLCUC.  All printing ASCII
3517c478bd9Sstevel@tonic-gate  * translate to themselves, except for lower-case letters which translate
3527c478bd9Sstevel@tonic-gate  * to their upper-case equivalents.  All other bytes have a zero in
3537c478bd9Sstevel@tonic-gate  * the table, which stops the copying.  Useless for ISO Latin Alphabet
3547c478bd9Sstevel@tonic-gate  * translations, but *sigh* OLCUC is really only defined for ASCII anyway.
3557c478bd9Sstevel@tonic-gate  * We only have this table so we can use the existing OLCUC processing with
3567c478bd9Sstevel@tonic-gate  * TS_MEUC set (multi-byte mode).  Nobody would ever think of actually
3577c478bd9Sstevel@tonic-gate  * _using_ it...would they?
3587c478bd9Sstevel@tonic-gate  */
3597c478bd9Sstevel@tonic-gate static unsigned char elcuctab[256] = {
3607c478bd9Sstevel@tonic-gate /* 000 */	0,	0,	0,	0,	0,	0,	0,	0,
3617c478bd9Sstevel@tonic-gate /* 010 */	0,	0,	0,	0,	0,	0,	0,	0,
3627c478bd9Sstevel@tonic-gate /* 020 */	0,	0,	0,	0,	0,	0,	0,	0,
3637c478bd9Sstevel@tonic-gate /* 030 */	0,	0,	0,	0,	0,	0,	0,	0,
3647c478bd9Sstevel@tonic-gate /* 040 */	' ',	'!',	'"',	'#',	'$',	'%',	'&',	'\'',
3657c478bd9Sstevel@tonic-gate /* 050 */	'(',	')',	'*',	'+',	',',	'-',	'.',	'/',
3667c478bd9Sstevel@tonic-gate /* 060 */	'0',	'1',	'2',	'3',	'4',	'5',	'6',	'7',
3677c478bd9Sstevel@tonic-gate /* 070 */	'8',	'9',	':',	';',	'<',	'=',	'>',	'?',
3687c478bd9Sstevel@tonic-gate /* 100 */	'@',	'A',	'B',	'C',	'D',	'E',	'F',	'G',
3697c478bd9Sstevel@tonic-gate /* 110 */	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
3707c478bd9Sstevel@tonic-gate /* 120 */	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
3717c478bd9Sstevel@tonic-gate /* 130 */	'X',	'Y',	'Z',	'[',	'\\',	']',	'^',	'_',
3727c478bd9Sstevel@tonic-gate /* 140 */	'`',	'A',	'B',	'C',	'D',	'E',	'F',	'G',
3737c478bd9Sstevel@tonic-gate /* 150 */	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
3747c478bd9Sstevel@tonic-gate /* 160 */	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
3757c478bd9Sstevel@tonic-gate /* 170 */	'X',	'Y',	'Z',	'{',	'|',	'}',	'~',	0,
3767c478bd9Sstevel@tonic-gate /* 200 - 377 aren't mapped (they're stoppers). */
3777c478bd9Sstevel@tonic-gate };
3787c478bd9Sstevel@tonic-gate 
3797c478bd9Sstevel@tonic-gate static struct streamtab ldtrinfo;
3807c478bd9Sstevel@tonic-gate 
3817c478bd9Sstevel@tonic-gate static struct fmodsw fsw = {
3827c478bd9Sstevel@tonic-gate 	"ldterm",
3837c478bd9Sstevel@tonic-gate 	&ldtrinfo,
3847c478bd9Sstevel@tonic-gate 	D_MTQPAIR | D_MP
3857c478bd9Sstevel@tonic-gate };
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate static struct modlstrmod modlstrmod = {
3887c478bd9Sstevel@tonic-gate 	&mod_strmodops, "terminal line discipline", &fsw
3897c478bd9Sstevel@tonic-gate };
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
3937c478bd9Sstevel@tonic-gate 	MODREV_1, &modlstrmod, NULL
3947c478bd9Sstevel@tonic-gate };
3957c478bd9Sstevel@tonic-gate 
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate int
3987c478bd9Sstevel@tonic-gate _init(void)
3997c478bd9Sstevel@tonic-gate {
4007c478bd9Sstevel@tonic-gate 	return (mod_install(&modlinkage));
4017c478bd9Sstevel@tonic-gate }
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate int
4047c478bd9Sstevel@tonic-gate _fini(void)
4057c478bd9Sstevel@tonic-gate {
4067c478bd9Sstevel@tonic-gate 	return (mod_remove(&modlinkage));
4077c478bd9Sstevel@tonic-gate }
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate int
4107c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
4117c478bd9Sstevel@tonic-gate {
4127c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
4137c478bd9Sstevel@tonic-gate }
4147c478bd9Sstevel@tonic-gate 
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate static int	ldtermopen(queue_t *, dev_t *, int, int, cred_t *);
4177c478bd9Sstevel@tonic-gate static int	ldtermclose(queue_t *, int, cred_t *);
4187c478bd9Sstevel@tonic-gate static void	ldtermrput(queue_t *, mblk_t *);
4197c478bd9Sstevel@tonic-gate static void	ldtermrsrv(queue_t *);
4207c478bd9Sstevel@tonic-gate static int	ldtermrmsg(queue_t *, mblk_t *);
4217c478bd9Sstevel@tonic-gate static void	ldtermwput(queue_t *, mblk_t *);
4227c478bd9Sstevel@tonic-gate static void	ldtermwsrv(queue_t *);
4237c478bd9Sstevel@tonic-gate static int	ldtermwmsg(queue_t *, mblk_t *);
4247c478bd9Sstevel@tonic-gate static mblk_t	*ldterm_docanon(unsigned char, mblk_t *, size_t, queue_t *,
4257c478bd9Sstevel@tonic-gate 				ldtermstd_state_t *, int *);
4267c478bd9Sstevel@tonic-gate static int	ldterm_unget(ldtermstd_state_t *);
4277c478bd9Sstevel@tonic-gate static void	ldterm_trim(ldtermstd_state_t *);
4287c478bd9Sstevel@tonic-gate static void	ldterm_rubout(unsigned char, queue_t *, size_t,
4297c478bd9Sstevel@tonic-gate 				ldtermstd_state_t *);
4307c478bd9Sstevel@tonic-gate static int	ldterm_tabcols(ldtermstd_state_t *);
4317c478bd9Sstevel@tonic-gate static void	ldterm_erase(queue_t *, size_t, ldtermstd_state_t *);
4327c478bd9Sstevel@tonic-gate static void	ldterm_werase(queue_t *, size_t, ldtermstd_state_t *);
4337c478bd9Sstevel@tonic-gate static void	ldterm_kill(queue_t *, size_t, ldtermstd_state_t *);
4347c478bd9Sstevel@tonic-gate static void	ldterm_reprint(queue_t *, size_t, ldtermstd_state_t *);
4357c478bd9Sstevel@tonic-gate static mblk_t	*ldterm_dononcanon(mblk_t *, mblk_t *, size_t, queue_t *,
4367c478bd9Sstevel@tonic-gate 					ldtermstd_state_t *);
4377c478bd9Sstevel@tonic-gate static int	ldterm_echo(unsigned char, queue_t *, size_t,
4387c478bd9Sstevel@tonic-gate 				ldtermstd_state_t *);
4397c478bd9Sstevel@tonic-gate static void	ldterm_outchar(unsigned char, queue_t *, size_t,
4407c478bd9Sstevel@tonic-gate 				ldtermstd_state_t *);
4417c478bd9Sstevel@tonic-gate static void	ldterm_outstring(unsigned char *, int, queue_t *, size_t,
4427c478bd9Sstevel@tonic-gate 					ldtermstd_state_t *tp);
4437c478bd9Sstevel@tonic-gate static mblk_t	*newmsg(ldtermstd_state_t *);
4447c478bd9Sstevel@tonic-gate static void	ldterm_msg_upstream(queue_t *, ldtermstd_state_t *);
4457c478bd9Sstevel@tonic-gate static void	ldterm_wenable(void *);
4467c478bd9Sstevel@tonic-gate static mblk_t	*ldterm_output_msg(queue_t *, mblk_t *, mblk_t **,
4477c478bd9Sstevel@tonic-gate 				ldtermstd_state_t *, size_t, int);
4487c478bd9Sstevel@tonic-gate static void	ldterm_flush_output(unsigned char, queue_t *,
4497c478bd9Sstevel@tonic-gate 					ldtermstd_state_t *);
4507c478bd9Sstevel@tonic-gate static void	ldterm_dosig(queue_t *, int, unsigned char, int, int);
4517c478bd9Sstevel@tonic-gate static void	ldterm_do_ioctl(queue_t *, mblk_t *);
4527c478bd9Sstevel@tonic-gate static int	chgstropts(struct termios *, ldtermstd_state_t *, queue_t *);
4537c478bd9Sstevel@tonic-gate static void	ldterm_ioctl_reply(queue_t *, mblk_t *);
4547c478bd9Sstevel@tonic-gate static void	vmin_satisfied(queue_t *, ldtermstd_state_t *, int);
4557c478bd9Sstevel@tonic-gate static void	vmin_settimer(queue_t *);
4567c478bd9Sstevel@tonic-gate static void	vmin_timed_out(void *);
4577c478bd9Sstevel@tonic-gate static void	ldterm_adjust_modes(ldtermstd_state_t *);
4587c478bd9Sstevel@tonic-gate static void	ldterm_eucwarn(ldtermstd_state_t *);
4597c478bd9Sstevel@tonic-gate static void	cp_eucwioc(eucioc_t *, eucioc_t *, int);
4607c478bd9Sstevel@tonic-gate static int	ldterm_codeset(uchar_t, uchar_t);
4617c478bd9Sstevel@tonic-gate 
4627c478bd9Sstevel@tonic-gate static void	ldterm_csi_erase(queue_t *, size_t, ldtermstd_state_t *);
4637c478bd9Sstevel@tonic-gate static void	ldterm_csi_werase(queue_t *, size_t, ldtermstd_state_t *);
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate static uchar_t	ldterm_utf8_width(uchar_t *, int);
4667c478bd9Sstevel@tonic-gate 
4677c478bd9Sstevel@tonic-gate /* Codeset type specific methods for EUC, PCCS, and, UTF-8 codeset types. */
4687c478bd9Sstevel@tonic-gate static int	__ldterm_dispwidth_euc(uchar_t, void *, int);
4697c478bd9Sstevel@tonic-gate static int	__ldterm_memwidth_euc(uchar_t, void *);
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate static int	__ldterm_dispwidth_pccs(uchar_t, void *, int);
4727c478bd9Sstevel@tonic-gate static int	__ldterm_memwidth_pccs(uchar_t, void *);
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate static int	__ldterm_dispwidth_utf8(uchar_t, void *, int);
4757c478bd9Sstevel@tonic-gate static int	__ldterm_memwidth_utf8(uchar_t, void *);
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate static const ldterm_cs_methods_t cs_methods[LDTERM_CS_TYPE_MAX + 1] = {
4787c478bd9Sstevel@tonic-gate 	{
4797c478bd9Sstevel@tonic-gate 		NULL,
4807c478bd9Sstevel@tonic-gate 		NULL
4817c478bd9Sstevel@tonic-gate 	},
4827c478bd9Sstevel@tonic-gate 	{
4837c478bd9Sstevel@tonic-gate 		__ldterm_dispwidth_euc,
4847c478bd9Sstevel@tonic-gate 		__ldterm_memwidth_euc
4857c478bd9Sstevel@tonic-gate 	},
4867c478bd9Sstevel@tonic-gate 	{
4877c478bd9Sstevel@tonic-gate 		__ldterm_dispwidth_pccs,
4887c478bd9Sstevel@tonic-gate 		__ldterm_memwidth_pccs
4897c478bd9Sstevel@tonic-gate 	},
4907c478bd9Sstevel@tonic-gate 	{
4917c478bd9Sstevel@tonic-gate 		__ldterm_dispwidth_utf8,
4927c478bd9Sstevel@tonic-gate 		__ldterm_memwidth_utf8
4937c478bd9Sstevel@tonic-gate 	}
4947c478bd9Sstevel@tonic-gate };
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate /*
4977c478bd9Sstevel@tonic-gate  * The default codeset is presumably C locale's ISO 646 in EUC but
4987c478bd9Sstevel@tonic-gate  * the data structure at below defined as the default codeset data also
4997c478bd9Sstevel@tonic-gate  * support any single byte (EUC) locales.
5007c478bd9Sstevel@tonic-gate  */
5017c478bd9Sstevel@tonic-gate static const ldterm_cs_data_t default_cs_data = {
5027c478bd9Sstevel@tonic-gate 	LDTERM_DATA_VERSION,
5037c478bd9Sstevel@tonic-gate 	LDTERM_CS_TYPE_EUC,
5047c478bd9Sstevel@tonic-gate 	(uchar_t)0,
5057c478bd9Sstevel@tonic-gate 	(uchar_t)0,
5067c478bd9Sstevel@tonic-gate 	(char *)NULL,
5077c478bd9Sstevel@tonic-gate 	{
5087c478bd9Sstevel@tonic-gate 		'\0', '\0', '\0', '\0',
5097c478bd9Sstevel@tonic-gate 		'\0', '\0', '\0', '\0',
5107c478bd9Sstevel@tonic-gate 		'\0', '\0', '\0', '\0',
5117c478bd9Sstevel@tonic-gate 		'\0', '\0', '\0', '\0',
5127c478bd9Sstevel@tonic-gate 		'\0', '\0', '\0', '\0',
5137c478bd9Sstevel@tonic-gate 		'\0', '\0', '\0', '\0',
5147c478bd9Sstevel@tonic-gate 		'\0', '\0', '\0', '\0',
5157c478bd9Sstevel@tonic-gate 		'\0', '\0', '\0', '\0',
5167c478bd9Sstevel@tonic-gate 		'\0', '\0', '\0', '\0',
5177c478bd9Sstevel@tonic-gate 		'\0', '\0', '\0', '\0'
5187c478bd9Sstevel@tonic-gate 	}
5197c478bd9Sstevel@tonic-gate };
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate /*
52285bb5f1dSis  * The following tables are from either u8_textprep.c or uconv.c at
52385bb5f1dSis  * usr/src/common/unicode/. The tables are used to figure out corresponding
52485bb5f1dSis  * UTF-8 character byte lengths and also the validity of given character bytes.
5257c478bd9Sstevel@tonic-gate  */
52685bb5f1dSis extern const int8_t u8_number_of_bytes[];
52785bb5f1dSis extern const uchar_t u8_masks_tbl[];
52885bb5f1dSis extern const uint8_t u8_valid_min_2nd_byte[];
52985bb5f1dSis extern const uint8_t u8_valid_max_2nd_byte[];
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate /*
5327c478bd9Sstevel@tonic-gate  * Unicode character width definition tables from uwidth.c:
5337c478bd9Sstevel@tonic-gate  */
5347c478bd9Sstevel@tonic-gate extern const ldterm_unicode_data_cell_t ldterm_ucode[][16384];
5357c478bd9Sstevel@tonic-gate 
5367c478bd9Sstevel@tonic-gate #ifdef LDDEBUG
5377c478bd9Sstevel@tonic-gate int	ldterm_debug = 0;
5387c478bd9Sstevel@tonic-gate #define	DEBUG1(a)	if (ldterm_debug == 1) printf a
5397c478bd9Sstevel@tonic-gate #define	DEBUG2(a)	if (ldterm_debug >= 2) printf a	/* allocations */
5407c478bd9Sstevel@tonic-gate #define	DEBUG3(a)	if (ldterm_debug >= 3) printf a	/* M_CTL Stuff */
5417c478bd9Sstevel@tonic-gate #define	DEBUG4(a)	if (ldterm_debug >= 4) printf a	/* M_READ Stuff */
5427c478bd9Sstevel@tonic-gate #define	DEBUG5(a)	if (ldterm_debug >= 5) printf a
5437c478bd9Sstevel@tonic-gate #define	DEBUG6(a)	if (ldterm_debug >= 6) printf a
5447c478bd9Sstevel@tonic-gate #define	DEBUG7(a)	if (ldterm_debug >= 7) printf a
5457c478bd9Sstevel@tonic-gate #else
5467c478bd9Sstevel@tonic-gate #define	DEBUG1(a)
5477c478bd9Sstevel@tonic-gate #define	DEBUG2(a)
5487c478bd9Sstevel@tonic-gate #define	DEBUG3(a)
5497c478bd9Sstevel@tonic-gate #define	DEBUG4(a)
5507c478bd9Sstevel@tonic-gate #define	DEBUG5(a)
5517c478bd9Sstevel@tonic-gate #define	DEBUG6(a)
5527c478bd9Sstevel@tonic-gate #define	DEBUG7(a)
5537c478bd9Sstevel@tonic-gate #endif		/* LDDEBUG */
5547c478bd9Sstevel@tonic-gate 
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate /*
5577c478bd9Sstevel@tonic-gate  * Since most of the buffering occurs either at the stream head or in
5587c478bd9Sstevel@tonic-gate  * the "message currently being assembled" buffer, we have a
5597c478bd9Sstevel@tonic-gate  * relatively small input queue, so that blockages above us get
5607c478bd9Sstevel@tonic-gate  * reflected fairly quickly to the module below us.  We also have a
5617c478bd9Sstevel@tonic-gate  * small maximum packet size, since you can put a message of that
5627c478bd9Sstevel@tonic-gate  * size on an empty queue no matter how much bigger than the high
5637c478bd9Sstevel@tonic-gate  * water mark it is.
5647c478bd9Sstevel@tonic-gate  */
5657c478bd9Sstevel@tonic-gate static struct module_info ldtermmiinfo = {
5667c478bd9Sstevel@tonic-gate 	0x0bad,
5677c478bd9Sstevel@tonic-gate 	"ldterm",
5687c478bd9Sstevel@tonic-gate 	0,
5697c478bd9Sstevel@tonic-gate 	256,
5707c478bd9Sstevel@tonic-gate 	HIWAT,
5717c478bd9Sstevel@tonic-gate 	LOWAT
5727c478bd9Sstevel@tonic-gate };
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate static struct qinit ldtermrinit = {
5767c478bd9Sstevel@tonic-gate 	(int (*)())ldtermrput,
5777c478bd9Sstevel@tonic-gate 	(int (*)())ldtermrsrv,
5787c478bd9Sstevel@tonic-gate 	ldtermopen,
5797c478bd9Sstevel@tonic-gate 	ldtermclose,
5807c478bd9Sstevel@tonic-gate 	NULL,
5817c478bd9Sstevel@tonic-gate 	&ldtermmiinfo
5827c478bd9Sstevel@tonic-gate };
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate 
5857c478bd9Sstevel@tonic-gate static struct module_info ldtermmoinfo = {
5867c478bd9Sstevel@tonic-gate 	0x0bad,
5877c478bd9Sstevel@tonic-gate 	"ldterm",
5887c478bd9Sstevel@tonic-gate 	0,
5897c478bd9Sstevel@tonic-gate 	INFPSZ,
5907c478bd9Sstevel@tonic-gate 	1,
5917c478bd9Sstevel@tonic-gate 	0
5927c478bd9Sstevel@tonic-gate };
5937c478bd9Sstevel@tonic-gate 
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate static struct qinit ldtermwinit = {
5967c478bd9Sstevel@tonic-gate 	(int (*)())ldtermwput,
5977c478bd9Sstevel@tonic-gate 	(int (*)())ldtermwsrv,
5987c478bd9Sstevel@tonic-gate 	ldtermopen,
5997c478bd9Sstevel@tonic-gate 	ldtermclose,
6007c478bd9Sstevel@tonic-gate 	NULL,
6017c478bd9Sstevel@tonic-gate 	&ldtermmoinfo
6027c478bd9Sstevel@tonic-gate };
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate 
6057c478bd9Sstevel@tonic-gate static struct streamtab ldtrinfo = {
6067c478bd9Sstevel@tonic-gate 	&ldtermrinit,
6077c478bd9Sstevel@tonic-gate 	&ldtermwinit,
6087c478bd9Sstevel@tonic-gate 	NULL,
6097c478bd9Sstevel@tonic-gate 	NULL
6107c478bd9Sstevel@tonic-gate };
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate /*
6137c478bd9Sstevel@tonic-gate  * Dummy qbufcall callback routine used by open and close.
6147c478bd9Sstevel@tonic-gate  * The framework will wake up qwait_sig when we return from
6157c478bd9Sstevel@tonic-gate  * this routine (as part of leaving the perimeters.)
6167c478bd9Sstevel@tonic-gate  * (The framework enters the perimeters before calling the qbufcall() callback
6177c478bd9Sstevel@tonic-gate  * and leaves the perimeters after the callback routine has executed. The
6187c478bd9Sstevel@tonic-gate  * framework performs an implicit wakeup of any thread in qwait/qwait_sig
6197c478bd9Sstevel@tonic-gate  * when it leaves the perimeter. See qwait(9E).)
6207c478bd9Sstevel@tonic-gate  */
6217c478bd9Sstevel@tonic-gate /* ARGSUSED */
6227c478bd9Sstevel@tonic-gate static void
6237c478bd9Sstevel@tonic-gate dummy_callback(void *arg)
6247c478bd9Sstevel@tonic-gate {}
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate static mblk_t *
6287c478bd9Sstevel@tonic-gate open_ioctl(queue_t *q, uint_t cmd)
6297c478bd9Sstevel@tonic-gate {
6307c478bd9Sstevel@tonic-gate 	mblk_t *mp;
6317c478bd9Sstevel@tonic-gate 	bufcall_id_t id;
6327c478bd9Sstevel@tonic-gate 	int retv;
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate 	while ((mp = mkiocb(cmd)) == NULL) {
6357c478bd9Sstevel@tonic-gate 		id = qbufcall(q, sizeof (struct iocblk), BPRI_MED,
6367c478bd9Sstevel@tonic-gate 		    dummy_callback, NULL);
6377c478bd9Sstevel@tonic-gate 		retv = qwait_sig(q);
6387c478bd9Sstevel@tonic-gate 		qunbufcall(q, id);
6397c478bd9Sstevel@tonic-gate 		if (retv == 0)
6407c478bd9Sstevel@tonic-gate 			break;
6417c478bd9Sstevel@tonic-gate 	}
6427c478bd9Sstevel@tonic-gate 	return (mp);
6437c478bd9Sstevel@tonic-gate }
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate static mblk_t *
6467c478bd9Sstevel@tonic-gate open_mblk(queue_t *q, size_t len)
6477c478bd9Sstevel@tonic-gate {
6487c478bd9Sstevel@tonic-gate 	mblk_t *mp;
6497c478bd9Sstevel@tonic-gate 	bufcall_id_t id;
6507c478bd9Sstevel@tonic-gate 	int retv;
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 	while ((mp = allocb(len, BPRI_MED)) == NULL) {
6537c478bd9Sstevel@tonic-gate 		id = qbufcall(q, len, BPRI_MED, dummy_callback, NULL);
6547c478bd9Sstevel@tonic-gate 		retv = qwait_sig(q);
6557c478bd9Sstevel@tonic-gate 		qunbufcall(q, id);
6567c478bd9Sstevel@tonic-gate 		if (retv == 0)
6577c478bd9Sstevel@tonic-gate 			break;
6587c478bd9Sstevel@tonic-gate 	}
6597c478bd9Sstevel@tonic-gate 	return (mp);
6607c478bd9Sstevel@tonic-gate }
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate /*
6637c478bd9Sstevel@tonic-gate  * Line discipline open.
6647c478bd9Sstevel@tonic-gate  */
6657c478bd9Sstevel@tonic-gate /* ARGSUSED1 */
6667c478bd9Sstevel@tonic-gate static int
6677c478bd9Sstevel@tonic-gate ldtermopen(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *crp)
6687c478bd9Sstevel@tonic-gate {
6697c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp;
6707c478bd9Sstevel@tonic-gate 	mblk_t *bp, *qryp;
6717c478bd9Sstevel@tonic-gate 	int len;
6727c478bd9Sstevel@tonic-gate 	struct stroptions *strop;
6737c478bd9Sstevel@tonic-gate 	struct termios *termiosp;
6747c478bd9Sstevel@tonic-gate 	queue_t *wq;
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 	if (q->q_ptr != NULL) {
6777c478bd9Sstevel@tonic-gate 		return (0);	/* already attached */
6787c478bd9Sstevel@tonic-gate 	}
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate 	tp = (ldtermstd_state_t *)kmem_zalloc(sizeof (ldtermstd_state_t),
6817c478bd9Sstevel@tonic-gate 	    KM_SLEEP);
6827c478bd9Sstevel@tonic-gate 
6837c478bd9Sstevel@tonic-gate 	/*
6847c478bd9Sstevel@tonic-gate 	 * Get termios defaults.  These are stored as
6857c478bd9Sstevel@tonic-gate 	 * a property in the "options" node.
6867c478bd9Sstevel@tonic-gate 	 */
6877c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop(DDI_DEV_T_ANY, ddi_root_node(), DDI_PROP_NOTPROM,
6887c478bd9Sstevel@tonic-gate 	    "ttymodes", (caddr_t)&termiosp, &len) == DDI_PROP_SUCCESS &&
6897c478bd9Sstevel@tonic-gate 	    len == sizeof (struct termios)) {
6907c478bd9Sstevel@tonic-gate 		tp->t_modes = *termiosp;
6917c478bd9Sstevel@tonic-gate 		tp->t_amodes = *termiosp;
6927c478bd9Sstevel@tonic-gate 		kmem_free(termiosp, len);
6937c478bd9Sstevel@tonic-gate 	} else {
6947c478bd9Sstevel@tonic-gate 		/*
6957c478bd9Sstevel@tonic-gate 		 * Gack!  Whine about it.
6967c478bd9Sstevel@tonic-gate 		 */
6977c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "ldterm: Couldn't get ttymodes property!");
6987c478bd9Sstevel@tonic-gate 	}
6997c478bd9Sstevel@tonic-gate 	bzero(&tp->t_dmodes, sizeof (struct termios));
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 	tp->t_state = 0;
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate 	tp->t_line = 0;
7047c478bd9Sstevel@tonic-gate 	tp->t_col = 0;
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 	tp->t_rocount = 0;
7077c478bd9Sstevel@tonic-gate 	tp->t_rocol = 0;
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 	tp->t_message = NULL;
7107c478bd9Sstevel@tonic-gate 	tp->t_endmsg = NULL;
7117c478bd9Sstevel@tonic-gate 	tp->t_msglen = 0;
7127c478bd9Sstevel@tonic-gate 	tp->t_rd_request = 0;
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate 	tp->t_echomp = NULL;
7157c478bd9Sstevel@tonic-gate 	tp->t_iocid = 0;
7167c478bd9Sstevel@tonic-gate 	tp->t_wbufcid = 0;
7177c478bd9Sstevel@tonic-gate 	tp->t_vtid = 0;
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate 	q->q_ptr = (caddr_t)tp;
7207c478bd9Sstevel@tonic-gate 	WR(q)->q_ptr = (caddr_t)tp;
7217c478bd9Sstevel@tonic-gate 	/*
7227c478bd9Sstevel@tonic-gate 	 * The following for EUC and also non-EUC codesets:
7237c478bd9Sstevel@tonic-gate 	 */
7247c478bd9Sstevel@tonic-gate 	tp->t_codeset = tp->t_eucleft = tp->t_eucign = tp->t_scratch_len = 0;
7257c478bd9Sstevel@tonic-gate 	bzero(&tp->eucwioc, EUCSIZE);
7267c478bd9Sstevel@tonic-gate 	tp->eucwioc.eucw[0] = 1;	/* ASCII mem & screen width */
7277c478bd9Sstevel@tonic-gate 	tp->eucwioc.scrw[0] = 1;
7287c478bd9Sstevel@tonic-gate 	tp->t_maxeuc = 1;	/* the max len in bytes of an EUC char */
7297c478bd9Sstevel@tonic-gate 	tp->t_eucp = NULL;
7307c478bd9Sstevel@tonic-gate 	tp->t_eucp_mp = NULL;
7317c478bd9Sstevel@tonic-gate 	tp->t_eucwarn = 0;	/* no bad chars seen yet */
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 	tp->t_csdata = default_cs_data;
7347c478bd9Sstevel@tonic-gate 	tp->t_csmethods = cs_methods[LDTERM_CS_TYPE_EUC];
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate 	qprocson(q);
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate 	/*
7397c478bd9Sstevel@tonic-gate 	 * Find out if the module below us does canonicalization; if
7407c478bd9Sstevel@tonic-gate 	 * so, we won't do it ourselves.
7417c478bd9Sstevel@tonic-gate 	 */
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate 	if ((qryp = open_ioctl(q, MC_CANONQUERY)) == NULL)
7447c478bd9Sstevel@tonic-gate 		goto open_abort;
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate 	/*
7477c478bd9Sstevel@tonic-gate 	 * Reformulate as an M_CTL message. The actual data will
7487c478bd9Sstevel@tonic-gate 	 * be in the b_cont field.
7497c478bd9Sstevel@tonic-gate 	 */
7507c478bd9Sstevel@tonic-gate 	qryp->b_datap->db_type = M_CTL;
7517c478bd9Sstevel@tonic-gate 	wq = OTHERQ(q);
7527c478bd9Sstevel@tonic-gate 	putnext(wq, qryp);
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate 	/* allocate a TCSBRK ioctl in case we'll need it on close */
7557c478bd9Sstevel@tonic-gate 	if ((qryp = open_ioctl(q, TCSBRK)) == NULL)
7567c478bd9Sstevel@tonic-gate 		goto open_abort;
7577c478bd9Sstevel@tonic-gate 	tp->t_drainmsg = qryp;
7587c478bd9Sstevel@tonic-gate 	if ((bp = open_mblk(q, sizeof (int))) == NULL)
7597c478bd9Sstevel@tonic-gate 		goto open_abort;
7607c478bd9Sstevel@tonic-gate 	qryp->b_cont = bp;
7617c478bd9Sstevel@tonic-gate 
7627c478bd9Sstevel@tonic-gate 	/*
7637c478bd9Sstevel@tonic-gate 	 * Find out if the underlying driver supports proper POSIX close
7647c478bd9Sstevel@tonic-gate 	 * semantics.  If not, we'll have to approximate it using TCSBRK.  If
7657c478bd9Sstevel@tonic-gate 	 * it does, it will respond with MC_HAS_POSIX, and we'll catch that in
7667c478bd9Sstevel@tonic-gate 	 * the ldtermrput routine.
7677c478bd9Sstevel@tonic-gate 	 *
7687c478bd9Sstevel@tonic-gate 	 * When the ldterm_drain_limit tunable is set to zero, we behave the
7697c478bd9Sstevel@tonic-gate 	 * same as old ldterm: don't send this new message, and always use
7707c478bd9Sstevel@tonic-gate 	 * TCSBRK during close.
7717c478bd9Sstevel@tonic-gate 	 */
7727c478bd9Sstevel@tonic-gate 	if (ldterm_drain_limit != 0) {
7737c478bd9Sstevel@tonic-gate 		if ((qryp = open_ioctl(q, MC_POSIXQUERY)) == NULL)
7747c478bd9Sstevel@tonic-gate 			goto open_abort;
7757c478bd9Sstevel@tonic-gate 		qryp->b_datap->db_type = M_CTL;
7767c478bd9Sstevel@tonic-gate 		putnext(wq, qryp);
7777c478bd9Sstevel@tonic-gate 	}
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 	/* prepare to clear the water marks on close */
7807c478bd9Sstevel@tonic-gate 	if ((bp = open_mblk(q, sizeof (struct stroptions))) == NULL)
7817c478bd9Sstevel@tonic-gate 		goto open_abort;
7827c478bd9Sstevel@tonic-gate 	tp->t_closeopts = bp;
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate 	/*
7857c478bd9Sstevel@tonic-gate 	 * Set the high-water and low-water marks on the stream head
7867c478bd9Sstevel@tonic-gate 	 * to values appropriate for a terminal.  Also set the "vmin"
7877c478bd9Sstevel@tonic-gate 	 * and "vtime" values to 1 and 0, turn on message-nondiscard
7887c478bd9Sstevel@tonic-gate 	 * mode (as we're in ICANON mode), and turn on "old-style
7897c478bd9Sstevel@tonic-gate 	 * NODELAY" mode.
7907c478bd9Sstevel@tonic-gate 	 */
7917c478bd9Sstevel@tonic-gate 	if ((bp = open_mblk(q, sizeof (struct stroptions))) == NULL)
7927c478bd9Sstevel@tonic-gate 		goto open_abort;
7937c478bd9Sstevel@tonic-gate 	strop = (struct stroptions *)bp->b_wptr;
7947c478bd9Sstevel@tonic-gate 	strop->so_flags = SO_READOPT|SO_HIWAT|SO_LOWAT|SO_NDELON|SO_ISTTY;
7957c478bd9Sstevel@tonic-gate 	strop->so_readopt = RMSGN;
7967c478bd9Sstevel@tonic-gate 	strop->so_hiwat = HIWAT;
7977c478bd9Sstevel@tonic-gate 	strop->so_lowat = LOWAT;
7987c478bd9Sstevel@tonic-gate 	bp->b_wptr += sizeof (struct stroptions);
7997c478bd9Sstevel@tonic-gate 	bp->b_datap->db_type = M_SETOPTS;
8007c478bd9Sstevel@tonic-gate 	putnext(q, bp);
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate 	return (0);		/* this can become a controlling TTY */
8037c478bd9Sstevel@tonic-gate 
8047c478bd9Sstevel@tonic-gate open_abort:
8057c478bd9Sstevel@tonic-gate 	qprocsoff(q);
8067c478bd9Sstevel@tonic-gate 	q->q_ptr = NULL;
8077c478bd9Sstevel@tonic-gate 	WR(q)->q_ptr = NULL;
8087c478bd9Sstevel@tonic-gate 	freemsg(tp->t_closeopts);
8097c478bd9Sstevel@tonic-gate 	freemsg(tp->t_drainmsg);
8107c478bd9Sstevel@tonic-gate 	/* Dump the state structure */
8117c478bd9Sstevel@tonic-gate 	kmem_free(tp, sizeof (ldtermstd_state_t));
8127c478bd9Sstevel@tonic-gate 	return (EINTR);
8137c478bd9Sstevel@tonic-gate }
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate struct close_timer {
8167c478bd9Sstevel@tonic-gate 	timeout_id_t id;
8177c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp;
8187c478bd9Sstevel@tonic-gate };
8197c478bd9Sstevel@tonic-gate 
8207c478bd9Sstevel@tonic-gate static void
8217c478bd9Sstevel@tonic-gate drain_timed_out(void *arg)
8227c478bd9Sstevel@tonic-gate {
8237c478bd9Sstevel@tonic-gate 	struct close_timer *ctp = arg;
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate 	ctp->id = 0;
8267c478bd9Sstevel@tonic-gate 	ctp->tp->t_state &= ~TS_IOCWAIT;
8277c478bd9Sstevel@tonic-gate }
8287c478bd9Sstevel@tonic-gate 
8297c478bd9Sstevel@tonic-gate /* ARGSUSED2 */
8307c478bd9Sstevel@tonic-gate static int
8317c478bd9Sstevel@tonic-gate ldtermclose(queue_t *q, int cflag, cred_t *crp)
8327c478bd9Sstevel@tonic-gate {
8337c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp = (ldtermstd_state_t *)q->q_ptr;
8347c478bd9Sstevel@tonic-gate 	struct stroptions *strop;
8357c478bd9Sstevel@tonic-gate 	mblk_t *bp;
8367c478bd9Sstevel@tonic-gate 	struct close_timer cltimer;
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate 	/*
8397c478bd9Sstevel@tonic-gate 	 * If we have an outstanding vmin timeout, cancel it.
8407c478bd9Sstevel@tonic-gate 	 */
8417c478bd9Sstevel@tonic-gate 	tp->t_state |= TS_CLOSE;
8427c478bd9Sstevel@tonic-gate 	if (tp->t_vtid != 0)
8437c478bd9Sstevel@tonic-gate 		(void) quntimeout(q, tp->t_vtid);
8447c478bd9Sstevel@tonic-gate 	tp->t_vtid = 0;
8457c478bd9Sstevel@tonic-gate 
8467c478bd9Sstevel@tonic-gate 	/*
8477c478bd9Sstevel@tonic-gate 	 * Cancel outstanding qbufcall request.
8487c478bd9Sstevel@tonic-gate 	 */
8497c478bd9Sstevel@tonic-gate 	if (tp->t_wbufcid != 0)
8507c478bd9Sstevel@tonic-gate 		qunbufcall(q, tp->t_wbufcid);
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate 	/*
8537c478bd9Sstevel@tonic-gate 	 * Reset the high-water and low-water marks on the stream
8547c478bd9Sstevel@tonic-gate 	 * head (?), turn on byte-stream mode, and turn off
8557c478bd9Sstevel@tonic-gate 	 * "old-style NODELAY" mode.
8567c478bd9Sstevel@tonic-gate 	 */
8577c478bd9Sstevel@tonic-gate 	bp = tp->t_closeopts;
8587c478bd9Sstevel@tonic-gate 	strop = (struct stroptions *)bp->b_wptr;
8597c478bd9Sstevel@tonic-gate 	strop->so_flags = SO_READOPT|SO_NDELOFF;
8607c478bd9Sstevel@tonic-gate 	strop->so_readopt = RNORM;
8617c478bd9Sstevel@tonic-gate 	bp->b_wptr += sizeof (struct stroptions);
8627c478bd9Sstevel@tonic-gate 	bp->b_datap->db_type = M_SETOPTS;
8637c478bd9Sstevel@tonic-gate 	putnext(q, bp);
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate 	if (cflag & (FNDELAY|FNONBLOCK)) {
8667c478bd9Sstevel@tonic-gate 		freemsg(tp->t_drainmsg);
8677c478bd9Sstevel@tonic-gate 	} else if ((bp = tp->t_drainmsg) != NULL) {
8687c478bd9Sstevel@tonic-gate 		struct iocblk *iocb;
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 		/*
8717c478bd9Sstevel@tonic-gate 		 * If the driver isn't known to have POSIX close semantics,
8727c478bd9Sstevel@tonic-gate 		 * then we have to emulate this the old way.  This is done by
8737c478bd9Sstevel@tonic-gate 		 * sending down TCSBRK,1 to drain the output and waiting for
8747c478bd9Sstevel@tonic-gate 		 * the reply.
8757c478bd9Sstevel@tonic-gate 		 */
8767c478bd9Sstevel@tonic-gate 		iocb = (struct iocblk *)bp->b_rptr;
8777c478bd9Sstevel@tonic-gate 		iocb->ioc_count = sizeof (int);
8787c478bd9Sstevel@tonic-gate 		*(int *)bp->b_cont->b_rptr = 1;
8797c478bd9Sstevel@tonic-gate 		bp->b_cont->b_wptr += sizeof (int);
8807c478bd9Sstevel@tonic-gate 		tp->t_state |= TS_IOCWAIT;
8817c478bd9Sstevel@tonic-gate 		tp->t_iocid = iocb->ioc_id;
8827c478bd9Sstevel@tonic-gate 		if (!putq(WR(q), bp))
8837c478bd9Sstevel@tonic-gate 			putnext(WR(q), bp);
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate 		/*
8867c478bd9Sstevel@tonic-gate 		 * If we're not able to receive signals at this point, then
8877c478bd9Sstevel@tonic-gate 		 * launch a timer.  This timer will prevent us from waiting
8887c478bd9Sstevel@tonic-gate 		 * forever for a signal that won't arrive.
8897c478bd9Sstevel@tonic-gate 		 */
8907c478bd9Sstevel@tonic-gate 		cltimer.id = 0;
8917c478bd9Sstevel@tonic-gate 		if (!ddi_can_receive_sig() && ldterm_drain_limit != 0) {
8927c478bd9Sstevel@tonic-gate 			cltimer.tp = tp;
8937c478bd9Sstevel@tonic-gate 			cltimer.id = qtimeout(q, drain_timed_out, &cltimer,
8947c478bd9Sstevel@tonic-gate 			    drv_usectohz(ldterm_drain_limit));
8957c478bd9Sstevel@tonic-gate 		}
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 		/*
8987c478bd9Sstevel@tonic-gate 		 * Note that the read side of ldterm and the qtimeout are
8997c478bd9Sstevel@tonic-gate 		 * protected by D_MTQPAIR, so no additional locking is needed
9007c478bd9Sstevel@tonic-gate 		 * here.
9017c478bd9Sstevel@tonic-gate 		 */
9027c478bd9Sstevel@tonic-gate 		while (tp->t_state & TS_IOCWAIT) {
9037c478bd9Sstevel@tonic-gate 			if (qwait_sig(q) == 0)
9047c478bd9Sstevel@tonic-gate 				break;
9057c478bd9Sstevel@tonic-gate 		}
9067c478bd9Sstevel@tonic-gate 		if (cltimer.id != 0)
9077c478bd9Sstevel@tonic-gate 			(void) quntimeout(q, cltimer.id);
9087c478bd9Sstevel@tonic-gate 	}
9097c478bd9Sstevel@tonic-gate 
9107c478bd9Sstevel@tonic-gate 	/*
9117c478bd9Sstevel@tonic-gate 	 * From here to the end, the routine does not sleep and does not
9127c478bd9Sstevel@tonic-gate 	 * reference STREAMS, so it's guaranteed to run to completion.
9137c478bd9Sstevel@tonic-gate 	 */
9147c478bd9Sstevel@tonic-gate 
9157c478bd9Sstevel@tonic-gate 	qprocsoff(q);
9167c478bd9Sstevel@tonic-gate 
9177c478bd9Sstevel@tonic-gate 	freemsg(tp->t_message);
9187c478bd9Sstevel@tonic-gate 	freemsg(tp->t_eucp_mp);
9197c478bd9Sstevel@tonic-gate 
9207c478bd9Sstevel@tonic-gate 	/* Dump the state structure, then unlink it */
9217c478bd9Sstevel@tonic-gate 	if (tp->t_csdata.locale_name != NULL)
9227c478bd9Sstevel@tonic-gate 		kmem_free(tp->t_csdata.locale_name,
9237c478bd9Sstevel@tonic-gate 		    strlen(tp->t_csdata.locale_name) + 1);
9247c478bd9Sstevel@tonic-gate 	kmem_free(tp, sizeof (ldtermstd_state_t));
9257c478bd9Sstevel@tonic-gate 	q->q_ptr = NULL;
9267c478bd9Sstevel@tonic-gate 	return (0);
9277c478bd9Sstevel@tonic-gate }
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate /*
9317c478bd9Sstevel@tonic-gate  * Put procedure for input from driver end of stream (read queue).
9327c478bd9Sstevel@tonic-gate  */
9337c478bd9Sstevel@tonic-gate static void
9347c478bd9Sstevel@tonic-gate ldtermrput(queue_t *q, mblk_t *mp)
9357c478bd9Sstevel@tonic-gate {
9367c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp;
9377c478bd9Sstevel@tonic-gate 	unsigned char c;
9387c478bd9Sstevel@tonic-gate 	queue_t *wrq = WR(q);		/* write queue of ldterm mod */
9397c478bd9Sstevel@tonic-gate 	queue_t *nextq = q->q_next;	/* queue below us */
9407c478bd9Sstevel@tonic-gate 	mblk_t *bp;
9417c478bd9Sstevel@tonic-gate 	struct iocblk *qryp;
9427c478bd9Sstevel@tonic-gate 	unsigned char *readp;
9437c478bd9Sstevel@tonic-gate 	unsigned char *writep;
9447c478bd9Sstevel@tonic-gate 	struct termios *emodes;		/* effective modes set by driver */
9457c478bd9Sstevel@tonic-gate 	int dbtype;
9467c478bd9Sstevel@tonic-gate 
9477c478bd9Sstevel@tonic-gate 	tp = (ldtermstd_state_t *)q->q_ptr;
9487c478bd9Sstevel@tonic-gate 	/*
9497c478bd9Sstevel@tonic-gate 	 * We received our ack from the driver saying there is nothing left to
9507c478bd9Sstevel@tonic-gate 	 * shovel out, so wake up the close routine.
9517c478bd9Sstevel@tonic-gate 	 */
9527c478bd9Sstevel@tonic-gate 	dbtype = DB_TYPE(mp);
9537c478bd9Sstevel@tonic-gate 	if ((dbtype == M_IOCACK || dbtype == M_IOCNAK) &&
9547c478bd9Sstevel@tonic-gate 	    (tp->t_state & (TS_CLOSE|TS_IOCWAIT)) == (TS_CLOSE|TS_IOCWAIT)) {
9557c478bd9Sstevel@tonic-gate 		struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate 		if (iocp->ioc_id == tp->t_iocid) {
9587c478bd9Sstevel@tonic-gate 			tp->t_state &= ~TS_IOCWAIT;
9597c478bd9Sstevel@tonic-gate 			freemsg(mp);
9607c478bd9Sstevel@tonic-gate 			return;
9617c478bd9Sstevel@tonic-gate 		}
9627c478bd9Sstevel@tonic-gate 	}
9637c478bd9Sstevel@tonic-gate 
9647c478bd9Sstevel@tonic-gate 	switch (dbtype) {
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 	default:
9677c478bd9Sstevel@tonic-gate 		(void) putq(q, mp);
9687c478bd9Sstevel@tonic-gate 		return;
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate 		/*
9717c478bd9Sstevel@tonic-gate 		 * Send these up unmolested
9727c478bd9Sstevel@tonic-gate 		 *
9737c478bd9Sstevel@tonic-gate 		 */
9747c478bd9Sstevel@tonic-gate 	case M_PCSIG:
9757c478bd9Sstevel@tonic-gate 	case M_SIG:
9767c478bd9Sstevel@tonic-gate 	case M_IOCNAK:
9777c478bd9Sstevel@tonic-gate 
9787c478bd9Sstevel@tonic-gate 		putnext(q, mp);
9797c478bd9Sstevel@tonic-gate 		return;
9807c478bd9Sstevel@tonic-gate 
9817c478bd9Sstevel@tonic-gate 	case M_IOCACK:
9827c478bd9Sstevel@tonic-gate 
9837c478bd9Sstevel@tonic-gate 		ldterm_ioctl_reply(q, mp);
9847c478bd9Sstevel@tonic-gate 		return;
9857c478bd9Sstevel@tonic-gate 
9867c478bd9Sstevel@tonic-gate 	case M_BREAK:
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate 		/*
9897c478bd9Sstevel@tonic-gate 		 * Parity errors are sent up as M_BREAKS with single
9907c478bd9Sstevel@tonic-gate 		 * character data (formerly handled in the driver)
9917c478bd9Sstevel@tonic-gate 		 */
9927c478bd9Sstevel@tonic-gate 		if (mp->b_wptr - mp->b_rptr == 1) {
9937c478bd9Sstevel@tonic-gate 			/*
9947c478bd9Sstevel@tonic-gate 			 * IGNPAR	PARMRK		RESULT
9957c478bd9Sstevel@tonic-gate 			 * off		off		0
9967c478bd9Sstevel@tonic-gate 			 * off		on		3 byte sequence
9977c478bd9Sstevel@tonic-gate 			 * on		either		ignored
9987c478bd9Sstevel@tonic-gate 			 */
9997c478bd9Sstevel@tonic-gate 			if (!(tp->t_amodes.c_iflag & IGNPAR)) {
10007c478bd9Sstevel@tonic-gate 				mp->b_wptr = mp->b_rptr;
10017c478bd9Sstevel@tonic-gate 				if (tp->t_amodes.c_iflag & PARMRK) {
10027c478bd9Sstevel@tonic-gate 					unsigned char c;
10037c478bd9Sstevel@tonic-gate 
10047c478bd9Sstevel@tonic-gate 					c = *mp->b_rptr;
10057c478bd9Sstevel@tonic-gate 					freemsg(mp);
10067c478bd9Sstevel@tonic-gate 					if ((mp = allocb(3, BPRI_HI)) == NULL) {
10077c478bd9Sstevel@tonic-gate 						cmn_err(CE_WARN,
10087c478bd9Sstevel@tonic-gate 						    "ldtermrput: no blocks");
10097c478bd9Sstevel@tonic-gate 						return;
10107c478bd9Sstevel@tonic-gate 					}
10117c478bd9Sstevel@tonic-gate 					mp->b_datap->db_type = M_DATA;
10127c478bd9Sstevel@tonic-gate 					*mp->b_wptr++ = (uchar_t)'\377';
10137c478bd9Sstevel@tonic-gate 					*mp->b_wptr++ = '\0';
10147c478bd9Sstevel@tonic-gate 					*mp->b_wptr++ = c;
10157c478bd9Sstevel@tonic-gate 					putnext(q, mp);
10167c478bd9Sstevel@tonic-gate 				} else {
10177c478bd9Sstevel@tonic-gate 					mp->b_datap->db_type = M_DATA;
10187c478bd9Sstevel@tonic-gate 					*mp->b_wptr++ = '\0';
10197c478bd9Sstevel@tonic-gate 					putnext(q, mp);
10207c478bd9Sstevel@tonic-gate 				}
10217c478bd9Sstevel@tonic-gate 			} else {
10227c478bd9Sstevel@tonic-gate 				freemsg(mp);
10237c478bd9Sstevel@tonic-gate 			}
10247c478bd9Sstevel@tonic-gate 			return;
10257c478bd9Sstevel@tonic-gate 		}
10267c478bd9Sstevel@tonic-gate 		/*
10277c478bd9Sstevel@tonic-gate 		 * We look at the apparent modes here instead of the
10287c478bd9Sstevel@tonic-gate 		 * effective modes. Effective modes cannot be used if
10297c478bd9Sstevel@tonic-gate 		 * IGNBRK, BRINT and PARMRK have been negotiated to
10307c478bd9Sstevel@tonic-gate 		 * be handled by the driver. Since M_BREAK should be
10317c478bd9Sstevel@tonic-gate 		 * sent upstream only if break processing was not
10327c478bd9Sstevel@tonic-gate 		 * already done, it should be ok to use the apparent
10337c478bd9Sstevel@tonic-gate 		 * modes.
10347c478bd9Sstevel@tonic-gate 		 */
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate 		if (!(tp->t_amodes.c_iflag & IGNBRK)) {
10377c478bd9Sstevel@tonic-gate 			if (tp->t_amodes.c_iflag & BRKINT) {
10387c478bd9Sstevel@tonic-gate 				ldterm_dosig(q, SIGINT, '\0', M_PCSIG, FLUSHRW);
10397c478bd9Sstevel@tonic-gate 				freemsg(mp);
10407c478bd9Sstevel@tonic-gate 			} else if (tp->t_amodes.c_iflag & PARMRK) {
10417c478bd9Sstevel@tonic-gate 				/*
10427c478bd9Sstevel@tonic-gate 				 * Send '\377','\0', '\0'.
10437c478bd9Sstevel@tonic-gate 				 */
10447c478bd9Sstevel@tonic-gate 				freemsg(mp);
10457c478bd9Sstevel@tonic-gate 				if ((mp = allocb(3, BPRI_HI)) == NULL) {
10467c478bd9Sstevel@tonic-gate 					cmn_err(CE_WARN,
10477c478bd9Sstevel@tonic-gate 					    "ldtermrput: no blocks");
10487c478bd9Sstevel@tonic-gate 					return;
10497c478bd9Sstevel@tonic-gate 				}
10507c478bd9Sstevel@tonic-gate 				mp->b_datap->db_type = M_DATA;
10517c478bd9Sstevel@tonic-gate 				*mp->b_wptr++ = (uchar_t)'\377';
10527c478bd9Sstevel@tonic-gate 				*mp->b_wptr++ = '\0';
10537c478bd9Sstevel@tonic-gate 				*mp->b_wptr++ = '\0';
10547c478bd9Sstevel@tonic-gate 				putnext(q, mp);
10557c478bd9Sstevel@tonic-gate 			} else {
10567c478bd9Sstevel@tonic-gate 				/*
10577c478bd9Sstevel@tonic-gate 				 * Act as if a '\0' came in.
10587c478bd9Sstevel@tonic-gate 				 */
10597c478bd9Sstevel@tonic-gate 				freemsg(mp);
10607c478bd9Sstevel@tonic-gate 				if ((mp = allocb(1, BPRI_HI)) == NULL) {
10617c478bd9Sstevel@tonic-gate 					cmn_err(CE_WARN,
10627c478bd9Sstevel@tonic-gate 					    "ldtermrput: no blocks");
10637c478bd9Sstevel@tonic-gate 					return;
10647c478bd9Sstevel@tonic-gate 				}
10657c478bd9Sstevel@tonic-gate 				mp->b_datap->db_type = M_DATA;
10667c478bd9Sstevel@tonic-gate 				*mp->b_wptr++ = '\0';
10677c478bd9Sstevel@tonic-gate 				putnext(q, mp);
10687c478bd9Sstevel@tonic-gate 			}
10697c478bd9Sstevel@tonic-gate 		} else {
10707c478bd9Sstevel@tonic-gate 			freemsg(mp);
10717c478bd9Sstevel@tonic-gate 		}
10727c478bd9Sstevel@tonic-gate 		return;
10737c478bd9Sstevel@tonic-gate 
10747c478bd9Sstevel@tonic-gate 	case M_CTL:
10757c478bd9Sstevel@tonic-gate 		DEBUG3(("ldtermrput: M_CTL received\n"));
10767c478bd9Sstevel@tonic-gate 		/*
10777c478bd9Sstevel@tonic-gate 		 * The M_CTL has been standardized to look like an
10787c478bd9Sstevel@tonic-gate 		 * M_IOCTL message.
10797c478bd9Sstevel@tonic-gate 		 */
10807c478bd9Sstevel@tonic-gate 
10817c478bd9Sstevel@tonic-gate 		if ((mp->b_wptr - mp->b_rptr) != sizeof (struct iocblk)) {
10827c478bd9Sstevel@tonic-gate 			DEBUG3((
10837c478bd9Sstevel@tonic-gate 			    "Non standard M_CTL received by ldterm module\n"));
10847c478bd9Sstevel@tonic-gate 			/* May be for someone else; pass it on */
10857c478bd9Sstevel@tonic-gate 			putnext(q, mp);
10867c478bd9Sstevel@tonic-gate 			return;
10877c478bd9Sstevel@tonic-gate 		}
10887c478bd9Sstevel@tonic-gate 		qryp = (struct iocblk *)mp->b_rptr;
10897c478bd9Sstevel@tonic-gate 
10907c478bd9Sstevel@tonic-gate 		switch (qryp->ioc_cmd) {
10917c478bd9Sstevel@tonic-gate 
10927c478bd9Sstevel@tonic-gate 		case MC_PART_CANON:
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate 			DEBUG3(("ldtermrput: M_CTL Query Reply\n"));
10957c478bd9Sstevel@tonic-gate 			if (!mp->b_cont) {
10967c478bd9Sstevel@tonic-gate 				DEBUG3(("No information in Query Message\n"));
10977c478bd9Sstevel@tonic-gate 				break;
10987c478bd9Sstevel@tonic-gate 			}
10997c478bd9Sstevel@tonic-gate 			if ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) ==
11007c478bd9Sstevel@tonic-gate 			    sizeof (struct termios)) {
11017c478bd9Sstevel@tonic-gate 				DEBUG3(("ldtermrput: M_CTL GrandScheme\n"));
11027c478bd9Sstevel@tonic-gate 				/* elaborate turning off scheme */
11037c478bd9Sstevel@tonic-gate 				emodes = (struct termios *)mp->b_cont->b_rptr;
11047c478bd9Sstevel@tonic-gate 				bcopy(emodes, &tp->t_dmodes,
11057c478bd9Sstevel@tonic-gate 					sizeof (struct termios));
11067c478bd9Sstevel@tonic-gate 				ldterm_adjust_modes(tp);
11077c478bd9Sstevel@tonic-gate 				break;
11087c478bd9Sstevel@tonic-gate 			} else {
11097c478bd9Sstevel@tonic-gate 				DEBUG3(("Incorrect query replysize\n"));
11107c478bd9Sstevel@tonic-gate 				break;
11117c478bd9Sstevel@tonic-gate 			}
11127c478bd9Sstevel@tonic-gate 
11137c478bd9Sstevel@tonic-gate 		case MC_NO_CANON:
11147c478bd9Sstevel@tonic-gate 			tp->t_state |= TS_NOCANON;
11157c478bd9Sstevel@tonic-gate 			/*
11167c478bd9Sstevel@tonic-gate 			 * Note: this is very nasty.  It's not clear
11177c478bd9Sstevel@tonic-gate 			 * what the right thing to do with a partial
11187c478bd9Sstevel@tonic-gate 			 * message is; We throw it out
11197c478bd9Sstevel@tonic-gate 			 */
11207c478bd9Sstevel@tonic-gate 			if (tp->t_message != NULL) {
11217c478bd9Sstevel@tonic-gate 				freemsg(tp->t_message);
11227c478bd9Sstevel@tonic-gate 				tp->t_message = NULL;
11237c478bd9Sstevel@tonic-gate 				tp->t_endmsg = NULL;
11247c478bd9Sstevel@tonic-gate 				tp->t_msglen = 0;
11257c478bd9Sstevel@tonic-gate 				tp->t_rocount = 0;
11267c478bd9Sstevel@tonic-gate 				tp->t_rocol = 0;
11277c478bd9Sstevel@tonic-gate 				if (tp->t_state & TS_MEUC) {
11287c478bd9Sstevel@tonic-gate 					ASSERT(tp->t_eucp_mp);
11297c478bd9Sstevel@tonic-gate 					tp->t_eucp = tp->t_eucp_mp->b_rptr;
11307c478bd9Sstevel@tonic-gate 					tp->t_codeset = 0;
11317c478bd9Sstevel@tonic-gate 					tp->t_eucleft = 0;
11327c478bd9Sstevel@tonic-gate 				}
11337c478bd9Sstevel@tonic-gate 			}
11347c478bd9Sstevel@tonic-gate 			break;
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate 		case MC_DO_CANON:
11377c478bd9Sstevel@tonic-gate 			tp->t_state &= ~TS_NOCANON;
11387c478bd9Sstevel@tonic-gate 			break;
11397c478bd9Sstevel@tonic-gate 
11407c478bd9Sstevel@tonic-gate 		case MC_HAS_POSIX:
11417c478bd9Sstevel@tonic-gate 			/* no longer any reason to drain from ldterm */
11427c478bd9Sstevel@tonic-gate 			if (ldterm_drain_limit != 0) {
11437c478bd9Sstevel@tonic-gate 				freemsg(tp->t_drainmsg);
11447c478bd9Sstevel@tonic-gate 				tp->t_drainmsg = NULL;
11457c478bd9Sstevel@tonic-gate 			}
11467c478bd9Sstevel@tonic-gate 			break;
11477c478bd9Sstevel@tonic-gate 
11487c478bd9Sstevel@tonic-gate 		default:
11497c478bd9Sstevel@tonic-gate 			DEBUG3(("Unknown M_CTL Message\n"));
11507c478bd9Sstevel@tonic-gate 			break;
11517c478bd9Sstevel@tonic-gate 		}
11527c478bd9Sstevel@tonic-gate 		putnext(q, mp);	/* In case anyone else has to see it */
11537c478bd9Sstevel@tonic-gate 		return;
11547c478bd9Sstevel@tonic-gate 
11557c478bd9Sstevel@tonic-gate 	case M_FLUSH:
11567c478bd9Sstevel@tonic-gate 		/*
11577c478bd9Sstevel@tonic-gate 		 * Flush everything we haven't looked at yet.
11587c478bd9Sstevel@tonic-gate 		 */
11597c478bd9Sstevel@tonic-gate 
11607c478bd9Sstevel@tonic-gate 		if ((tp->t_state & TS_ISPTSTTY) && (*mp->b_rptr & FLUSHBAND))
11617c478bd9Sstevel@tonic-gate 			flushband(q, *(mp->b_rptr + 1), FLUSHDATA);
11627c478bd9Sstevel@tonic-gate 		else
11637c478bd9Sstevel@tonic-gate 			flushq(q, FLUSHDATA);
11647c478bd9Sstevel@tonic-gate 
11657c478bd9Sstevel@tonic-gate 		/*
11667c478bd9Sstevel@tonic-gate 		 * Flush everything we have looked at.
11677c478bd9Sstevel@tonic-gate 		 */
11687c478bd9Sstevel@tonic-gate 		freemsg(tp->t_message);
11697c478bd9Sstevel@tonic-gate 		tp->t_message = NULL;
11707c478bd9Sstevel@tonic-gate 		tp->t_endmsg = NULL;
11717c478bd9Sstevel@tonic-gate 		tp->t_msglen = 0;
11727c478bd9Sstevel@tonic-gate 		tp->t_rocount = 0;
11737c478bd9Sstevel@tonic-gate 		tp->t_rocol = 0;
11747c478bd9Sstevel@tonic-gate 		if (tp->t_state & TS_MEUC) {	/* EUC multi-byte */
11757c478bd9Sstevel@tonic-gate 			ASSERT(tp->t_eucp_mp);
11767c478bd9Sstevel@tonic-gate 			tp->t_eucp = tp->t_eucp_mp->b_rptr;
11777c478bd9Sstevel@tonic-gate 		}
11787c478bd9Sstevel@tonic-gate 		putnext(q, mp);	/* pass it on */
11797c478bd9Sstevel@tonic-gate 
11807c478bd9Sstevel@tonic-gate 		/*
11817c478bd9Sstevel@tonic-gate 		 * Relieve input flow control
11827c478bd9Sstevel@tonic-gate 		 */
11837c478bd9Sstevel@tonic-gate 		if ((tp->t_modes.c_iflag & IXOFF) &&
11847c478bd9Sstevel@tonic-gate 		    (tp->t_state & TS_TBLOCK) &&
11857c478bd9Sstevel@tonic-gate 		    !(tp->t_state & TS_IFBLOCK) && q->q_count <= TTXOLO) {
11867c478bd9Sstevel@tonic-gate 			tp->t_state &= ~TS_TBLOCK;
11877c478bd9Sstevel@tonic-gate 			(void) putnextctl(wrq, M_STARTI);
11887c478bd9Sstevel@tonic-gate 			DEBUG1(("M_STARTI down\n"));
11897c478bd9Sstevel@tonic-gate 		}
11907c478bd9Sstevel@tonic-gate 		return;
11917c478bd9Sstevel@tonic-gate 
11927c478bd9Sstevel@tonic-gate 	case M_DATA:
11937c478bd9Sstevel@tonic-gate 		break;
11947c478bd9Sstevel@tonic-gate 	}
11957c478bd9Sstevel@tonic-gate 	(void) drv_setparm(SYSRAWC, msgdsize(mp));
11967c478bd9Sstevel@tonic-gate 
11977c478bd9Sstevel@tonic-gate 	/*
11987c478bd9Sstevel@tonic-gate 	 * Flow control: send "start input" message if blocked and
11997c478bd9Sstevel@tonic-gate 	 * our queue is below its low water mark.
12007c478bd9Sstevel@tonic-gate 	 */
12017c478bd9Sstevel@tonic-gate 	if ((tp->t_modes.c_iflag & IXOFF) && (tp->t_state & TS_TBLOCK) &&
12027c478bd9Sstevel@tonic-gate 	    !(tp->t_state & TS_IFBLOCK) && q->q_count <= TTXOLO) {
12037c478bd9Sstevel@tonic-gate 		tp->t_state &= ~TS_TBLOCK;
12047c478bd9Sstevel@tonic-gate 		(void) putnextctl(wrq, M_STARTI);
12057c478bd9Sstevel@tonic-gate 		DEBUG1(("M_STARTI down\n"));
12067c478bd9Sstevel@tonic-gate 	}
12077c478bd9Sstevel@tonic-gate 	/*
12087c478bd9Sstevel@tonic-gate 	 * If somebody below us ("intelligent" communications
12097c478bd9Sstevel@tonic-gate 	 * board, pseudo-tty controlled by an editor) is doing
12107c478bd9Sstevel@tonic-gate 	 * canonicalization, don't scan it for special characters.
12117c478bd9Sstevel@tonic-gate 	 */
12127c478bd9Sstevel@tonic-gate 	if (tp->t_state & TS_NOCANON) {
12137c478bd9Sstevel@tonic-gate 		(void) putq(q, mp);
12147c478bd9Sstevel@tonic-gate 		return;
12157c478bd9Sstevel@tonic-gate 	}
12167c478bd9Sstevel@tonic-gate 	bp = mp;
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate 	do {
12197c478bd9Sstevel@tonic-gate 		readp = bp->b_rptr;
12207c478bd9Sstevel@tonic-gate 		writep = readp;
12217c478bd9Sstevel@tonic-gate 		if (tp->t_modes.c_iflag & (INLCR|IGNCR|ICRNL|IUCLC|IXON) ||
12227c478bd9Sstevel@tonic-gate 		    tp->t_modes.c_lflag & (ISIG|ICANON)) {
12237c478bd9Sstevel@tonic-gate 			/*
12247c478bd9Sstevel@tonic-gate 			 * We're doing some sort of non-trivial
12257c478bd9Sstevel@tonic-gate 			 * processing of input; look at every
12267c478bd9Sstevel@tonic-gate 			 * character.
12277c478bd9Sstevel@tonic-gate 			 */
12287c478bd9Sstevel@tonic-gate 			while (readp < bp->b_wptr) {
12297c478bd9Sstevel@tonic-gate 				c = *readp++;
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate 				if (tp->t_modes.c_iflag & ISTRIP)
12327c478bd9Sstevel@tonic-gate 					c &= 0177;
12337c478bd9Sstevel@tonic-gate 
12347c478bd9Sstevel@tonic-gate 				/*
12357c478bd9Sstevel@tonic-gate 				 * First, check that this hasn't been
12367c478bd9Sstevel@tonic-gate 				 * escaped with the "literal next"
12377c478bd9Sstevel@tonic-gate 				 * character.
12387c478bd9Sstevel@tonic-gate 				 */
12397c478bd9Sstevel@tonic-gate 				if (tp->t_state & TS_PLNCH) {
12407c478bd9Sstevel@tonic-gate 					tp->t_state &= ~TS_PLNCH;
12417c478bd9Sstevel@tonic-gate 					tp->t_modes.c_lflag &= ~FLUSHO;
12427c478bd9Sstevel@tonic-gate 					*writep++ = c;
12437c478bd9Sstevel@tonic-gate 					continue;
12447c478bd9Sstevel@tonic-gate 				}
12457c478bd9Sstevel@tonic-gate 				/*
12467c478bd9Sstevel@tonic-gate 				 * Setting a special character to NUL
12477c478bd9Sstevel@tonic-gate 				 * disables it, so if this character
12487c478bd9Sstevel@tonic-gate 				 * is NUL, it should not be compared
12497c478bd9Sstevel@tonic-gate 				 * with any of the special characters.
12507c478bd9Sstevel@tonic-gate 				 * It should, however, restart frozen
12517c478bd9Sstevel@tonic-gate 				 * output if IXON and IXANY are set.
12527c478bd9Sstevel@tonic-gate 				 */
12537c478bd9Sstevel@tonic-gate 				if (c == _POSIX_VDISABLE) {
12547c478bd9Sstevel@tonic-gate 					if (tp->t_modes.c_iflag & IXON &&
12557c478bd9Sstevel@tonic-gate 					    tp->t_state & TS_TTSTOP &&
12567c478bd9Sstevel@tonic-gate 					    tp->t_modes.c_lflag & IEXTEN &&
12577c478bd9Sstevel@tonic-gate 					    tp->t_modes.c_iflag & IXANY) {
12587c478bd9Sstevel@tonic-gate 						tp->t_state &=
12597c478bd9Sstevel@tonic-gate 						    ~(TS_TTSTOP|TS_OFBLOCK);
12607c478bd9Sstevel@tonic-gate 						(void) putnextctl(wrq, M_START);
12617c478bd9Sstevel@tonic-gate 					}
12627c478bd9Sstevel@tonic-gate 					tp->t_modes.c_lflag &= ~FLUSHO;
12637c478bd9Sstevel@tonic-gate 					*writep++ = c;
12647c478bd9Sstevel@tonic-gate 					continue;
12657c478bd9Sstevel@tonic-gate 				}
12667c478bd9Sstevel@tonic-gate 				/*
12677c478bd9Sstevel@tonic-gate 				 * If stopped, start if you can; if
12687c478bd9Sstevel@tonic-gate 				 * running, stop if you must.
12697c478bd9Sstevel@tonic-gate 				 */
12707c478bd9Sstevel@tonic-gate 				if (tp->t_modes.c_iflag & IXON) {
12717c478bd9Sstevel@tonic-gate 					if (tp->t_state & TS_TTSTOP) {
12727c478bd9Sstevel@tonic-gate 						if (c ==
12737c478bd9Sstevel@tonic-gate 						    tp->t_modes.c_cc[VSTART] ||
12747c478bd9Sstevel@tonic-gate 						    (tp->t_modes.c_lflag &
12757c478bd9Sstevel@tonic-gate 						    IEXTEN &&
12767c478bd9Sstevel@tonic-gate 						    tp->t_modes.c_iflag &
12777c478bd9Sstevel@tonic-gate 						    IXANY)) {
12787c478bd9Sstevel@tonic-gate 							tp->t_state &=
127985bb5f1dSis 							    ~(TS_TTSTOP |
128085bb5f1dSis 							    TS_OFBLOCK);
12817c478bd9Sstevel@tonic-gate 							(void) putnextctl(wrq,
12827c478bd9Sstevel@tonic-gate 							    M_START);
12837c478bd9Sstevel@tonic-gate 						}
12847c478bd9Sstevel@tonic-gate 					} else {
12857c478bd9Sstevel@tonic-gate 						if (c ==
12867c478bd9Sstevel@tonic-gate 						    tp->t_modes.c_cc[VSTOP]) {
12877c478bd9Sstevel@tonic-gate 							tp->t_state |=
12887c478bd9Sstevel@tonic-gate 							    TS_TTSTOP;
12897c478bd9Sstevel@tonic-gate 							(void) putnextctl(wrq,
12907c478bd9Sstevel@tonic-gate 							    M_STOP);
12917c478bd9Sstevel@tonic-gate 						}
12927c478bd9Sstevel@tonic-gate 					}
12937c478bd9Sstevel@tonic-gate 					if (c == tp->t_modes.c_cc[VSTOP] ||
12947c478bd9Sstevel@tonic-gate 					    c == tp->t_modes.c_cc[VSTART])
12957c478bd9Sstevel@tonic-gate 						continue;
12967c478bd9Sstevel@tonic-gate 				}
12977c478bd9Sstevel@tonic-gate 				/*
12987c478bd9Sstevel@tonic-gate 				 * Check for "literal next" character
12997c478bd9Sstevel@tonic-gate 				 * and "flush output" character.
13007c478bd9Sstevel@tonic-gate 				 * Note that we omit checks for ISIG
13017c478bd9Sstevel@tonic-gate 				 * and ICANON, since the IEXTEN
13027c478bd9Sstevel@tonic-gate 				 * setting subsumes them.
13037c478bd9Sstevel@tonic-gate 				 */
13047c478bd9Sstevel@tonic-gate 				if (tp->t_modes.c_lflag & IEXTEN) {
13057c478bd9Sstevel@tonic-gate 					if (c == tp->t_modes.c_cc[VLNEXT]) {
13067c478bd9Sstevel@tonic-gate 						/*
13077c478bd9Sstevel@tonic-gate 						 * Remember that we saw a
13087c478bd9Sstevel@tonic-gate 						 * "literal next" while
13097c478bd9Sstevel@tonic-gate 						 * scanning input, but leave
13107c478bd9Sstevel@tonic-gate 						 * leave it in the message so
13117c478bd9Sstevel@tonic-gate 						 * that the service routine
13127c478bd9Sstevel@tonic-gate 						 * can see it too.
13137c478bd9Sstevel@tonic-gate 						 */
13147c478bd9Sstevel@tonic-gate 						tp->t_state |= TS_PLNCH;
13157c478bd9Sstevel@tonic-gate 						tp->t_modes.c_lflag &= ~FLUSHO;
13167c478bd9Sstevel@tonic-gate 						*writep++ = c;
13177c478bd9Sstevel@tonic-gate 						continue;
13187c478bd9Sstevel@tonic-gate 					}
13197c478bd9Sstevel@tonic-gate 					if (c == tp->t_modes.c_cc[VDISCARD]) {
13207c478bd9Sstevel@tonic-gate 						ldterm_flush_output(c, wrq, tp);
13217c478bd9Sstevel@tonic-gate 						continue;
13227c478bd9Sstevel@tonic-gate 					}
13237c478bd9Sstevel@tonic-gate 				}
13247c478bd9Sstevel@tonic-gate 				tp->t_modes.c_lflag &= ~FLUSHO;
13257c478bd9Sstevel@tonic-gate 
13267c478bd9Sstevel@tonic-gate 				/*
13277c478bd9Sstevel@tonic-gate 				 * Check for signal-generating
13287c478bd9Sstevel@tonic-gate 				 * characters.
13297c478bd9Sstevel@tonic-gate 				 */
13307c478bd9Sstevel@tonic-gate 				if (tp->t_modes.c_lflag & ISIG) {
13317c478bd9Sstevel@tonic-gate 					if (c == tp->t_modes.c_cc[VINTR]) {
13327c478bd9Sstevel@tonic-gate 						ldterm_dosig(q, SIGINT, c,
13337c478bd9Sstevel@tonic-gate 						    M_PCSIG, FLUSHRW);
13347c478bd9Sstevel@tonic-gate 						continue;
13357c478bd9Sstevel@tonic-gate 					}
13367c478bd9Sstevel@tonic-gate 					if (c == tp->t_modes.c_cc[VQUIT]) {
13377c478bd9Sstevel@tonic-gate 						ldterm_dosig(q, SIGQUIT, c,
13387c478bd9Sstevel@tonic-gate 						    M_PCSIG, FLUSHRW);
13397c478bd9Sstevel@tonic-gate 						continue;
13407c478bd9Sstevel@tonic-gate 					}
13417c478bd9Sstevel@tonic-gate 					if (c == tp->t_modes.c_cc[VSWTCH]) {
13427c478bd9Sstevel@tonic-gate 						/*
13437c478bd9Sstevel@tonic-gate 						 * Ancient SXT support; discard
13447c478bd9Sstevel@tonic-gate 						 * character without action.
13457c478bd9Sstevel@tonic-gate 						 */
13467c478bd9Sstevel@tonic-gate 						continue;
13477c478bd9Sstevel@tonic-gate 					}
13487c478bd9Sstevel@tonic-gate 					if (c == tp->t_modes.c_cc[VSUSP]) {
13497c478bd9Sstevel@tonic-gate 						ldterm_dosig(q, SIGTSTP, c,
13507c478bd9Sstevel@tonic-gate 						    M_PCSIG, FLUSHRW);
13517c478bd9Sstevel@tonic-gate 						continue;
13527c478bd9Sstevel@tonic-gate 					}
13537c478bd9Sstevel@tonic-gate 					if ((tp->t_modes.c_lflag & IEXTEN) &&
13547c478bd9Sstevel@tonic-gate 					    (c == tp->t_modes.c_cc[VDSUSP])) {
13557c478bd9Sstevel@tonic-gate 						ldterm_dosig(q, SIGTSTP, c,
13567c478bd9Sstevel@tonic-gate 						    M_SIG, 0);
13577c478bd9Sstevel@tonic-gate 						continue;
13587c478bd9Sstevel@tonic-gate 					}
1359*19d32b9aSRobert Mustacchi 
1360*19d32b9aSRobert Mustacchi 					/*
1361*19d32b9aSRobert Mustacchi 					 * Consumers do not expect the ^T to be
1362*19d32b9aSRobert Mustacchi 					 * echoed out when we generate a
1363*19d32b9aSRobert Mustacchi 					 * VSTATUS.
1364*19d32b9aSRobert Mustacchi 					 */
1365*19d32b9aSRobert Mustacchi 					if (c == tp->t_modes.c_cc[VSTATUS]) {
1366*19d32b9aSRobert Mustacchi 						ldterm_dosig(q, SIGINFO, '\0',
1367*19d32b9aSRobert Mustacchi 						    M_PCSIG, FLUSHRW);
1368*19d32b9aSRobert Mustacchi 						continue;
1369*19d32b9aSRobert Mustacchi 					}
13707c478bd9Sstevel@tonic-gate 				}
13717c478bd9Sstevel@tonic-gate 				/*
13727c478bd9Sstevel@tonic-gate 				 * Throw away CR if IGNCR set, or
13737c478bd9Sstevel@tonic-gate 				 * turn it into NL if ICRNL set.
13747c478bd9Sstevel@tonic-gate 				 */
13757c478bd9Sstevel@tonic-gate 				if (c == '\r') {
13767c478bd9Sstevel@tonic-gate 					if (tp->t_modes.c_iflag & IGNCR)
13777c478bd9Sstevel@tonic-gate 						continue;
13787c478bd9Sstevel@tonic-gate 					if (tp->t_modes.c_iflag & ICRNL)
13797c478bd9Sstevel@tonic-gate 						c = '\n';
13807c478bd9Sstevel@tonic-gate 				} else {
13817c478bd9Sstevel@tonic-gate 					/*
13827c478bd9Sstevel@tonic-gate 					 * Turn NL into CR if INLCR
13837c478bd9Sstevel@tonic-gate 					 * set.
13847c478bd9Sstevel@tonic-gate 					 */
13857c478bd9Sstevel@tonic-gate 					if (c == '\n' &&
13867c478bd9Sstevel@tonic-gate 					    tp->t_modes.c_iflag & INLCR)
13877c478bd9Sstevel@tonic-gate 						c = '\r';
13887c478bd9Sstevel@tonic-gate 				}
13897c478bd9Sstevel@tonic-gate 
13907c478bd9Sstevel@tonic-gate 				/*
13917c478bd9Sstevel@tonic-gate 				 * Map upper case input to lower case
13927c478bd9Sstevel@tonic-gate 				 * if IUCLC flag set.
13937c478bd9Sstevel@tonic-gate 				 */
13947c478bd9Sstevel@tonic-gate 				if (tp->t_modes.c_iflag & IUCLC &&
13957c478bd9Sstevel@tonic-gate 				    c >= 'A' && c <= 'Z')
13967c478bd9Sstevel@tonic-gate 					c += 'a' - 'A';
13977c478bd9Sstevel@tonic-gate 
13987c478bd9Sstevel@tonic-gate 				/*
13997c478bd9Sstevel@tonic-gate 				 * Put the possibly-transformed
14007c478bd9Sstevel@tonic-gate 				 * character back in the message.
14017c478bd9Sstevel@tonic-gate 				 */
14027c478bd9Sstevel@tonic-gate 				*writep++ = c;
14037c478bd9Sstevel@tonic-gate 			}
14047c478bd9Sstevel@tonic-gate 
14057c478bd9Sstevel@tonic-gate 			/*
14067c478bd9Sstevel@tonic-gate 			 * If we didn't copy some characters because
14077c478bd9Sstevel@tonic-gate 			 * we were ignoring them, fix the size of the
14087c478bd9Sstevel@tonic-gate 			 * data block by adjusting the write pointer.
14097c478bd9Sstevel@tonic-gate 			 * XXX This may result in a zero-length
14107c478bd9Sstevel@tonic-gate 			 * block; will this cause anybody gastric
14117c478bd9Sstevel@tonic-gate 			 * distress?
14127c478bd9Sstevel@tonic-gate 			 */
14137c478bd9Sstevel@tonic-gate 			bp->b_wptr -= (readp - writep);
14147c478bd9Sstevel@tonic-gate 		} else {
14157c478bd9Sstevel@tonic-gate 			/*
14167c478bd9Sstevel@tonic-gate 			 * We won't be doing anything other than
14177c478bd9Sstevel@tonic-gate 			 * possibly stripping the input.
14187c478bd9Sstevel@tonic-gate 			 */
14197c478bd9Sstevel@tonic-gate 			if (tp->t_modes.c_iflag & ISTRIP) {
14207c478bd9Sstevel@tonic-gate 				while (readp < bp->b_wptr)
14217c478bd9Sstevel@tonic-gate 					*writep++ = *readp++ & 0177;
14227c478bd9Sstevel@tonic-gate 			}
14237c478bd9Sstevel@tonic-gate 			tp->t_modes.c_lflag &= ~FLUSHO;
14247c478bd9Sstevel@tonic-gate 		}
14257c478bd9Sstevel@tonic-gate 
14267c478bd9Sstevel@tonic-gate 	} while ((bp = bp->b_cont) != NULL);	/* next block, if any */
14277c478bd9Sstevel@tonic-gate 
14287c478bd9Sstevel@tonic-gate 	/*
14297c478bd9Sstevel@tonic-gate 	 * Queue the message for service procedure if the
14307c478bd9Sstevel@tonic-gate 	 * queue is not empty or canputnext() fails or
14317c478bd9Sstevel@tonic-gate 	 * tp->t_state & TS_RESCAN is true.
14327c478bd9Sstevel@tonic-gate 	 */
14337c478bd9Sstevel@tonic-gate 
14347c478bd9Sstevel@tonic-gate 	if (q->q_first != NULL || !bcanputnext(q, mp->b_band) ||
14357c478bd9Sstevel@tonic-gate 	    (tp->t_state & TS_RESCAN))
14367c478bd9Sstevel@tonic-gate 		(void) putq(q, mp);
14377c478bd9Sstevel@tonic-gate 	else
14387c478bd9Sstevel@tonic-gate 		(void) ldtermrmsg(q, mp);
14397c478bd9Sstevel@tonic-gate 
14407c478bd9Sstevel@tonic-gate 	/*
14417c478bd9Sstevel@tonic-gate 	 * Flow control: send "stop input" message if our queue is
14427c478bd9Sstevel@tonic-gate 	 * approaching its high-water mark. The message will be
14437c478bd9Sstevel@tonic-gate 	 * dropped on the floor in the service procedure, if we
14447c478bd9Sstevel@tonic-gate 	 * cannot ship it up and we have had it upto our neck!
14457c478bd9Sstevel@tonic-gate 	 *
14467c478bd9Sstevel@tonic-gate 	 * Set QWANTW to ensure that the read queue service procedure
14477c478bd9Sstevel@tonic-gate 	 * gets run when nextq empties up again, so that it can
14487c478bd9Sstevel@tonic-gate 	 * unstop the input.
14497c478bd9Sstevel@tonic-gate 	 */
14507c478bd9Sstevel@tonic-gate 	if ((tp->t_modes.c_iflag & IXOFF) && !(tp->t_state & TS_TBLOCK) &&
14517c478bd9Sstevel@tonic-gate 	    q->q_count >= TTXOHI) {
14527c478bd9Sstevel@tonic-gate 		mutex_enter(QLOCK(nextq));
14537c478bd9Sstevel@tonic-gate 		nextq->q_flag |= QWANTW;
14547c478bd9Sstevel@tonic-gate 		mutex_exit(QLOCK(nextq));
14557c478bd9Sstevel@tonic-gate 		tp->t_state |= TS_TBLOCK;
14567c478bd9Sstevel@tonic-gate 		(void) putnextctl(wrq, M_STOPI);
14577c478bd9Sstevel@tonic-gate 		DEBUG1(("M_STOPI down\n"));
14587c478bd9Sstevel@tonic-gate 	}
14597c478bd9Sstevel@tonic-gate }
14607c478bd9Sstevel@tonic-gate 
14617c478bd9Sstevel@tonic-gate 
14627c478bd9Sstevel@tonic-gate /*
14637c478bd9Sstevel@tonic-gate  * Line discipline input server processing.  Erase/kill and escape
14647c478bd9Sstevel@tonic-gate  * ('\') processing, gathering into messages, upper/lower case input
14657c478bd9Sstevel@tonic-gate  * mapping.
14667c478bd9Sstevel@tonic-gate  */
14677c478bd9Sstevel@tonic-gate static void
14687c478bd9Sstevel@tonic-gate ldtermrsrv(queue_t *q)
14697c478bd9Sstevel@tonic-gate {
14707c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp;
14717c478bd9Sstevel@tonic-gate 	mblk_t *mp;
14727c478bd9Sstevel@tonic-gate 
14737c478bd9Sstevel@tonic-gate 	tp = (ldtermstd_state_t *)q->q_ptr;
14747c478bd9Sstevel@tonic-gate 
14757c478bd9Sstevel@tonic-gate 	if (tp->t_state & TS_RESCAN) {
14767c478bd9Sstevel@tonic-gate 		/*
14777c478bd9Sstevel@tonic-gate 		 * Canonicalization was turned on or off. Put the
14787c478bd9Sstevel@tonic-gate 		 * message being assembled back in the input queue,
14797c478bd9Sstevel@tonic-gate 		 * so that we rescan it.
14807c478bd9Sstevel@tonic-gate 		 */
14817c478bd9Sstevel@tonic-gate 		if (tp->t_message != NULL) {
14827c478bd9Sstevel@tonic-gate 			DEBUG5(("RESCAN WAS SET; put back in q\n"));
14837c478bd9Sstevel@tonic-gate 			if (tp->t_msglen != 0)
14847c478bd9Sstevel@tonic-gate 				(void) putbq(q, tp->t_message);
14857c478bd9Sstevel@tonic-gate 			else
14867c478bd9Sstevel@tonic-gate 				freemsg(tp->t_message);
14877c478bd9Sstevel@tonic-gate 			tp->t_message = NULL;
14887c478bd9Sstevel@tonic-gate 			tp->t_endmsg = NULL;
14897c478bd9Sstevel@tonic-gate 			tp->t_msglen = 0;
14907c478bd9Sstevel@tonic-gate 		}
14917c478bd9Sstevel@tonic-gate 		if (tp->t_state & TS_MEUC) {
14927c478bd9Sstevel@tonic-gate 			ASSERT(tp->t_eucp_mp);
14937c478bd9Sstevel@tonic-gate 			tp->t_eucp = tp->t_eucp_mp->b_rptr;
14947c478bd9Sstevel@tonic-gate 			tp->t_codeset = 0;
14957c478bd9Sstevel@tonic-gate 			tp->t_eucleft = 0;
14967c478bd9Sstevel@tonic-gate 		}
14977c478bd9Sstevel@tonic-gate 		tp->t_state &= ~TS_RESCAN;
14987c478bd9Sstevel@tonic-gate 	}
14997c478bd9Sstevel@tonic-gate 
15007c478bd9Sstevel@tonic-gate 	while ((mp = getq(q)) != NULL) {
15017c478bd9Sstevel@tonic-gate 		if (!ldtermrmsg(q, mp))
15027c478bd9Sstevel@tonic-gate 			break;
15037c478bd9Sstevel@tonic-gate 	}
15047c478bd9Sstevel@tonic-gate 
15057c478bd9Sstevel@tonic-gate 	/*
15067c478bd9Sstevel@tonic-gate 	 * Flow control: send start message if blocked and our queue
15077c478bd9Sstevel@tonic-gate 	 * is below its low water mark.
15087c478bd9Sstevel@tonic-gate 	 */
15097c478bd9Sstevel@tonic-gate 	if ((tp->t_modes.c_iflag & IXOFF) && (tp->t_state & TS_TBLOCK) &&
15107c478bd9Sstevel@tonic-gate 	    !(tp->t_state & TS_IFBLOCK) && q->q_count <= TTXOLO) {
15117c478bd9Sstevel@tonic-gate 		tp->t_state &= ~TS_TBLOCK;
15127c478bd9Sstevel@tonic-gate 		(void) putctl(WR(q), M_STARTI);
15137c478bd9Sstevel@tonic-gate 	}
15147c478bd9Sstevel@tonic-gate }
15157c478bd9Sstevel@tonic-gate 
15167c478bd9Sstevel@tonic-gate /*
15177c478bd9Sstevel@tonic-gate  * This routine is called from both ldtermrput and ldtermrsrv to
15187c478bd9Sstevel@tonic-gate  * do the actual work of dealing with mp. Return 1 on sucesss and
15197c478bd9Sstevel@tonic-gate  * 0 on failure.
15207c478bd9Sstevel@tonic-gate  */
15217c478bd9Sstevel@tonic-gate static int
15227c478bd9Sstevel@tonic-gate ldtermrmsg(queue_t *q, mblk_t *mp)
15237c478bd9Sstevel@tonic-gate {
15247c478bd9Sstevel@tonic-gate 	unsigned char c;
15257c478bd9Sstevel@tonic-gate 	int dofree;
15267c478bd9Sstevel@tonic-gate 	int status = 1;
15277c478bd9Sstevel@tonic-gate 	size_t   ebsize;
15287c478bd9Sstevel@tonic-gate 	mblk_t *bp;
15297c478bd9Sstevel@tonic-gate 	mblk_t *bpt;
15307c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp;
15317c478bd9Sstevel@tonic-gate 
15327c478bd9Sstevel@tonic-gate 	bpt = NULL;
15337c478bd9Sstevel@tonic-gate 
15347c478bd9Sstevel@tonic-gate 	tp = (ldtermstd_state_t *)q->q_ptr;
15357c478bd9Sstevel@tonic-gate 
15367c478bd9Sstevel@tonic-gate 	if (mp->b_datap->db_type <= QPCTL && !bcanputnext(q, mp->b_band)) {
15377c478bd9Sstevel@tonic-gate 		/*
15387c478bd9Sstevel@tonic-gate 		 * Stream head is flow controlled. If echo is
15397c478bd9Sstevel@tonic-gate 		 * turned on, flush the read side or send a
15407c478bd9Sstevel@tonic-gate 		 * bell down the line to stop input and
15417c478bd9Sstevel@tonic-gate 		 * process the current message.
15427c478bd9Sstevel@tonic-gate 		 * Otherwise(putbq) the user will not see any
15437c478bd9Sstevel@tonic-gate 		 * response to to the typed input. Typically
15447c478bd9Sstevel@tonic-gate 		 * happens if there is no reader process.
15457c478bd9Sstevel@tonic-gate 		 * Note that you will loose the data in this
15467c478bd9Sstevel@tonic-gate 		 * case if the data is coming too fast. There
15477c478bd9Sstevel@tonic-gate 		 * is an assumption here that if ECHO is
15487c478bd9Sstevel@tonic-gate 		 * turned on its some user typing the data on
15497c478bd9Sstevel@tonic-gate 		 * a terminal and its not network.
15507c478bd9Sstevel@tonic-gate 		 */
15517c478bd9Sstevel@tonic-gate 		if (tp->t_modes.c_lflag & ECHO) {
15527c478bd9Sstevel@tonic-gate 			if ((tp->t_modes.c_iflag & IMAXBEL) &&
15537c478bd9Sstevel@tonic-gate 			    (tp->t_modes.c_lflag & ICANON)) {
15547c478bd9Sstevel@tonic-gate 				freemsg(mp);
15557c478bd9Sstevel@tonic-gate 				if (canputnext(WR(q)))
15567c478bd9Sstevel@tonic-gate 					ldterm_outchar(CTRL('g'), WR(q), 4, tp);
15577c478bd9Sstevel@tonic-gate 				status = 0;
15587c478bd9Sstevel@tonic-gate 				goto echo;
15597c478bd9Sstevel@tonic-gate 			} else {
15607c478bd9Sstevel@tonic-gate 				(void) putctl1(q, M_FLUSH, FLUSHR);
15617c478bd9Sstevel@tonic-gate 			}
15627c478bd9Sstevel@tonic-gate 		} else {
15637c478bd9Sstevel@tonic-gate 			(void) putbq(q, mp);
15647c478bd9Sstevel@tonic-gate 			status = 0;
15657c478bd9Sstevel@tonic-gate 			goto out;	/* read side is blocked */
15667c478bd9Sstevel@tonic-gate 		}
15677c478bd9Sstevel@tonic-gate 	}
15687c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
15697c478bd9Sstevel@tonic-gate 
15707c478bd9Sstevel@tonic-gate 	default:
15717c478bd9Sstevel@tonic-gate 		putnext(q, mp);	/* pass it on */
15727c478bd9Sstevel@tonic-gate 		goto out;
15737c478bd9Sstevel@tonic-gate 
15747c478bd9Sstevel@tonic-gate 	case M_HANGUP:
15757c478bd9Sstevel@tonic-gate 		/*
15767c478bd9Sstevel@tonic-gate 		 * Flush everything we haven't looked at yet.
15777c478bd9Sstevel@tonic-gate 		 */
15787c478bd9Sstevel@tonic-gate 		flushq(q, FLUSHDATA);
15797c478bd9Sstevel@tonic-gate 
15807c478bd9Sstevel@tonic-gate 		/*
15817c478bd9Sstevel@tonic-gate 		 * Flush everything we have looked at.
15827c478bd9Sstevel@tonic-gate 		 */
15837c478bd9Sstevel@tonic-gate 		freemsg(tp->t_message);
15847c478bd9Sstevel@tonic-gate 		tp->t_message = NULL;
15857c478bd9Sstevel@tonic-gate 		tp->t_endmsg = NULL;
15867c478bd9Sstevel@tonic-gate 		tp->t_msglen = 0;
15877c478bd9Sstevel@tonic-gate 		/*
15887c478bd9Sstevel@tonic-gate 		 * XXX  should we set read request
15897c478bd9Sstevel@tonic-gate 		 * tp->t_rd_request to NULL?
15907c478bd9Sstevel@tonic-gate 		 */
15917c478bd9Sstevel@tonic-gate 		tp->t_rocount = 0;	/* if it hasn't been typed */
15927c478bd9Sstevel@tonic-gate 		tp->t_rocol = 0;	/* it hasn't been echoed :-) */
15937c478bd9Sstevel@tonic-gate 		if (tp->t_state & TS_MEUC) {
15947c478bd9Sstevel@tonic-gate 			ASSERT(tp->t_eucp_mp);
15957c478bd9Sstevel@tonic-gate 			tp->t_eucp = tp->t_eucp_mp->b_rptr;
15967c478bd9Sstevel@tonic-gate 		}
15977c478bd9Sstevel@tonic-gate 		/*
15987c478bd9Sstevel@tonic-gate 		 * Restart output, since it's probably got
15997c478bd9Sstevel@tonic-gate 		 * nowhere to go anyway, and we're probably
16007c478bd9Sstevel@tonic-gate 		 * not going to see another ^Q for a while.
16017c478bd9Sstevel@tonic-gate 		 */
16027c478bd9Sstevel@tonic-gate 		if (tp->t_state & TS_TTSTOP) {
16037c478bd9Sstevel@tonic-gate 			tp->t_state &= ~(TS_TTSTOP|TS_OFBLOCK);
16047c478bd9Sstevel@tonic-gate 			(void) putnextctl(WR(q), M_START);
16057c478bd9Sstevel@tonic-gate 		}
16067c478bd9Sstevel@tonic-gate 		/*
16077c478bd9Sstevel@tonic-gate 		 * This message will travel up the read
16087c478bd9Sstevel@tonic-gate 		 * queue, flushing as it goes, get turned
16097c478bd9Sstevel@tonic-gate 		 * around at the stream head, and travel back
16107c478bd9Sstevel@tonic-gate 		 * down the write queue, flushing as it goes.
16117c478bd9Sstevel@tonic-gate 		 */
16127c478bd9Sstevel@tonic-gate 		(void) putnextctl1(q, M_FLUSH, FLUSHW);
16137c478bd9Sstevel@tonic-gate 
16147c478bd9Sstevel@tonic-gate 		/*
16157c478bd9Sstevel@tonic-gate 		 * This message will travel down the write
16167c478bd9Sstevel@tonic-gate 		 * queue, flushing as it goes, get turned
16177c478bd9Sstevel@tonic-gate 		 * around at the driver, and travel back up
16187c478bd9Sstevel@tonic-gate 		 * the read queue, flushing as it goes.
16197c478bd9Sstevel@tonic-gate 		 */
16207c478bd9Sstevel@tonic-gate 		(void) putctl1(WR(q), M_FLUSH, FLUSHR);
16217c478bd9Sstevel@tonic-gate 
16227c478bd9Sstevel@tonic-gate 		/*
16237c478bd9Sstevel@tonic-gate 		 * Now that that's done, we send a SIGCONT
16247c478bd9Sstevel@tonic-gate 		 * upstream, followed by the M_HANGUP.
16257c478bd9Sstevel@tonic-gate 		 */
16267c478bd9Sstevel@tonic-gate 		/* (void) putnextctl1(q, M_PCSIG, SIGCONT); */
16277c478bd9Sstevel@tonic-gate 		putnext(q, mp);
16287c478bd9Sstevel@tonic-gate 		goto out;
16297c478bd9Sstevel@tonic-gate 
16307c478bd9Sstevel@tonic-gate 	case M_IOCACK:
16317c478bd9Sstevel@tonic-gate 
16327c478bd9Sstevel@tonic-gate 		/*
16337c478bd9Sstevel@tonic-gate 		 * Augment whatever information the driver is
16347c478bd9Sstevel@tonic-gate 		 * returning  with the information we supply.
16357c478bd9Sstevel@tonic-gate 		 */
16367c478bd9Sstevel@tonic-gate 		ldterm_ioctl_reply(q, mp);
16377c478bd9Sstevel@tonic-gate 		goto out;
16387c478bd9Sstevel@tonic-gate 
16397c478bd9Sstevel@tonic-gate 	case M_DATA:
16407c478bd9Sstevel@tonic-gate 		break;
16417c478bd9Sstevel@tonic-gate 	}
16427c478bd9Sstevel@tonic-gate 
16437c478bd9Sstevel@tonic-gate 	/*
16447c478bd9Sstevel@tonic-gate 	 * This is an M_DATA message.
16457c478bd9Sstevel@tonic-gate 	 */
16467c478bd9Sstevel@tonic-gate 
16477c478bd9Sstevel@tonic-gate 	/*
16487c478bd9Sstevel@tonic-gate 	 * If somebody below us ("intelligent" communications
16497c478bd9Sstevel@tonic-gate 	 * board, pseudo-tty controlled by an editor) is
16507c478bd9Sstevel@tonic-gate 	 * doing canonicalization, don't scan it for special
16517c478bd9Sstevel@tonic-gate 	 * characters.
16527c478bd9Sstevel@tonic-gate 	 */
16537c478bd9Sstevel@tonic-gate 	if (tp->t_state & TS_NOCANON) {
16547c478bd9Sstevel@tonic-gate 		putnext(q, mp);
16557c478bd9Sstevel@tonic-gate 		goto out;
16567c478bd9Sstevel@tonic-gate 	}
16577c478bd9Sstevel@tonic-gate 	bp = mp;
16587c478bd9Sstevel@tonic-gate 
16597c478bd9Sstevel@tonic-gate 	if ((bpt = newmsg(tp)) != NULL) {
16607c478bd9Sstevel@tonic-gate 		mblk_t *bcont;
16617c478bd9Sstevel@tonic-gate 
16627c478bd9Sstevel@tonic-gate 		do {
16637c478bd9Sstevel@tonic-gate 			ASSERT(bp->b_wptr >= bp->b_rptr);
16647c478bd9Sstevel@tonic-gate 			ebsize = bp->b_wptr - bp->b_rptr;
16657c478bd9Sstevel@tonic-gate 			if (ebsize > EBSIZE)
16667c478bd9Sstevel@tonic-gate 				ebsize = EBSIZE;
16677c478bd9Sstevel@tonic-gate 			bcont = bp->b_cont;
16687c478bd9Sstevel@tonic-gate 			if (CANON_MODE) {
16697c478bd9Sstevel@tonic-gate 				/*
16707c478bd9Sstevel@tonic-gate 				 * By default, free the message once processed
16717c478bd9Sstevel@tonic-gate 				 */
16727c478bd9Sstevel@tonic-gate 				dofree = 1;
16737c478bd9Sstevel@tonic-gate 
16747c478bd9Sstevel@tonic-gate 				/*
16757c478bd9Sstevel@tonic-gate 				 * update sysinfo canch
16767c478bd9Sstevel@tonic-gate 				 * character. The value of
16777c478bd9Sstevel@tonic-gate 				 * canch may vary as compared
16787c478bd9Sstevel@tonic-gate 				 * to character tty
16797c478bd9Sstevel@tonic-gate 				 * implementation.
16807c478bd9Sstevel@tonic-gate 				 */
16817c478bd9Sstevel@tonic-gate 				while (bp->b_rptr < bp->b_wptr) {
16827c478bd9Sstevel@tonic-gate 					c = *bp->b_rptr++;
16837c478bd9Sstevel@tonic-gate 					if ((bpt = ldterm_docanon(c,
16847c478bd9Sstevel@tonic-gate 					    bpt, ebsize, q, tp, &dofree)) ==
16857c478bd9Sstevel@tonic-gate 					    NULL)
16867c478bd9Sstevel@tonic-gate 						break;
16877c478bd9Sstevel@tonic-gate 				}
16887c478bd9Sstevel@tonic-gate 				/*
16897c478bd9Sstevel@tonic-gate 				 * Release this block or put back on queue.
16907c478bd9Sstevel@tonic-gate 				 */
16917c478bd9Sstevel@tonic-gate 				if (dofree)
16927c478bd9Sstevel@tonic-gate 					freeb(bp);
16937c478bd9Sstevel@tonic-gate 				else {
16947c478bd9Sstevel@tonic-gate 					(void) putbq(q, bp);
16957c478bd9Sstevel@tonic-gate 					break;
16967c478bd9Sstevel@tonic-gate 				}
16977c478bd9Sstevel@tonic-gate 			} else
169885bb5f1dSis 				bpt = ldterm_dononcanon(bp, bpt, ebsize, q, tp);
16997c478bd9Sstevel@tonic-gate 			if (bpt == NULL) {
17007c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
17017c478bd9Sstevel@tonic-gate 				    "ldtermrsrv: out of blocks");
17027c478bd9Sstevel@tonic-gate 				freemsg(bcont);
17037c478bd9Sstevel@tonic-gate 				break;
17047c478bd9Sstevel@tonic-gate 			}
17057c478bd9Sstevel@tonic-gate 		} while ((bp = bcont) != NULL);
17067c478bd9Sstevel@tonic-gate 	}
17077c478bd9Sstevel@tonic-gate echo:
17087c478bd9Sstevel@tonic-gate 	/*
17097c478bd9Sstevel@tonic-gate 	 * Send whatever we echoed downstream.
17107c478bd9Sstevel@tonic-gate 	 */
17117c478bd9Sstevel@tonic-gate 	if (tp->t_echomp != NULL) {
17127c478bd9Sstevel@tonic-gate 		if (canputnext(WR(q)))
17137c478bd9Sstevel@tonic-gate 			putnext(WR(q), tp->t_echomp);
17147c478bd9Sstevel@tonic-gate 		else
17157c478bd9Sstevel@tonic-gate 			freemsg(tp->t_echomp);
17167c478bd9Sstevel@tonic-gate 		tp->t_echomp = NULL;
17177c478bd9Sstevel@tonic-gate 	}
17187c478bd9Sstevel@tonic-gate 
17197c478bd9Sstevel@tonic-gate out:
17207c478bd9Sstevel@tonic-gate 	return (status);
17217c478bd9Sstevel@tonic-gate }
17227c478bd9Sstevel@tonic-gate 
17237c478bd9Sstevel@tonic-gate 
17247c478bd9Sstevel@tonic-gate /*
17257c478bd9Sstevel@tonic-gate  * Do canonical mode input; check whether this character is to be
17267c478bd9Sstevel@tonic-gate  * treated as a special character - if so, check whether it's equal
17277c478bd9Sstevel@tonic-gate  * to any of the special characters and handle it accordingly.
17287c478bd9Sstevel@tonic-gate  * Otherwise, just add it to the current line.
17297c478bd9Sstevel@tonic-gate  */
17307c478bd9Sstevel@tonic-gate static mblk_t *
17317c478bd9Sstevel@tonic-gate ldterm_docanon(uchar_t c, mblk_t *bpt, size_t ebsize, queue_t *q,
17327c478bd9Sstevel@tonic-gate     ldtermstd_state_t *tp, int *dofreep)
17337c478bd9Sstevel@tonic-gate {
17347c478bd9Sstevel@tonic-gate 	queue_t *wrq = WR(q);
17357c478bd9Sstevel@tonic-gate 	int i;
17367c478bd9Sstevel@tonic-gate 
17377c478bd9Sstevel@tonic-gate 	/*
17387c478bd9Sstevel@tonic-gate 	 * If the previous character was the "literal next"
17397c478bd9Sstevel@tonic-gate 	 * character, treat this character as regular input.
17407c478bd9Sstevel@tonic-gate 	 */
17417c478bd9Sstevel@tonic-gate 	if (tp->t_state & TS_SLNCH)
17427c478bd9Sstevel@tonic-gate 		goto escaped;
17437c478bd9Sstevel@tonic-gate 
17447c478bd9Sstevel@tonic-gate 	/*
17457c478bd9Sstevel@tonic-gate 	 * Setting a special character to NUL disables it, so if this
17467c478bd9Sstevel@tonic-gate 	 * character is NUL, it should not be compared with any of
17477c478bd9Sstevel@tonic-gate 	 * the special characters.
17487c478bd9Sstevel@tonic-gate 	 */
17497c478bd9Sstevel@tonic-gate 	if (c == _POSIX_VDISABLE) {
17507c478bd9Sstevel@tonic-gate 		tp->t_state &= ~TS_QUOT;
17517c478bd9Sstevel@tonic-gate 		goto escaped;
17527c478bd9Sstevel@tonic-gate 	}
17537c478bd9Sstevel@tonic-gate 	/*
17547c478bd9Sstevel@tonic-gate 	 * If this character is the literal next character, echo it
17557c478bd9Sstevel@tonic-gate 	 * as '^', backspace over it, and record that fact.
17567c478bd9Sstevel@tonic-gate 	 */
17577c478bd9Sstevel@tonic-gate 	if ((tp->t_modes.c_lflag & IEXTEN) && c == tp->t_modes.c_cc[VLNEXT]) {
17587c478bd9Sstevel@tonic-gate 		if (tp->t_modes.c_lflag & ECHO)
17597c478bd9Sstevel@tonic-gate 			ldterm_outstring((unsigned char *)"^\b", 2, wrq,
17607c478bd9Sstevel@tonic-gate 			    ebsize, tp);
17617c478bd9Sstevel@tonic-gate 		tp->t_state |= TS_SLNCH;
17627c478bd9Sstevel@tonic-gate 		goto out;
17637c478bd9Sstevel@tonic-gate 	}
17647c478bd9Sstevel@tonic-gate 	/*
17657c478bd9Sstevel@tonic-gate 	 * Check for the editing character. If the display width of
17667c478bd9Sstevel@tonic-gate 	 * the last byte at the canonical buffer is not one and also
17677c478bd9Sstevel@tonic-gate 	 * smaller than or equal to UNKNOWN_WIDTH, the character at
17687c478bd9Sstevel@tonic-gate 	 * the end of the buffer is a multi-byte and/or multi-column
17697c478bd9Sstevel@tonic-gate 	 * character.
17707c478bd9Sstevel@tonic-gate 	 */
17717c478bd9Sstevel@tonic-gate 	if (c == tp->t_modes.c_cc[VERASE]) {
17727c478bd9Sstevel@tonic-gate 		if (tp->t_state & TS_QUOT) {
17737c478bd9Sstevel@tonic-gate 			/*
17747c478bd9Sstevel@tonic-gate 			 * Get rid of the backslash, and put the
17757c478bd9Sstevel@tonic-gate 			 * erase character in its place.
17767c478bd9Sstevel@tonic-gate 			 */
17777c478bd9Sstevel@tonic-gate 			ldterm_erase(wrq, ebsize, tp);
17787c478bd9Sstevel@tonic-gate 			bpt = tp->t_endmsg;
17797c478bd9Sstevel@tonic-gate 			goto escaped;
17807c478bd9Sstevel@tonic-gate 		} else {
17817c478bd9Sstevel@tonic-gate 			if ((tp->t_state & TS_MEUC) && tp->t_msglen &&
17827c478bd9Sstevel@tonic-gate 			    (*(tp->t_eucp - 1) != 1 &&
17837c478bd9Sstevel@tonic-gate 			    *(tp->t_eucp - 1) <= UNKNOWN_WIDTH))
17847c478bd9Sstevel@tonic-gate 				ldterm_csi_erase(wrq, ebsize, tp);
17857c478bd9Sstevel@tonic-gate 			else
17867c478bd9Sstevel@tonic-gate 				ldterm_erase(wrq, ebsize, tp);
17877c478bd9Sstevel@tonic-gate 			bpt = tp->t_endmsg;
17887c478bd9Sstevel@tonic-gate 			goto out;
17897c478bd9Sstevel@tonic-gate 		}
17907c478bd9Sstevel@tonic-gate 	}
17917c478bd9Sstevel@tonic-gate 	if ((tp->t_modes.c_lflag & IEXTEN) && c == tp->t_modes.c_cc[VWERASE]) {
17927c478bd9Sstevel@tonic-gate 		/*
17937c478bd9Sstevel@tonic-gate 		 * Do "ASCII word" or "multibyte character token/chunk" erase.
17947c478bd9Sstevel@tonic-gate 		 */
17957c478bd9Sstevel@tonic-gate 		if (tp->t_state & TS_MEUC)
17967c478bd9Sstevel@tonic-gate 			ldterm_csi_werase(wrq, ebsize, tp);
17977c478bd9Sstevel@tonic-gate 		else
17987c478bd9Sstevel@tonic-gate 			ldterm_werase(wrq, ebsize, tp);
17997c478bd9Sstevel@tonic-gate 		bpt = tp->t_endmsg;
18007c478bd9Sstevel@tonic-gate 		goto out;
18017c478bd9Sstevel@tonic-gate 	}
18027c478bd9Sstevel@tonic-gate 	if (c == tp->t_modes.c_cc[VKILL]) {
18037c478bd9Sstevel@tonic-gate 		if (tp->t_state & TS_QUOT) {
18047c478bd9Sstevel@tonic-gate 			/*
18057c478bd9Sstevel@tonic-gate 			 * Get rid of the backslash, and put the kill
18067c478bd9Sstevel@tonic-gate 			 * character in its place.
18077c478bd9Sstevel@tonic-gate 			 */
18087c478bd9Sstevel@tonic-gate 			ldterm_erase(wrq, ebsize, tp);
18097c478bd9Sstevel@tonic-gate 			bpt = tp->t_endmsg;
18107c478bd9Sstevel@tonic-gate 			goto escaped;
18117c478bd9Sstevel@tonic-gate 		} else {
18127c478bd9Sstevel@tonic-gate 			ldterm_kill(wrq, ebsize, tp);
18137c478bd9Sstevel@tonic-gate 			bpt = tp->t_endmsg;
18147c478bd9Sstevel@tonic-gate 			goto out;
18157c478bd9Sstevel@tonic-gate 		}
18167c478bd9Sstevel@tonic-gate 	}
18177c478bd9Sstevel@tonic-gate 	if ((tp->t_modes.c_lflag & IEXTEN) && c == tp->t_modes.c_cc[VREPRINT]) {
18187c478bd9Sstevel@tonic-gate 		ldterm_reprint(wrq, ebsize, tp);
18197c478bd9Sstevel@tonic-gate 		goto out;
18207c478bd9Sstevel@tonic-gate 	}
18217c478bd9Sstevel@tonic-gate 	/*
18227c478bd9Sstevel@tonic-gate 	 * If the preceding character was a backslash: if the current
18237c478bd9Sstevel@tonic-gate 	 * character is an EOF, get rid of the backslash and treat
18247c478bd9Sstevel@tonic-gate 	 * the EOF as data; if we're in XCASE mode and the current
18257c478bd9Sstevel@tonic-gate 	 * character is part of a backslash-X escape sequence,
18267c478bd9Sstevel@tonic-gate 	 * process it; otherwise, just treat the current character
18277c478bd9Sstevel@tonic-gate 	 * normally.
18287c478bd9Sstevel@tonic-gate 	 */
18297c478bd9Sstevel@tonic-gate 	if (tp->t_state & TS_QUOT) {
18307c478bd9Sstevel@tonic-gate 		tp->t_state &= ~TS_QUOT;
18317c478bd9Sstevel@tonic-gate 		if (c == tp->t_modes.c_cc[VEOF]) {
18327c478bd9Sstevel@tonic-gate 			/*
18337c478bd9Sstevel@tonic-gate 			 * EOF character. Since it's escaped, get rid
18347c478bd9Sstevel@tonic-gate 			 * of the backslash and put the EOF character
18357c478bd9Sstevel@tonic-gate 			 * in its place.
18367c478bd9Sstevel@tonic-gate 			 */
18377c478bd9Sstevel@tonic-gate 			ldterm_erase(wrq, ebsize, tp);
18387c478bd9Sstevel@tonic-gate 			bpt = tp->t_endmsg;
18397c478bd9Sstevel@tonic-gate 		} else {
18407c478bd9Sstevel@tonic-gate 			/*
18417c478bd9Sstevel@tonic-gate 			 * If we're in XCASE mode, and the current
18427c478bd9Sstevel@tonic-gate 			 * character is part of a backslash-X
18437c478bd9Sstevel@tonic-gate 			 * sequence, get rid of the backslash and
18447c478bd9Sstevel@tonic-gate 			 * replace the current character with what
18457c478bd9Sstevel@tonic-gate 			 * that sequence maps to.
18467c478bd9Sstevel@tonic-gate 			 */
18477c478bd9Sstevel@tonic-gate 			if ((tp->t_modes.c_lflag & XCASE) &&
18487c478bd9Sstevel@tonic-gate 			    imaptab[c] != '\0') {
18497c478bd9Sstevel@tonic-gate 				ldterm_erase(wrq, ebsize, tp);
18507c478bd9Sstevel@tonic-gate 				bpt = tp->t_endmsg;
18517c478bd9Sstevel@tonic-gate 				c = imaptab[c];
18527c478bd9Sstevel@tonic-gate 			}
18537c478bd9Sstevel@tonic-gate 		}
18547c478bd9Sstevel@tonic-gate 	} else {
18557c478bd9Sstevel@tonic-gate 		/*
18567c478bd9Sstevel@tonic-gate 		 * Previous character wasn't backslash; check whether
18577c478bd9Sstevel@tonic-gate 		 * this was the EOF character.
18587c478bd9Sstevel@tonic-gate 		 */
18597c478bd9Sstevel@tonic-gate 		if (c == tp->t_modes.c_cc[VEOF]) {
18607c478bd9Sstevel@tonic-gate 			/*
18617c478bd9Sstevel@tonic-gate 			 * EOF character. Don't echo it unless
18627c478bd9Sstevel@tonic-gate 			 * ECHOCTL is set, don't stuff it in the
18637c478bd9Sstevel@tonic-gate 			 * current line, but send the line up the
18647c478bd9Sstevel@tonic-gate 			 * stream.
18657c478bd9Sstevel@tonic-gate 			 */
18667c478bd9Sstevel@tonic-gate 			if ((tp->t_modes.c_lflag & ECHOCTL) &&
18677c478bd9Sstevel@tonic-gate 			    (tp->t_modes.c_lflag & IEXTEN) &&
18687c478bd9Sstevel@tonic-gate 			    (tp->t_modes.c_lflag & ECHO)) {
18697c478bd9Sstevel@tonic-gate 				i = ldterm_echo(c, wrq, ebsize, tp);
18707c478bd9Sstevel@tonic-gate 				while (i > 0) {
18717c478bd9Sstevel@tonic-gate 					ldterm_outchar('\b', wrq, ebsize, tp);
18727c478bd9Sstevel@tonic-gate 					i--;
18737c478bd9Sstevel@tonic-gate 				}
18747c478bd9Sstevel@tonic-gate 			}
18757c478bd9Sstevel@tonic-gate 			bpt->b_datap->db_type = M_DATA;
18767c478bd9Sstevel@tonic-gate 			ldterm_msg_upstream(q, tp);
18777c478bd9Sstevel@tonic-gate 			if (!canputnext(q)) {
18787c478bd9Sstevel@tonic-gate 				bpt = NULL;
18797c478bd9Sstevel@tonic-gate 				*dofreep = 0;
18807c478bd9Sstevel@tonic-gate 			} else {
18817c478bd9Sstevel@tonic-gate 				bpt = newmsg(tp);
18827c478bd9Sstevel@tonic-gate 				*dofreep = 1;
18837c478bd9Sstevel@tonic-gate 			}
18847c478bd9Sstevel@tonic-gate 			goto out;
18857c478bd9Sstevel@tonic-gate 		}
18867c478bd9Sstevel@tonic-gate 	}
18877c478bd9Sstevel@tonic-gate 
18887c478bd9Sstevel@tonic-gate escaped:
18897c478bd9Sstevel@tonic-gate 	/*
18907c478bd9Sstevel@tonic-gate 	 * First, make sure we can fit one WHOLE multi-byte char in the
18917c478bd9Sstevel@tonic-gate 	 * buffer.  This is one place where we have overhead even if
18927c478bd9Sstevel@tonic-gate 	 * not in multi-byte mode; the overhead is subtracting
18937c478bd9Sstevel@tonic-gate 	 * tp->t_maxeuc from MAX_CANON before checking.
18947c478bd9Sstevel@tonic-gate 	 *
18957c478bd9Sstevel@tonic-gate 	 * Allows MAX_CANON bytes in the buffer before throwing awaying
18967c478bd9Sstevel@tonic-gate 	 * the the overflow of characters.
18977c478bd9Sstevel@tonic-gate 	 */
18987c478bd9Sstevel@tonic-gate 	if ((tp->t_msglen > ((MAX_CANON + 1) - (int)tp->t_maxeuc)) &&
18997c478bd9Sstevel@tonic-gate 	    !((tp->t_state & TS_MEUC) && tp->t_eucleft)) {
19007c478bd9Sstevel@tonic-gate 
19017c478bd9Sstevel@tonic-gate 		/*
19027c478bd9Sstevel@tonic-gate 		 * Byte will cause line to overflow, or the next EUC
19037c478bd9Sstevel@tonic-gate 		 * won't fit: Ring the bell or discard all input, and
19047c478bd9Sstevel@tonic-gate 		 * don't save the byte away.
19057c478bd9Sstevel@tonic-gate 		 */
19067c478bd9Sstevel@tonic-gate 		if (tp->t_modes.c_iflag & IMAXBEL) {
19077c478bd9Sstevel@tonic-gate 			if (canputnext(wrq))
19087c478bd9Sstevel@tonic-gate 				ldterm_outchar(CTRL('g'), wrq, ebsize, tp);
19097c478bd9Sstevel@tonic-gate 			goto out;
19107c478bd9Sstevel@tonic-gate 		} else {
19117c478bd9Sstevel@tonic-gate 			/*
19127c478bd9Sstevel@tonic-gate 			 * MAX_CANON processing. free everything in
19137c478bd9Sstevel@tonic-gate 			 * the current line and start with the
19147c478bd9Sstevel@tonic-gate 			 * current character as the first character.
19157c478bd9Sstevel@tonic-gate 			 */
19167c478bd9Sstevel@tonic-gate 			DEBUG7(("ldterm_docanon: MAX_CANON processing\n"));
19177c478bd9Sstevel@tonic-gate 			freemsg(tp->t_message);
19187c478bd9Sstevel@tonic-gate 			tp->t_message = NULL;
19197c478bd9Sstevel@tonic-gate 			tp->t_endmsg = NULL;
19207c478bd9Sstevel@tonic-gate 			tp->t_msglen = 0;
19217c478bd9Sstevel@tonic-gate 			tp->t_rocount = 0;	/* if it hasn't been type */
19227c478bd9Sstevel@tonic-gate 			tp->t_rocol = 0;	/* it hasn't been echoed :-) */
19237c478bd9Sstevel@tonic-gate 			if (tp->t_state & TS_MEUC) {
19247c478bd9Sstevel@tonic-gate 				ASSERT(tp->t_eucp_mp);
19257c478bd9Sstevel@tonic-gate 				tp->t_eucp = tp->t_eucp_mp->b_rptr;
19267c478bd9Sstevel@tonic-gate 			}
19277c478bd9Sstevel@tonic-gate 			tp->t_state &= ~TS_SLNCH;
19287c478bd9Sstevel@tonic-gate 			bpt = newmsg(tp);
19297c478bd9Sstevel@tonic-gate 		}
19307c478bd9Sstevel@tonic-gate 	}
19317c478bd9Sstevel@tonic-gate 	/*
19327c478bd9Sstevel@tonic-gate 	 * Add the character to the current line.
19337c478bd9Sstevel@tonic-gate 	 */
19347c478bd9Sstevel@tonic-gate 	if (bpt->b_wptr >= bpt->b_datap->db_lim) {
19357c478bd9Sstevel@tonic-gate 		/*
19367c478bd9Sstevel@tonic-gate 		 * No more room in this mblk; save this one away, and
19377c478bd9Sstevel@tonic-gate 		 * allocate a new one.
19387c478bd9Sstevel@tonic-gate 		 */
19397c478bd9Sstevel@tonic-gate 		bpt->b_datap->db_type = M_DATA;
19407c478bd9Sstevel@tonic-gate 		if ((bpt = allocb(IBSIZE, BPRI_MED)) == NULL)
19417c478bd9Sstevel@tonic-gate 			goto out;
19427c478bd9Sstevel@tonic-gate 
19437c478bd9Sstevel@tonic-gate 		/*
19447c478bd9Sstevel@tonic-gate 		 * Chain the new one to the end of the old one, and
19457c478bd9Sstevel@tonic-gate 		 * mark it as the last block in the current line.
19467c478bd9Sstevel@tonic-gate 		 */
19477c478bd9Sstevel@tonic-gate 		tp->t_endmsg->b_cont = bpt;
19487c478bd9Sstevel@tonic-gate 		tp->t_endmsg = bpt;
19497c478bd9Sstevel@tonic-gate 	}
19507c478bd9Sstevel@tonic-gate 	*bpt->b_wptr++ = c;
19517c478bd9Sstevel@tonic-gate 	tp->t_msglen++;		/* message length in BYTES */
19527c478bd9Sstevel@tonic-gate 
19537c478bd9Sstevel@tonic-gate 	/*
19547c478bd9Sstevel@tonic-gate 	 * In multi-byte mode, we have to keep track of where we are.
19557c478bd9Sstevel@tonic-gate 	 * The first bytes of multi-byte chars get the full count for the
19567c478bd9Sstevel@tonic-gate 	 * whole character.  We don't do any column calculations
19577c478bd9Sstevel@tonic-gate 	 * here, but we need the information for when we do. We could
19587c478bd9Sstevel@tonic-gate 	 * come across cases where we are getting garbage on the
19597c478bd9Sstevel@tonic-gate 	 * line, but we're in multi-byte mode.  In that case, we may
19607c478bd9Sstevel@tonic-gate 	 * see ASCII controls come in the middle of what should have been a
19617c478bd9Sstevel@tonic-gate 	 * multi-byte character.  Call ldterm_eucwarn...eventually, a
19627c478bd9Sstevel@tonic-gate 	 * warning message will be printed about it.
19637c478bd9Sstevel@tonic-gate 	 */
19647c478bd9Sstevel@tonic-gate 	if (tp->t_state & TS_MEUC) {
19657c478bd9Sstevel@tonic-gate 		if (tp->t_eucleft) {	/* if in a multi-byte char already */
19667c478bd9Sstevel@tonic-gate 			--tp->t_eucleft;
19677c478bd9Sstevel@tonic-gate 			*tp->t_eucp++ = 0;	/* is a subsequent byte */
19687c478bd9Sstevel@tonic-gate 			if (c < (uchar_t)0x20)
19697c478bd9Sstevel@tonic-gate 				ldterm_eucwarn(tp);
19707c478bd9Sstevel@tonic-gate 		} else { /* is the first byte of a multi-byte, or is ASCII */
19717c478bd9Sstevel@tonic-gate 			if (ISASCII(c)) {
19727c478bd9Sstevel@tonic-gate 				*tp->t_eucp++ =
19737c478bd9Sstevel@tonic-gate 				    tp->t_csmethods.ldterm_dispwidth(c,
197485bb5f1dSis 				    (void *)tp, tp->t_modes.c_lflag & ECHOCTL);
19757c478bd9Sstevel@tonic-gate 				tp->t_codeset = 0;
19767c478bd9Sstevel@tonic-gate 			} else {
19777c478bd9Sstevel@tonic-gate 				*tp->t_eucp++ =
19787c478bd9Sstevel@tonic-gate 				    tp->t_csmethods.ldterm_dispwidth(c,
197985bb5f1dSis 				    (void *)tp, tp->t_modes.c_lflag & ECHOCTL);
19807c478bd9Sstevel@tonic-gate 				tp->t_eucleft =
19817c478bd9Sstevel@tonic-gate 				    tp->t_csmethods.ldterm_memwidth(c,
19827c478bd9Sstevel@tonic-gate 				    (void *)tp) - 1;
19837c478bd9Sstevel@tonic-gate 				tp->t_codeset = ldterm_codeset(
19847c478bd9Sstevel@tonic-gate 				    tp->t_csdata.codeset_type, c);
19857c478bd9Sstevel@tonic-gate 			}
19867c478bd9Sstevel@tonic-gate 		}
19877c478bd9Sstevel@tonic-gate 	}
19887c478bd9Sstevel@tonic-gate 	/*
19897c478bd9Sstevel@tonic-gate 	 * AT&T is concerned about the following but we aren't since
19907c478bd9Sstevel@tonic-gate 	 * we have already shipped code that works.
19917c478bd9Sstevel@tonic-gate 	 *
19927c478bd9Sstevel@tonic-gate 	 * EOL2/XCASE should be conditioned with IEXTEN to be truly
19937c478bd9Sstevel@tonic-gate 	 * POSIX conformant. This is going to cause problems for
19947c478bd9Sstevel@tonic-gate 	 * pre-SVR4.0 programs that don't know about IEXTEN. Hence
19957c478bd9Sstevel@tonic-gate 	 * EOL2/IEXTEN is not conditioned with IEXTEN.
19967c478bd9Sstevel@tonic-gate 	 */
19977c478bd9Sstevel@tonic-gate 	if (!(tp->t_state & TS_SLNCH) &&
19987c478bd9Sstevel@tonic-gate 	    (c == '\n' || (c != '\0' && (c == tp->t_modes.c_cc[VEOL] ||
19997c478bd9Sstevel@tonic-gate 	    (c == tp->t_modes.c_cc[VEOL2]))))) {
20007c478bd9Sstevel@tonic-gate 		/*
20017c478bd9Sstevel@tonic-gate 		 * || ((tp->t_modes.c_lflag & IEXTEN) && c ==
20027c478bd9Sstevel@tonic-gate 		 * tp->t_modes.c_cc[VEOL2]))))) {
20037c478bd9Sstevel@tonic-gate 		 */
20047c478bd9Sstevel@tonic-gate 		/*
20057c478bd9Sstevel@tonic-gate 		 * It's a line-termination character; send the line
20067c478bd9Sstevel@tonic-gate 		 * up the stream.
20077c478bd9Sstevel@tonic-gate 		 */
20087c478bd9Sstevel@tonic-gate 		bpt->b_datap->db_type = M_DATA;
20097c478bd9Sstevel@tonic-gate 		ldterm_msg_upstream(q, tp);
20107c478bd9Sstevel@tonic-gate 		if (tp->t_state & TS_MEUC) {
20117c478bd9Sstevel@tonic-gate 			ASSERT(tp->t_eucp_mp);
20127c478bd9Sstevel@tonic-gate 			tp->t_eucp = tp->t_eucp_mp->b_rptr;
20137c478bd9Sstevel@tonic-gate 		}
20147c478bd9Sstevel@tonic-gate 		if ((bpt = newmsg(tp)) == NULL)
20157c478bd9Sstevel@tonic-gate 			goto out;
20167c478bd9Sstevel@tonic-gate 	} else {
20177c478bd9Sstevel@tonic-gate 		/*
20187c478bd9Sstevel@tonic-gate 		 * Character was escaped with LNEXT.
20197c478bd9Sstevel@tonic-gate 		 */
20207c478bd9Sstevel@tonic-gate 		if (tp->t_rocount++ == 0)
20217c478bd9Sstevel@tonic-gate 			tp->t_rocol = tp->t_col;
20227c478bd9Sstevel@tonic-gate 		tp->t_state &= ~(TS_SLNCH|TS_QUOT);
20237c478bd9Sstevel@tonic-gate 		/*
20247c478bd9Sstevel@tonic-gate 		 * If the current character is a single byte and single
20257c478bd9Sstevel@tonic-gate 		 * column character and it is the backslash character and
20267c478bd9Sstevel@tonic-gate 		 * IEXTEN, then the state will have TS_QUOT.
20277c478bd9Sstevel@tonic-gate 		 */
20287c478bd9Sstevel@tonic-gate 		if ((c == '\\') && (tp->t_modes.c_lflag & IEXTEN) &&
20297c478bd9Sstevel@tonic-gate 		    (!(tp->t_state & TS_MEUC) ||
20307c478bd9Sstevel@tonic-gate 		    ((tp->t_state & TS_MEUC) && (!tp->t_eucleft))))
20317c478bd9Sstevel@tonic-gate 			tp->t_state |= TS_QUOT;
20327c478bd9Sstevel@tonic-gate 	}
20337c478bd9Sstevel@tonic-gate 
20347c478bd9Sstevel@tonic-gate 	/*
20357c478bd9Sstevel@tonic-gate 	 * Echo it.
20367c478bd9Sstevel@tonic-gate 	 */
20377c478bd9Sstevel@tonic-gate 	if (tp->t_state & TS_ERASE) {
20387c478bd9Sstevel@tonic-gate 		tp->t_state &= ~TS_ERASE;
20397c478bd9Sstevel@tonic-gate 		if (tp->t_modes.c_lflag & ECHO)
20407c478bd9Sstevel@tonic-gate 			ldterm_outchar('/', wrq, ebsize, tp);
20417c478bd9Sstevel@tonic-gate 	}
20427c478bd9Sstevel@tonic-gate 	if (tp->t_modes.c_lflag & ECHO)
20437c478bd9Sstevel@tonic-gate 		(void) ldterm_echo(c, wrq, ebsize, tp);
20447c478bd9Sstevel@tonic-gate 	else {
20457c478bd9Sstevel@tonic-gate 		/*
20467c478bd9Sstevel@tonic-gate 		 * Echo NL when ECHO turned off, if ECHONL flag is
20477c478bd9Sstevel@tonic-gate 		 * set.
20487c478bd9Sstevel@tonic-gate 		 */
20497c478bd9Sstevel@tonic-gate 		if (c == '\n' && (tp->t_modes.c_lflag & ECHONL))
20507c478bd9Sstevel@tonic-gate 			ldterm_outchar(c, wrq, ebsize, tp);
20517c478bd9Sstevel@tonic-gate 	}
20527c478bd9Sstevel@tonic-gate 
20537c478bd9Sstevel@tonic-gate out:
20547c478bd9Sstevel@tonic-gate 
20557c478bd9Sstevel@tonic-gate 	return (bpt);
20567c478bd9Sstevel@tonic-gate }
20577c478bd9Sstevel@tonic-gate 
20587c478bd9Sstevel@tonic-gate 
20597c478bd9Sstevel@tonic-gate static int
20607c478bd9Sstevel@tonic-gate ldterm_unget(ldtermstd_state_t *tp)
20617c478bd9Sstevel@tonic-gate {
20627c478bd9Sstevel@tonic-gate 	mblk_t *bpt;
20637c478bd9Sstevel@tonic-gate 
20647c478bd9Sstevel@tonic-gate 	if ((bpt = tp->t_endmsg) == NULL)
20657c478bd9Sstevel@tonic-gate 		return (-1);	/* no buffers */
20667c478bd9Sstevel@tonic-gate 	if (bpt->b_rptr == bpt->b_wptr)
20677c478bd9Sstevel@tonic-gate 		return (-1);	/* zero-length record */
20687c478bd9Sstevel@tonic-gate 	tp->t_msglen--;		/* one fewer character */
20697c478bd9Sstevel@tonic-gate 	return (*--bpt->b_wptr);
20707c478bd9Sstevel@tonic-gate }
20717c478bd9Sstevel@tonic-gate 
20727c478bd9Sstevel@tonic-gate 
20737c478bd9Sstevel@tonic-gate static void
20747c478bd9Sstevel@tonic-gate ldterm_trim(ldtermstd_state_t *tp)
20757c478bd9Sstevel@tonic-gate {
20767c478bd9Sstevel@tonic-gate 	mblk_t *bpt;
20777c478bd9Sstevel@tonic-gate 	mblk_t *bp;
20787c478bd9Sstevel@tonic-gate 
20797c478bd9Sstevel@tonic-gate 	ASSERT(tp->t_endmsg);
20807c478bd9Sstevel@tonic-gate 	bpt = tp->t_endmsg;
20817c478bd9Sstevel@tonic-gate 
20827c478bd9Sstevel@tonic-gate 	if (bpt->b_rptr == bpt->b_wptr) {
20837c478bd9Sstevel@tonic-gate 		/*
20847c478bd9Sstevel@tonic-gate 		 * This mblk is now empty. Find the previous mblk;
20857c478bd9Sstevel@tonic-gate 		 * throw this one away, unless it's the first one.
20867c478bd9Sstevel@tonic-gate 		 */
20877c478bd9Sstevel@tonic-gate 		bp = tp->t_message;
20887c478bd9Sstevel@tonic-gate 		if (bp != bpt) {
20897c478bd9Sstevel@tonic-gate 			while (bp->b_cont != bpt) {
20907c478bd9Sstevel@tonic-gate 				ASSERT(bp->b_cont);
20917c478bd9Sstevel@tonic-gate 				bp = bp->b_cont;
20927c478bd9Sstevel@tonic-gate 			}
20937c478bd9Sstevel@tonic-gate 			bp->b_cont = NULL;
20947c478bd9Sstevel@tonic-gate 			freeb(bpt);
20957c478bd9Sstevel@tonic-gate 			tp->t_endmsg = bp;	/* point to that mblk */
20967c478bd9Sstevel@tonic-gate 		}
20977c478bd9Sstevel@tonic-gate 	}
20987c478bd9Sstevel@tonic-gate }
20997c478bd9Sstevel@tonic-gate 
21007c478bd9Sstevel@tonic-gate 
21017c478bd9Sstevel@tonic-gate /*
21027c478bd9Sstevel@tonic-gate  * Rubout one character from the current line being built for tp as
21037c478bd9Sstevel@tonic-gate  * cleanly as possible.  q is the write queue for tp. Most of this
21047c478bd9Sstevel@tonic-gate  * can't be applied to multi-byte processing.  We do our own thing
21057c478bd9Sstevel@tonic-gate  * for that... See the "ldterm_eucerase" routine.  We never call
21067c478bd9Sstevel@tonic-gate  * ldterm_rubout on a multi-byte or multi-column character.
21077c478bd9Sstevel@tonic-gate  */
21087c478bd9Sstevel@tonic-gate static void
21097c478bd9Sstevel@tonic-gate ldterm_rubout(uchar_t c, queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
21107c478bd9Sstevel@tonic-gate {
21117c478bd9Sstevel@tonic-gate 	int tabcols;
21127c478bd9Sstevel@tonic-gate 	static unsigned char crtrubout[] = "\b \b\b \b";
21137c478bd9Sstevel@tonic-gate #define	RUBOUT1	&crtrubout[3]	/* rub out one position */
21147c478bd9Sstevel@tonic-gate #define	RUBOUT2	&crtrubout[0]	/* rub out two positions */
21157c478bd9Sstevel@tonic-gate 
21167c478bd9Sstevel@tonic-gate 	if (!(tp->t_modes.c_lflag & ECHO))
21177c478bd9Sstevel@tonic-gate 		return;
21187c478bd9Sstevel@tonic-gate 	if (tp->t_modes.c_lflag & ECHOE) {
21197c478bd9Sstevel@tonic-gate 		/*
21207c478bd9Sstevel@tonic-gate 		 * "CRT rubout"; try erasing it from the screen.
21217c478bd9Sstevel@tonic-gate 		 */
21227c478bd9Sstevel@tonic-gate 		if (tp->t_rocount == 0) {
21237c478bd9Sstevel@tonic-gate 			/*
21247c478bd9Sstevel@tonic-gate 			 * After the character being erased was
21257c478bd9Sstevel@tonic-gate 			 * echoed, some data was written to the
21267c478bd9Sstevel@tonic-gate 			 * terminal; we can't erase it cleanly, so we
21277c478bd9Sstevel@tonic-gate 			 * just reprint the whole line as if the user
21287c478bd9Sstevel@tonic-gate 			 * had typed the reprint character.
21297c478bd9Sstevel@tonic-gate 			 */
21307c478bd9Sstevel@tonic-gate 			ldterm_reprint(q, ebsize, tp);
21317c478bd9Sstevel@tonic-gate 			return;
21327c478bd9Sstevel@tonic-gate 		} else {
21337c478bd9Sstevel@tonic-gate 			/*
21347c478bd9Sstevel@tonic-gate 			 * XXX what about escaped characters?
21357c478bd9Sstevel@tonic-gate 			 */
21367c478bd9Sstevel@tonic-gate 			switch (typetab[c]) {
21377c478bd9Sstevel@tonic-gate 
21387c478bd9Sstevel@tonic-gate 			case ORDINARY:
21397c478bd9Sstevel@tonic-gate 				if ((tp->t_modes.c_lflag & XCASE) &&
21407c478bd9Sstevel@tonic-gate 				    omaptab[c])
21417c478bd9Sstevel@tonic-gate 					ldterm_outstring(RUBOUT1, 3, q, ebsize,
21427c478bd9Sstevel@tonic-gate 					    tp);
21437c478bd9Sstevel@tonic-gate 				ldterm_outstring(RUBOUT1, 3, q, ebsize, tp);
21447c478bd9Sstevel@tonic-gate 				break;
21457c478bd9Sstevel@tonic-gate 
21467c478bd9Sstevel@tonic-gate 			case VTAB:
21477c478bd9Sstevel@tonic-gate 			case BACKSPACE:
21487c478bd9Sstevel@tonic-gate 			case CONTROL:
21497c478bd9Sstevel@tonic-gate 			case RETURN:
21507c478bd9Sstevel@tonic-gate 			case NEWLINE:
21517c478bd9Sstevel@tonic-gate 				if ((tp->t_modes.c_lflag & ECHOCTL) &&
21527c478bd9Sstevel@tonic-gate 				    (tp->t_modes.c_lflag & IEXTEN))
21537c478bd9Sstevel@tonic-gate 					ldterm_outstring(RUBOUT2, 6, q, ebsize,
21547c478bd9Sstevel@tonic-gate 					    tp);
21557c478bd9Sstevel@tonic-gate 				break;
21567c478bd9Sstevel@tonic-gate 
21577c478bd9Sstevel@tonic-gate 			case TAB:
21587c478bd9Sstevel@tonic-gate 				if (tp->t_rocount < tp->t_msglen) {
21597c478bd9Sstevel@tonic-gate 					/*
21607c478bd9Sstevel@tonic-gate 					 * While the tab being erased was
21617c478bd9Sstevel@tonic-gate 					 * expanded, some data was written
21627c478bd9Sstevel@tonic-gate 					 * to the terminal; we can't erase
21637c478bd9Sstevel@tonic-gate 					 * it cleanly, so we just reprint
21647c478bd9Sstevel@tonic-gate 					 * the whole line as if the user
21657c478bd9Sstevel@tonic-gate 					 * had typed the reprint character.
21667c478bd9Sstevel@tonic-gate 					 */
21677c478bd9Sstevel@tonic-gate 					ldterm_reprint(q, ebsize, tp);
21687c478bd9Sstevel@tonic-gate 					return;
21697c478bd9Sstevel@tonic-gate 				}
21707c478bd9Sstevel@tonic-gate 				tabcols = ldterm_tabcols(tp);
21717c478bd9Sstevel@tonic-gate 				while (--tabcols >= 0)
21727c478bd9Sstevel@tonic-gate 					ldterm_outchar('\b', q, ebsize, tp);
21737c478bd9Sstevel@tonic-gate 				break;
21747c478bd9Sstevel@tonic-gate 			}
21757c478bd9Sstevel@tonic-gate 		}
21767c478bd9Sstevel@tonic-gate 	} else if ((tp->t_modes.c_lflag & ECHOPRT) &&
21777c478bd9Sstevel@tonic-gate 	    (tp->t_modes.c_lflag & IEXTEN)) {
21787c478bd9Sstevel@tonic-gate 		/*
21797c478bd9Sstevel@tonic-gate 		 * "Printing rubout"; echo it between \ and /.
21807c478bd9Sstevel@tonic-gate 		 */
21817c478bd9Sstevel@tonic-gate 		if (!(tp->t_state & TS_ERASE)) {
21827c478bd9Sstevel@tonic-gate 			ldterm_outchar('\\', q, ebsize, tp);
21837c478bd9Sstevel@tonic-gate 			tp->t_state |= TS_ERASE;
21847c478bd9Sstevel@tonic-gate 		}
21857c478bd9Sstevel@tonic-gate 		(void) ldterm_echo(c, q, ebsize, tp);
21867c478bd9Sstevel@tonic-gate 	} else
21877c478bd9Sstevel@tonic-gate 		(void) ldterm_echo(tp->t_modes.c_cc[VERASE], q, ebsize, tp);
21887c478bd9Sstevel@tonic-gate 	tp->t_rocount--;	/* we "unechoed" this character */
21897c478bd9Sstevel@tonic-gate }
21907c478bd9Sstevel@tonic-gate 
21917c478bd9Sstevel@tonic-gate 
21927c478bd9Sstevel@tonic-gate /*
21937c478bd9Sstevel@tonic-gate  * Find the number of characters the tab we just deleted took up by
21947c478bd9Sstevel@tonic-gate  * zipping through the current line and recomputing the column
21957c478bd9Sstevel@tonic-gate  * number.
21967c478bd9Sstevel@tonic-gate  */
21977c478bd9Sstevel@tonic-gate static int
21987c478bd9Sstevel@tonic-gate ldterm_tabcols(ldtermstd_state_t *tp)
21997c478bd9Sstevel@tonic-gate {
22007c478bd9Sstevel@tonic-gate 	int col;
22017c478bd9Sstevel@tonic-gate 	int i;
22027c478bd9Sstevel@tonic-gate 	mblk_t *bp;
22037c478bd9Sstevel@tonic-gate 	unsigned char *readp, *endp;
22047c478bd9Sstevel@tonic-gate 	unsigned char c;
22057c478bd9Sstevel@tonic-gate 	uchar_t *startp;
22067c478bd9Sstevel@tonic-gate 	char errflg;
22077c478bd9Sstevel@tonic-gate 	uchar_t u8[LDTERM_CS_MAX_BYTE_LENGTH];
22087c478bd9Sstevel@tonic-gate 
22097c478bd9Sstevel@tonic-gate 	col = tp->t_rocol;
22107c478bd9Sstevel@tonic-gate 	/*
22117c478bd9Sstevel@tonic-gate 	 * If we're doing multi-byte stuff, zip through the list of
22127c478bd9Sstevel@tonic-gate 	 * widths to figure out where we are (we've kept track in most
22137c478bd9Sstevel@tonic-gate 	 * cases).
22147c478bd9Sstevel@tonic-gate 	 */
22157c478bd9Sstevel@tonic-gate 	if (tp->t_state & TS_MEUC) {
22167c478bd9Sstevel@tonic-gate 		ASSERT(tp->t_eucp_mp);
22177c478bd9Sstevel@tonic-gate 		bp = tp->t_message;
22187c478bd9Sstevel@tonic-gate 		startp = bp->b_datap->db_base;
22197c478bd9Sstevel@tonic-gate 		readp = tp->t_eucp_mp->b_rptr;
22207c478bd9Sstevel@tonic-gate 		endp = tp->t_eucp;
22217c478bd9Sstevel@tonic-gate 		errflg = (char)0;
22227c478bd9Sstevel@tonic-gate 		while (readp < endp) {
22237c478bd9Sstevel@tonic-gate 			switch (*readp) {
22247c478bd9Sstevel@tonic-gate 			case EUC_TWIDTH:	/* it's a tab */
22257c478bd9Sstevel@tonic-gate 				col |= 07;	/* bump up */
22267c478bd9Sstevel@tonic-gate 				col++;
22277c478bd9Sstevel@tonic-gate 				break;
22287c478bd9Sstevel@tonic-gate 			case EUC_BSWIDTH:	/* backspace */
22297c478bd9Sstevel@tonic-gate 				if (col)
22307c478bd9Sstevel@tonic-gate 					col--;
22317c478bd9Sstevel@tonic-gate 				break;
22327c478bd9Sstevel@tonic-gate 			case EUC_NLWIDTH:	/* newline */
22337c478bd9Sstevel@tonic-gate 				if (tp->t_modes.c_oflag & ONLRET)
22347c478bd9Sstevel@tonic-gate 					col = 0;
22357c478bd9Sstevel@tonic-gate 				break;
22367c478bd9Sstevel@tonic-gate 			case EUC_CRWIDTH:	/* return */
22377c478bd9Sstevel@tonic-gate 				col = 0;
22387c478bd9Sstevel@tonic-gate 				break;
22397c478bd9Sstevel@tonic-gate 			case UNKNOWN_WIDTH:	/* UTF-8 unknown width */
22407c478bd9Sstevel@tonic-gate 				if (tp->t_csdata.codeset_type !=
22417c478bd9Sstevel@tonic-gate 				    LDTERM_CS_TYPE_UTF8 || errflg) {
22427c478bd9Sstevel@tonic-gate 					*readp = 1;
22437c478bd9Sstevel@tonic-gate 					col++;
22447c478bd9Sstevel@tonic-gate 					break;
22457c478bd9Sstevel@tonic-gate 				}
22467c478bd9Sstevel@tonic-gate 				/*
22477c478bd9Sstevel@tonic-gate 				 * Collect the current UTF-8 character bytes
22487c478bd9Sstevel@tonic-gate 				 * from (possibly multiple) data buffers so
22497c478bd9Sstevel@tonic-gate 				 * that we can figure out the display width.
22507c478bd9Sstevel@tonic-gate 				 */
22517c478bd9Sstevel@tonic-gate 				u8[0] = *startp;
22527c478bd9Sstevel@tonic-gate 				for (i = 1; (i < LDTERM_CS_MAX_BYTE_LENGTH) &&
225385bb5f1dSis 				    (*(readp + i) == 0); i++) {
22547c478bd9Sstevel@tonic-gate 					startp++;
22557c478bd9Sstevel@tonic-gate 					if (startp >= bp->b_datap->db_lim) {
22567c478bd9Sstevel@tonic-gate 						if (bp->b_cont) {
22577c478bd9Sstevel@tonic-gate 							bp = bp->b_cont;
22587c478bd9Sstevel@tonic-gate 							startp =
225985bb5f1dSis 							    bp->b_datap->
226085bb5f1dSis 							    db_base;
22617c478bd9Sstevel@tonic-gate 						} else {
22627c478bd9Sstevel@tonic-gate 							*readp = 1;
22637c478bd9Sstevel@tonic-gate 							col++;
22647c478bd9Sstevel@tonic-gate 							break;
22657c478bd9Sstevel@tonic-gate 						}
22667c478bd9Sstevel@tonic-gate 					}
22677c478bd9Sstevel@tonic-gate 					u8[i] = *startp;
22687c478bd9Sstevel@tonic-gate 				}
22697c478bd9Sstevel@tonic-gate 
22707c478bd9Sstevel@tonic-gate 				/* tp->t_eucp_mp contains wrong info?? */
22717c478bd9Sstevel@tonic-gate 				if (*readp == 1)
22727c478bd9Sstevel@tonic-gate 					break;
22737c478bd9Sstevel@tonic-gate 
22747c478bd9Sstevel@tonic-gate 				*readp = ldterm_utf8_width(u8, i);
22757c478bd9Sstevel@tonic-gate 
22767c478bd9Sstevel@tonic-gate 				col += *readp;
22777c478bd9Sstevel@tonic-gate 				readp += (i - 1);
22787c478bd9Sstevel@tonic-gate 				break;
22797c478bd9Sstevel@tonic-gate 			default:
22807c478bd9Sstevel@tonic-gate 				col += *readp;
22817c478bd9Sstevel@tonic-gate 				break;
22827c478bd9Sstevel@tonic-gate 			}
22837c478bd9Sstevel@tonic-gate 			++readp;
22847c478bd9Sstevel@tonic-gate 			++startp;
22857c478bd9Sstevel@tonic-gate 			if (startp >= bp->b_datap->db_lim) {
22867c478bd9Sstevel@tonic-gate 				if (bp->b_cont) {
22877c478bd9Sstevel@tonic-gate 					bp = bp->b_cont;
22887c478bd9Sstevel@tonic-gate 					startp = bp->b_datap->db_base;
22897c478bd9Sstevel@tonic-gate 				} else {
22907c478bd9Sstevel@tonic-gate 					/*
22917c478bd9Sstevel@tonic-gate 					 * This will happen only if
22927c478bd9Sstevel@tonic-gate 					 * tp->t_eucp_mp contains wrong
22937c478bd9Sstevel@tonic-gate 					 * display width info.
22947c478bd9Sstevel@tonic-gate 					 */
22957c478bd9Sstevel@tonic-gate 					errflg = (char)1;
22967c478bd9Sstevel@tonic-gate 					startp--;
22977c478bd9Sstevel@tonic-gate 				}
22987c478bd9Sstevel@tonic-gate 			}
22997c478bd9Sstevel@tonic-gate 		}
23007c478bd9Sstevel@tonic-gate 		goto eucout;	/* finished! */
23017c478bd9Sstevel@tonic-gate 	}
23027c478bd9Sstevel@tonic-gate 	bp = tp->t_message;
23037c478bd9Sstevel@tonic-gate 	do {
23047c478bd9Sstevel@tonic-gate 		readp = bp->b_rptr;
23057c478bd9Sstevel@tonic-gate 		while (readp < bp->b_wptr) {
23067c478bd9Sstevel@tonic-gate 			c = *readp++;
23077c478bd9Sstevel@tonic-gate 			if ((tp->t_modes.c_lflag & ECHOCTL) &&
23087c478bd9Sstevel@tonic-gate 			    (tp->t_modes.c_lflag & IEXTEN)) {
23097c478bd9Sstevel@tonic-gate 				if (c <= 037 && c != '\t' && c != '\n' ||
23107c478bd9Sstevel@tonic-gate 				    c == 0177) {
23117c478bd9Sstevel@tonic-gate 					col += 2;
23127c478bd9Sstevel@tonic-gate 					continue;
23137c478bd9Sstevel@tonic-gate 				}
23147c478bd9Sstevel@tonic-gate 			}
23157c478bd9Sstevel@tonic-gate 			/*
23167c478bd9Sstevel@tonic-gate 			 * Column position calculated here.
23177c478bd9Sstevel@tonic-gate 			 */
23187c478bd9Sstevel@tonic-gate 			switch (typetab[c]) {
23197c478bd9Sstevel@tonic-gate 
23207c478bd9Sstevel@tonic-gate 				/*
23217c478bd9Sstevel@tonic-gate 				 * Ordinary characters; advance by
23227c478bd9Sstevel@tonic-gate 				 * one.
23237c478bd9Sstevel@tonic-gate 				 */
23247c478bd9Sstevel@tonic-gate 			case ORDINARY:
23257c478bd9Sstevel@tonic-gate 				col++;
23267c478bd9Sstevel@tonic-gate 				break;
23277c478bd9Sstevel@tonic-gate 
23287c478bd9Sstevel@tonic-gate 				/*
23297c478bd9Sstevel@tonic-gate 				 * Non-printing characters; nothing
23307c478bd9Sstevel@tonic-gate 				 * happens.
23317c478bd9Sstevel@tonic-gate 				 */
23327c478bd9Sstevel@tonic-gate 			case CONTROL:
23337c478bd9Sstevel@tonic-gate 				break;
23347c478bd9Sstevel@tonic-gate 
23357c478bd9Sstevel@tonic-gate 				/* Backspace */
23367c478bd9Sstevel@tonic-gate 			case BACKSPACE:
23377c478bd9Sstevel@tonic-gate 				if (col != 0)
23387c478bd9Sstevel@tonic-gate 					col--;
23397c478bd9Sstevel@tonic-gate 				break;
23407c478bd9Sstevel@tonic-gate 
23417c478bd9Sstevel@tonic-gate 				/* Newline; column depends on flags. */
23427c478bd9Sstevel@tonic-gate 			case NEWLINE:
23437c478bd9Sstevel@tonic-gate 				if (tp->t_modes.c_oflag & ONLRET)
23447c478bd9Sstevel@tonic-gate 					col = 0;
23457c478bd9Sstevel@tonic-gate 				break;
23467c478bd9Sstevel@tonic-gate 
23477c478bd9Sstevel@tonic-gate 				/* tab */
23487c478bd9Sstevel@tonic-gate 			case TAB:
23497c478bd9Sstevel@tonic-gate 				col |= 07;
23507c478bd9Sstevel@tonic-gate 				col++;
23517c478bd9Sstevel@tonic-gate 				break;
23527c478bd9Sstevel@tonic-gate 
23537c478bd9Sstevel@tonic-gate 				/* vertical motion */
23547c478bd9Sstevel@tonic-gate 			case VTAB:
23557c478bd9Sstevel@tonic-gate 				break;
23567c478bd9Sstevel@tonic-gate 
23577c478bd9Sstevel@tonic-gate 				/* carriage return */
23587c478bd9Sstevel@tonic-gate 			case RETURN:
23597c478bd9Sstevel@tonic-gate 				col = 0;
23607c478bd9Sstevel@tonic-gate 				break;
23617c478bd9Sstevel@tonic-gate 			}
23627c478bd9Sstevel@tonic-gate 		}
23637c478bd9Sstevel@tonic-gate 	} while ((bp = bp->b_cont) != NULL);	/* next block, if any */
23647c478bd9Sstevel@tonic-gate 
23657c478bd9Sstevel@tonic-gate 	/*
23667c478bd9Sstevel@tonic-gate 	 * "col" is now the column number before the tab. "tp->t_col"
23677c478bd9Sstevel@tonic-gate 	 * is still the column number after the tab, since we haven't
23687c478bd9Sstevel@tonic-gate 	 * erased the tab yet. Thus "tp->t_col - col" is the number
23697c478bd9Sstevel@tonic-gate 	 * of positions the tab moved.
23707c478bd9Sstevel@tonic-gate 	 */
23717c478bd9Sstevel@tonic-gate eucout:
23727c478bd9Sstevel@tonic-gate 	col = tp->t_col - col;
23737c478bd9Sstevel@tonic-gate 	if (col > 8)
23747c478bd9Sstevel@tonic-gate 		col = 8;	/* overflow screw */
23757c478bd9Sstevel@tonic-gate 	return (col);
23767c478bd9Sstevel@tonic-gate }
23777c478bd9Sstevel@tonic-gate 
23787c478bd9Sstevel@tonic-gate 
23797c478bd9Sstevel@tonic-gate /*
23807c478bd9Sstevel@tonic-gate  * Erase a single character; We ONLY ONLY deal with ASCII or
23817c478bd9Sstevel@tonic-gate  * single-column single-byte codeset character.  For multi-byte characters,
23827c478bd9Sstevel@tonic-gate  * see "ldterm_csi_erase".
23837c478bd9Sstevel@tonic-gate  */
23847c478bd9Sstevel@tonic-gate static void
23857c478bd9Sstevel@tonic-gate ldterm_erase(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
23867c478bd9Sstevel@tonic-gate {
23877c478bd9Sstevel@tonic-gate 	int c;
23887c478bd9Sstevel@tonic-gate 
23897c478bd9Sstevel@tonic-gate 	if ((c = ldterm_unget(tp)) != -1) {
23907c478bd9Sstevel@tonic-gate 		ldterm_rubout((unsigned char) c, q, ebsize, tp);
23917c478bd9Sstevel@tonic-gate 		ldterm_trim(tp);
23927c478bd9Sstevel@tonic-gate 		if (tp->t_state & TS_MEUC)
23937c478bd9Sstevel@tonic-gate 			--tp->t_eucp;
23947c478bd9Sstevel@tonic-gate 	}
23957c478bd9Sstevel@tonic-gate }
23967c478bd9Sstevel@tonic-gate 
23977c478bd9Sstevel@tonic-gate 
23987c478bd9Sstevel@tonic-gate /*
23997c478bd9Sstevel@tonic-gate  * Erase an entire word, single-byte EUC only please.
24007c478bd9Sstevel@tonic-gate  */
24017c478bd9Sstevel@tonic-gate static void
24027c478bd9Sstevel@tonic-gate ldterm_werase(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
24037c478bd9Sstevel@tonic-gate {
24047c478bd9Sstevel@tonic-gate 	int c;
24057c478bd9Sstevel@tonic-gate 
24067c478bd9Sstevel@tonic-gate 	/*
24077c478bd9Sstevel@tonic-gate 	 * Erase trailing white space, if any.
24087c478bd9Sstevel@tonic-gate 	 */
24097c478bd9Sstevel@tonic-gate 	while ((c = ldterm_unget(tp)) == ' ' || c == '\t') {
24107c478bd9Sstevel@tonic-gate 		ldterm_rubout((unsigned char) c, q, ebsize, tp);
24117c478bd9Sstevel@tonic-gate 		ldterm_trim(tp);
24127c478bd9Sstevel@tonic-gate 	}
24137c478bd9Sstevel@tonic-gate 
24147c478bd9Sstevel@tonic-gate 	/*
24157c478bd9Sstevel@tonic-gate 	 * Erase non-white-space characters, if any.
24167c478bd9Sstevel@tonic-gate 	 */
24177c478bd9Sstevel@tonic-gate 	while (c != -1 && c != ' ' && c != '\t') {
24187c478bd9Sstevel@tonic-gate 		ldterm_rubout((unsigned char) c, q, ebsize, tp);
24197c478bd9Sstevel@tonic-gate 		ldterm_trim(tp);
24207c478bd9Sstevel@tonic-gate 		c = ldterm_unget(tp);
24217c478bd9Sstevel@tonic-gate 	}
24227c478bd9Sstevel@tonic-gate 	if (c != -1) {
24237c478bd9Sstevel@tonic-gate 		/*
24247c478bd9Sstevel@tonic-gate 		 * We removed one too many characters; put the last
24257c478bd9Sstevel@tonic-gate 		 * one back.
24267c478bd9Sstevel@tonic-gate 		 */
24277c478bd9Sstevel@tonic-gate 		tp->t_endmsg->b_wptr++;	/* put 'c' back */
24287c478bd9Sstevel@tonic-gate 		tp->t_msglen++;
24297c478bd9Sstevel@tonic-gate 	}
24307c478bd9Sstevel@tonic-gate }
24317c478bd9Sstevel@tonic-gate 
24327c478bd9Sstevel@tonic-gate 
24337c478bd9Sstevel@tonic-gate /*
24347c478bd9Sstevel@tonic-gate  * ldterm_csi_werase - This is multi-byte equivalent of "word erase".
24357c478bd9Sstevel@tonic-gate  * "Word erase" only makes sense in languages which space between words,
24367c478bd9Sstevel@tonic-gate  * and it's presumptuous for us to attempt "word erase" when we don't
24377c478bd9Sstevel@tonic-gate  * know anything about what's really going on.  It makes no sense for
24387c478bd9Sstevel@tonic-gate  * many languages, as the criteria for defining words and tokens may
24397c478bd9Sstevel@tonic-gate  * be completely different.
24407c478bd9Sstevel@tonic-gate  *
24417c478bd9Sstevel@tonic-gate  * In the TS_MEUC case (which is how we got here), we define a token to
24427c478bd9Sstevel@tonic-gate  * be space- or tab-delimited, and erase one of them.  It helps to
24437c478bd9Sstevel@tonic-gate  * have this for command lines, but it's otherwise useless for text
24447c478bd9Sstevel@tonic-gate  * editing applications; you need more sophistication than we can
24457c478bd9Sstevel@tonic-gate  * provide here.
24467c478bd9Sstevel@tonic-gate  */
24477c478bd9Sstevel@tonic-gate static void
24487c478bd9Sstevel@tonic-gate ldterm_csi_werase(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
24497c478bd9Sstevel@tonic-gate {
24507c478bd9Sstevel@tonic-gate 	int c, i;
24517c478bd9Sstevel@tonic-gate 	int len;
24527c478bd9Sstevel@tonic-gate 	uchar_t *ip;
24537c478bd9Sstevel@tonic-gate 	uchar_t	u8[LDTERM_CS_MAX_BYTE_LENGTH];
24547c478bd9Sstevel@tonic-gate 	uchar_t	u8_2[LDTERM_CS_MAX_BYTE_LENGTH];
24557c478bd9Sstevel@tonic-gate 
24567c478bd9Sstevel@tonic-gate 	/*
24577c478bd9Sstevel@tonic-gate 	 * ip points to the width of the actual bytes.  t_eucp points
24587c478bd9Sstevel@tonic-gate 	 * one byte beyond, where the next thing will be inserted.
24597c478bd9Sstevel@tonic-gate 	 */
24607c478bd9Sstevel@tonic-gate 	ip = tp->t_eucp - 1;
24617c478bd9Sstevel@tonic-gate 	/*
24627c478bd9Sstevel@tonic-gate 	 * Erase trailing white space, if any.
24637c478bd9Sstevel@tonic-gate 	 */
24647c478bd9Sstevel@tonic-gate 	while ((c = ldterm_unget(tp)) == ' ' || c == '\t') {
24657c478bd9Sstevel@tonic-gate 		tp->t_eucp--;
24667c478bd9Sstevel@tonic-gate 		ldterm_rubout((unsigned char) c, q, ebsize, tp);
24677c478bd9Sstevel@tonic-gate 		ldterm_trim(tp);
24687c478bd9Sstevel@tonic-gate 		--ip;
24697c478bd9Sstevel@tonic-gate 	}
24707c478bd9Sstevel@tonic-gate 
24717c478bd9Sstevel@tonic-gate 	/*
24727c478bd9Sstevel@tonic-gate 	 * Erase non-white-space characters, if any.  The outer loop
24737c478bd9Sstevel@tonic-gate 	 * bops through each byte in the buffer. Multi-byte is removed, as
24747c478bd9Sstevel@tonic-gate 	 * is ASCII, one byte at a time. The inner loop (for) is only
24757c478bd9Sstevel@tonic-gate 	 * executed for first bytes of multi-byte.  The inner loop erases
24767c478bd9Sstevel@tonic-gate 	 * the number of columns required for the multi-byte char.  We check
24777c478bd9Sstevel@tonic-gate 	 * for ASCII first, and ldterm_rubout knows about ASCII.
24787c478bd9Sstevel@tonic-gate 	 */
24797c478bd9Sstevel@tonic-gate 	len = 0;
24807c478bd9Sstevel@tonic-gate 	while (c != -1 && c != ' ' && c != '\t') {
24817c478bd9Sstevel@tonic-gate 		tp->t_eucp--;
24827c478bd9Sstevel@tonic-gate 		if (len < LDTERM_CS_MAX_BYTE_LENGTH) {
24837c478bd9Sstevel@tonic-gate 			u8[len++] = (uchar_t)c;
24847c478bd9Sstevel@tonic-gate 		}
24857c478bd9Sstevel@tonic-gate 		/*
24867c478bd9Sstevel@tonic-gate 		 * Unlike EUC, except the leading byte, some bytes of
24877c478bd9Sstevel@tonic-gate 		 * a non-EUC multi-byte characters are in the ASCII code
24887c478bd9Sstevel@tonic-gate 		 * range, esp., 0x41 ~ 0x7a. Thus, we cannot simply check
24897c478bd9Sstevel@tonic-gate 		 * ISASCII().
24907c478bd9Sstevel@tonic-gate 		 * Checking the (*ip == 1 || *ip == 2 || *ip > UNKNOWN_WIDTH)
24917c478bd9Sstevel@tonic-gate 		 * will ensure that it is a single byte character (even though
24927c478bd9Sstevel@tonic-gate 		 * it is on display width not byte length) and can be further
24937c478bd9Sstevel@tonic-gate 		 * checked whether it is an ASCII character or not.
24947c478bd9Sstevel@tonic-gate 		 *
24957c478bd9Sstevel@tonic-gate 		 * When ECHOCTL is on and 'c' is an ASCII control character,
24967c478bd9Sstevel@tonic-gate 		 * *ip == 2 happens.
24977c478bd9Sstevel@tonic-gate 		 */
24987c478bd9Sstevel@tonic-gate 		if ((*ip == 1 || *ip == 2 || *ip > UNKNOWN_WIDTH) &&
24997c478bd9Sstevel@tonic-gate 		    ISASCII(c)) {
25007c478bd9Sstevel@tonic-gate 			ldterm_rubout((unsigned char) c, q, ebsize, tp);
25017c478bd9Sstevel@tonic-gate 			len = 0;
25027c478bd9Sstevel@tonic-gate 		} else if (*ip) {
25037c478bd9Sstevel@tonic-gate 			if (*ip == UNKNOWN_WIDTH) {
25047c478bd9Sstevel@tonic-gate 				if (tp->t_csdata.codeset_type ==
25057c478bd9Sstevel@tonic-gate 				    LDTERM_CS_TYPE_UTF8) {
25067c478bd9Sstevel@tonic-gate 					for (i = 0; i < len; i++)
25077c478bd9Sstevel@tonic-gate 						u8_2[i] = u8[len - i - 1];
25087c478bd9Sstevel@tonic-gate 					*ip = ldterm_utf8_width(u8_2, len);
25097c478bd9Sstevel@tonic-gate 				} else {
25107c478bd9Sstevel@tonic-gate 					*ip = 1;
25117c478bd9Sstevel@tonic-gate 				}
25127c478bd9Sstevel@tonic-gate 			}
25137c478bd9Sstevel@tonic-gate 			/*
25147c478bd9Sstevel@tonic-gate 			 * erase for number of columns required for
25157c478bd9Sstevel@tonic-gate 			 * this multi-byte character. Hopefully, matches
25167c478bd9Sstevel@tonic-gate 			 * ldterm_dispwidth!
25177c478bd9Sstevel@tonic-gate 			 */
25187c478bd9Sstevel@tonic-gate 			for (i = 0; i < (int)*ip; i++)
25197c478bd9Sstevel@tonic-gate 				ldterm_rubout(' ', q, ebsize, tp);
25207c478bd9Sstevel@tonic-gate 			len = 0;
25217c478bd9Sstevel@tonic-gate 		}
25227c478bd9Sstevel@tonic-gate 		ldterm_trim(tp);
25237c478bd9Sstevel@tonic-gate 		--ip;
25247c478bd9Sstevel@tonic-gate 		c = ldterm_unget(tp);
25257c478bd9Sstevel@tonic-gate 	}
25267c478bd9Sstevel@tonic-gate 	if (c != -1) {
25277c478bd9Sstevel@tonic-gate 		/*
25287c478bd9Sstevel@tonic-gate 		 * We removed one too many characters; put the last
25297c478bd9Sstevel@tonic-gate 		 * one back.
25307c478bd9Sstevel@tonic-gate 		 */
25317c478bd9Sstevel@tonic-gate 		tp->t_endmsg->b_wptr++;	/* put 'c' back */
25327c478bd9Sstevel@tonic-gate 		tp->t_msglen++;
25337c478bd9Sstevel@tonic-gate 	}
25347c478bd9Sstevel@tonic-gate }
25357c478bd9Sstevel@tonic-gate 
25367c478bd9Sstevel@tonic-gate 
25377c478bd9Sstevel@tonic-gate /*
25387c478bd9Sstevel@tonic-gate  * Kill an entire line, erasing each character one-by-one (if ECHOKE
25397c478bd9Sstevel@tonic-gate  * is set) or just echoing the kill character, followed by a newline
25407c478bd9Sstevel@tonic-gate  * (if ECHOK is set).  Multi-byte processing is included here.
25417c478bd9Sstevel@tonic-gate  */
25427c478bd9Sstevel@tonic-gate 
25437c478bd9Sstevel@tonic-gate static void
25447c478bd9Sstevel@tonic-gate ldterm_kill(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
25457c478bd9Sstevel@tonic-gate {
25467c478bd9Sstevel@tonic-gate 	int c, i;
25477c478bd9Sstevel@tonic-gate 	int len;
25487c478bd9Sstevel@tonic-gate 	uchar_t *ip;
25497c478bd9Sstevel@tonic-gate 	uchar_t u8[LDTERM_CS_MAX_BYTE_LENGTH];
25507c478bd9Sstevel@tonic-gate 	uchar_t u8_2[LDTERM_CS_MAX_BYTE_LENGTH];
25517c478bd9Sstevel@tonic-gate 
25527c478bd9Sstevel@tonic-gate 	if ((tp->t_modes.c_lflag & ECHOKE) &&
25537c478bd9Sstevel@tonic-gate 	    (tp->t_modes.c_lflag & IEXTEN) &&
25547c478bd9Sstevel@tonic-gate 	    (tp->t_msglen == tp->t_rocount)) {
25557c478bd9Sstevel@tonic-gate 		if (tp->t_state & TS_MEUC) {
25567c478bd9Sstevel@tonic-gate 			ip = tp->t_eucp - 1;
25577c478bd9Sstevel@tonic-gate 			/*
25587c478bd9Sstevel@tonic-gate 			 * This loop similar to "ldterm_csi_werase" above.
25597c478bd9Sstevel@tonic-gate 			 */
25607c478bd9Sstevel@tonic-gate 			len = 0;
25617c478bd9Sstevel@tonic-gate 			while ((c = ldterm_unget(tp)) != (-1)) {
25627c478bd9Sstevel@tonic-gate 				tp->t_eucp--;
25637c478bd9Sstevel@tonic-gate 				if (len < LDTERM_CS_MAX_BYTE_LENGTH) {
25647c478bd9Sstevel@tonic-gate 					u8[len++] = (uchar_t)c;
25657c478bd9Sstevel@tonic-gate 				}
25667c478bd9Sstevel@tonic-gate 				if ((*ip == 1 || *ip == 2 ||
25677c478bd9Sstevel@tonic-gate 				    *ip > UNKNOWN_WIDTH) && ISASCII(c)) {
25687c478bd9Sstevel@tonic-gate 					ldterm_rubout((unsigned char) c, q,
25697c478bd9Sstevel@tonic-gate 					    ebsize, tp);
25707c478bd9Sstevel@tonic-gate 					len = 0;
25717c478bd9Sstevel@tonic-gate 				} else if (*ip) {
25727c478bd9Sstevel@tonic-gate 					if (*ip == UNKNOWN_WIDTH) {
25737c478bd9Sstevel@tonic-gate 						if (tp->t_csdata.codeset_type
25747c478bd9Sstevel@tonic-gate 						    == LDTERM_CS_TYPE_UTF8) {
25757c478bd9Sstevel@tonic-gate 							for (i = 0; i < len;
25767c478bd9Sstevel@tonic-gate 							    i++)
25777c478bd9Sstevel@tonic-gate 								u8_2[i] =
25787c478bd9Sstevel@tonic-gate 								    u8[len-i-1];
25797c478bd9Sstevel@tonic-gate 							*ip = ldterm_utf8_width(
25807c478bd9Sstevel@tonic-gate 							    u8_2, len);
25817c478bd9Sstevel@tonic-gate 						} else {
25827c478bd9Sstevel@tonic-gate 							*ip = 1;
25837c478bd9Sstevel@tonic-gate 						}
25847c478bd9Sstevel@tonic-gate 					}
25857c478bd9Sstevel@tonic-gate 					for (i = 0; i < (int)*ip; i++)
25867c478bd9Sstevel@tonic-gate 						ldterm_rubout(' ', q, ebsize,
25877c478bd9Sstevel@tonic-gate 						    tp);
25887c478bd9Sstevel@tonic-gate 					len = 0;
25897c478bd9Sstevel@tonic-gate 				}
25907c478bd9Sstevel@tonic-gate 				ldterm_trim(tp);
25917c478bd9Sstevel@tonic-gate 				--ip;
25927c478bd9Sstevel@tonic-gate 			}
25937c478bd9Sstevel@tonic-gate 		} else {
25947c478bd9Sstevel@tonic-gate 			while ((c = ldterm_unget(tp)) != -1) {
25957c478bd9Sstevel@tonic-gate 				ldterm_rubout((unsigned char) c, q, ebsize, tp);
25967c478bd9Sstevel@tonic-gate 				ldterm_trim(tp);
25977c478bd9Sstevel@tonic-gate 			}
25987c478bd9Sstevel@tonic-gate 		}
25997c478bd9Sstevel@tonic-gate 	} else {
26007c478bd9Sstevel@tonic-gate 		(void) ldterm_echo(tp->t_modes.c_cc[VKILL], q, ebsize, tp);
26017c478bd9Sstevel@tonic-gate 		if (tp->t_modes.c_lflag & ECHOK)
26027c478bd9Sstevel@tonic-gate 			(void) ldterm_echo('\n', q, ebsize, tp);
26037c478bd9Sstevel@tonic-gate 		while (ldterm_unget(tp) != -1) {
26047c478bd9Sstevel@tonic-gate 			if (tp->t_state & TS_MEUC)
26057c478bd9Sstevel@tonic-gate 				--tp->t_eucp;
26067c478bd9Sstevel@tonic-gate 			ldterm_trim(tp);
26077c478bd9Sstevel@tonic-gate 		}
26087c478bd9Sstevel@tonic-gate 		tp->t_rocount = 0;
26097c478bd9Sstevel@tonic-gate 		if (tp->t_state & TS_MEUC)
26107c478bd9Sstevel@tonic-gate 			tp->t_eucp = tp->t_eucp_mp->b_rptr;
26117c478bd9Sstevel@tonic-gate 	}
26127c478bd9Sstevel@tonic-gate 	tp->t_state &= ~(TS_QUOT|TS_ERASE|TS_SLNCH);
26137c478bd9Sstevel@tonic-gate }
26147c478bd9Sstevel@tonic-gate 
26157c478bd9Sstevel@tonic-gate 
26167c478bd9Sstevel@tonic-gate /*
26177c478bd9Sstevel@tonic-gate  * Reprint the current input line. We assume c_cc has already been
26187c478bd9Sstevel@tonic-gate  * checked. XXX just the current line, not the whole queue? What
26197c478bd9Sstevel@tonic-gate  * about DEFECHO mode?
26207c478bd9Sstevel@tonic-gate  */
26217c478bd9Sstevel@tonic-gate static void
26227c478bd9Sstevel@tonic-gate ldterm_reprint(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
26237c478bd9Sstevel@tonic-gate {
26247c478bd9Sstevel@tonic-gate 	mblk_t *bp;
26257c478bd9Sstevel@tonic-gate 	unsigned char *readp;
26267c478bd9Sstevel@tonic-gate 
26277c478bd9Sstevel@tonic-gate 	if (tp->t_modes.c_cc[VREPRINT] != (unsigned char) 0)
26287c478bd9Sstevel@tonic-gate 		(void) ldterm_echo(tp->t_modes.c_cc[VREPRINT], q, ebsize, tp);
26297c478bd9Sstevel@tonic-gate 	ldterm_outchar('\n', q, ebsize, tp);
26307c478bd9Sstevel@tonic-gate 
26317c478bd9Sstevel@tonic-gate 	bp = tp->t_message;
26327c478bd9Sstevel@tonic-gate 	do {
26337c478bd9Sstevel@tonic-gate 		readp = bp->b_rptr;
26347c478bd9Sstevel@tonic-gate 		while (readp < bp->b_wptr)
26357c478bd9Sstevel@tonic-gate 			(void) ldterm_echo(*readp++, q, ebsize, tp);
26367c478bd9Sstevel@tonic-gate 	} while ((bp = bp->b_cont) != NULL);	/* next block, if any */
26377c478bd9Sstevel@tonic-gate 
26387c478bd9Sstevel@tonic-gate 	tp->t_state &= ~TS_ERASE;
26397c478bd9Sstevel@tonic-gate 	tp->t_rocount = tp->t_msglen;	/* we reechoed the entire line */
26407c478bd9Sstevel@tonic-gate 	tp->t_rocol = 0;
26417c478bd9Sstevel@tonic-gate }
26427c478bd9Sstevel@tonic-gate 
26437c478bd9Sstevel@tonic-gate 
26447c478bd9Sstevel@tonic-gate /*
26457c478bd9Sstevel@tonic-gate  * Non canonical processing. Called with q locked from  ldtermrsrv.
26467c478bd9Sstevel@tonic-gate  *
26477c478bd9Sstevel@tonic-gate  */
26487c478bd9Sstevel@tonic-gate static mblk_t *
26497c478bd9Sstevel@tonic-gate ldterm_dononcanon(mblk_t *bp, mblk_t *bpt, size_t ebsize, queue_t *q,
26507c478bd9Sstevel@tonic-gate     ldtermstd_state_t *tp)
26517c478bd9Sstevel@tonic-gate {
26527c478bd9Sstevel@tonic-gate 	queue_t *wrq = WR(q);
26537c478bd9Sstevel@tonic-gate 	unsigned char *rptr;
26547c478bd9Sstevel@tonic-gate 	size_t bytes_in_bp;
26557c478bd9Sstevel@tonic-gate 	size_t roomleft;
26567c478bd9Sstevel@tonic-gate 	size_t bytes_to_move;
26577c478bd9Sstevel@tonic-gate 	int free_flag = 0;
26587c478bd9Sstevel@tonic-gate 
26597c478bd9Sstevel@tonic-gate 	if (tp->t_modes.c_lflag & (ECHO|ECHONL|IEXTEN)) {
26607c478bd9Sstevel@tonic-gate 		unsigned char *wptr;
26617c478bd9Sstevel@tonic-gate 		unsigned char c;
26627c478bd9Sstevel@tonic-gate 
26637c478bd9Sstevel@tonic-gate 		/*
26647c478bd9Sstevel@tonic-gate 		 * Either we must echo the characters, or we must
26657c478bd9Sstevel@tonic-gate 		 * echo NL, or we must check for VLNEXT. Process
26667c478bd9Sstevel@tonic-gate 		 * characters one at a time.
26677c478bd9Sstevel@tonic-gate 		 */
26687c478bd9Sstevel@tonic-gate 		rptr = bp->b_rptr;
26697c478bd9Sstevel@tonic-gate 		wptr = bp->b_rptr;
26707c478bd9Sstevel@tonic-gate 		while (rptr < bp->b_wptr) {
26717c478bd9Sstevel@tonic-gate 			c = *rptr++;
26727c478bd9Sstevel@tonic-gate 			/*
26737c478bd9Sstevel@tonic-gate 			 * If this character is the literal next
26747c478bd9Sstevel@tonic-gate 			 * character, echo it as '^' and backspace
26757c478bd9Sstevel@tonic-gate 			 * over it if echoing is enabled, indicate
26767c478bd9Sstevel@tonic-gate 			 * that the next character is to be treated
26777c478bd9Sstevel@tonic-gate 			 * literally, and remove the LNEXT from the
26787c478bd9Sstevel@tonic-gate 			 * input stream.
26797c478bd9Sstevel@tonic-gate 			 *
26807c478bd9Sstevel@tonic-gate 			 * If the *previous* character was the literal
26817c478bd9Sstevel@tonic-gate 			 * next character, don't check whether this
26827c478bd9Sstevel@tonic-gate 			 * is a literal next or not.
26837c478bd9Sstevel@tonic-gate 			 */
26847c478bd9Sstevel@tonic-gate 			if ((tp->t_modes.c_lflag & IEXTEN) &&
26857c478bd9Sstevel@tonic-gate 			    !(tp->t_state & TS_SLNCH) &&
26867c478bd9Sstevel@tonic-gate 			    c != _POSIX_VDISABLE &&
26877c478bd9Sstevel@tonic-gate 			    c == tp->t_modes.c_cc[VLNEXT]) {
26887c478bd9Sstevel@tonic-gate 				if (tp->t_modes.c_lflag & ECHO)
26897c478bd9Sstevel@tonic-gate 					ldterm_outstring(
26907c478bd9Sstevel@tonic-gate 					    (unsigned char *)"^\b",
26917c478bd9Sstevel@tonic-gate 					    2, wrq, ebsize, tp);
26927c478bd9Sstevel@tonic-gate 				tp->t_state |= TS_SLNCH;
26937c478bd9Sstevel@tonic-gate 				continue;	/* and ignore it */
26947c478bd9Sstevel@tonic-gate 			}
26957c478bd9Sstevel@tonic-gate 			/*
26967c478bd9Sstevel@tonic-gate 			 * Not a "literal next" character, so it
26977c478bd9Sstevel@tonic-gate 			 * should show up as input. If it was
26987c478bd9Sstevel@tonic-gate 			 * literal-nexted, turn off the literal-next
26997c478bd9Sstevel@tonic-gate 			 * flag.
27007c478bd9Sstevel@tonic-gate 			 */
27017c478bd9Sstevel@tonic-gate 			tp->t_state &= ~TS_SLNCH;
27027c478bd9Sstevel@tonic-gate 			*wptr++ = c;
27037c478bd9Sstevel@tonic-gate 			if (tp->t_modes.c_lflag & ECHO) {
27047c478bd9Sstevel@tonic-gate 				/*
27057c478bd9Sstevel@tonic-gate 				 * Echo the character.
27067c478bd9Sstevel@tonic-gate 				 */
27077c478bd9Sstevel@tonic-gate 				(void) ldterm_echo(c, wrq, ebsize, tp);
27087c478bd9Sstevel@tonic-gate 			} else if (tp->t_modes.c_lflag & ECHONL) {
27097c478bd9Sstevel@tonic-gate 				/*
27107c478bd9Sstevel@tonic-gate 				 * Echo NL, even though ECHO is not
27117c478bd9Sstevel@tonic-gate 				 * set.
27127c478bd9Sstevel@tonic-gate 				 */
27137c478bd9Sstevel@tonic-gate 				if (c == '\n')
271485bb5f1dSis 					ldterm_outchar('\n', wrq, 1, tp);
27157c478bd9Sstevel@tonic-gate 			}
27167c478bd9Sstevel@tonic-gate 		}
27177c478bd9Sstevel@tonic-gate 		bp->b_wptr = wptr;
27187c478bd9Sstevel@tonic-gate 	} else {
27197c478bd9Sstevel@tonic-gate 		/*
27207c478bd9Sstevel@tonic-gate 		 * If there are any characters in this buffer, and
27217c478bd9Sstevel@tonic-gate 		 * the first of them was literal-nexted, turn off the
27227c478bd9Sstevel@tonic-gate 		 * literal-next flag.
27237c478bd9Sstevel@tonic-gate 		 */
27247c478bd9Sstevel@tonic-gate 		if (bp->b_rptr != bp->b_wptr)
27257c478bd9Sstevel@tonic-gate 			tp->t_state &= ~TS_SLNCH;
27267c478bd9Sstevel@tonic-gate 	}
27277c478bd9Sstevel@tonic-gate 
27287c478bd9Sstevel@tonic-gate 	ASSERT(bp->b_wptr >= bp->b_rptr);
27297c478bd9Sstevel@tonic-gate 	bytes_in_bp = bp->b_wptr - bp->b_rptr;
27307c478bd9Sstevel@tonic-gate 	rptr = bp->b_rptr;
27317c478bd9Sstevel@tonic-gate 	while (bytes_in_bp != 0) {
27327c478bd9Sstevel@tonic-gate 		roomleft = bpt->b_datap->db_lim - bpt->b_wptr;
27337c478bd9Sstevel@tonic-gate 		if (roomleft == 0) {
27347c478bd9Sstevel@tonic-gate 			/*
27357c478bd9Sstevel@tonic-gate 			 * No more room in this mblk; save this one
27367c478bd9Sstevel@tonic-gate 			 * away, and allocate a new one.
27377c478bd9Sstevel@tonic-gate 			 */
27387c478bd9Sstevel@tonic-gate 			if ((bpt = allocb(IBSIZE, BPRI_MED)) == NULL) {
27397c478bd9Sstevel@tonic-gate 				freeb(bp);
27407c478bd9Sstevel@tonic-gate 				DEBUG4(("ldterm_do_noncanon: allcob failed\n"));
27417c478bd9Sstevel@tonic-gate 				return (bpt);
27427c478bd9Sstevel@tonic-gate 			}
27437c478bd9Sstevel@tonic-gate 			/*
27447c478bd9Sstevel@tonic-gate 			 * Chain the new one to the end of the old
27457c478bd9Sstevel@tonic-gate 			 * one, and mark it as the last block in the
27467c478bd9Sstevel@tonic-gate 			 * current lump.
27477c478bd9Sstevel@tonic-gate 			 */
27487c478bd9Sstevel@tonic-gate 			tp->t_endmsg->b_cont = bpt;
27497c478bd9Sstevel@tonic-gate 			tp->t_endmsg = bpt;
27507c478bd9Sstevel@tonic-gate 			roomleft = IBSIZE;
27517c478bd9Sstevel@tonic-gate 		}
27527c478bd9Sstevel@tonic-gate 		DEBUG5(("roomleft=%d, bytes_in_bp=%d, tp->t_rd_request=%d\n",
27537c478bd9Sstevel@tonic-gate 		    roomleft, bytes_in_bp, tp->t_rd_request));
27547c478bd9Sstevel@tonic-gate 		/*
27557c478bd9Sstevel@tonic-gate 		 * if there is a read pending before this data got
27567c478bd9Sstevel@tonic-gate 		 * here move bytes according to the minimum of room
27577c478bd9Sstevel@tonic-gate 		 * left in this buffer, bytes in the message and byte
27587c478bd9Sstevel@tonic-gate 		 * count requested in the read. If there is no read
27597c478bd9Sstevel@tonic-gate 		 * pending, move the minimum of the first two
27607c478bd9Sstevel@tonic-gate 		 */
27617c478bd9Sstevel@tonic-gate 		if (tp->t_rd_request == 0)
27627c478bd9Sstevel@tonic-gate 			bytes_to_move = MIN(roomleft, bytes_in_bp);
27637c478bd9Sstevel@tonic-gate 		else
27647c478bd9Sstevel@tonic-gate 			bytes_to_move =
27657c478bd9Sstevel@tonic-gate 			    MIN(MIN(roomleft, bytes_in_bp), tp->t_rd_request);
27667c478bd9Sstevel@tonic-gate 		DEBUG5(("Bytes to move = %lu\n", bytes_to_move));
27677c478bd9Sstevel@tonic-gate 		if (bytes_to_move == 0)
27687c478bd9Sstevel@tonic-gate 			break;
27697c478bd9Sstevel@tonic-gate 		bcopy(rptr, bpt->b_wptr, bytes_to_move);
27707c478bd9Sstevel@tonic-gate 		bpt->b_wptr += bytes_to_move;
27717c478bd9Sstevel@tonic-gate 		rptr += bytes_to_move;
27727c478bd9Sstevel@tonic-gate 		tp->t_msglen += bytes_to_move;
27737c478bd9Sstevel@tonic-gate 		bytes_in_bp -= bytes_to_move;
27747c478bd9Sstevel@tonic-gate 	}
27757c478bd9Sstevel@tonic-gate 	if (bytes_in_bp == 0) {
27767c478bd9Sstevel@tonic-gate 		DEBUG4(("bytes_in_bp is zero\n"));
27777c478bd9Sstevel@tonic-gate 		freeb(bp);
27787c478bd9Sstevel@tonic-gate 	} else
27797c478bd9Sstevel@tonic-gate 		free_flag = 1;	/* for debugging olny */
27807c478bd9Sstevel@tonic-gate 
27817c478bd9Sstevel@tonic-gate 	DEBUG4(("ldterm_do_noncanon: VMIN = %d, VTIME = %d, msglen = %d, \
27827c478bd9Sstevel@tonic-gate 		tid = %d\n", V_MIN, V_TIME, tp->t_msglen, tp->t_vtid));
27837c478bd9Sstevel@tonic-gate 	/*
27847c478bd9Sstevel@tonic-gate 	 * If there is a pending read request at the stream head we
27857c478bd9Sstevel@tonic-gate 	 * need to do VMIN/VTIME processing. The four possible cases
27867c478bd9Sstevel@tonic-gate 	 * are:
27877c478bd9Sstevel@tonic-gate 	 *	MIN = 0, TIME > 0
27887c478bd9Sstevel@tonic-gate 	 *	MIN = >, TIME = 0
27897c478bd9Sstevel@tonic-gate 	 *	MIN > 0, TIME > 0
27907c478bd9Sstevel@tonic-gate 	 *	MIN = 0, TIME = 0
27917c478bd9Sstevel@tonic-gate 	 * If we can satisfy VMIN, send it up, and start a new
27927c478bd9Sstevel@tonic-gate 	 * timer if necessary.  These four cases of VMIN/VTIME
27937c478bd9Sstevel@tonic-gate 	 * are also dealt with in the write side put routine
27947c478bd9Sstevel@tonic-gate 	 * when the M_READ is first seen.
27957c478bd9Sstevel@tonic-gate 	 */
27967c478bd9Sstevel@tonic-gate 
27977c478bd9Sstevel@tonic-gate 	DEBUG4(("Incoming data while M_READ'ing\n"));
27987c478bd9Sstevel@tonic-gate 	/*
27997c478bd9Sstevel@tonic-gate 	 * Case 1:  Any data will satisfy the read, so send
28007c478bd9Sstevel@tonic-gate 	 * it upstream.
28017c478bd9Sstevel@tonic-gate 	 */
28027c478bd9Sstevel@tonic-gate 	if (V_MIN == 0 && V_TIME > 0) {
28037c478bd9Sstevel@tonic-gate 		if (tp->t_msglen)
28047c478bd9Sstevel@tonic-gate 			vmin_satisfied(q, tp, 1);
28057c478bd9Sstevel@tonic-gate 		else {
28067c478bd9Sstevel@tonic-gate 			/* EMPTY */
28077c478bd9Sstevel@tonic-gate 			DEBUG4(("ldterm_do_noncanon called, but no data!\n"));
28087c478bd9Sstevel@tonic-gate 		}
28097c478bd9Sstevel@tonic-gate 		/*
28107c478bd9Sstevel@tonic-gate 		 * Case 2:  This should never time out, so
28117c478bd9Sstevel@tonic-gate 		 * until there's enough data, do nothing.
28127c478bd9Sstevel@tonic-gate 		 */
28137c478bd9Sstevel@tonic-gate 	} else if (V_MIN > 0 && V_TIME == 0) {
28147c478bd9Sstevel@tonic-gate 		if (tp->t_msglen >= (int)V_MIN)
28157c478bd9Sstevel@tonic-gate 			vmin_satisfied(q, tp, 1);
28167c478bd9Sstevel@tonic-gate 
28177c478bd9Sstevel@tonic-gate 		/*
28187c478bd9Sstevel@tonic-gate 		 * Case 3:  If MIN is satisfied, send it up.
28197c478bd9Sstevel@tonic-gate 		 * Also, remember to start a new timer *every*
28207c478bd9Sstevel@tonic-gate 		 * time we see something if MIN isn't
28217c478bd9Sstevel@tonic-gate 		 * safisfied
28227c478bd9Sstevel@tonic-gate 		 */
28237c478bd9Sstevel@tonic-gate 	} else if (V_MIN > 0 && V_TIME > 0) {
28247c478bd9Sstevel@tonic-gate 		if (tp->t_msglen >= (int)V_MIN)
28257c478bd9Sstevel@tonic-gate 			vmin_satisfied(q, tp, 1);
28267c478bd9Sstevel@tonic-gate 		else
28277c478bd9Sstevel@tonic-gate 			vmin_settimer(q);
28287c478bd9Sstevel@tonic-gate 		/*
28297c478bd9Sstevel@tonic-gate 		 * Case 4:  Not possible.  This request
28307c478bd9Sstevel@tonic-gate 		 * should always be satisfied from the write
28317c478bd9Sstevel@tonic-gate 		 * side, left here for debugging.
28327c478bd9Sstevel@tonic-gate 		 */
28337c478bd9Sstevel@tonic-gate 	} else {	/* V_MIN == 0 && V_TIME == 0 */
28347c478bd9Sstevel@tonic-gate 			vmin_satisfied(q, tp, 1);
28357c478bd9Sstevel@tonic-gate 	}
28367c478bd9Sstevel@tonic-gate 
28377c478bd9Sstevel@tonic-gate 	if (free_flag) {
28387c478bd9Sstevel@tonic-gate 		/* EMPTY */
28397c478bd9Sstevel@tonic-gate 		DEBUG4(("CAUTION message block not freed\n"));
28407c478bd9Sstevel@tonic-gate 	}
28417c478bd9Sstevel@tonic-gate 	return (newmsg(tp));
28427c478bd9Sstevel@tonic-gate }
28437c478bd9Sstevel@tonic-gate 
28447c478bd9Sstevel@tonic-gate 
28457c478bd9Sstevel@tonic-gate /*
28467c478bd9Sstevel@tonic-gate  * Echo a typed byte to the terminal.  Returns the number of bytes
28477c478bd9Sstevel@tonic-gate  * printed. Bytes of EUC characters drop through the ECHOCTL stuff
28487c478bd9Sstevel@tonic-gate  * and are just output as themselves.
28497c478bd9Sstevel@tonic-gate  */
28507c478bd9Sstevel@tonic-gate static int
28517c478bd9Sstevel@tonic-gate ldterm_echo(uchar_t c, queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
28527c478bd9Sstevel@tonic-gate {
28537c478bd9Sstevel@tonic-gate 	int i;
28547c478bd9Sstevel@tonic-gate 
28557c478bd9Sstevel@tonic-gate 	if (!(tp->t_modes.c_lflag & ECHO))
28567c478bd9Sstevel@tonic-gate 		return (0);
28577c478bd9Sstevel@tonic-gate 	i = 0;
28587c478bd9Sstevel@tonic-gate 
28597c478bd9Sstevel@tonic-gate 	/*
28607c478bd9Sstevel@tonic-gate 	 * Echo control characters (c <= 37) only if the ECHOCTRL
28617c478bd9Sstevel@tonic-gate 	 * flag is set as ^X.
28627c478bd9Sstevel@tonic-gate 	 */
28637c478bd9Sstevel@tonic-gate 
28647c478bd9Sstevel@tonic-gate 	if ((tp->t_modes.c_lflag & ECHOCTL) &&
28657c478bd9Sstevel@tonic-gate 	    (tp->t_modes.c_lflag & IEXTEN)) {
28667c478bd9Sstevel@tonic-gate 		if (c <= 037 && c != '\t' && c != '\n') {
28677c478bd9Sstevel@tonic-gate 			ldterm_outchar('^', q, ebsize, tp);
28687c478bd9Sstevel@tonic-gate 			i++;
28697c478bd9Sstevel@tonic-gate 			if (tp->t_modes.c_oflag & OLCUC)
28707c478bd9Sstevel@tonic-gate 				c += 'a' - 1;
28717c478bd9Sstevel@tonic-gate 			else
28727c478bd9Sstevel@tonic-gate 				c += 'A' - 1;
28737c478bd9Sstevel@tonic-gate 		} else if (c == 0177) {
28747c478bd9Sstevel@tonic-gate 			ldterm_outchar('^', q, ebsize, tp);
28757c478bd9Sstevel@tonic-gate 			i++;
28767c478bd9Sstevel@tonic-gate 			c = '?';
28777c478bd9Sstevel@tonic-gate 		}
28787c478bd9Sstevel@tonic-gate 		ldterm_outchar(c, q, ebsize, tp);
28797c478bd9Sstevel@tonic-gate 		return (i + 1);
28807c478bd9Sstevel@tonic-gate 		/* echo only special control character and the Bell */
28817c478bd9Sstevel@tonic-gate 	} else if ((c > 037 && c != 0177) || c == '\t' || c == '\n' ||
28827c478bd9Sstevel@tonic-gate 	    c == '\r' || c == '\b' || c == 007 ||
28837c478bd9Sstevel@tonic-gate 	    c == tp->t_modes.c_cc[VKILL]) {
28847c478bd9Sstevel@tonic-gate 		ldterm_outchar(c, q, ebsize, tp);
28857c478bd9Sstevel@tonic-gate 		return (i + 1);
28867c478bd9Sstevel@tonic-gate 	}
28877c478bd9Sstevel@tonic-gate 	return (i);
28887c478bd9Sstevel@tonic-gate }
28897c478bd9Sstevel@tonic-gate 
28907c478bd9Sstevel@tonic-gate 
28917c478bd9Sstevel@tonic-gate /*
28927c478bd9Sstevel@tonic-gate  * Put a character on the output queue.
28937c478bd9Sstevel@tonic-gate  */
28947c478bd9Sstevel@tonic-gate static void
28957c478bd9Sstevel@tonic-gate ldterm_outchar(uchar_t c, queue_t *q, size_t bsize, ldtermstd_state_t *tp)
28967c478bd9Sstevel@tonic-gate {
28977c478bd9Sstevel@tonic-gate 	mblk_t *curbp;
28987c478bd9Sstevel@tonic-gate 
28997c478bd9Sstevel@tonic-gate 	/*
29007c478bd9Sstevel@tonic-gate 	 * Don't even look at the characters unless we have something
29017c478bd9Sstevel@tonic-gate 	 * useful to do with them.
29027c478bd9Sstevel@tonic-gate 	 */
29037c478bd9Sstevel@tonic-gate 	if ((tp->t_modes.c_oflag & OPOST) ||
29047c478bd9Sstevel@tonic-gate 	    ((tp->t_modes.c_lflag & XCASE) &&
29057c478bd9Sstevel@tonic-gate 	    (tp->t_modes.c_lflag & ICANON))) {
29067c478bd9Sstevel@tonic-gate 		mblk_t *mp;
29077c478bd9Sstevel@tonic-gate 
29087c478bd9Sstevel@tonic-gate 		if ((mp = allocb(4, BPRI_HI)) == NULL) {
29097c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
29107c478bd9Sstevel@tonic-gate 			    "ldterm: (ldterm_outchar) out of blocks");
29117c478bd9Sstevel@tonic-gate 			return;
29127c478bd9Sstevel@tonic-gate 		}
29137c478bd9Sstevel@tonic-gate 		*mp->b_wptr++ = c;
29147c478bd9Sstevel@tonic-gate 		mp = ldterm_output_msg(q, mp, &tp->t_echomp, tp, bsize, 1);
29157c478bd9Sstevel@tonic-gate 		if (mp != NULL)
29167c478bd9Sstevel@tonic-gate 			freemsg(mp);
29177c478bd9Sstevel@tonic-gate 
29187c478bd9Sstevel@tonic-gate 	} else {
29197c478bd9Sstevel@tonic-gate 		if ((curbp = tp->t_echomp) != NULL) {
29207c478bd9Sstevel@tonic-gate 			while (curbp->b_cont != NULL)
29217c478bd9Sstevel@tonic-gate 				curbp = curbp->b_cont;
29227c478bd9Sstevel@tonic-gate 			if (curbp->b_datap->db_lim == curbp->b_wptr) {
29237c478bd9Sstevel@tonic-gate 				mblk_t *newbp;
29247c478bd9Sstevel@tonic-gate 
29257c478bd9Sstevel@tonic-gate 				if ((newbp = allocb(bsize, BPRI_HI)) == NULL) {
29267c478bd9Sstevel@tonic-gate 					cmn_err(CE_WARN,
29277c478bd9Sstevel@tonic-gate 					    "ldterm_outchar: out of blocks");
29287c478bd9Sstevel@tonic-gate 					return;
29297c478bd9Sstevel@tonic-gate 				}
29307c478bd9Sstevel@tonic-gate 				curbp->b_cont = newbp;
29317c478bd9Sstevel@tonic-gate 				curbp = newbp;
29327c478bd9Sstevel@tonic-gate 			}
29337c478bd9Sstevel@tonic-gate 		} else {
29347c478bd9Sstevel@tonic-gate 			if ((curbp = allocb(bsize, BPRI_HI)) == NULL) {
29357c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
29367c478bd9Sstevel@tonic-gate 				    "ldterm_outchar: out of blocks");
29377c478bd9Sstevel@tonic-gate 				return;
29387c478bd9Sstevel@tonic-gate 			}
29397c478bd9Sstevel@tonic-gate 			tp->t_echomp = curbp;
29407c478bd9Sstevel@tonic-gate 		}
29417c478bd9Sstevel@tonic-gate 		*curbp->b_wptr++ = c;
29427c478bd9Sstevel@tonic-gate 	}
29437c478bd9Sstevel@tonic-gate }
29447c478bd9Sstevel@tonic-gate 
29457c478bd9Sstevel@tonic-gate 
29467c478bd9Sstevel@tonic-gate /*
29477c478bd9Sstevel@tonic-gate  * Copy a string, of length len, to the output queue.
29487c478bd9Sstevel@tonic-gate  */
29497c478bd9Sstevel@tonic-gate static void
29507c478bd9Sstevel@tonic-gate ldterm_outstring(uchar_t *cp, int len, queue_t *q, size_t bsize,
29517c478bd9Sstevel@tonic-gate     ldtermstd_state_t *tp)
29527c478bd9Sstevel@tonic-gate {
29537c478bd9Sstevel@tonic-gate 	while (len > 0) {
29547c478bd9Sstevel@tonic-gate 		ldterm_outchar(*cp++, q, bsize, tp);
29557c478bd9Sstevel@tonic-gate 		len--;
29567c478bd9Sstevel@tonic-gate 	}
29577c478bd9Sstevel@tonic-gate }
29587c478bd9Sstevel@tonic-gate 
29597c478bd9Sstevel@tonic-gate 
29607c478bd9Sstevel@tonic-gate static mblk_t *
29617c478bd9Sstevel@tonic-gate newmsg(ldtermstd_state_t *tp)
29627c478bd9Sstevel@tonic-gate {
29637c478bd9Sstevel@tonic-gate 	mblk_t *bp;
29647c478bd9Sstevel@tonic-gate 
29657c478bd9Sstevel@tonic-gate 	/*
29667c478bd9Sstevel@tonic-gate 	 * If no current message, allocate a block for it.
29677c478bd9Sstevel@tonic-gate 	 */
29687c478bd9Sstevel@tonic-gate 	if ((bp = tp->t_endmsg) == NULL) {
29697c478bd9Sstevel@tonic-gate 		if ((bp = allocb(IBSIZE, BPRI_MED)) == NULL) {
29707c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
29717c478bd9Sstevel@tonic-gate 			    "ldterm: (ldtermrsrv/newmsg) out of blocks");
29727c478bd9Sstevel@tonic-gate 			return (bp);
29737c478bd9Sstevel@tonic-gate 		}
29747c478bd9Sstevel@tonic-gate 		tp->t_message = bp;
29757c478bd9Sstevel@tonic-gate 		tp->t_endmsg = bp;
29767c478bd9Sstevel@tonic-gate 	}
29777c478bd9Sstevel@tonic-gate 	return (bp);
29787c478bd9Sstevel@tonic-gate }
29797c478bd9Sstevel@tonic-gate 
29807c478bd9Sstevel@tonic-gate 
29817c478bd9Sstevel@tonic-gate static void
29827c478bd9Sstevel@tonic-gate ldterm_msg_upstream(queue_t *q, ldtermstd_state_t *tp)
29837c478bd9Sstevel@tonic-gate {
29847c478bd9Sstevel@tonic-gate 	ssize_t s;
29857c478bd9Sstevel@tonic-gate 	mblk_t *bp;
29867c478bd9Sstevel@tonic-gate 
29877c478bd9Sstevel@tonic-gate 	bp = tp->t_message;
29887c478bd9Sstevel@tonic-gate 	s = msgdsize(bp);
29897c478bd9Sstevel@tonic-gate 	if (bp)
29907c478bd9Sstevel@tonic-gate 		putnext(q, tp->t_message);
29917c478bd9Sstevel@tonic-gate 
29927c478bd9Sstevel@tonic-gate 	/*
29937c478bd9Sstevel@tonic-gate 	 * update sysinfo canch character.
29947c478bd9Sstevel@tonic-gate 	 */
29957c478bd9Sstevel@tonic-gate 	if (CANON_MODE)
29967c478bd9Sstevel@tonic-gate 		(void) drv_setparm(SYSCANC, s);
29977c478bd9Sstevel@tonic-gate 	tp->t_message = NULL;
29987c478bd9Sstevel@tonic-gate 	tp->t_endmsg = NULL;
29997c478bd9Sstevel@tonic-gate 	tp->t_msglen = 0;
30007c478bd9Sstevel@tonic-gate 	tp->t_rocount = 0;
30017c478bd9Sstevel@tonic-gate 	tp->t_rd_request = 0;
30027c478bd9Sstevel@tonic-gate 	if (tp->t_state & TS_MEUC) {
30037c478bd9Sstevel@tonic-gate 		ASSERT(tp->t_eucp_mp);
30047c478bd9Sstevel@tonic-gate 		tp->t_eucp = tp->t_eucp_mp->b_rptr;
30057c478bd9Sstevel@tonic-gate 		/* can't reset everything, as we may have other input */
30067c478bd9Sstevel@tonic-gate 	}
30077c478bd9Sstevel@tonic-gate }
30087c478bd9Sstevel@tonic-gate 
30097c478bd9Sstevel@tonic-gate 
30107c478bd9Sstevel@tonic-gate /*
30117c478bd9Sstevel@tonic-gate  * Re-enable the write-side service procedure.  When an allocation
30127c478bd9Sstevel@tonic-gate  * failure causes write-side processing to stall, we disable the
30137c478bd9Sstevel@tonic-gate  * write side and arrange to call this function when allocation once
30147c478bd9Sstevel@tonic-gate  * again becomes possible.
30157c478bd9Sstevel@tonic-gate  */
30167c478bd9Sstevel@tonic-gate static void
30177c478bd9Sstevel@tonic-gate ldterm_wenable(void *addr)
30187c478bd9Sstevel@tonic-gate {
30197c478bd9Sstevel@tonic-gate 	queue_t *q = addr;
30207c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp;
30217c478bd9Sstevel@tonic-gate 
30227c478bd9Sstevel@tonic-gate 	tp = (ldtermstd_state_t *)q->q_ptr;
30237c478bd9Sstevel@tonic-gate 	/*
30247c478bd9Sstevel@tonic-gate 	 * The bufcall is no longer pending.
30257c478bd9Sstevel@tonic-gate 	 */
30267c478bd9Sstevel@tonic-gate 	tp->t_wbufcid = 0;
30277c478bd9Sstevel@tonic-gate 	enableok(q);
30287c478bd9Sstevel@tonic-gate 	qenable(q);
30297c478bd9Sstevel@tonic-gate }
30307c478bd9Sstevel@tonic-gate 
30317c478bd9Sstevel@tonic-gate 
30327c478bd9Sstevel@tonic-gate /*
30337c478bd9Sstevel@tonic-gate  * Line discipline output queue put procedure.  Attempts to process
30347c478bd9Sstevel@tonic-gate  * the message directly and send it on downstream, queueing it only
30357c478bd9Sstevel@tonic-gate  * if there's already something pending or if its downstream neighbor
30367c478bd9Sstevel@tonic-gate  * is clogged.
30377c478bd9Sstevel@tonic-gate  */
30387c478bd9Sstevel@tonic-gate static void
30397c478bd9Sstevel@tonic-gate ldtermwput(queue_t *q, mblk_t *mp)
30407c478bd9Sstevel@tonic-gate {
30417c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp;
30427c478bd9Sstevel@tonic-gate 	unsigned char type = mp->b_datap->db_type;
30437c478bd9Sstevel@tonic-gate 
30447c478bd9Sstevel@tonic-gate 	tp = (ldtermstd_state_t *)q->q_ptr;
30457c478bd9Sstevel@tonic-gate 
30467c478bd9Sstevel@tonic-gate 	/*
30477c478bd9Sstevel@tonic-gate 	 * Always process priority messages, regardless of whether or
30487c478bd9Sstevel@tonic-gate 	 * not our queue is nonempty.
30497c478bd9Sstevel@tonic-gate 	 */
30507c478bd9Sstevel@tonic-gate 	if (type >= QPCTL) {
30517c478bd9Sstevel@tonic-gate 		switch (type) {
30527c478bd9Sstevel@tonic-gate 
30537c478bd9Sstevel@tonic-gate 		case M_FLUSH:
30547c478bd9Sstevel@tonic-gate 			/*
30557c478bd9Sstevel@tonic-gate 			 * Get rid of it, see comment in
30567c478bd9Sstevel@tonic-gate 			 * ldterm_dosig().
30577c478bd9Sstevel@tonic-gate 			 */
30587c478bd9Sstevel@tonic-gate 			if ((tp->t_state & TS_FLUSHWAIT) &&
30597c478bd9Sstevel@tonic-gate 			    (*mp->b_rptr == FLUSHW)) {
30607c478bd9Sstevel@tonic-gate 				tp->t_state &= ~TS_FLUSHWAIT;
30617c478bd9Sstevel@tonic-gate 				freemsg(mp);
30627c478bd9Sstevel@tonic-gate 				return;
30637c478bd9Sstevel@tonic-gate 			}
30647c478bd9Sstevel@tonic-gate 			/*
30657c478bd9Sstevel@tonic-gate 			 * This is coming from above, so we only
30667c478bd9Sstevel@tonic-gate 			 * handle the write queue here.  If FLUSHR is
30677c478bd9Sstevel@tonic-gate 			 * set, it will get turned around at the
30687c478bd9Sstevel@tonic-gate 			 * driver, and the read procedure will see it
30697c478bd9Sstevel@tonic-gate 			 * eventually.
30707c478bd9Sstevel@tonic-gate 			 */
30717c478bd9Sstevel@tonic-gate 			if (*mp->b_rptr & FLUSHW) {
30727c478bd9Sstevel@tonic-gate 				if ((tp->t_state & TS_ISPTSTTY) &&
30737c478bd9Sstevel@tonic-gate 				    (*mp->b_rptr & FLUSHBAND))
307485bb5f1dSis 					flushband(q, *(mp->b_rptr + 1),
307585bb5f1dSis 					    FLUSHDATA);
30767c478bd9Sstevel@tonic-gate 				else
30777c478bd9Sstevel@tonic-gate 					flushq(q, FLUSHDATA);
30787c478bd9Sstevel@tonic-gate 			}
30797c478bd9Sstevel@tonic-gate 
30807c478bd9Sstevel@tonic-gate 			putnext(q, mp);
30817c478bd9Sstevel@tonic-gate 			/*
30827c478bd9Sstevel@tonic-gate 			 * If a timed read is interrupted, there is
30837c478bd9Sstevel@tonic-gate 			 * no way to cancel an existing M_READ
30847c478bd9Sstevel@tonic-gate 			 * request.  We kludge by allowing a flush to
30857c478bd9Sstevel@tonic-gate 			 * do so.
30867c478bd9Sstevel@tonic-gate 			 */
30877c478bd9Sstevel@tonic-gate 			if (tp->t_state & TS_MREAD)
30887c478bd9Sstevel@tonic-gate 				vmin_satisfied(RD(q), tp, 0);
30897c478bd9Sstevel@tonic-gate 			break;
30907c478bd9Sstevel@tonic-gate 
30917c478bd9Sstevel@tonic-gate 		case M_READ:
30927c478bd9Sstevel@tonic-gate 			DEBUG1(("ldtermwmsg:M_READ RECEIVED\n"));
30937c478bd9Sstevel@tonic-gate 			/*
30947c478bd9Sstevel@tonic-gate 			 * Stream head needs data to satisfy timed
30957c478bd9Sstevel@tonic-gate 			 * read. Has meaning only if ICANON flag is
30967c478bd9Sstevel@tonic-gate 			 * off indicating raw mode
30977c478bd9Sstevel@tonic-gate 			 */
30987c478bd9Sstevel@tonic-gate 
30997c478bd9Sstevel@tonic-gate 			DEBUG4((
31007c478bd9Sstevel@tonic-gate 			    "M_READ: RAW_MODE=%d, CNT=%d, VMIN=%d, VTIME=%d\n",
31017c478bd9Sstevel@tonic-gate 			    RAW_MODE, *(unsigned int *)mp->b_rptr, V_MIN,
31027c478bd9Sstevel@tonic-gate 			    V_TIME));
31037c478bd9Sstevel@tonic-gate 
31047c478bd9Sstevel@tonic-gate 			tp->t_rd_request = *(unsigned int *)mp->b_rptr;
31057c478bd9Sstevel@tonic-gate 
31067c478bd9Sstevel@tonic-gate 			if (RAW_MODE) {
31077c478bd9Sstevel@tonic-gate 				if (newmsg(tp) != NULL) {
31087c478bd9Sstevel@tonic-gate 					/*
31097c478bd9Sstevel@tonic-gate 					 * VMIN/VTIME processing...
31107c478bd9Sstevel@tonic-gate 					 * The four possible cases are:
31117c478bd9Sstevel@tonic-gate 					 *	MIN = 0, TIME > 0
31127c478bd9Sstevel@tonic-gate 					 *	MIN = >, TIME = 0
31137c478bd9Sstevel@tonic-gate 					 *	MIN > 0, TIME > 0
31147c478bd9Sstevel@tonic-gate 					 *	MIN = 0, TIME = 0
31157c478bd9Sstevel@tonic-gate 					 * These four conditions must be dealt
31167c478bd9Sstevel@tonic-gate 					 * with on the read side as well in
31177c478bd9Sstevel@tonic-gate 					 * ldterm_do_noncanon(). Set TS_MREAD
31187c478bd9Sstevel@tonic-gate 					 * so that the read side will know
31197c478bd9Sstevel@tonic-gate 					 * there is a pending read request
31207c478bd9Sstevel@tonic-gate 					 * waiting at the stream head.  If we
31217c478bd9Sstevel@tonic-gate 					 * can satisfy MIN do it here, rather
31227c478bd9Sstevel@tonic-gate 					 * than on the read side.  If we can't,
31237c478bd9Sstevel@tonic-gate 					 * start timers if necessary and let
31247c478bd9Sstevel@tonic-gate 					 * the other side deal with it.
31257c478bd9Sstevel@tonic-gate 					 *
31267c478bd9Sstevel@tonic-gate 					 * We got another M_READ before the
31277c478bd9Sstevel@tonic-gate 					 * pending one completed, cancel any
31287c478bd9Sstevel@tonic-gate 					 * existing timeout.
31297c478bd9Sstevel@tonic-gate 					 */
31307c478bd9Sstevel@tonic-gate 					if (tp->t_state & TS_MREAD) {
31317c478bd9Sstevel@tonic-gate 						vmin_satisfied(RD(q),
31327c478bd9Sstevel@tonic-gate 						    tp, 0);
31337c478bd9Sstevel@tonic-gate 					}
31347c478bd9Sstevel@tonic-gate 					tp->t_state |= TS_MREAD;
31357c478bd9Sstevel@tonic-gate 					/*
31367c478bd9Sstevel@tonic-gate 					 * Case 1:  Any data will
31377c478bd9Sstevel@tonic-gate 					 * satisfy read, otherwise
31387c478bd9Sstevel@tonic-gate 					 * start timer
31397c478bd9Sstevel@tonic-gate 					 */
31407c478bd9Sstevel@tonic-gate 					if (V_MIN == 0 && V_TIME > 0) {
31417c478bd9Sstevel@tonic-gate 						if (tp->t_msglen)
31427c478bd9Sstevel@tonic-gate 							vmin_satisfied(RD(q),
31437c478bd9Sstevel@tonic-gate 							    tp, 1);
31447c478bd9Sstevel@tonic-gate 						else
31457c478bd9Sstevel@tonic-gate 							vmin_settimer(RD(q));
31467c478bd9Sstevel@tonic-gate 
31477c478bd9Sstevel@tonic-gate 						/*
31487c478bd9Sstevel@tonic-gate 						 * Case 2:  If we have enough
31497c478bd9Sstevel@tonic-gate 						 * data, send up now.
31507c478bd9Sstevel@tonic-gate 						 * Otherwise, the read side
31517c478bd9Sstevel@tonic-gate 						 * should wait forever until MIN
31527c478bd9Sstevel@tonic-gate 						 * is satisified.
31537c478bd9Sstevel@tonic-gate 						 */
31547c478bd9Sstevel@tonic-gate 					} else if (V_MIN > 0 && V_TIME == 0) {
31557c478bd9Sstevel@tonic-gate 						if (tp->t_msglen >= (int)V_MIN)
31567c478bd9Sstevel@tonic-gate 							vmin_satisfied(RD(q),
31577c478bd9Sstevel@tonic-gate 							    tp, 1);
31587c478bd9Sstevel@tonic-gate 
31597c478bd9Sstevel@tonic-gate 						/*
31607c478bd9Sstevel@tonic-gate 						 * Case 3:  If we can satisfy
31617c478bd9Sstevel@tonic-gate 						 * the read, send it up. If we
31627c478bd9Sstevel@tonic-gate 						 * don't have enough data, but
31637c478bd9Sstevel@tonic-gate 						 * there is at least one char,
31647c478bd9Sstevel@tonic-gate 						 * start a timer.  Otherwise,
31657c478bd9Sstevel@tonic-gate 						 * let the read side start
31667c478bd9Sstevel@tonic-gate 						 * the timer.
31677c478bd9Sstevel@tonic-gate 						 */
31687c478bd9Sstevel@tonic-gate 					} else if (V_MIN > 0 && V_TIME > 0) {
31697c478bd9Sstevel@tonic-gate 						if (tp->t_msglen >= (int)V_MIN)
31707c478bd9Sstevel@tonic-gate 							vmin_satisfied(RD(q),
31717c478bd9Sstevel@tonic-gate 							    tp, 1);
31727c478bd9Sstevel@tonic-gate 						else if (tp->t_msglen)
31737c478bd9Sstevel@tonic-gate 							vmin_settimer(RD(q));
31747c478bd9Sstevel@tonic-gate 						/*
31757c478bd9Sstevel@tonic-gate 						 * Case 4:  Read returns
31767c478bd9Sstevel@tonic-gate 						 * whatever data is available
31777c478bd9Sstevel@tonic-gate 						 * or zero if none.
31787c478bd9Sstevel@tonic-gate 						 */
31797c478bd9Sstevel@tonic-gate 					} else { /* V_MIN == 0 && V_TIME == 0 */
31807c478bd9Sstevel@tonic-gate 						vmin_satisfied(RD(q), tp, 1);
31817c478bd9Sstevel@tonic-gate 					}
31827c478bd9Sstevel@tonic-gate 
31837c478bd9Sstevel@tonic-gate 				} else	/* should do bufcall, really! */
31847c478bd9Sstevel@tonic-gate 					cmn_err(CE_WARN,
31857c478bd9Sstevel@tonic-gate 					    "ldtermwmsg: out of blocks");
31867c478bd9Sstevel@tonic-gate 			}
31877c478bd9Sstevel@tonic-gate 			/*
31887c478bd9Sstevel@tonic-gate 			 * pass M_READ down
31897c478bd9Sstevel@tonic-gate 			 */
31907c478bd9Sstevel@tonic-gate 			putnext(q, mp);
31917c478bd9Sstevel@tonic-gate 			break;
31927c478bd9Sstevel@tonic-gate 
31937c478bd9Sstevel@tonic-gate 		default:
31947c478bd9Sstevel@tonic-gate 			/* Pass it through unmolested. */
31957c478bd9Sstevel@tonic-gate 			putnext(q, mp);
31967c478bd9Sstevel@tonic-gate 			break;
31977c478bd9Sstevel@tonic-gate 		}
31987c478bd9Sstevel@tonic-gate 		return;
31997c478bd9Sstevel@tonic-gate 	}
32007c478bd9Sstevel@tonic-gate 	/*
32017c478bd9Sstevel@tonic-gate 	 * If our queue is nonempty or there's a traffic jam
32027c478bd9Sstevel@tonic-gate 	 * downstream, this message must get in line.
32037c478bd9Sstevel@tonic-gate 	 */
32047c478bd9Sstevel@tonic-gate 	if (q->q_first != NULL || !bcanputnext(q, mp->b_band)) {
32057c478bd9Sstevel@tonic-gate 		/*
32067c478bd9Sstevel@tonic-gate 		 * Exception: ioctls, except for those defined to
32077c478bd9Sstevel@tonic-gate 		 * take effect after output has drained, should be
32087c478bd9Sstevel@tonic-gate 		 * processed immediately.
32097c478bd9Sstevel@tonic-gate 		 */
32107c478bd9Sstevel@tonic-gate 		if (type == M_IOCTL) {
32117c478bd9Sstevel@tonic-gate 			struct iocblk *iocp;
32127c478bd9Sstevel@tonic-gate 
32137c478bd9Sstevel@tonic-gate 			iocp = (struct iocblk *)mp->b_rptr;
32147c478bd9Sstevel@tonic-gate 			switch (iocp->ioc_cmd) {
32157c478bd9Sstevel@tonic-gate 
32167c478bd9Sstevel@tonic-gate 				/*
32177c478bd9Sstevel@tonic-gate 				 * Queue these.
32187c478bd9Sstevel@tonic-gate 				 */
32197c478bd9Sstevel@tonic-gate 			case TCSETSW:
32207c478bd9Sstevel@tonic-gate 			case TCSETSF:
32217c478bd9Sstevel@tonic-gate 			case TCSETAW:
32227c478bd9Sstevel@tonic-gate 			case TCSETAF:
32237c478bd9Sstevel@tonic-gate 			case TCSBRK:
32247c478bd9Sstevel@tonic-gate 				break;
32257c478bd9Sstevel@tonic-gate 
32267c478bd9Sstevel@tonic-gate 				/*
32277c478bd9Sstevel@tonic-gate 				 * Handle all others immediately.
32287c478bd9Sstevel@tonic-gate 				 */
32297c478bd9Sstevel@tonic-gate 			default:
32307c478bd9Sstevel@tonic-gate 				(void) ldtermwmsg(q, mp);
32317c478bd9Sstevel@tonic-gate 				return;
32327c478bd9Sstevel@tonic-gate 			}
32337c478bd9Sstevel@tonic-gate 		}
32347c478bd9Sstevel@tonic-gate 		(void) putq(q, mp);
32357c478bd9Sstevel@tonic-gate 		return;
32367c478bd9Sstevel@tonic-gate 	}
32377c478bd9Sstevel@tonic-gate 	/*
32387c478bd9Sstevel@tonic-gate 	 * We can take the fast path through, by simply calling
32397c478bd9Sstevel@tonic-gate 	 * ldtermwmsg to dispose of mp.
32407c478bd9Sstevel@tonic-gate 	 */
32417c478bd9Sstevel@tonic-gate 	(void) ldtermwmsg(q, mp);
32427c478bd9Sstevel@tonic-gate }
32437c478bd9Sstevel@tonic-gate 
32447c478bd9Sstevel@tonic-gate 
32457c478bd9Sstevel@tonic-gate /*
32467c478bd9Sstevel@tonic-gate  * Line discipline output queue service procedure.
32477c478bd9Sstevel@tonic-gate  */
32487c478bd9Sstevel@tonic-gate static void
32497c478bd9Sstevel@tonic-gate ldtermwsrv(queue_t *q)
32507c478bd9Sstevel@tonic-gate {
32517c478bd9Sstevel@tonic-gate 	mblk_t *mp;
32527c478bd9Sstevel@tonic-gate 
32537c478bd9Sstevel@tonic-gate 	/*
32547c478bd9Sstevel@tonic-gate 	 * We expect this loop to iterate at most once, but must be
32557c478bd9Sstevel@tonic-gate 	 * prepared for more in case our upstream neighbor isn't
32567c478bd9Sstevel@tonic-gate 	 * paying strict attention to what canput tells it.
32577c478bd9Sstevel@tonic-gate 	 */
32587c478bd9Sstevel@tonic-gate 	while ((mp = getq(q)) != NULL) {
32597c478bd9Sstevel@tonic-gate 		/*
32607c478bd9Sstevel@tonic-gate 		 * N.B.: ldtermwput has already handled high-priority
32617c478bd9Sstevel@tonic-gate 		 * messages, so we don't have to worry about them
32627c478bd9Sstevel@tonic-gate 		 * here. Hence, the putbq call is safe.
32637c478bd9Sstevel@tonic-gate 		 */
32647c478bd9Sstevel@tonic-gate 		if (!bcanputnext(q, mp->b_band)) {
32657c478bd9Sstevel@tonic-gate 			(void) putbq(q, mp);
32667c478bd9Sstevel@tonic-gate 			break;
32677c478bd9Sstevel@tonic-gate 		}
32687c478bd9Sstevel@tonic-gate 		if (!ldtermwmsg(q, mp)) {
32697c478bd9Sstevel@tonic-gate 			/*
32707c478bd9Sstevel@tonic-gate 			 * Couldn't handle the whole thing; give up
32717c478bd9Sstevel@tonic-gate 			 * for now and wait to be rescheduled.
32727c478bd9Sstevel@tonic-gate 			 */
32737c478bd9Sstevel@tonic-gate 			break;
32747c478bd9Sstevel@tonic-gate 		}
32757c478bd9Sstevel@tonic-gate 	}
32767c478bd9Sstevel@tonic-gate }
32777c478bd9Sstevel@tonic-gate 
32787c478bd9Sstevel@tonic-gate 
32797c478bd9Sstevel@tonic-gate /*
32807c478bd9Sstevel@tonic-gate  * Process the write-side message denoted by mp.  If mp can't be
32817c478bd9Sstevel@tonic-gate  * processed completely (due to allocation failures), put the
32827c478bd9Sstevel@tonic-gate  * residual unprocessed part on the front of the write queue, disable
32837c478bd9Sstevel@tonic-gate  * the queue, and schedule a qbufcall to arrange to complete its
32847c478bd9Sstevel@tonic-gate  * processing later.
32857c478bd9Sstevel@tonic-gate  *
32867c478bd9Sstevel@tonic-gate  * Return 1 if the message was processed completely and 0 if not.
32877c478bd9Sstevel@tonic-gate  *
32887c478bd9Sstevel@tonic-gate  * This routine is called from both ldtermwput and ldtermwsrv to do the
32897c478bd9Sstevel@tonic-gate  * actual work of dealing with mp.  ldtermwput will have already
32907c478bd9Sstevel@tonic-gate  * dealt with high priority messages.
32917c478bd9Sstevel@tonic-gate  */
32927c478bd9Sstevel@tonic-gate static int
32937c478bd9Sstevel@tonic-gate ldtermwmsg(queue_t *q, mblk_t *mp)
32947c478bd9Sstevel@tonic-gate {
32957c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp;
32967c478bd9Sstevel@tonic-gate 	mblk_t *residmp = NULL;
32977c478bd9Sstevel@tonic-gate 	size_t size;
32987c478bd9Sstevel@tonic-gate 
32997c478bd9Sstevel@tonic-gate 	tp = (ldtermstd_state_t *)q->q_ptr;
33007c478bd9Sstevel@tonic-gate 
33017c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
33027c478bd9Sstevel@tonic-gate 
33037c478bd9Sstevel@tonic-gate 	case M_IOCTL:
33047c478bd9Sstevel@tonic-gate 		ldterm_do_ioctl(q, mp);
33057c478bd9Sstevel@tonic-gate 		break;
33067c478bd9Sstevel@tonic-gate 
33077c478bd9Sstevel@tonic-gate 	case M_DATA:
33087c478bd9Sstevel@tonic-gate 		{
33097c478bd9Sstevel@tonic-gate 			mblk_t *omp = NULL;
33107c478bd9Sstevel@tonic-gate 
33117c478bd9Sstevel@tonic-gate 			if ((tp->t_modes.c_lflag & FLUSHO) &&
33127c478bd9Sstevel@tonic-gate 			    (tp->t_modes.c_lflag & IEXTEN)) {
33137c478bd9Sstevel@tonic-gate 				freemsg(mp);	/* drop on floor */
33147c478bd9Sstevel@tonic-gate 				break;
33157c478bd9Sstevel@tonic-gate 			}
33167c478bd9Sstevel@tonic-gate 			tp->t_rocount = 0;
33177c478bd9Sstevel@tonic-gate 			/*
33187c478bd9Sstevel@tonic-gate 			 * Don't even look at the characters unless
33197c478bd9Sstevel@tonic-gate 			 * we have something useful to do with them.
33207c478bd9Sstevel@tonic-gate 			 */
33217c478bd9Sstevel@tonic-gate 			if (((tp->t_modes.c_oflag & OPOST) ||
33227c478bd9Sstevel@tonic-gate 			    ((tp->t_modes.c_lflag & XCASE) &&
33237c478bd9Sstevel@tonic-gate 			    (tp->t_modes.c_lflag & ICANON))) &&
33247c478bd9Sstevel@tonic-gate 			    (msgdsize(mp) || !(tp->t_state & TS_ISPTSTTY))) {
33257c478bd9Sstevel@tonic-gate 				unsigned char band = mp->b_band;
33267c478bd9Sstevel@tonic-gate 				short flag = mp->b_flag;
33277c478bd9Sstevel@tonic-gate 
33287c478bd9Sstevel@tonic-gate 				residmp = ldterm_output_msg(q, mp, &omp,
33297c478bd9Sstevel@tonic-gate 				    tp, OBSIZE, 0);
33307c478bd9Sstevel@tonic-gate 				if ((mp = omp) == NULL)
33317c478bd9Sstevel@tonic-gate 					break;
33327c478bd9Sstevel@tonic-gate 				mp->b_band |= band;
33337c478bd9Sstevel@tonic-gate 				mp->b_flag |= flag;
33347c478bd9Sstevel@tonic-gate 			}
33357c478bd9Sstevel@tonic-gate 			/* Update sysinfo outch */
33367c478bd9Sstevel@tonic-gate 			(void) drv_setparm(SYSOUTC, msgdsize(mp));
33377c478bd9Sstevel@tonic-gate 			putnext(q, mp);
33387c478bd9Sstevel@tonic-gate 			break;
33397c478bd9Sstevel@tonic-gate 		}
33407c478bd9Sstevel@tonic-gate 
33417c478bd9Sstevel@tonic-gate 	default:
33427c478bd9Sstevel@tonic-gate 		putnext(q, mp);	/* pass it through unmolested */
33437c478bd9Sstevel@tonic-gate 		break;
33447c478bd9Sstevel@tonic-gate 	}
33457c478bd9Sstevel@tonic-gate 
33467c478bd9Sstevel@tonic-gate 	if (residmp == NULL)
33477c478bd9Sstevel@tonic-gate 		return (1);
33487c478bd9Sstevel@tonic-gate 
33497c478bd9Sstevel@tonic-gate 	/*
33507c478bd9Sstevel@tonic-gate 	 * An allocation failure occurred that prevented the message
33517c478bd9Sstevel@tonic-gate 	 * from being completely processed.  First, disable our
33527c478bd9Sstevel@tonic-gate 	 * queue, since it's pointless to attempt further processing
33537c478bd9Sstevel@tonic-gate 	 * until the allocation situation is resolved.  (This must
33547c478bd9Sstevel@tonic-gate 	 * precede the putbq call below, which would otherwise mark
33557c478bd9Sstevel@tonic-gate 	 * the queue to be serviced.)
33567c478bd9Sstevel@tonic-gate 	 */
33577c478bd9Sstevel@tonic-gate 	noenable(q);
33587c478bd9Sstevel@tonic-gate 	/*
33597c478bd9Sstevel@tonic-gate 	 * Stuff the remnant on our write queue so that we can
33607c478bd9Sstevel@tonic-gate 	 * complete it later when times become less lean.  Note that
33617c478bd9Sstevel@tonic-gate 	 * this sets QFULL, so that our upstream neighbor will be
33627c478bd9Sstevel@tonic-gate 	 * blocked by flow control.
33637c478bd9Sstevel@tonic-gate 	 */
33647c478bd9Sstevel@tonic-gate 	(void) putbq(q, residmp);
33657c478bd9Sstevel@tonic-gate 	/*
33667c478bd9Sstevel@tonic-gate 	 * Schedule a qbufcall to re-enable the queue.  The failure
33677c478bd9Sstevel@tonic-gate 	 * won't have been for an allocation of more than OBSIZE
33687c478bd9Sstevel@tonic-gate 	 * bytes, so don't ask for more than that from bufcall.
33697c478bd9Sstevel@tonic-gate 	 */
33707c478bd9Sstevel@tonic-gate 	size = msgdsize(residmp);
33717c478bd9Sstevel@tonic-gate 	if (size > OBSIZE)
33727c478bd9Sstevel@tonic-gate 		size = OBSIZE;
33737c478bd9Sstevel@tonic-gate 	if (tp->t_wbufcid)
33747c478bd9Sstevel@tonic-gate 		qunbufcall(q, tp->t_wbufcid);
33757c478bd9Sstevel@tonic-gate 	tp->t_wbufcid = qbufcall(q, size, BPRI_MED, ldterm_wenable, q);
33767c478bd9Sstevel@tonic-gate 
33777c478bd9Sstevel@tonic-gate 	return (0);
33787c478bd9Sstevel@tonic-gate }
33797c478bd9Sstevel@tonic-gate 
33807c478bd9Sstevel@tonic-gate 
33817c478bd9Sstevel@tonic-gate /*
33827c478bd9Sstevel@tonic-gate  * Perform output processing on a message, accumulating the output
33837c478bd9Sstevel@tonic-gate  * characters in a new message.
33847c478bd9Sstevel@tonic-gate  */
33857c478bd9Sstevel@tonic-gate static mblk_t *
33867c478bd9Sstevel@tonic-gate ldterm_output_msg(queue_t *q, mblk_t *imp, mblk_t **omp,
33877c478bd9Sstevel@tonic-gate     ldtermstd_state_t *tp, size_t bsize, int echoing)
33887c478bd9Sstevel@tonic-gate {
33897c478bd9Sstevel@tonic-gate 	mblk_t *ibp;		/* block we're examining from input message */
33907c478bd9Sstevel@tonic-gate 	mblk_t *obp;		/* block we're filling in output message */
33917c478bd9Sstevel@tonic-gate 	mblk_t *cbp;		/* continuation block */
33927c478bd9Sstevel@tonic-gate 	mblk_t *oobp;		/* old value of obp; valid if NEW_BLOCK fails */
33937c478bd9Sstevel@tonic-gate 	mblk_t **contpp;	/* where to stuff ptr to newly-allocated blk */
33947c478bd9Sstevel@tonic-gate 	unsigned char c, n;
33957c478bd9Sstevel@tonic-gate 	int count, ctype;
33967c478bd9Sstevel@tonic-gate 	ssize_t bytes_left;
33977c478bd9Sstevel@tonic-gate 
33987c478bd9Sstevel@tonic-gate 	mblk_t *bp;		/* block to stuff an M_DELAY message in */
33997c478bd9Sstevel@tonic-gate 
34007c478bd9Sstevel@tonic-gate 
34017c478bd9Sstevel@tonic-gate 	/*
34027c478bd9Sstevel@tonic-gate 	 * Allocate a new block into which to put bytes. If we can't,
34037c478bd9Sstevel@tonic-gate 	 * we just drop the rest of the message on the floor. If x is
34047c478bd9Sstevel@tonic-gate 	 * non-zero, just fall thru; failure requires cleanup before
34057c478bd9Sstevel@tonic-gate 	 * going out
34067c478bd9Sstevel@tonic-gate 	 */
34077c478bd9Sstevel@tonic-gate 
34087c478bd9Sstevel@tonic-gate #define	NEW_BLOCK(x) \
34097c478bd9Sstevel@tonic-gate 	{ \
34107c478bd9Sstevel@tonic-gate 		oobp = obp; \
34117c478bd9Sstevel@tonic-gate 		if ((obp = allocb(bsize, BPRI_MED)) == NULL) { \
34127c478bd9Sstevel@tonic-gate 			if (x == 0) \
34137c478bd9Sstevel@tonic-gate 				goto outofbufs; \
34147c478bd9Sstevel@tonic-gate 		} else { \
34157c478bd9Sstevel@tonic-gate 			*contpp = obp; \
34167c478bd9Sstevel@tonic-gate 			contpp = &obp->b_cont; \
34177c478bd9Sstevel@tonic-gate 			bytes_left = obp->b_datap->db_lim - obp->b_wptr; \
34187c478bd9Sstevel@tonic-gate 		} \
34197c478bd9Sstevel@tonic-gate 	}
34207c478bd9Sstevel@tonic-gate 
34217c478bd9Sstevel@tonic-gate 	ibp = imp;
34227c478bd9Sstevel@tonic-gate 
34237c478bd9Sstevel@tonic-gate 	/*
34247c478bd9Sstevel@tonic-gate 	 * When we allocate the first block of a message, we should
34257c478bd9Sstevel@tonic-gate 	 * stuff the pointer to it in "*omp".  All subsequent blocks
34267c478bd9Sstevel@tonic-gate 	 * should have the pointer to them stuffed into the "b_cont"
34277c478bd9Sstevel@tonic-gate 	 * field of the previous block.  "contpp" points to the place
34287c478bd9Sstevel@tonic-gate 	 * where we should stuff the pointer.
34297c478bd9Sstevel@tonic-gate 	 *
34307c478bd9Sstevel@tonic-gate 	 * If we already have a message we're filling in, continue doing
34317c478bd9Sstevel@tonic-gate 	 * so.
34327c478bd9Sstevel@tonic-gate 	 */
34337c478bd9Sstevel@tonic-gate 	if ((obp = *omp) != NULL) {
34347c478bd9Sstevel@tonic-gate 		while (obp->b_cont != NULL)
34357c478bd9Sstevel@tonic-gate 			obp = obp->b_cont;
34367c478bd9Sstevel@tonic-gate 		contpp = &obp->b_cont;
34377c478bd9Sstevel@tonic-gate 		bytes_left = obp->b_datap->db_lim - obp->b_wptr;
34387c478bd9Sstevel@tonic-gate 	} else {
34397c478bd9Sstevel@tonic-gate 		contpp = omp;
34407c478bd9Sstevel@tonic-gate 		bytes_left = 0;
34417c478bd9Sstevel@tonic-gate 	}
34427c478bd9Sstevel@tonic-gate 
34437c478bd9Sstevel@tonic-gate 	do {
34447c478bd9Sstevel@tonic-gate 		while (ibp->b_rptr < ibp->b_wptr) {
34457c478bd9Sstevel@tonic-gate 			/*
34467c478bd9Sstevel@tonic-gate 			 * Make sure there's room for one more
34477c478bd9Sstevel@tonic-gate 			 * character.  At most, we'll need "t_maxeuc"
34487c478bd9Sstevel@tonic-gate 			 * bytes.
34497c478bd9Sstevel@tonic-gate 			 */
34507c478bd9Sstevel@tonic-gate 			if ((bytes_left < (int)tp->t_maxeuc)) {
34517c478bd9Sstevel@tonic-gate 				/* LINTED */
34527c478bd9Sstevel@tonic-gate 				NEW_BLOCK(0);
34537c478bd9Sstevel@tonic-gate 			}
34547c478bd9Sstevel@tonic-gate 			/*
34557c478bd9Sstevel@tonic-gate 			 * If doing XCASE processing (not very
34567c478bd9Sstevel@tonic-gate 			 * likely, in this day and age), look at each
34577c478bd9Sstevel@tonic-gate 			 * character individually.
34587c478bd9Sstevel@tonic-gate 			 */
34597c478bd9Sstevel@tonic-gate 			if ((tp->t_modes.c_lflag & XCASE) &&
34607c478bd9Sstevel@tonic-gate 			    (tp->t_modes.c_lflag & ICANON)) {
34617c478bd9Sstevel@tonic-gate 				c = *ibp->b_rptr++;
34627c478bd9Sstevel@tonic-gate 
34637c478bd9Sstevel@tonic-gate 				/*
34647c478bd9Sstevel@tonic-gate 				 * We need to make sure that this is not
34657c478bd9Sstevel@tonic-gate 				 * a following byte of a multibyte character
34667c478bd9Sstevel@tonic-gate 				 * before applying an XCASE processing.
34677c478bd9Sstevel@tonic-gate 				 *
34687c478bd9Sstevel@tonic-gate 				 * tp->t_eucign will be 0 if and only
34697c478bd9Sstevel@tonic-gate 				 * if the current 'c' is an ASCII character
34707c478bd9Sstevel@tonic-gate 				 * and also a byte. Otherwise, it will have
34717c478bd9Sstevel@tonic-gate 				 * the byte length of a multibyte character.
34727c478bd9Sstevel@tonic-gate 				 */
34737c478bd9Sstevel@tonic-gate 				if ((tp->t_state & TS_MEUC) &&
34747c478bd9Sstevel@tonic-gate 				    tp->t_eucign == 0 && NOTASCII(c)) {
34757c478bd9Sstevel@tonic-gate 					tp->t_eucign =
34767c478bd9Sstevel@tonic-gate 					    tp->t_csmethods.ldterm_memwidth(
34777c478bd9Sstevel@tonic-gate 					    c, (void *)tp);
34787c478bd9Sstevel@tonic-gate 					tp->t_scratch_len = tp->t_eucign;
34797c478bd9Sstevel@tonic-gate 
34807c478bd9Sstevel@tonic-gate 					if (tp->t_csdata.codeset_type !=
34817c478bd9Sstevel@tonic-gate 					    LDTERM_CS_TYPE_UTF8) {
34827c478bd9Sstevel@tonic-gate 						tp->t_col +=
348385bb5f1dSis 						    tp->
348485bb5f1dSis 						    t_csmethods.
348585bb5f1dSis 						    ldterm_dispwidth(c,
348685bb5f1dSis 						    (void *)tp,
348785bb5f1dSis 						    tp->t_modes.c_lflag &
348885bb5f1dSis 						    ECHOCTL);
34897c478bd9Sstevel@tonic-gate 					}
34907c478bd9Sstevel@tonic-gate 				}
34917c478bd9Sstevel@tonic-gate 
34927c478bd9Sstevel@tonic-gate 				/*
34937c478bd9Sstevel@tonic-gate 				 * If character is mapped on output,
34947c478bd9Sstevel@tonic-gate 				 * put out a backslash followed by
34957c478bd9Sstevel@tonic-gate 				 * what it is mapped to.
34967c478bd9Sstevel@tonic-gate 				 */
34977c478bd9Sstevel@tonic-gate 				if (tp->t_eucign == 0 && omaptab[c] != 0 &&
34987c478bd9Sstevel@tonic-gate 				    (!echoing || c != '\\')) {
34997c478bd9Sstevel@tonic-gate 					/* backslash is an ordinary character */
35007c478bd9Sstevel@tonic-gate 					tp->t_col++;
35017c478bd9Sstevel@tonic-gate 					*obp->b_wptr++ = '\\';
35027c478bd9Sstevel@tonic-gate 					bytes_left--;
35037c478bd9Sstevel@tonic-gate 					if (bytes_left == 0) {
35047c478bd9Sstevel@tonic-gate 						/* LINTED */
35057c478bd9Sstevel@tonic-gate 						NEW_BLOCK(1);
35067c478bd9Sstevel@tonic-gate 					}
35077c478bd9Sstevel@tonic-gate 					/*
35087c478bd9Sstevel@tonic-gate 					 * Allocation failed, make
35097c478bd9Sstevel@tonic-gate 					 * state consistent before
35107c478bd9Sstevel@tonic-gate 					 * returning
35117c478bd9Sstevel@tonic-gate 					 */
35127c478bd9Sstevel@tonic-gate 					if (obp == NULL) {
35137c478bd9Sstevel@tonic-gate 						ibp->b_rptr--;
35147c478bd9Sstevel@tonic-gate 						tp->t_col--;
35157c478bd9Sstevel@tonic-gate 						oobp->b_wptr--;
35167c478bd9Sstevel@tonic-gate 						goto outofbufs;
35177c478bd9Sstevel@tonic-gate 					}
35187c478bd9Sstevel@tonic-gate 					c = omaptab[c];
35197c478bd9Sstevel@tonic-gate 				}
35207c478bd9Sstevel@tonic-gate 				/*
35217c478bd9Sstevel@tonic-gate 				 * If no other output processing is
35227c478bd9Sstevel@tonic-gate 				 * required, push the character into
35237c478bd9Sstevel@tonic-gate 				 * the block and get another.
35247c478bd9Sstevel@tonic-gate 				 */
35257c478bd9Sstevel@tonic-gate 				if (!(tp->t_modes.c_oflag & OPOST)) {
35267c478bd9Sstevel@tonic-gate 					if (tp->t_eucign > 0) {
35277c478bd9Sstevel@tonic-gate 						--tp->t_eucign;
35287c478bd9Sstevel@tonic-gate 					} else {
35297c478bd9Sstevel@tonic-gate 						tp->t_col++;
35307c478bd9Sstevel@tonic-gate 					}
35317c478bd9Sstevel@tonic-gate 					*obp->b_wptr++ = c;
35327c478bd9Sstevel@tonic-gate 					bytes_left--;
35337c478bd9Sstevel@tonic-gate 					continue;
35347c478bd9Sstevel@tonic-gate 				}
35357c478bd9Sstevel@tonic-gate 				/*
35367c478bd9Sstevel@tonic-gate 				 * OPOST output flag is set. Map
35377c478bd9Sstevel@tonic-gate 				 * lower case to upper case if OLCUC
35387c478bd9Sstevel@tonic-gate 				 * flag is set and the 'c' is a lowercase
35397c478bd9Sstevel@tonic-gate 				 * ASCII character.
35407c478bd9Sstevel@tonic-gate 				 */
35417c478bd9Sstevel@tonic-gate 				if (tp->t_eucign == 0 &&
35427c478bd9Sstevel@tonic-gate 				    (tp->t_modes.c_oflag & OLCUC) &&
35437c478bd9Sstevel@tonic-gate 				    c >= 'a' && c <= 'z')
35447c478bd9Sstevel@tonic-gate 					c -= 'a' - 'A';
35457c478bd9Sstevel@tonic-gate 			} else {
35467c478bd9Sstevel@tonic-gate 				/*
35477c478bd9Sstevel@tonic-gate 				 * Copy all the ORDINARY characters,
35487c478bd9Sstevel@tonic-gate 				 * possibly mapping upper case to
35497c478bd9Sstevel@tonic-gate 				 * lower case.  We use "movtuc",
35507c478bd9Sstevel@tonic-gate 				 * STOPPING when we can't move some
35517c478bd9Sstevel@tonic-gate 				 * character. For multi-byte or
35527c478bd9Sstevel@tonic-gate 				 * multi-column EUC, we can't depend
35537c478bd9Sstevel@tonic-gate 				 * on the regular tables. Rather than
35547c478bd9Sstevel@tonic-gate 				 * just drop through to the "big
35557c478bd9Sstevel@tonic-gate 				 * switch" for all characters, it
35567c478bd9Sstevel@tonic-gate 				 * _might_ be faster to let "movtuc"
35577c478bd9Sstevel@tonic-gate 				 * move a bunch of characters.
35587c478bd9Sstevel@tonic-gate 				 * Chances are, even in multi-byte
35597c478bd9Sstevel@tonic-gate 				 * mode we'll have lots of ASCII
35607c478bd9Sstevel@tonic-gate 				 * going through. We check the flag
35617c478bd9Sstevel@tonic-gate 				 * once, and call movtuc with the
35627c478bd9Sstevel@tonic-gate 				 * appropriate table as an argument.
35637c478bd9Sstevel@tonic-gate 				 *
35647c478bd9Sstevel@tonic-gate 				 * "movtuc will work for all codeset
35657c478bd9Sstevel@tonic-gate 				 * types since it stops at the beginning
35667c478bd9Sstevel@tonic-gate 				 * byte of a multibyte character.
35677c478bd9Sstevel@tonic-gate 				 */
35687c478bd9Sstevel@tonic-gate 				size_t bytes_to_move;
35697c478bd9Sstevel@tonic-gate 				size_t bytes_moved;
35707c478bd9Sstevel@tonic-gate 
35717c478bd9Sstevel@tonic-gate 				ASSERT(ibp->b_wptr >= ibp->b_rptr);
35727c478bd9Sstevel@tonic-gate 				bytes_to_move = ibp->b_wptr - ibp->b_rptr;
35737c478bd9Sstevel@tonic-gate 				if (bytes_to_move > bytes_left)
35747c478bd9Sstevel@tonic-gate 					bytes_to_move = bytes_left;
35757c478bd9Sstevel@tonic-gate 				if (tp->t_state & TS_MEUC) {
35767c478bd9Sstevel@tonic-gate 					bytes_moved = movtuc(bytes_to_move,
35777c478bd9Sstevel@tonic-gate 					    ibp->b_rptr, obp->b_wptr,
35787c478bd9Sstevel@tonic-gate 					    (tp->t_modes.c_oflag & OLCUC ?
35797c478bd9Sstevel@tonic-gate 					    elcuctab : enotrantab));
35807c478bd9Sstevel@tonic-gate 				} else {
35817c478bd9Sstevel@tonic-gate 					bytes_moved = movtuc(bytes_to_move,
35827c478bd9Sstevel@tonic-gate 					    ibp->b_rptr, obp->b_wptr,
35837c478bd9Sstevel@tonic-gate 					    (tp->t_modes.c_oflag & OLCUC ?
35847c478bd9Sstevel@tonic-gate 					    lcuctab : notrantab));
35857c478bd9Sstevel@tonic-gate 				}
35867c478bd9Sstevel@tonic-gate 				/*
35877c478bd9Sstevel@tonic-gate 				 * We're save to just do this column
35887c478bd9Sstevel@tonic-gate 				 * calculation, because if TS_MEUC is
35897c478bd9Sstevel@tonic-gate 				 * set, we used the proper EUC
35907c478bd9Sstevel@tonic-gate 				 * tables, and won't have copied any
35917c478bd9Sstevel@tonic-gate 				 * EUC bytes.
35927c478bd9Sstevel@tonic-gate 				 */
35937c478bd9Sstevel@tonic-gate 				tp->t_col += bytes_moved;
35947c478bd9Sstevel@tonic-gate 				ibp->b_rptr += bytes_moved;
35957c478bd9Sstevel@tonic-gate 				obp->b_wptr += bytes_moved;
35967c478bd9Sstevel@tonic-gate 				bytes_left -= bytes_moved;
35977c478bd9Sstevel@tonic-gate 				if (ibp->b_rptr >= ibp->b_wptr)
35987c478bd9Sstevel@tonic-gate 					continue;	/* moved all of block */
35997c478bd9Sstevel@tonic-gate 				if (bytes_left == 0) {
36007c478bd9Sstevel@tonic-gate 					/* LINTED */
36017c478bd9Sstevel@tonic-gate 					NEW_BLOCK(0);
36027c478bd9Sstevel@tonic-gate 				}
36037c478bd9Sstevel@tonic-gate 				c = *ibp->b_rptr++;	/* stopper */
36047c478bd9Sstevel@tonic-gate 			}
36057c478bd9Sstevel@tonic-gate 
36067c478bd9Sstevel@tonic-gate 			/*
36077c478bd9Sstevel@tonic-gate 			 * Again, we need to make sure that this is not
36087c478bd9Sstevel@tonic-gate 			 * a following byte of a multibyte character at
36097c478bd9Sstevel@tonic-gate 			 * here.
36107c478bd9Sstevel@tonic-gate 			 *
36117c478bd9Sstevel@tonic-gate 			 * 'tp->t_eucign' will be 0 iff the current 'c' is
36127c478bd9Sstevel@tonic-gate 			 * an ASCII character. Otherwise, it will have
36137c478bd9Sstevel@tonic-gate 			 * the byte length of a multibyte character.
36147c478bd9Sstevel@tonic-gate 			 * We also add the display width to 'tp->t_col' if
36157c478bd9Sstevel@tonic-gate 			 * the current codeset is not UTF-8 since this is
36167c478bd9Sstevel@tonic-gate 			 * a leading byte of a multibyte character.
36177c478bd9Sstevel@tonic-gate 			 * For UTF-8 codeset type, we add the display width
36187c478bd9Sstevel@tonic-gate 			 * when we get the last byte of a character.
36197c478bd9Sstevel@tonic-gate 			 */
36207c478bd9Sstevel@tonic-gate 			if ((tp->t_state & TS_MEUC) && tp->t_eucign == 0 &&
36217c478bd9Sstevel@tonic-gate 			    NOTASCII(c)) {
36227c478bd9Sstevel@tonic-gate 				tp->t_eucign = tp->t_csmethods.ldterm_memwidth(
36237c478bd9Sstevel@tonic-gate 				    c, (void *)tp);
36247c478bd9Sstevel@tonic-gate 				tp->t_scratch_len = tp->t_eucign;
36257c478bd9Sstevel@tonic-gate 
36267c478bd9Sstevel@tonic-gate 				if (tp->t_csdata.codeset_type !=
36277c478bd9Sstevel@tonic-gate 				    LDTERM_CS_TYPE_UTF8) {
36287c478bd9Sstevel@tonic-gate 					tp->t_col +=
36297c478bd9Sstevel@tonic-gate 					    tp->t_csmethods.ldterm_dispwidth(c,
36307c478bd9Sstevel@tonic-gate 					    (void *)tp,
36317c478bd9Sstevel@tonic-gate 					    tp->t_modes.c_lflag & ECHOCTL);
36327c478bd9Sstevel@tonic-gate 				}
36337c478bd9Sstevel@tonic-gate 			}
36347c478bd9Sstevel@tonic-gate 
36357c478bd9Sstevel@tonic-gate 			/*
36367c478bd9Sstevel@tonic-gate 			 * If the driver has requested, don't process
36377c478bd9Sstevel@tonic-gate 			 * output flags.  However, if we're in
36387c478bd9Sstevel@tonic-gate 			 * multi-byte mode, we HAVE to look at
36397c478bd9Sstevel@tonic-gate 			 * EVERYTHING going out to maintain column
36407c478bd9Sstevel@tonic-gate 			 * position properly. Therefore IF the driver
36417c478bd9Sstevel@tonic-gate 			 * says don't AND we're not doing multi-byte,
36427c478bd9Sstevel@tonic-gate 			 * then don't do it.  Otherwise, do it.
36437c478bd9Sstevel@tonic-gate 			 *
36447c478bd9Sstevel@tonic-gate 			 * NOTE:  Hardware USUALLY doesn't expand tabs
36457c478bd9Sstevel@tonic-gate 			 * properly for multi-byte situations anyway;
36467c478bd9Sstevel@tonic-gate 			 * that's a known problem with the 3B2
36477c478bd9Sstevel@tonic-gate 			 * "PORTS" board firmware, and any other
36487c478bd9Sstevel@tonic-gate 			 * hardware that doesn't ACTUALLY know about
36497c478bd9Sstevel@tonic-gate 			 * the current EUC mapping that WE are using
36507c478bd9Sstevel@tonic-gate 			 * at this very moment.  The problem is that
36517c478bd9Sstevel@tonic-gate 			 * memory width is INDEPENDENT of screen
36527c478bd9Sstevel@tonic-gate 			 * width - no relation - so WE know how wide
36537c478bd9Sstevel@tonic-gate 			 * the characters are, but an off-the-host
36547c478bd9Sstevel@tonic-gate 			 * board probably doesn't.  So, until we're
36557c478bd9Sstevel@tonic-gate 			 * SURE that the hardware below us can
36567c478bd9Sstevel@tonic-gate 			 * correctly expand tabs in a
36577c478bd9Sstevel@tonic-gate 			 * multi-byte/multi-column EUC situation, we
36587c478bd9Sstevel@tonic-gate 			 * do it ourselves.
36597c478bd9Sstevel@tonic-gate 			 */
36607c478bd9Sstevel@tonic-gate 			/*
36617c478bd9Sstevel@tonic-gate 			 * Map <CR>to<NL> on output if OCRNL flag
36627c478bd9Sstevel@tonic-gate 			 * set. ONLCR processing is not done if OCRNL
36637c478bd9Sstevel@tonic-gate 			 * is set.
36647c478bd9Sstevel@tonic-gate 			 */
36657c478bd9Sstevel@tonic-gate 			if (c == '\r' && (tp->t_modes.c_oflag & OCRNL)) {
36667c478bd9Sstevel@tonic-gate 				c = '\n';
36677c478bd9Sstevel@tonic-gate 				ctype = typetab[c];
36687c478bd9Sstevel@tonic-gate 				goto jocrnl;
36697c478bd9Sstevel@tonic-gate 			}
36707c478bd9Sstevel@tonic-gate 
36717c478bd9Sstevel@tonic-gate 			if (tp->t_csdata.codeset_type == LDTERM_CS_TYPE_EUC) {
36727c478bd9Sstevel@tonic-gate 				ctype = typetab[c];
36737c478bd9Sstevel@tonic-gate 			} else {
36747c478bd9Sstevel@tonic-gate 				/*
36757c478bd9Sstevel@tonic-gate 				 * In other codeset types, we safely assume
36767c478bd9Sstevel@tonic-gate 				 * any byte of a multibyte character will have
36777c478bd9Sstevel@tonic-gate 				 * 'ORDINARY' type. For ASCII characters, we
36787c478bd9Sstevel@tonic-gate 				 * still use the typetab[].
36797c478bd9Sstevel@tonic-gate 				 */
36807c478bd9Sstevel@tonic-gate 				if (tp->t_eucign == 0)
36817c478bd9Sstevel@tonic-gate 					ctype = typetab[c];
36827c478bd9Sstevel@tonic-gate 				else
36837c478bd9Sstevel@tonic-gate 					ctype = ORDINARY;
36847c478bd9Sstevel@tonic-gate 			}
36857c478bd9Sstevel@tonic-gate 
36867c478bd9Sstevel@tonic-gate 			/*
36877c478bd9Sstevel@tonic-gate 			 * Map <NL> to <CR><NL> on output if ONLCR
36887c478bd9Sstevel@tonic-gate 			 * flag is set.
36897c478bd9Sstevel@tonic-gate 			 */
36907c478bd9Sstevel@tonic-gate 			if (c == '\n' && (tp->t_modes.c_oflag & ONLCR)) {
36917c478bd9Sstevel@tonic-gate 				if (!(tp->t_state & TS_TTCR)) {
36927c478bd9Sstevel@tonic-gate 					tp->t_state |= TS_TTCR;
36937c478bd9Sstevel@tonic-gate 					c = '\r';
36947c478bd9Sstevel@tonic-gate 					ctype = typetab['\r'];
36957c478bd9Sstevel@tonic-gate 					--ibp->b_rptr;
36967c478bd9Sstevel@tonic-gate 				} else
36977c478bd9Sstevel@tonic-gate 					tp->t_state &= ~TS_TTCR;
36987c478bd9Sstevel@tonic-gate 			}
36997c478bd9Sstevel@tonic-gate 			/*
37007c478bd9Sstevel@tonic-gate 			 * Delay values and column position
37017c478bd9Sstevel@tonic-gate 			 * calculated here.  For EUC chars in
37027c478bd9Sstevel@tonic-gate 			 * multi-byte mode, we use "t_eucign" to help
37037c478bd9Sstevel@tonic-gate 			 * calculate columns.  When we see the first
37047c478bd9Sstevel@tonic-gate 			 * byte of an EUC, we set t_eucign to the
37057c478bd9Sstevel@tonic-gate 			 * number of bytes that will FOLLOW it, and
37067c478bd9Sstevel@tonic-gate 			 * we add the screen width of the WHOLE EUC
37077c478bd9Sstevel@tonic-gate 			 * character to the column position.  In
37087c478bd9Sstevel@tonic-gate 			 * particular, we can't count SS2 or SS3 as
37097c478bd9Sstevel@tonic-gate 			 * printing characters.  Remember, folks, the
37107c478bd9Sstevel@tonic-gate 			 * screen width and memory width are
37117c478bd9Sstevel@tonic-gate 			 * independent - no relation. We could have
37127c478bd9Sstevel@tonic-gate 			 * dropped through for ASCII, but we want to
37137c478bd9Sstevel@tonic-gate 			 * catch any bad characters (i.e., t_eucign
37147c478bd9Sstevel@tonic-gate 			 * set and an ASCII char received) and
37157c478bd9Sstevel@tonic-gate 			 * possibly report the garbage situation.
37167c478bd9Sstevel@tonic-gate 			 */
37177c478bd9Sstevel@tonic-gate 	jocrnl:
37187c478bd9Sstevel@tonic-gate 
37197c478bd9Sstevel@tonic-gate 			count = 0;
37207c478bd9Sstevel@tonic-gate 			switch (ctype) {
37217c478bd9Sstevel@tonic-gate 
37227c478bd9Sstevel@tonic-gate 			case T_SS2:
37237c478bd9Sstevel@tonic-gate 			case T_SS3:
37247c478bd9Sstevel@tonic-gate 			case ORDINARY:
37257c478bd9Sstevel@tonic-gate 				if (tp->t_state & TS_MEUC) {
37267c478bd9Sstevel@tonic-gate 					if (tp->t_eucign) {
37277c478bd9Sstevel@tonic-gate 						*obp->b_wptr++ = c;
37287c478bd9Sstevel@tonic-gate 						bytes_left--;
37297c478bd9Sstevel@tonic-gate 
37307c478bd9Sstevel@tonic-gate 						tp->t_scratch[tp->t_scratch_len
37317c478bd9Sstevel@tonic-gate 						    - tp->t_eucign] = c;
37327c478bd9Sstevel@tonic-gate 
37337c478bd9Sstevel@tonic-gate 						--tp->t_eucign;
37347c478bd9Sstevel@tonic-gate 
37357c478bd9Sstevel@tonic-gate 						if (tp->t_csdata.codeset_type
37367c478bd9Sstevel@tonic-gate 						    == LDTERM_CS_TYPE_UTF8 &&
37377c478bd9Sstevel@tonic-gate 						    tp->t_eucign <= 0) {
37387c478bd9Sstevel@tonic-gate 							tp->t_col +=
37397c478bd9Sstevel@tonic-gate 							    ldterm_utf8_width(
37407c478bd9Sstevel@tonic-gate 							    tp->t_scratch,
37417c478bd9Sstevel@tonic-gate 							    tp->t_scratch_len);
37427c478bd9Sstevel@tonic-gate 						}
37437c478bd9Sstevel@tonic-gate 					} else {
37447c478bd9Sstevel@tonic-gate 						if (tp->t_modes.c_oflag & OLCUC)
37457c478bd9Sstevel@tonic-gate 							n = elcuctab[c];
37467c478bd9Sstevel@tonic-gate 						else
37477c478bd9Sstevel@tonic-gate 							n = enotrantab[c];
37487c478bd9Sstevel@tonic-gate 						if (n)
37497c478bd9Sstevel@tonic-gate 							c = n;
37507c478bd9Sstevel@tonic-gate 						tp->t_col++;
37517c478bd9Sstevel@tonic-gate 						*obp->b_wptr++ = c;
37527c478bd9Sstevel@tonic-gate 						bytes_left--;
37537c478bd9Sstevel@tonic-gate 					}
37547c478bd9Sstevel@tonic-gate 				} else {	/* ho hum, ASCII mode... */
37557c478bd9Sstevel@tonic-gate 					if (tp->t_modes.c_oflag & OLCUC)
37567c478bd9Sstevel@tonic-gate 						n = lcuctab[c];
37577c478bd9Sstevel@tonic-gate 					else
37587c478bd9Sstevel@tonic-gate 						n = notrantab[c];
37597c478bd9Sstevel@tonic-gate 					if (n)
37607c478bd9Sstevel@tonic-gate 						c = n;
37617c478bd9Sstevel@tonic-gate 					tp->t_col++;
37627c478bd9Sstevel@tonic-gate 					*obp->b_wptr++ = c;
37637c478bd9Sstevel@tonic-gate 					bytes_left--;
37647c478bd9Sstevel@tonic-gate 				}
37657c478bd9Sstevel@tonic-gate 				break;
37667c478bd9Sstevel@tonic-gate 
37677c478bd9Sstevel@tonic-gate 				/*
37687c478bd9Sstevel@tonic-gate 				 * If we're doing ECHOCTL, we've
37697c478bd9Sstevel@tonic-gate 				 * already mapped the thing during
37707c478bd9Sstevel@tonic-gate 				 * the process of canonising.  Don't
37717c478bd9Sstevel@tonic-gate 				 * bother here, as it's not one that
37727c478bd9Sstevel@tonic-gate 				 * we did.
37737c478bd9Sstevel@tonic-gate 				 */
37747c478bd9Sstevel@tonic-gate 			case CONTROL:
37757c478bd9Sstevel@tonic-gate 				*obp->b_wptr++ = c;
37767c478bd9Sstevel@tonic-gate 				bytes_left--;
37777c478bd9Sstevel@tonic-gate 				break;
37787c478bd9Sstevel@tonic-gate 
37797c478bd9Sstevel@tonic-gate 				/*
37807c478bd9Sstevel@tonic-gate 				 * This is probably a backspace
37817c478bd9Sstevel@tonic-gate 				 * received, not one that we're
37827c478bd9Sstevel@tonic-gate 				 * echoing.  Let it go as a
37837c478bd9Sstevel@tonic-gate 				 * single-column backspace.
37847c478bd9Sstevel@tonic-gate 				 */
37857c478bd9Sstevel@tonic-gate 			case BACKSPACE:
37867c478bd9Sstevel@tonic-gate 				if (tp->t_col)
37877c478bd9Sstevel@tonic-gate 					tp->t_col--;
37887c478bd9Sstevel@tonic-gate 				if (tp->t_modes.c_oflag & BSDLY) {
37897c478bd9Sstevel@tonic-gate 					if (tp->t_modes.c_oflag & OFILL)
37907c478bd9Sstevel@tonic-gate 						count = 1;
37917c478bd9Sstevel@tonic-gate 				}
37927c478bd9Sstevel@tonic-gate 				*obp->b_wptr++ = c;
37937c478bd9Sstevel@tonic-gate 				bytes_left--;
37947c478bd9Sstevel@tonic-gate 				break;
37957c478bd9Sstevel@tonic-gate 
37967c478bd9Sstevel@tonic-gate 			case NEWLINE:
37977c478bd9Sstevel@tonic-gate 				if (tp->t_modes.c_oflag & ONLRET)
37987c478bd9Sstevel@tonic-gate 					goto cr;
37997c478bd9Sstevel@tonic-gate 				if ((tp->t_modes.c_oflag & NLDLY) == NL1)
38007c478bd9Sstevel@tonic-gate 					count = 2;
38017c478bd9Sstevel@tonic-gate 				*obp->b_wptr++ = c;
38027c478bd9Sstevel@tonic-gate 				bytes_left--;
38037c478bd9Sstevel@tonic-gate 				break;
38047c478bd9Sstevel@tonic-gate 
38057c478bd9Sstevel@tonic-gate 			case TAB:
38067c478bd9Sstevel@tonic-gate 				/*
38077c478bd9Sstevel@tonic-gate 				 * Map '\t' to spaces if XTABS flag
38087c478bd9Sstevel@tonic-gate 				 * is set.  The calculation of
38097c478bd9Sstevel@tonic-gate 				 * "t_eucign" has probably insured
38107c478bd9Sstevel@tonic-gate 				 * that column will be correct, as we
38117c478bd9Sstevel@tonic-gate 				 * bumped t_col by the DISP width,
38127c478bd9Sstevel@tonic-gate 				 * not the memory width.
38137c478bd9Sstevel@tonic-gate 				 */
38147c478bd9Sstevel@tonic-gate 				if ((tp->t_modes.c_oflag & TABDLY) == XTABS) {
38157c478bd9Sstevel@tonic-gate 					for (;;) {
38167c478bd9Sstevel@tonic-gate 						*obp->b_wptr++ = ' ';
38177c478bd9Sstevel@tonic-gate 						bytes_left--;
38187c478bd9Sstevel@tonic-gate 						tp->t_col++;
38197c478bd9Sstevel@tonic-gate 						if ((tp->t_col & 07) == 0)
38207c478bd9Sstevel@tonic-gate 							break;	/* every 8th */
38217c478bd9Sstevel@tonic-gate 						/*
38227c478bd9Sstevel@tonic-gate 						 * If we don't have
38237c478bd9Sstevel@tonic-gate 						 * room to fully
38247c478bd9Sstevel@tonic-gate 						 * expand this tab in
38257c478bd9Sstevel@tonic-gate 						 * this block, back
38267c478bd9Sstevel@tonic-gate 						 * up to continue
38277c478bd9Sstevel@tonic-gate 						 * expanding it into
38287c478bd9Sstevel@tonic-gate 						 * the next block.
38297c478bd9Sstevel@tonic-gate 						 */
38307c478bd9Sstevel@tonic-gate 						if (obp->b_wptr >=
38317c478bd9Sstevel@tonic-gate 						    obp->b_datap->db_lim) {
38327c478bd9Sstevel@tonic-gate 							ibp->b_rptr--;
38337c478bd9Sstevel@tonic-gate 							break;
38347c478bd9Sstevel@tonic-gate 						}
38357c478bd9Sstevel@tonic-gate 					}
38367c478bd9Sstevel@tonic-gate 				} else {
38377c478bd9Sstevel@tonic-gate 					tp->t_col |= 07;
38387c478bd9Sstevel@tonic-gate 					tp->t_col++;
38397c478bd9Sstevel@tonic-gate 					if (tp->t_modes.c_oflag & OFILL) {
38407c478bd9Sstevel@tonic-gate 						if (tp->t_modes.c_oflag &
38417c478bd9Sstevel@tonic-gate 						    TABDLY)
38427c478bd9Sstevel@tonic-gate 							count = 2;
38437c478bd9Sstevel@tonic-gate 					} else {
38447c478bd9Sstevel@tonic-gate 						switch (tp->t_modes.c_oflag &
38457c478bd9Sstevel@tonic-gate 						    TABDLY) {
38467c478bd9Sstevel@tonic-gate 						case TAB2:
38477c478bd9Sstevel@tonic-gate 							count = 6;
38487c478bd9Sstevel@tonic-gate 							break;
38497c478bd9Sstevel@tonic-gate 
38507c478bd9Sstevel@tonic-gate 						case TAB1:
38517c478bd9Sstevel@tonic-gate 							count = 1 + (tp->t_col |
38527c478bd9Sstevel@tonic-gate 							    ~07);
38537c478bd9Sstevel@tonic-gate 							if (count < 5)
38547c478bd9Sstevel@tonic-gate 								count = 0;
38557c478bd9Sstevel@tonic-gate 							break;
38567c478bd9Sstevel@tonic-gate 						}
38577c478bd9Sstevel@tonic-gate 					}
38587c478bd9Sstevel@tonic-gate 					*obp->b_wptr++ = c;
38597c478bd9Sstevel@tonic-gate 					bytes_left--;
38607c478bd9Sstevel@tonic-gate 				}
38617c478bd9Sstevel@tonic-gate 				break;
38627c478bd9Sstevel@tonic-gate 
38637c478bd9Sstevel@tonic-gate 			case VTAB:
38647c478bd9Sstevel@tonic-gate 				if ((tp->t_modes.c_oflag & VTDLY) &&
38657c478bd9Sstevel@tonic-gate 				    !(tp->t_modes.c_oflag & OFILL))
38667c478bd9Sstevel@tonic-gate 					count = 127;
38677c478bd9Sstevel@tonic-gate 				*obp->b_wptr++ = c;
38687c478bd9Sstevel@tonic-gate 				bytes_left--;
38697c478bd9Sstevel@tonic-gate 				break;
38707c478bd9Sstevel@tonic-gate 
38717c478bd9Sstevel@tonic-gate 			case RETURN:
38727c478bd9Sstevel@tonic-gate 				/*
38737c478bd9Sstevel@tonic-gate 				 * Ignore <CR> in column 0 if ONOCR
38747c478bd9Sstevel@tonic-gate 				 * flag set.
38757c478bd9Sstevel@tonic-gate 				 */
38767c478bd9Sstevel@tonic-gate 				if (tp->t_col == 0 &&
38777c478bd9Sstevel@tonic-gate 				    (tp->t_modes.c_oflag & ONOCR))
38787c478bd9Sstevel@tonic-gate 					break;
38797c478bd9Sstevel@tonic-gate 
38807c478bd9Sstevel@tonic-gate 		cr:
38817c478bd9Sstevel@tonic-gate 				switch (tp->t_modes.c_oflag & CRDLY) {
38827c478bd9Sstevel@tonic-gate 
38837c478bd9Sstevel@tonic-gate 				case CR1:
38847c478bd9Sstevel@tonic-gate 					if (tp->t_modes.c_oflag & OFILL)
38857c478bd9Sstevel@tonic-gate 						count = 2;
38867c478bd9Sstevel@tonic-gate 					else
38877c478bd9Sstevel@tonic-gate 						count = tp->t_col % 2;
38887c478bd9Sstevel@tonic-gate 					break;
38897c478bd9Sstevel@tonic-gate 
38907c478bd9Sstevel@tonic-gate 				case CR2:
38917c478bd9Sstevel@tonic-gate 					if (tp->t_modes.c_oflag & OFILL)
38927c478bd9Sstevel@tonic-gate 						count = 4;
38937c478bd9Sstevel@tonic-gate 					else
38947c478bd9Sstevel@tonic-gate 						count = 6;
38957c478bd9Sstevel@tonic-gate 					break;
38967c478bd9Sstevel@tonic-gate 
38977c478bd9Sstevel@tonic-gate 				case CR3:
38987c478bd9Sstevel@tonic-gate 					if (tp->t_modes.c_oflag & OFILL)
38997c478bd9Sstevel@tonic-gate 						count = 0;
39007c478bd9Sstevel@tonic-gate 					else
39017c478bd9Sstevel@tonic-gate 						count = 9;
39027c478bd9Sstevel@tonic-gate 					break;
39037c478bd9Sstevel@tonic-gate 				}
39047c478bd9Sstevel@tonic-gate 				tp->t_col = 0;
39057c478bd9Sstevel@tonic-gate 				*obp->b_wptr++ = c;
39067c478bd9Sstevel@tonic-gate 				bytes_left--;
39077c478bd9Sstevel@tonic-gate 				break;
39087c478bd9Sstevel@tonic-gate 			}
39097c478bd9Sstevel@tonic-gate 
39107c478bd9Sstevel@tonic-gate 			if (count != 0) {
39117c478bd9Sstevel@tonic-gate 				if (tp->t_modes.c_oflag & OFILL) {
39127c478bd9Sstevel@tonic-gate 					do {
39137c478bd9Sstevel@tonic-gate 						if (bytes_left == 0) {
39147c478bd9Sstevel@tonic-gate 							/* LINTED */
39157c478bd9Sstevel@tonic-gate 							NEW_BLOCK(0);
39167c478bd9Sstevel@tonic-gate 						}
39177c478bd9Sstevel@tonic-gate 						if (tp->t_modes.c_oflag & OFDEL)
39187c478bd9Sstevel@tonic-gate 							*obp->b_wptr++ = CDEL;
39197c478bd9Sstevel@tonic-gate 						else
39207c478bd9Sstevel@tonic-gate 							*obp->b_wptr++ = CNUL;
39217c478bd9Sstevel@tonic-gate 						bytes_left--;
39227c478bd9Sstevel@tonic-gate 					} while (--count != 0);
39237c478bd9Sstevel@tonic-gate 				} else {
39247c478bd9Sstevel@tonic-gate 					if ((tp->t_modes.c_lflag & FLUSHO) &&
39257c478bd9Sstevel@tonic-gate 					    (tp->t_modes.c_lflag & IEXTEN)) {
39267c478bd9Sstevel@tonic-gate 						/* drop on floor */
39277c478bd9Sstevel@tonic-gate 						freemsg(*omp);
39287c478bd9Sstevel@tonic-gate 					} else {
39297c478bd9Sstevel@tonic-gate 						/*
39307c478bd9Sstevel@tonic-gate 						 * Update sysinfo
39317c478bd9Sstevel@tonic-gate 						 * outch
39327c478bd9Sstevel@tonic-gate 						 */
39337c478bd9Sstevel@tonic-gate 						(void) drv_setparm(SYSOUTC,
39347c478bd9Sstevel@tonic-gate 						    msgdsize(*omp));
39357c478bd9Sstevel@tonic-gate 						putnext(q, *omp);
39367c478bd9Sstevel@tonic-gate 						/*
39377c478bd9Sstevel@tonic-gate 						 * Send M_DELAY
39387c478bd9Sstevel@tonic-gate 						 * downstream
39397c478bd9Sstevel@tonic-gate 						 */
39407c478bd9Sstevel@tonic-gate 						if ((bp =
39417c478bd9Sstevel@tonic-gate 						    allocb(1, BPRI_MED)) !=
39427c478bd9Sstevel@tonic-gate 						    NULL) {
39437c478bd9Sstevel@tonic-gate 							bp->b_datap->db_type =
39447c478bd9Sstevel@tonic-gate 							    M_DELAY;
39457c478bd9Sstevel@tonic-gate 							*bp->b_wptr++ =
39467c478bd9Sstevel@tonic-gate 							    (uchar_t)count;
39477c478bd9Sstevel@tonic-gate 							putnext(q, bp);
39487c478bd9Sstevel@tonic-gate 						}
39497c478bd9Sstevel@tonic-gate 					}
39507c478bd9Sstevel@tonic-gate 					bytes_left = 0;
39517c478bd9Sstevel@tonic-gate 					/*
39527c478bd9Sstevel@tonic-gate 					 * We have to start a new
39537c478bd9Sstevel@tonic-gate 					 * message; the delay
39547c478bd9Sstevel@tonic-gate 					 * introduces a break between
39557c478bd9Sstevel@tonic-gate 					 * messages.
39567c478bd9Sstevel@tonic-gate 					 */
39577c478bd9Sstevel@tonic-gate 					*omp = NULL;
39587c478bd9Sstevel@tonic-gate 					contpp = omp;
39597c478bd9Sstevel@tonic-gate 				}
39607c478bd9Sstevel@tonic-gate 			}
39617c478bd9Sstevel@tonic-gate 		}
39627c478bd9Sstevel@tonic-gate 		cbp = ibp->b_cont;
39637c478bd9Sstevel@tonic-gate 		freeb(ibp);
39647c478bd9Sstevel@tonic-gate 	} while ((ibp = cbp) != NULL);	/* next block, if any */
39657c478bd9Sstevel@tonic-gate 
39667c478bd9Sstevel@tonic-gate outofbufs:
39677c478bd9Sstevel@tonic-gate 	return (ibp);
39687c478bd9Sstevel@tonic-gate #undef NEW_BLOCK
39697c478bd9Sstevel@tonic-gate }
39707c478bd9Sstevel@tonic-gate 
39717c478bd9Sstevel@tonic-gate 
39727c478bd9Sstevel@tonic-gate #if !defined(__sparc)
39737c478bd9Sstevel@tonic-gate int
39747c478bd9Sstevel@tonic-gate movtuc(size_t size, unsigned char *from, unsigned char *origto,
39757c478bd9Sstevel@tonic-gate 	unsigned char *table)
39767c478bd9Sstevel@tonic-gate {
39777c478bd9Sstevel@tonic-gate 	unsigned char *to = origto;
39787c478bd9Sstevel@tonic-gate 	unsigned char c;
39797c478bd9Sstevel@tonic-gate 
39807c478bd9Sstevel@tonic-gate 	while (size != 0 && (c = table[*from++]) != 0) {
39817c478bd9Sstevel@tonic-gate 		*to++ = c;
39827c478bd9Sstevel@tonic-gate 		size--;
39837c478bd9Sstevel@tonic-gate 	}
39847c478bd9Sstevel@tonic-gate 	return (to - origto);
39857c478bd9Sstevel@tonic-gate }
39867c478bd9Sstevel@tonic-gate #endif
39877c478bd9Sstevel@tonic-gate 
39887c478bd9Sstevel@tonic-gate static void
39897c478bd9Sstevel@tonic-gate ldterm_flush_output(uchar_t c, queue_t *q, ldtermstd_state_t *tp)
39907c478bd9Sstevel@tonic-gate {
39917c478bd9Sstevel@tonic-gate 	/* Already conditioned with IEXTEN during VDISCARD processing */
39927c478bd9Sstevel@tonic-gate 	if (tp->t_modes.c_lflag & FLUSHO)
39937c478bd9Sstevel@tonic-gate 		tp->t_modes.c_lflag &= ~FLUSHO;
39947c478bd9Sstevel@tonic-gate 	else {
39957c478bd9Sstevel@tonic-gate 		flushq(q, FLUSHDATA);	/* flush our write queue */
39967c478bd9Sstevel@tonic-gate 		/* flush ones below us */
39977c478bd9Sstevel@tonic-gate 		(void) putnextctl1(q, M_FLUSH, FLUSHW);
39987c478bd9Sstevel@tonic-gate 		if ((tp->t_echomp = allocb(EBSIZE, BPRI_HI)) != NULL) {
39997c478bd9Sstevel@tonic-gate 			(void) ldterm_echo(c, q, 1, tp);
40007c478bd9Sstevel@tonic-gate 			if (tp->t_msglen != 0)
40017c478bd9Sstevel@tonic-gate 				ldterm_reprint(q, EBSIZE, tp);
40027c478bd9Sstevel@tonic-gate 			if (tp->t_echomp != NULL) {
40037c478bd9Sstevel@tonic-gate 				putnext(q, tp->t_echomp);
40047c478bd9Sstevel@tonic-gate 				tp->t_echomp = NULL;
40057c478bd9Sstevel@tonic-gate 			}
40067c478bd9Sstevel@tonic-gate 		}
40077c478bd9Sstevel@tonic-gate 		tp->t_modes.c_lflag |= FLUSHO;
40087c478bd9Sstevel@tonic-gate 	}
40097c478bd9Sstevel@tonic-gate }
40107c478bd9Sstevel@tonic-gate 
40117c478bd9Sstevel@tonic-gate 
40127c478bd9Sstevel@tonic-gate /*
40137c478bd9Sstevel@tonic-gate  * Signal generated by the reader: M_PCSIG and M_FLUSH messages sent.
40147c478bd9Sstevel@tonic-gate  */
40157c478bd9Sstevel@tonic-gate static void
40167c478bd9Sstevel@tonic-gate ldterm_dosig(queue_t *q, int sig, uchar_t c, int mtype, int mode)
40177c478bd9Sstevel@tonic-gate {
40187c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp = (ldtermstd_state_t *)q->q_ptr;
40197c478bd9Sstevel@tonic-gate 	int sndsig = 0;
40207c478bd9Sstevel@tonic-gate 
40217c478bd9Sstevel@tonic-gate 	/*
40227c478bd9Sstevel@tonic-gate 	 * c == \0 is brk case; need to flush on BRKINT even if
40237c478bd9Sstevel@tonic-gate 	 * noflsh is set.
40247c478bd9Sstevel@tonic-gate 	 */
40257c478bd9Sstevel@tonic-gate 	if ((!(tp->t_modes.c_lflag & NOFLSH)) || (c == '\0')) {
40267c478bd9Sstevel@tonic-gate 		if (mode) {
40277c478bd9Sstevel@tonic-gate 			if (tp->t_state & TS_TTSTOP) {
40287c478bd9Sstevel@tonic-gate 				sndsig = 1;
40297c478bd9Sstevel@tonic-gate 				(void) putnextctl1(q, mtype, sig);
40307c478bd9Sstevel@tonic-gate 			}
40317c478bd9Sstevel@tonic-gate 			/*
40327c478bd9Sstevel@tonic-gate 			 * Flush read or write side.
40337c478bd9Sstevel@tonic-gate 			 * Restart the input or output.
40347c478bd9Sstevel@tonic-gate 			 */
40357c478bd9Sstevel@tonic-gate 			if (mode & FLUSHR) {
40367c478bd9Sstevel@tonic-gate 				flushq(q, FLUSHDATA);
40377c478bd9Sstevel@tonic-gate 				(void) putnextctl1(WR(q), M_FLUSH, mode);
40387c478bd9Sstevel@tonic-gate 				if (tp->t_state & (TS_TBLOCK|TS_IFBLOCK)) {
40397c478bd9Sstevel@tonic-gate 					(void) putnextctl(WR(q), M_STARTI);
40407c478bd9Sstevel@tonic-gate 					tp->t_state &= ~(TS_TBLOCK|TS_IFBLOCK);
40417c478bd9Sstevel@tonic-gate 				}
40427c478bd9Sstevel@tonic-gate 			}
40437c478bd9Sstevel@tonic-gate 			if (mode & FLUSHW) {
40447c478bd9Sstevel@tonic-gate 				flushq(WR(q), FLUSHDATA);
40457c478bd9Sstevel@tonic-gate 				/*
40467c478bd9Sstevel@tonic-gate 				 * XXX This is extremely gross.
40477c478bd9Sstevel@tonic-gate 				 * Since we can't be sure our M_FLUSH
40487c478bd9Sstevel@tonic-gate 				 * will have run its course by the
40497c478bd9Sstevel@tonic-gate 				 * time we do the echo below, we set
40507c478bd9Sstevel@tonic-gate 				 * state and toss it in the write put
40517c478bd9Sstevel@tonic-gate 				 * routine to prevent flushing our
40527c478bd9Sstevel@tonic-gate 				 * own data.  Note that downstream
40537c478bd9Sstevel@tonic-gate 				 * modules on the write side will be
40547c478bd9Sstevel@tonic-gate 				 * flushed by the M_FLUSH sent above.
40557c478bd9Sstevel@tonic-gate 				 */
40567c478bd9Sstevel@tonic-gate 				tp->t_state |= TS_FLUSHWAIT;
40577c478bd9Sstevel@tonic-gate 				(void) putnextctl1(q, M_FLUSH, FLUSHW);
40587c478bd9Sstevel@tonic-gate 				if (tp->t_state & TS_TTSTOP) {
40597c478bd9Sstevel@tonic-gate 					(void) putnextctl(WR(q), M_START);
40607c478bd9Sstevel@tonic-gate 					tp->t_state &= ~(TS_TTSTOP|TS_OFBLOCK);
40617c478bd9Sstevel@tonic-gate 				}
40627c478bd9Sstevel@tonic-gate 			}
40637c478bd9Sstevel@tonic-gate 		}
40647c478bd9Sstevel@tonic-gate 	}
40657c478bd9Sstevel@tonic-gate 	tp->t_state &= ~TS_QUOT;
40667c478bd9Sstevel@tonic-gate 	if (sndsig == 0)
40677c478bd9Sstevel@tonic-gate 		(void) putnextctl1(q, mtype, sig);
40687c478bd9Sstevel@tonic-gate 
40697c478bd9Sstevel@tonic-gate 	if (c != '\0') {
40707c478bd9Sstevel@tonic-gate 		if ((tp->t_echomp = allocb(4, BPRI_HI)) != NULL) {
40717c478bd9Sstevel@tonic-gate 			(void) ldterm_echo(c, WR(q), 4, tp);
40727c478bd9Sstevel@tonic-gate 			putnext(WR(q), tp->t_echomp);
40737c478bd9Sstevel@tonic-gate 			tp->t_echomp = NULL;
40747c478bd9Sstevel@tonic-gate 		}
40757c478bd9Sstevel@tonic-gate 	}
40767c478bd9Sstevel@tonic-gate }
40777c478bd9Sstevel@tonic-gate 
40787c478bd9Sstevel@tonic-gate 
40797c478bd9Sstevel@tonic-gate /*
40807c478bd9Sstevel@tonic-gate  * Called when an M_IOCTL message is seen on the write queue; does
40817c478bd9Sstevel@tonic-gate  * whatever we're supposed to do with it, and either replies
40827c478bd9Sstevel@tonic-gate  * immediately or passes it to the next module down.
40837c478bd9Sstevel@tonic-gate  */
40847c478bd9Sstevel@tonic-gate static void
40857c478bd9Sstevel@tonic-gate ldterm_do_ioctl(queue_t *q, mblk_t *mp)
40867c478bd9Sstevel@tonic-gate {
40877c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp;
40887c478bd9Sstevel@tonic-gate 	struct iocblk *iocp;
40897c478bd9Sstevel@tonic-gate 	struct eucioc *euciocp;	/* needed for EUC ioctls */
40907c478bd9Sstevel@tonic-gate 	ldterm_cs_data_user_t *csdp;
40917c478bd9Sstevel@tonic-gate 	int i;
40927c478bd9Sstevel@tonic-gate 	int locale_name_sz;
40937c478bd9Sstevel@tonic-gate 	uchar_t maxbytelen;
40947c478bd9Sstevel@tonic-gate 	uchar_t maxscreenlen;
40957c478bd9Sstevel@tonic-gate 	int error;
40967c478bd9Sstevel@tonic-gate 
40977c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
40987c478bd9Sstevel@tonic-gate 	tp = (ldtermstd_state_t *)q->q_ptr;
40997c478bd9Sstevel@tonic-gate 
41007c478bd9Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
41017c478bd9Sstevel@tonic-gate 
41027c478bd9Sstevel@tonic-gate 	case TCSETS:
41037c478bd9Sstevel@tonic-gate 	case TCSETSW:
41047c478bd9Sstevel@tonic-gate 	case TCSETSF:
41057c478bd9Sstevel@tonic-gate 		{
41067c478bd9Sstevel@tonic-gate 			/*
41077c478bd9Sstevel@tonic-gate 			 * Set current parameters and special
41087c478bd9Sstevel@tonic-gate 			 * characters.
41097c478bd9Sstevel@tonic-gate 			 */
41107c478bd9Sstevel@tonic-gate 			struct termios *cb;
41117c478bd9Sstevel@tonic-gate 			struct termios oldmodes;
41127c478bd9Sstevel@tonic-gate 
41137c478bd9Sstevel@tonic-gate 			error = miocpullup(mp, sizeof (struct termios));
41147c478bd9Sstevel@tonic-gate 			if (error != 0) {
41157c478bd9Sstevel@tonic-gate 				miocnak(q, mp, 0, error);
41167c478bd9Sstevel@tonic-gate 				return;
41177c478bd9Sstevel@tonic-gate 			}
41187c478bd9Sstevel@tonic-gate 
41197c478bd9Sstevel@tonic-gate 			cb = (struct termios *)mp->b_cont->b_rptr;
41207c478bd9Sstevel@tonic-gate 
41217c478bd9Sstevel@tonic-gate 			oldmodes = tp->t_amodes;
41227c478bd9Sstevel@tonic-gate 			tp->t_amodes = *cb;
41237c478bd9Sstevel@tonic-gate 			if ((tp->t_amodes.c_lflag & PENDIN) &&
41247c478bd9Sstevel@tonic-gate 			    (tp->t_modes.c_lflag & IEXTEN)) {
41257c478bd9Sstevel@tonic-gate 				/*
41267c478bd9Sstevel@tonic-gate 				 * Yuk.  The C shell file completion
41277c478bd9Sstevel@tonic-gate 				 * code actually uses this "feature",
41287c478bd9Sstevel@tonic-gate 				 * so we have to support it.
41297c478bd9Sstevel@tonic-gate 				 */
41307c478bd9Sstevel@tonic-gate 				if (tp->t_message != NULL) {
41317c478bd9Sstevel@tonic-gate 					tp->t_state |= TS_RESCAN;
41327c478bd9Sstevel@tonic-gate 					qenable(RD(q));
41337c478bd9Sstevel@tonic-gate 				}
41347c478bd9Sstevel@tonic-gate 				tp->t_amodes.c_lflag &= ~PENDIN;
41357c478bd9Sstevel@tonic-gate 			}
41367c478bd9Sstevel@tonic-gate 			bcopy(tp->t_amodes.c_cc, tp->t_modes.c_cc, NCCS);
41377c478bd9Sstevel@tonic-gate 
41387c478bd9Sstevel@tonic-gate 			/*
41397c478bd9Sstevel@tonic-gate 			 * ldterm_adjust_modes does not deal with
41407c478bd9Sstevel@tonic-gate 			 * cflags
41417c478bd9Sstevel@tonic-gate 			 */
41427c478bd9Sstevel@tonic-gate 			tp->t_modes.c_cflag = tp->t_amodes.c_cflag;
41437c478bd9Sstevel@tonic-gate 
41447c478bd9Sstevel@tonic-gate 			ldterm_adjust_modes(tp);
41457c478bd9Sstevel@tonic-gate 			if (chgstropts(&oldmodes, tp, RD(q)) == (-1)) {
41467c478bd9Sstevel@tonic-gate 				miocnak(q, mp, 0, EAGAIN);
41477c478bd9Sstevel@tonic-gate 				return;
41487c478bd9Sstevel@tonic-gate 			}
41497c478bd9Sstevel@tonic-gate 			/*
41507c478bd9Sstevel@tonic-gate 			 * The driver may want to know about the
41517c478bd9Sstevel@tonic-gate 			 * following iflags: IGNBRK, BRKINT, IGNPAR,
41527c478bd9Sstevel@tonic-gate 			 * PARMRK, INPCK, IXON, IXANY.
41537c478bd9Sstevel@tonic-gate 			 */
41547c478bd9Sstevel@tonic-gate 			break;
41557c478bd9Sstevel@tonic-gate 		}
41567c478bd9Sstevel@tonic-gate 
41577c478bd9Sstevel@tonic-gate 	case TCSETA:
41587c478bd9Sstevel@tonic-gate 	case TCSETAW:
41597c478bd9Sstevel@tonic-gate 	case TCSETAF:
41607c478bd9Sstevel@tonic-gate 		{
41617c478bd9Sstevel@tonic-gate 			/*
41627c478bd9Sstevel@tonic-gate 			 * Old-style "ioctl" to set current
41637c478bd9Sstevel@tonic-gate 			 * parameters and special characters. Don't
41647c478bd9Sstevel@tonic-gate 			 * clear out the unset portions, leave them
41657c478bd9Sstevel@tonic-gate 			 * as they are.
41667c478bd9Sstevel@tonic-gate 			 */
41677c478bd9Sstevel@tonic-gate 			struct termio *cb;
41687c478bd9Sstevel@tonic-gate 			struct termios oldmodes;
41697c478bd9Sstevel@tonic-gate 
41707c478bd9Sstevel@tonic-gate 			error = miocpullup(mp, sizeof (struct termio));
41717c478bd9Sstevel@tonic-gate 			if (error != 0) {
41727c478bd9Sstevel@tonic-gate 				miocnak(q, mp, 0, error);
41737c478bd9Sstevel@tonic-gate 				return;
41747c478bd9Sstevel@tonic-gate 			}
41757c478bd9Sstevel@tonic-gate 
41767c478bd9Sstevel@tonic-gate 			cb = (struct termio *)mp->b_cont->b_rptr;
41777c478bd9Sstevel@tonic-gate 
41787c478bd9Sstevel@tonic-gate 			oldmodes = tp->t_amodes;
41797c478bd9Sstevel@tonic-gate 			tp->t_amodes.c_iflag =
418085bb5f1dSis 			    (tp->t_amodes.c_iflag & 0xffff0000 | cb->c_iflag);
41817c478bd9Sstevel@tonic-gate 			tp->t_amodes.c_oflag =
418285bb5f1dSis 			    (tp->t_amodes.c_oflag & 0xffff0000 | cb->c_oflag);
41837c478bd9Sstevel@tonic-gate 			tp->t_amodes.c_cflag =
418485bb5f1dSis 			    (tp->t_amodes.c_cflag & 0xffff0000 | cb->c_cflag);
41857c478bd9Sstevel@tonic-gate 			tp->t_amodes.c_lflag =
418685bb5f1dSis 			    (tp->t_amodes.c_lflag & 0xffff0000 | cb->c_lflag);
41877c478bd9Sstevel@tonic-gate 
41887c478bd9Sstevel@tonic-gate 			bcopy(cb->c_cc, tp->t_modes.c_cc, NCC);
41897c478bd9Sstevel@tonic-gate 			/* TCGETS returns amodes, so update that too */
41907c478bd9Sstevel@tonic-gate 			bcopy(cb->c_cc, tp->t_amodes.c_cc, NCC);
41917c478bd9Sstevel@tonic-gate 
41927c478bd9Sstevel@tonic-gate 			/* ldterm_adjust_modes does not deal with cflags */
41937c478bd9Sstevel@tonic-gate 
41947c478bd9Sstevel@tonic-gate 			tp->t_modes.c_cflag = tp->t_amodes.c_cflag;
41957c478bd9Sstevel@tonic-gate 
41967c478bd9Sstevel@tonic-gate 			ldterm_adjust_modes(tp);
41977c478bd9Sstevel@tonic-gate 			if (chgstropts(&oldmodes, tp, RD(q)) == (-1)) {
41987c478bd9Sstevel@tonic-gate 				miocnak(q, mp, 0, EAGAIN);
41997c478bd9Sstevel@tonic-gate 				return;
42007c478bd9Sstevel@tonic-gate 			}
42017c478bd9Sstevel@tonic-gate 			/*
42027c478bd9Sstevel@tonic-gate 			 * The driver may want to know about the
42037c478bd9Sstevel@tonic-gate 			 * following iflags: IGNBRK, BRKINT, IGNPAR,
42047c478bd9Sstevel@tonic-gate 			 * PARMRK, INPCK, IXON, IXANY.
42057c478bd9Sstevel@tonic-gate 			 */
42067c478bd9Sstevel@tonic-gate 			break;
42077c478bd9Sstevel@tonic-gate 		}
42087c478bd9Sstevel@tonic-gate 
42097c478bd9Sstevel@tonic-gate 	case TCFLSH:
42107c478bd9Sstevel@tonic-gate 		/*
42117c478bd9Sstevel@tonic-gate 		 * Do the flush on the write queue immediately, and
42127c478bd9Sstevel@tonic-gate 		 * queue up any flush on the read queue for the
42137c478bd9Sstevel@tonic-gate 		 * service procedure to see.  Then turn it into the
42147c478bd9Sstevel@tonic-gate 		 * appropriate M_FLUSH message, so that the module
42157c478bd9Sstevel@tonic-gate 		 * below us doesn't have to know about TCFLSH.
42167c478bd9Sstevel@tonic-gate 		 */
42177c478bd9Sstevel@tonic-gate 		error = miocpullup(mp, sizeof (int));
42187c478bd9Sstevel@tonic-gate 		if (error != 0) {
42197c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, error);
42207c478bd9Sstevel@tonic-gate 			return;
42217c478bd9Sstevel@tonic-gate 		}
42227c478bd9Sstevel@tonic-gate 
42237c478bd9Sstevel@tonic-gate 		ASSERT(mp->b_datap != NULL);
42247c478bd9Sstevel@tonic-gate 		if (*(int *)mp->b_cont->b_rptr == 0) {
42257c478bd9Sstevel@tonic-gate 			ASSERT(mp->b_datap != NULL);
42267c478bd9Sstevel@tonic-gate 			(void) putnextctl1(q, M_FLUSH, FLUSHR);
42277c478bd9Sstevel@tonic-gate 			(void) putctl1(RD(q), M_FLUSH, FLUSHR);
42287c478bd9Sstevel@tonic-gate 		} else if (*(int *)mp->b_cont->b_rptr == 1) {
42297c478bd9Sstevel@tonic-gate 			flushq(q, FLUSHDATA);
42307c478bd9Sstevel@tonic-gate 			ASSERT(mp->b_datap != NULL);
42317c478bd9Sstevel@tonic-gate 			tp->t_state |= TS_FLUSHWAIT;
42327c478bd9Sstevel@tonic-gate 			(void) putnextctl1(RD(q), M_FLUSH, FLUSHW);
42337c478bd9Sstevel@tonic-gate 			(void) putnextctl1(q, M_FLUSH, FLUSHW);
42347c478bd9Sstevel@tonic-gate 		} else if (*(int *)mp->b_cont->b_rptr == 2) {
42357c478bd9Sstevel@tonic-gate 			flushq(q, FLUSHDATA);
42367c478bd9Sstevel@tonic-gate 			ASSERT(mp->b_datap != NULL);
42377c478bd9Sstevel@tonic-gate 			(void) putnextctl1(q, M_FLUSH, FLUSHRW);
42387c478bd9Sstevel@tonic-gate 			tp->t_state |= TS_FLUSHWAIT;
42397c478bd9Sstevel@tonic-gate 			(void) putnextctl1(RD(q), M_FLUSH, FLUSHRW);
42407c478bd9Sstevel@tonic-gate 		} else {
42417c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, EINVAL);
42427c478bd9Sstevel@tonic-gate 			return;
42437c478bd9Sstevel@tonic-gate 		}
42447c478bd9Sstevel@tonic-gate 		ASSERT(mp->b_datap != NULL);
42457c478bd9Sstevel@tonic-gate 		iocp->ioc_rval = 0;
42467c478bd9Sstevel@tonic-gate 		miocack(q, mp, 0, 0);
42477c478bd9Sstevel@tonic-gate 		return;
42487c478bd9Sstevel@tonic-gate 
42497c478bd9Sstevel@tonic-gate 	case TCXONC:
42507c478bd9Sstevel@tonic-gate 		error = miocpullup(mp, sizeof (int));
42517c478bd9Sstevel@tonic-gate 		if (error != 0) {
42527c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, error);
42537c478bd9Sstevel@tonic-gate 			return;
42547c478bd9Sstevel@tonic-gate 		}
42557c478bd9Sstevel@tonic-gate 
42567c478bd9Sstevel@tonic-gate 		switch (*(int *)mp->b_cont->b_rptr) {
42577c478bd9Sstevel@tonic-gate 		case 0:
42587c478bd9Sstevel@tonic-gate 			if (!(tp->t_state & TS_TTSTOP)) {
42597c478bd9Sstevel@tonic-gate 				(void) putnextctl(q, M_STOP);
42607c478bd9Sstevel@tonic-gate 				tp->t_state |= (TS_TTSTOP|TS_OFBLOCK);
42617c478bd9Sstevel@tonic-gate 			}
42627c478bd9Sstevel@tonic-gate 			break;
42637c478bd9Sstevel@tonic-gate 
42647c478bd9Sstevel@tonic-gate 		case 1:
42657c478bd9Sstevel@tonic-gate 			if (tp->t_state & TS_TTSTOP) {
42667c478bd9Sstevel@tonic-gate 				(void) putnextctl(q, M_START);
42677c478bd9Sstevel@tonic-gate 				tp->t_state &= ~(TS_TTSTOP|TS_OFBLOCK);
42687c478bd9Sstevel@tonic-gate 			}
42697c478bd9Sstevel@tonic-gate 			break;
42707c478bd9Sstevel@tonic-gate 
42717c478bd9Sstevel@tonic-gate 		case 2:
42727c478bd9Sstevel@tonic-gate 			(void) putnextctl(q, M_STOPI);
42737c478bd9Sstevel@tonic-gate 			tp->t_state |= (TS_TBLOCK|TS_IFBLOCK);
42747c478bd9Sstevel@tonic-gate 			break;
42757c478bd9Sstevel@tonic-gate 
42767c478bd9Sstevel@tonic-gate 		case 3:
42777c478bd9Sstevel@tonic-gate 			(void) putnextctl(q, M_STARTI);
42787c478bd9Sstevel@tonic-gate 			tp->t_state &= ~(TS_TBLOCK|TS_IFBLOCK);
42797c478bd9Sstevel@tonic-gate 			break;
42807c478bd9Sstevel@tonic-gate 
42817c478bd9Sstevel@tonic-gate 		default:
42827c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, EINVAL);
42837c478bd9Sstevel@tonic-gate 			return;
42847c478bd9Sstevel@tonic-gate 		}
42857c478bd9Sstevel@tonic-gate 		ASSERT(mp->b_datap != NULL);
42867c478bd9Sstevel@tonic-gate 		iocp->ioc_rval = 0;
42877c478bd9Sstevel@tonic-gate 		miocack(q, mp, 0, 0);
42887c478bd9Sstevel@tonic-gate 		return;
42897c478bd9Sstevel@tonic-gate 		/*
42907c478bd9Sstevel@tonic-gate 		 * TCSBRK is expected to be handled by the driver.
42917c478bd9Sstevel@tonic-gate 		 * The reason its left for the driver is that when
42927c478bd9Sstevel@tonic-gate 		 * the argument to TCSBRK is zero driver has to drain
42937c478bd9Sstevel@tonic-gate 		 * the data and sending a M_IOCACK from LDTERM before
42947c478bd9Sstevel@tonic-gate 		 * the driver drains the data is going to cause
42957c478bd9Sstevel@tonic-gate 		 * problems.
42967c478bd9Sstevel@tonic-gate 		 */
42977c478bd9Sstevel@tonic-gate 
42987c478bd9Sstevel@tonic-gate 		/*
42997c478bd9Sstevel@tonic-gate 		 * The following are EUC related ioctls.  For
43007c478bd9Sstevel@tonic-gate 		 * EUC_WSET, we have to pass the information on, even
43017c478bd9Sstevel@tonic-gate 		 * though we ACK the call.  It's vital in the EUC
43027c478bd9Sstevel@tonic-gate 		 * environment that everybody downstream knows about
43037c478bd9Sstevel@tonic-gate 		 * the EUC codeset widths currently in use; we
43047c478bd9Sstevel@tonic-gate 		 * therefore pass down the information in an M_CTL
43057c478bd9Sstevel@tonic-gate 		 * message.  It will bottom out in the driver.
43067c478bd9Sstevel@tonic-gate 		 */
43077c478bd9Sstevel@tonic-gate 	case EUC_WSET:
43087c478bd9Sstevel@tonic-gate 		{
43097c478bd9Sstevel@tonic-gate 
43107c478bd9Sstevel@tonic-gate 			/* only needed for EUC_WSET */
43117c478bd9Sstevel@tonic-gate 			struct iocblk *riocp;
43127c478bd9Sstevel@tonic-gate 
43137c478bd9Sstevel@tonic-gate 			mblk_t *dmp, *dmp_cont;
43147c478bd9Sstevel@tonic-gate 
43157c478bd9Sstevel@tonic-gate 			/*
43167c478bd9Sstevel@tonic-gate 			 * If the user didn't supply any information,
43177c478bd9Sstevel@tonic-gate 			 * NAK it.
43187c478bd9Sstevel@tonic-gate 			 */
43197c478bd9Sstevel@tonic-gate 			error = miocpullup(mp, sizeof (struct eucioc));
43207c478bd9Sstevel@tonic-gate 			if (error != 0) {
43217c478bd9Sstevel@tonic-gate 				miocnak(q, mp, 0, error);
43227c478bd9Sstevel@tonic-gate 				return;
43237c478bd9Sstevel@tonic-gate 			}
43247c478bd9Sstevel@tonic-gate 
43257c478bd9Sstevel@tonic-gate 			euciocp = (struct eucioc *)mp->b_cont->b_rptr;
43267c478bd9Sstevel@tonic-gate 			/*
43277c478bd9Sstevel@tonic-gate 			 * Check here for something reasonable.  If
43287c478bd9Sstevel@tonic-gate 			 * anything will take more than EUC_MAXW
43297c478bd9Sstevel@tonic-gate 			 * columns or more than EUC_MAXW bytes
43307c478bd9Sstevel@tonic-gate 			 * following SS2 or SS3, then just reject it
43317c478bd9Sstevel@tonic-gate 			 * out of hand. It's not impossible for us to
43327c478bd9Sstevel@tonic-gate 			 * do it, it just isn't reasonable.  So far,
43337c478bd9Sstevel@tonic-gate 			 * in the world, we've seen the absolute max
43347c478bd9Sstevel@tonic-gate 			 * columns to be 2 and the max number of
43357c478bd9Sstevel@tonic-gate 			 * bytes to be 3.  This allows room for some
43367c478bd9Sstevel@tonic-gate 			 * expansion of that, but it probably won't
43377c478bd9Sstevel@tonic-gate 			 * even be necessary. At the moment, we
43387c478bd9Sstevel@tonic-gate 			 * return a "range" error.  If you really
43397c478bd9Sstevel@tonic-gate 			 * need to, you can push EUC_MAXW up to over
43407c478bd9Sstevel@tonic-gate 			 * 200; it doesn't make sense, though, with
43417c478bd9Sstevel@tonic-gate 			 * only a CANBSIZ sized input limit (usually
43427c478bd9Sstevel@tonic-gate 			 * 256)!
43437c478bd9Sstevel@tonic-gate 			 */
43447c478bd9Sstevel@tonic-gate 			for (i = 0; i < 4; i++) {
43457c478bd9Sstevel@tonic-gate 				if ((euciocp->eucw[i] > EUC_MAXW) ||
43467c478bd9Sstevel@tonic-gate 				    (euciocp->scrw[i] > EUC_MAXW)) {
43477c478bd9Sstevel@tonic-gate 					miocnak(q, mp, 0, ERANGE);
43487c478bd9Sstevel@tonic-gate 					return;
43497c478bd9Sstevel@tonic-gate 				}
43507c478bd9Sstevel@tonic-gate 			}
43517c478bd9Sstevel@tonic-gate 			/*
43527c478bd9Sstevel@tonic-gate 			 * Otherwise, save the information in tp,
43537c478bd9Sstevel@tonic-gate 			 * force codeset 0 (ASCII) to be one byte,
43547c478bd9Sstevel@tonic-gate 			 * one column.
43557c478bd9Sstevel@tonic-gate 			 */
43567c478bd9Sstevel@tonic-gate 			cp_eucwioc(euciocp, &tp->eucwioc, EUCIN);
43577c478bd9Sstevel@tonic-gate 			tp->eucwioc.eucw[0] = tp->eucwioc.scrw[0] = 1;
43587c478bd9Sstevel@tonic-gate 			/*
43597c478bd9Sstevel@tonic-gate 			 * Now, check out whether we're doing
43607c478bd9Sstevel@tonic-gate 			 * multibyte processing. if we are, we need
43617c478bd9Sstevel@tonic-gate 			 * to allocate a block to hold the parallel
43627c478bd9Sstevel@tonic-gate 			 * array. By convention, we've been passed
43637c478bd9Sstevel@tonic-gate 			 * what amounts to a CSWIDTH definition.  We
43647c478bd9Sstevel@tonic-gate 			 * actually NEED the number of bytes for
43657c478bd9Sstevel@tonic-gate 			 * Codesets 2 & 3.
43667c478bd9Sstevel@tonic-gate 			 */
43677c478bd9Sstevel@tonic-gate 			tp->t_maxeuc = 0;	/* reset to say we're NOT */
43687c478bd9Sstevel@tonic-gate 
43697c478bd9Sstevel@tonic-gate 			tp->t_state &= ~TS_MEUC;
43707c478bd9Sstevel@tonic-gate 			/*
43717c478bd9Sstevel@tonic-gate 			 * We'll set TS_MEUC if we're doing
43727c478bd9Sstevel@tonic-gate 			 * multi-column OR multi- byte OR both.  It
43737c478bd9Sstevel@tonic-gate 			 * makes things easier...  NOTE:  If we fail
43747c478bd9Sstevel@tonic-gate 			 * to get the buffer we need to hold display
43757c478bd9Sstevel@tonic-gate 			 * widths, then DON'T let the TS_MEUC bit get
43767c478bd9Sstevel@tonic-gate 			 * set!
43777c478bd9Sstevel@tonic-gate 			 */
43787c478bd9Sstevel@tonic-gate 			for (i = 0; i < 4; i++) {
43797c478bd9Sstevel@tonic-gate 				if (tp->eucwioc.eucw[i] > tp->t_maxeuc)
43807c478bd9Sstevel@tonic-gate 					tp->t_maxeuc = tp->eucwioc.eucw[i];
43817c478bd9Sstevel@tonic-gate 				if (tp->eucwioc.scrw[i] > 1)
43827c478bd9Sstevel@tonic-gate 					tp->t_state |= TS_MEUC;
43837c478bd9Sstevel@tonic-gate 			}
43847c478bd9Sstevel@tonic-gate 			if ((tp->t_maxeuc > 1) || (tp->t_state & TS_MEUC)) {
43857c478bd9Sstevel@tonic-gate 				if (!tp->t_eucp_mp) {
43867c478bd9Sstevel@tonic-gate 					if (!(tp->t_eucp_mp = allocb(CANBSIZ,
43877c478bd9Sstevel@tonic-gate 					    BPRI_HI))) {
43887c478bd9Sstevel@tonic-gate 						tp->t_maxeuc = 1;
43897c478bd9Sstevel@tonic-gate 						tp->t_state &= ~TS_MEUC;
43907c478bd9Sstevel@tonic-gate 						cmn_err(CE_WARN,
43917c478bd9Sstevel@tonic-gate 						    "Can't allocate eucp_mp");
43927c478bd9Sstevel@tonic-gate 						miocnak(q, mp, 0, ENOSR);
43937c478bd9Sstevel@tonic-gate 						return;
43947c478bd9Sstevel@tonic-gate 					}
43957c478bd9Sstevel@tonic-gate 					/*
43967c478bd9Sstevel@tonic-gate 					 * here, if there's junk in
43977c478bd9Sstevel@tonic-gate 					 * the canonical buffer, then
43987c478bd9Sstevel@tonic-gate 					 * move the eucp pointer past
43997c478bd9Sstevel@tonic-gate 					 * it, so we don't run off
44007c478bd9Sstevel@tonic-gate 					 * the beginning.  This is a
44017c478bd9Sstevel@tonic-gate 					 * total botch, but will
44027c478bd9Sstevel@tonic-gate 					 * hopefully keep stuff from
44037c478bd9Sstevel@tonic-gate 					 * getting too messed up
44047c478bd9Sstevel@tonic-gate 					 * until the user flushes
44057c478bd9Sstevel@tonic-gate 					 * this line!
44067c478bd9Sstevel@tonic-gate 					 */
44077c478bd9Sstevel@tonic-gate 					if (tp->t_msglen) {
440885bb5f1dSis 						tp->t_eucp =
440985bb5f1dSis 						    tp->t_eucp_mp->b_rptr;
44107c478bd9Sstevel@tonic-gate 						for (i = tp->t_msglen; i; i--)
44117c478bd9Sstevel@tonic-gate 							*tp->t_eucp++ = 1;
441285bb5f1dSis 					} else {
441385bb5f1dSis 						tp->t_eucp =
441485bb5f1dSis 						    tp->t_eucp_mp->b_rptr;
441585bb5f1dSis 					}
44167c478bd9Sstevel@tonic-gate 				}
44177c478bd9Sstevel@tonic-gate 				/* doing multi-byte handling */
44187c478bd9Sstevel@tonic-gate 				tp->t_state |= TS_MEUC;
44197c478bd9Sstevel@tonic-gate 
44207c478bd9Sstevel@tonic-gate 			} else if (tp->t_eucp_mp) {
44217c478bd9Sstevel@tonic-gate 				freemsg(tp->t_eucp_mp);
44227c478bd9Sstevel@tonic-gate 				tp->t_eucp_mp = NULL;
44237c478bd9Sstevel@tonic-gate 				tp->t_eucp = NULL;
44247c478bd9Sstevel@tonic-gate 			}
44257c478bd9Sstevel@tonic-gate 
44267c478bd9Sstevel@tonic-gate 			/*
44277c478bd9Sstevel@tonic-gate 			 * Save the EUC width data we have at
44287c478bd9Sstevel@tonic-gate 			 * the t_csdata, set t_csdata.codeset_type to
44297c478bd9Sstevel@tonic-gate 			 * EUC one, and, switch the codeset methods at
44307c478bd9Sstevel@tonic-gate 			 * t_csmethods.
44317c478bd9Sstevel@tonic-gate 			 */
44327c478bd9Sstevel@tonic-gate 			bzero(&tp->t_csdata.eucpc_data,
44337c478bd9Sstevel@tonic-gate 			    (sizeof (ldterm_eucpc_data_t) *
44347c478bd9Sstevel@tonic-gate 			    LDTERM_CS_MAX_CODESETS));
44357c478bd9Sstevel@tonic-gate 			tp->t_csdata.eucpc_data[0].byte_length =
44367c478bd9Sstevel@tonic-gate 			    tp->eucwioc.eucw[1];
44377c478bd9Sstevel@tonic-gate 			tp->t_csdata.eucpc_data[0].screen_width =
44387c478bd9Sstevel@tonic-gate 			    tp->eucwioc.scrw[1];
44397c478bd9Sstevel@tonic-gate 			tp->t_csdata.eucpc_data[1].byte_length =
44407c478bd9Sstevel@tonic-gate 			    tp->eucwioc.eucw[2];
44417c478bd9Sstevel@tonic-gate 			tp->t_csdata.eucpc_data[1].screen_width =
44427c478bd9Sstevel@tonic-gate 			    tp->eucwioc.scrw[2];
44437c478bd9Sstevel@tonic-gate 			tp->t_csdata.eucpc_data[2].byte_length =
44447c478bd9Sstevel@tonic-gate 			    tp->eucwioc.eucw[3];
44457c478bd9Sstevel@tonic-gate 			tp->t_csdata.eucpc_data[2].screen_width =
44467c478bd9Sstevel@tonic-gate 			    tp->eucwioc.scrw[3];
44477c478bd9Sstevel@tonic-gate 			tp->t_csdata.version = LDTERM_DATA_VERSION;
44487c478bd9Sstevel@tonic-gate 			tp->t_csdata.codeset_type = LDTERM_CS_TYPE_EUC;
44497c478bd9Sstevel@tonic-gate 			/*
44507c478bd9Sstevel@tonic-gate 			 * We are not using the 'csinfo_num' anyway if the
44517c478bd9Sstevel@tonic-gate 			 * current codeset type is EUC. So, set it to
44527c478bd9Sstevel@tonic-gate 			 * the maximum possible.
44537c478bd9Sstevel@tonic-gate 			 */
44547c478bd9Sstevel@tonic-gate 			tp->t_csdata.csinfo_num =
44557c478bd9Sstevel@tonic-gate 			    LDTERM_CS_TYPE_EUC_MAX_SUBCS;
44567c478bd9Sstevel@tonic-gate 			if (tp->t_csdata.locale_name != (char *)NULL) {
44577c478bd9Sstevel@tonic-gate 				kmem_free(tp->t_csdata.locale_name,
44587c478bd9Sstevel@tonic-gate 				    strlen(tp->t_csdata.locale_name) + 1);
44597c478bd9Sstevel@tonic-gate 				tp->t_csdata.locale_name = (char *)NULL;
44607c478bd9Sstevel@tonic-gate 			}
44617c478bd9Sstevel@tonic-gate 			tp->t_csmethods = cs_methods[LDTERM_CS_TYPE_EUC];
44627c478bd9Sstevel@tonic-gate 
44637c478bd9Sstevel@tonic-gate 			/*
44647c478bd9Sstevel@tonic-gate 			 * If we are able to allocate two blocks (the
44657c478bd9Sstevel@tonic-gate 			 * iocblk and the associated data), then pass
44667c478bd9Sstevel@tonic-gate 			 * it downstream, otherwise we'll need to NAK
44677c478bd9Sstevel@tonic-gate 			 * it, and drop whatever we WERE able to
44687c478bd9Sstevel@tonic-gate 			 * allocate.
44697c478bd9Sstevel@tonic-gate 			 */
44707c478bd9Sstevel@tonic-gate 			if ((dmp = mkiocb(EUC_WSET)) == NULL) {
44717c478bd9Sstevel@tonic-gate 				miocnak(q, mp, 0, ENOSR);
44727c478bd9Sstevel@tonic-gate 				return;
44737c478bd9Sstevel@tonic-gate 			}
44747c478bd9Sstevel@tonic-gate 			if ((dmp_cont = allocb(EUCSIZE, BPRI_HI)) == NULL) {
44757c478bd9Sstevel@tonic-gate 				freemsg(dmp);
44767c478bd9Sstevel@tonic-gate 				miocnak(q, mp, 0, ENOSR);
44777c478bd9Sstevel@tonic-gate 				return;
44787c478bd9Sstevel@tonic-gate 			}
44797c478bd9Sstevel@tonic-gate 
44807c478bd9Sstevel@tonic-gate 			/*
44817c478bd9Sstevel@tonic-gate 			 * We got both buffers.  Copy out the EUC
44827c478bd9Sstevel@tonic-gate 			 * information (as we received it, not what
44837c478bd9Sstevel@tonic-gate 			 * we're using!) & pass it on.
44847c478bd9Sstevel@tonic-gate 			 */
44857c478bd9Sstevel@tonic-gate 			bcopy(mp->b_cont->b_rptr, dmp_cont->b_rptr, EUCSIZE);
44867c478bd9Sstevel@tonic-gate 			dmp_cont->b_wptr += EUCSIZE;
44877c478bd9Sstevel@tonic-gate 			dmp->b_cont = dmp_cont;
44887c478bd9Sstevel@tonic-gate 			dmp->b_datap->db_type = M_CTL;
44897c478bd9Sstevel@tonic-gate 			dmp_cont->b_datap->db_type = M_DATA;
44907c478bd9Sstevel@tonic-gate 			riocp = (struct iocblk *)dmp->b_rptr;
44917c478bd9Sstevel@tonic-gate 			riocp->ioc_count = EUCSIZE;
44927c478bd9Sstevel@tonic-gate 			putnext(q, dmp);
44937c478bd9Sstevel@tonic-gate 
44947c478bd9Sstevel@tonic-gate 			/*
44957c478bd9Sstevel@tonic-gate 			 * Now ACK the ioctl.
44967c478bd9Sstevel@tonic-gate 			 */
44977c478bd9Sstevel@tonic-gate 			iocp->ioc_rval = 0;
44987c478bd9Sstevel@tonic-gate 			miocack(q, mp, 0, 0);
44997c478bd9Sstevel@tonic-gate 			return;
45007c478bd9Sstevel@tonic-gate 		}
45017c478bd9Sstevel@tonic-gate 
45027c478bd9Sstevel@tonic-gate 	case EUC_WGET:
45037c478bd9Sstevel@tonic-gate 		error = miocpullup(mp, sizeof (struct eucioc));
45047c478bd9Sstevel@tonic-gate 		if (error != 0) {
45057c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, error);
45067c478bd9Sstevel@tonic-gate 			return;
45077c478bd9Sstevel@tonic-gate 		}
45087c478bd9Sstevel@tonic-gate 		euciocp = (struct eucioc *)mp->b_cont->b_rptr;
45097c478bd9Sstevel@tonic-gate 		cp_eucwioc(&tp->eucwioc, euciocp, EUCOUT);
45107c478bd9Sstevel@tonic-gate 		iocp->ioc_rval = 0;
45117c478bd9Sstevel@tonic-gate 		miocack(q, mp, EUCSIZE, 0);
45127c478bd9Sstevel@tonic-gate 		return;
45137c478bd9Sstevel@tonic-gate 
45147c478bd9Sstevel@tonic-gate 	case CSDATA_SET:
45157c478bd9Sstevel@tonic-gate 		error = miocpullup(mp, sizeof (ldterm_cs_data_user_t));
45167c478bd9Sstevel@tonic-gate 		if (error != 0) {
45177c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, error);
45187c478bd9Sstevel@tonic-gate 			return;
45197c478bd9Sstevel@tonic-gate 		}
45207c478bd9Sstevel@tonic-gate 
45217c478bd9Sstevel@tonic-gate 		csdp = (ldterm_cs_data_user_t *)mp->b_cont->b_rptr;
45227c478bd9Sstevel@tonic-gate 
45237c478bd9Sstevel@tonic-gate 		/* Validate the codeset data provided. */
45247c478bd9Sstevel@tonic-gate 		if (csdp->version > LDTERM_DATA_VERSION ||
45257c478bd9Sstevel@tonic-gate 		    csdp->codeset_type < LDTERM_CS_TYPE_MIN ||
45267c478bd9Sstevel@tonic-gate 		    csdp->codeset_type > LDTERM_CS_TYPE_MAX) {
45277c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, ERANGE);
45287c478bd9Sstevel@tonic-gate 			return;
45297c478bd9Sstevel@tonic-gate 		}
45307c478bd9Sstevel@tonic-gate 
45317c478bd9Sstevel@tonic-gate 		if ((csdp->codeset_type == LDTERM_CS_TYPE_EUC &&
45327c478bd9Sstevel@tonic-gate 		    csdp->csinfo_num > LDTERM_CS_TYPE_EUC_MAX_SUBCS) ||
45337c478bd9Sstevel@tonic-gate 		    (csdp->codeset_type == LDTERM_CS_TYPE_PCCS &&
45347c478bd9Sstevel@tonic-gate 		    (csdp->csinfo_num < LDTERM_CS_TYPE_PCCS_MIN_SUBCS ||
45357c478bd9Sstevel@tonic-gate 		    csdp->csinfo_num > LDTERM_CS_TYPE_PCCS_MAX_SUBCS))) {
45367c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, ERANGE);
45377c478bd9Sstevel@tonic-gate 			return;
45387c478bd9Sstevel@tonic-gate 		}
45397c478bd9Sstevel@tonic-gate 
45407c478bd9Sstevel@tonic-gate 		maxbytelen = maxscreenlen = 0;
45417c478bd9Sstevel@tonic-gate 		if (csdp->codeset_type == LDTERM_CS_TYPE_EUC) {
45427c478bd9Sstevel@tonic-gate 			for (i = 0; i < LDTERM_CS_TYPE_EUC_MAX_SUBCS; i++) {
45437c478bd9Sstevel@tonic-gate 				if (csdp->eucpc_data[i].byte_length >
45447c478bd9Sstevel@tonic-gate 				    EUC_MAXW ||
45457c478bd9Sstevel@tonic-gate 				    csdp->eucpc_data[i].screen_width >
45467c478bd9Sstevel@tonic-gate 				    EUC_MAXW) {
45477c478bd9Sstevel@tonic-gate 					miocnak(q, mp, 0, ERANGE);
45487c478bd9Sstevel@tonic-gate 					return;
45497c478bd9Sstevel@tonic-gate 				}
45507c478bd9Sstevel@tonic-gate 
45517c478bd9Sstevel@tonic-gate 				if (csdp->eucpc_data[i].byte_length >
45527c478bd9Sstevel@tonic-gate 				    maxbytelen)
45537c478bd9Sstevel@tonic-gate 					maxbytelen =
45547c478bd9Sstevel@tonic-gate 					    csdp->eucpc_data[i].byte_length;
45557c478bd9Sstevel@tonic-gate 				if (csdp->eucpc_data[i].screen_width >
45567c478bd9Sstevel@tonic-gate 				    maxscreenlen)
45577c478bd9Sstevel@tonic-gate 					maxscreenlen =
45587c478bd9Sstevel@tonic-gate 					    csdp->eucpc_data[i].screen_width;
45597c478bd9Sstevel@tonic-gate 			}
45607c478bd9Sstevel@tonic-gate 			/* POSIX/C locale? */
45617c478bd9Sstevel@tonic-gate 			if (maxbytelen == 0 && maxscreenlen == 0)
45627c478bd9Sstevel@tonic-gate 				maxbytelen = maxscreenlen = 1;
45637c478bd9Sstevel@tonic-gate 		} else if (csdp->codeset_type == LDTERM_CS_TYPE_PCCS) {
45647c478bd9Sstevel@tonic-gate 			for (i = 0; i < LDTERM_CS_MAX_CODESETS; i++) {
45657c478bd9Sstevel@tonic-gate 				if (csdp->eucpc_data[i].byte_length >
45667c478bd9Sstevel@tonic-gate 				    LDTERM_CS_MAX_BYTE_LENGTH) {
45677c478bd9Sstevel@tonic-gate 					miocnak(q, mp, 0, ERANGE);
45687c478bd9Sstevel@tonic-gate 					return;
45697c478bd9Sstevel@tonic-gate 				}
45707c478bd9Sstevel@tonic-gate 				if (csdp->eucpc_data[i].byte_length >
45717c478bd9Sstevel@tonic-gate 				    maxbytelen)
45727c478bd9Sstevel@tonic-gate 					maxbytelen =
45737c478bd9Sstevel@tonic-gate 					    csdp->eucpc_data[i].byte_length;
45747c478bd9Sstevel@tonic-gate 				if (csdp->eucpc_data[i].screen_width >
45757c478bd9Sstevel@tonic-gate 				    maxscreenlen)
45767c478bd9Sstevel@tonic-gate 					maxscreenlen =
45777c478bd9Sstevel@tonic-gate 					    csdp->eucpc_data[i].screen_width;
45787c478bd9Sstevel@tonic-gate 			}
45797c478bd9Sstevel@tonic-gate 		} else if (csdp->codeset_type == LDTERM_CS_TYPE_UTF8) {
45807c478bd9Sstevel@tonic-gate 			maxbytelen = 4;
45817c478bd9Sstevel@tonic-gate 			maxscreenlen = 2;
45827c478bd9Sstevel@tonic-gate 		}
45837c478bd9Sstevel@tonic-gate 
45847c478bd9Sstevel@tonic-gate 		locale_name_sz = 0;
45857c478bd9Sstevel@tonic-gate 		if (csdp->locale_name) {
45867c478bd9Sstevel@tonic-gate 			for (i = 0; i < MAXNAMELEN; i++)
45877c478bd9Sstevel@tonic-gate 				if (csdp->locale_name[i] == '\0')
45887c478bd9Sstevel@tonic-gate 					break;
45897c478bd9Sstevel@tonic-gate 			/*
45907c478bd9Sstevel@tonic-gate 			 * We cannot have any string that is not NULL byte
45917c478bd9Sstevel@tonic-gate 			 * terminated.
45927c478bd9Sstevel@tonic-gate 			 */
45937c478bd9Sstevel@tonic-gate 			if (i >= MAXNAMELEN) {
45947c478bd9Sstevel@tonic-gate 				miocnak(q, mp, 0, ERANGE);
45957c478bd9Sstevel@tonic-gate 				return;
45967c478bd9Sstevel@tonic-gate 			}
45977c478bd9Sstevel@tonic-gate 
45987c478bd9Sstevel@tonic-gate 			locale_name_sz = i + 1;
45997c478bd9Sstevel@tonic-gate 		}
46007c478bd9Sstevel@tonic-gate 
46017c478bd9Sstevel@tonic-gate 		/*
46027c478bd9Sstevel@tonic-gate 		 * As the final check, if there was invalid codeset_type
46037c478bd9Sstevel@tonic-gate 		 * given, or invalid byte_length was specified, it's an error.
46047c478bd9Sstevel@tonic-gate 		 */
46057c478bd9Sstevel@tonic-gate 		if (maxbytelen <= 0 || maxscreenlen <= 0) {
46067c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, ERANGE);
46077c478bd9Sstevel@tonic-gate 			return;
46087c478bd9Sstevel@tonic-gate 		}
46097c478bd9Sstevel@tonic-gate 
46107c478bd9Sstevel@tonic-gate 		/* Do the switching. */
46117c478bd9Sstevel@tonic-gate 		tp->t_maxeuc = maxbytelen;
46127c478bd9Sstevel@tonic-gate 		tp->t_state &= ~TS_MEUC;
46137c478bd9Sstevel@tonic-gate 		if (maxbytelen > 1 || maxscreenlen > 1) {
46147c478bd9Sstevel@tonic-gate 			if (!tp->t_eucp_mp) {
46157c478bd9Sstevel@tonic-gate 				if (!(tp->t_eucp_mp = allocb(CANBSIZ,
46167c478bd9Sstevel@tonic-gate 				    BPRI_HI))) {
46177c478bd9Sstevel@tonic-gate 					cmn_err(CE_WARN,
46187c478bd9Sstevel@tonic-gate 					    "Can't allocate eucp_mp");
46197c478bd9Sstevel@tonic-gate 					miocnak(q, mp, 0, ENOSR);
46207c478bd9Sstevel@tonic-gate 					return;
46217c478bd9Sstevel@tonic-gate 				}
46227c478bd9Sstevel@tonic-gate 				/*
46237c478bd9Sstevel@tonic-gate 				 * If there's junk in the canonical buffer,
46247c478bd9Sstevel@tonic-gate 				 * then move the eucp pointer past it,
46257c478bd9Sstevel@tonic-gate 				 * so we don't run off the beginning. This is
46267c478bd9Sstevel@tonic-gate 				 * a total botch, but will hopefully keep
46277c478bd9Sstevel@tonic-gate 				 * stuff from getting too messed up until
46287c478bd9Sstevel@tonic-gate 				 * the user flushes this line!
46297c478bd9Sstevel@tonic-gate 				 */
46307c478bd9Sstevel@tonic-gate 				if (tp->t_msglen) {
46317c478bd9Sstevel@tonic-gate 					tp->t_eucp = tp->t_eucp_mp->b_rptr;
46327c478bd9Sstevel@tonic-gate 					for (i = tp->t_msglen; i; i--)
46337c478bd9Sstevel@tonic-gate 						*tp->t_eucp++ = 1;
46347c478bd9Sstevel@tonic-gate 				} else {
46357c478bd9Sstevel@tonic-gate 					tp->t_eucp = tp->t_eucp_mp->b_rptr;
46367c478bd9Sstevel@tonic-gate 				}
46377c478bd9Sstevel@tonic-gate 			}
46387c478bd9Sstevel@tonic-gate 
46397c478bd9Sstevel@tonic-gate 			/*
46407c478bd9Sstevel@tonic-gate 			 * We only set TS_MEUC for a multibyte/multi-column
46417c478bd9Sstevel@tonic-gate 			 * codeset.
46427c478bd9Sstevel@tonic-gate 			 */
46437c478bd9Sstevel@tonic-gate 			tp->t_state |= TS_MEUC;
46447c478bd9Sstevel@tonic-gate 
46457c478bd9Sstevel@tonic-gate 			tp->t_csdata.version = csdp->version;
46467c478bd9Sstevel@tonic-gate 			tp->t_csdata.codeset_type = csdp->codeset_type;
46477c478bd9Sstevel@tonic-gate 			tp->t_csdata.csinfo_num = csdp->csinfo_num;
46487c478bd9Sstevel@tonic-gate 			bcopy(csdp->eucpc_data, tp->t_csdata.eucpc_data,
46497c478bd9Sstevel@tonic-gate 			    sizeof (ldterm_eucpc_data_t) *
46507c478bd9Sstevel@tonic-gate 			    LDTERM_CS_MAX_CODESETS);
46517c478bd9Sstevel@tonic-gate 			tp->t_csmethods = cs_methods[csdp->codeset_type];
46527c478bd9Sstevel@tonic-gate 
46537c478bd9Sstevel@tonic-gate 			if (csdp->codeset_type == LDTERM_CS_TYPE_EUC) {
46547c478bd9Sstevel@tonic-gate 				tp->eucwioc.eucw[0] = 1;
46557c478bd9Sstevel@tonic-gate 				tp->eucwioc.scrw[0] = 1;
46567c478bd9Sstevel@tonic-gate 
46577c478bd9Sstevel@tonic-gate 				tp->eucwioc.eucw[1] =
46587c478bd9Sstevel@tonic-gate 				    csdp->eucpc_data[0].byte_length;
46597c478bd9Sstevel@tonic-gate 				tp->eucwioc.scrw[1] =
46607c478bd9Sstevel@tonic-gate 				    csdp->eucpc_data[0].screen_width;
46617c478bd9Sstevel@tonic-gate 
46627c478bd9Sstevel@tonic-gate 				tp->eucwioc.eucw[2] =
46637c478bd9Sstevel@tonic-gate 				    csdp->eucpc_data[1].byte_length + 1;
46647c478bd9Sstevel@tonic-gate 				tp->eucwioc.scrw[2] =
46657c478bd9Sstevel@tonic-gate 				    csdp->eucpc_data[1].screen_width;
46667c478bd9Sstevel@tonic-gate 
46677c478bd9Sstevel@tonic-gate 				tp->eucwioc.eucw[3] =
46687c478bd9Sstevel@tonic-gate 				    csdp->eucpc_data[2].byte_length + 1;
46697c478bd9Sstevel@tonic-gate 				tp->eucwioc.scrw[3] =
46707c478bd9Sstevel@tonic-gate 				    csdp->eucpc_data[2].screen_width;
46717c478bd9Sstevel@tonic-gate 			} else {
46727c478bd9Sstevel@tonic-gate 				/*
46737c478bd9Sstevel@tonic-gate 				 * We are not going to use this data
46747c478bd9Sstevel@tonic-gate 				 * structure. So, clear it. Also, stty(1) will
46757c478bd9Sstevel@tonic-gate 				 * make use of the cleared tp->eucwioc when
46767c478bd9Sstevel@tonic-gate 				 * it prints out codeset width setting.
46777c478bd9Sstevel@tonic-gate 				 */
46787c478bd9Sstevel@tonic-gate 				bzero(&tp->eucwioc, EUCSIZE);
46797c478bd9Sstevel@tonic-gate 			}
46807c478bd9Sstevel@tonic-gate 		} else {
46817c478bd9Sstevel@tonic-gate 			/*
46827c478bd9Sstevel@tonic-gate 			 * If this codeset is a single byte codeset that
46837c478bd9Sstevel@tonic-gate 			 * requires only single display column for all
46847c478bd9Sstevel@tonic-gate 			 * characters, we switch to default EUC codeset
46857c478bd9Sstevel@tonic-gate 			 * methods and data setting.
46867c478bd9Sstevel@tonic-gate 			 */
46877c478bd9Sstevel@tonic-gate 
46887c478bd9Sstevel@tonic-gate 			if (tp->t_eucp_mp) {
46897c478bd9Sstevel@tonic-gate 				freemsg(tp->t_eucp_mp);
46907c478bd9Sstevel@tonic-gate 				tp->t_eucp_mp = NULL;
46917c478bd9Sstevel@tonic-gate 				tp->t_eucp = NULL;
46927c478bd9Sstevel@tonic-gate 			}
46937c478bd9Sstevel@tonic-gate 
46947c478bd9Sstevel@tonic-gate 			bzero(&tp->eucwioc, EUCSIZE);
46957c478bd9Sstevel@tonic-gate 			tp->eucwioc.eucw[0] = 1;
46967c478bd9Sstevel@tonic-gate 			tp->eucwioc.scrw[0] = 1;
46977c478bd9Sstevel@tonic-gate 			if (tp->t_csdata.locale_name != (char *)NULL) {
46987c478bd9Sstevel@tonic-gate 				kmem_free(tp->t_csdata.locale_name,
46997c478bd9Sstevel@tonic-gate 				    strlen(tp->t_csdata.locale_name) + 1);
47007c478bd9Sstevel@tonic-gate 			}
47017c478bd9Sstevel@tonic-gate 			tp->t_csdata = default_cs_data;
47027c478bd9Sstevel@tonic-gate 			tp->t_csmethods = cs_methods[LDTERM_CS_TYPE_EUC];
47037c478bd9Sstevel@tonic-gate 		}
47047c478bd9Sstevel@tonic-gate 
47057c478bd9Sstevel@tonic-gate 		/* Copy over locale_name. */
47067c478bd9Sstevel@tonic-gate 		if (tp->t_csdata.locale_name != (char *)NULL) {
47077c478bd9Sstevel@tonic-gate 			kmem_free(tp->t_csdata.locale_name,
47087c478bd9Sstevel@tonic-gate 			    strlen(tp->t_csdata.locale_name) + 1);
47097c478bd9Sstevel@tonic-gate 		}
47107c478bd9Sstevel@tonic-gate 		if (locale_name_sz > 1) {
47117c478bd9Sstevel@tonic-gate 			tp->t_csdata.locale_name = (char *)kmem_alloc(
47127c478bd9Sstevel@tonic-gate 			    locale_name_sz, KM_SLEEP);
47137c478bd9Sstevel@tonic-gate 			(void) strcpy(tp->t_csdata.locale_name,
47147c478bd9Sstevel@tonic-gate 			    csdp->locale_name);
47157c478bd9Sstevel@tonic-gate 		} else {
47167c478bd9Sstevel@tonic-gate 			tp->t_csdata.locale_name = (char *)NULL;
47177c478bd9Sstevel@tonic-gate 		}
47187c478bd9Sstevel@tonic-gate 
47197c478bd9Sstevel@tonic-gate 		/*
47207c478bd9Sstevel@tonic-gate 		 * Now ACK the ioctl.
47217c478bd9Sstevel@tonic-gate 		 */
47227c478bd9Sstevel@tonic-gate 		iocp->ioc_rval = 0;
47237c478bd9Sstevel@tonic-gate 		miocack(q, mp, 0, 0);
47247c478bd9Sstevel@tonic-gate 		return;
47257c478bd9Sstevel@tonic-gate 
47267c478bd9Sstevel@tonic-gate 	case CSDATA_GET:
47277c478bd9Sstevel@tonic-gate 		error = miocpullup(mp, sizeof (ldterm_cs_data_user_t));
47287c478bd9Sstevel@tonic-gate 		if (error != 0) {
47297c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, error);
47307c478bd9Sstevel@tonic-gate 			return;
47317c478bd9Sstevel@tonic-gate 		}
47327c478bd9Sstevel@tonic-gate 
47337c478bd9Sstevel@tonic-gate 		csdp = (ldterm_cs_data_user_t *)mp->b_cont->b_rptr;
47347c478bd9Sstevel@tonic-gate 
47357c478bd9Sstevel@tonic-gate 		csdp->version = tp->t_csdata.version;
47367c478bd9Sstevel@tonic-gate 		csdp->codeset_type = tp->t_csdata.codeset_type;
47377c478bd9Sstevel@tonic-gate 		csdp->csinfo_num = tp->t_csdata.csinfo_num;
47387c478bd9Sstevel@tonic-gate 		csdp->pad = tp->t_csdata.pad;
47397c478bd9Sstevel@tonic-gate 		if (tp->t_csdata.locale_name) {
47407c478bd9Sstevel@tonic-gate 			(void) strcpy(csdp->locale_name,
47417c478bd9Sstevel@tonic-gate 			    tp->t_csdata.locale_name);
47427c478bd9Sstevel@tonic-gate 		} else {
47437c478bd9Sstevel@tonic-gate 			csdp->locale_name[0] = '\0';
47447c478bd9Sstevel@tonic-gate 		}
47457c478bd9Sstevel@tonic-gate 		bcopy(tp->t_csdata.eucpc_data, csdp->eucpc_data,
47467c478bd9Sstevel@tonic-gate 		    sizeof (ldterm_eucpc_data_t) * LDTERM_CS_MAX_CODESETS);
47477c478bd9Sstevel@tonic-gate 		/*
47487c478bd9Sstevel@tonic-gate 		 * If the codeset is an EUC codeset and if it has 2nd and/or
47497c478bd9Sstevel@tonic-gate 		 * 3rd supplementary codesets, we subtract one from each
47507c478bd9Sstevel@tonic-gate 		 * byte length of the supplementary codesets. This is
47517c478bd9Sstevel@tonic-gate 		 * because single shift characters, SS2 and SS3, are not
47527c478bd9Sstevel@tonic-gate 		 * included in the byte lengths in the user space.
47537c478bd9Sstevel@tonic-gate 		 */
47547c478bd9Sstevel@tonic-gate 		if (csdp->codeset_type == LDTERM_CS_TYPE_EUC) {
47557c478bd9Sstevel@tonic-gate 			if (csdp->eucpc_data[1].byte_length)
47567c478bd9Sstevel@tonic-gate 				csdp->eucpc_data[1].byte_length -= 1;
47577c478bd9Sstevel@tonic-gate 			if (csdp->eucpc_data[2].byte_length)
47587c478bd9Sstevel@tonic-gate 				csdp->eucpc_data[2].byte_length -= 1;
47597c478bd9Sstevel@tonic-gate 		}
47607c478bd9Sstevel@tonic-gate 		iocp->ioc_rval = 0;
47617c478bd9Sstevel@tonic-gate 		miocack(q, mp, sizeof (ldterm_cs_data_user_t), 0);
47627c478bd9Sstevel@tonic-gate 		return;
47637c478bd9Sstevel@tonic-gate 
47647c478bd9Sstevel@tonic-gate 	case PTSSTTY:
47657c478bd9Sstevel@tonic-gate 		tp->t_state |= TS_ISPTSTTY;
47667c478bd9Sstevel@tonic-gate 		break;
47677c478bd9Sstevel@tonic-gate 
47687c478bd9Sstevel@tonic-gate 	}
47697c478bd9Sstevel@tonic-gate 
47707c478bd9Sstevel@tonic-gate 	putnext(q, mp);
47717c478bd9Sstevel@tonic-gate }
47727c478bd9Sstevel@tonic-gate 
47737c478bd9Sstevel@tonic-gate 
47747c478bd9Sstevel@tonic-gate /*
47757c478bd9Sstevel@tonic-gate  * Send an M_SETOPTS message upstream if any mode changes are being
47767c478bd9Sstevel@tonic-gate  * made that affect the stream head options. returns -1 if allocb
47777c478bd9Sstevel@tonic-gate  * fails, else returns 0.
47787c478bd9Sstevel@tonic-gate  */
47797c478bd9Sstevel@tonic-gate static int
47807c478bd9Sstevel@tonic-gate chgstropts(struct termios *oldmodep, ldtermstd_state_t *tp, queue_t *q)
47817c478bd9Sstevel@tonic-gate {
47827c478bd9Sstevel@tonic-gate 	struct stroptions optbuf;
47837c478bd9Sstevel@tonic-gate 	mblk_t *bp;
47847c478bd9Sstevel@tonic-gate 
47857c478bd9Sstevel@tonic-gate 	optbuf.so_flags = 0;
47867c478bd9Sstevel@tonic-gate 	if ((oldmodep->c_lflag ^ tp->t_modes.c_lflag) & ICANON) {
47877c478bd9Sstevel@tonic-gate 		/*
47887c478bd9Sstevel@tonic-gate 		 * Canonical mode is changing state; switch the
47897c478bd9Sstevel@tonic-gate 		 * stream head to message-nondiscard or byte-stream
47907c478bd9Sstevel@tonic-gate 		 * mode.  Also, rerun the service procedure so it can
47917c478bd9Sstevel@tonic-gate 		 * change its mind about whether to send data
47927c478bd9Sstevel@tonic-gate 		 * upstream or not.
47937c478bd9Sstevel@tonic-gate 		 */
47947c478bd9Sstevel@tonic-gate 		if (tp->t_modes.c_lflag & ICANON) {
47957c478bd9Sstevel@tonic-gate 			DEBUG4(("CHANGING TO CANON MODE\n"));
47967c478bd9Sstevel@tonic-gate 			optbuf.so_flags = SO_READOPT|SO_MREADOFF;
47977c478bd9Sstevel@tonic-gate 			optbuf.so_readopt = RMSGN;
47987c478bd9Sstevel@tonic-gate 
47997c478bd9Sstevel@tonic-gate 			/*
48007c478bd9Sstevel@tonic-gate 			 * if there is a pending raw mode timeout,
48017c478bd9Sstevel@tonic-gate 			 * clear it
48027c478bd9Sstevel@tonic-gate 			 */
48037c478bd9Sstevel@tonic-gate 
48047c478bd9Sstevel@tonic-gate 			/*
48057c478bd9Sstevel@tonic-gate 			 * Clear VMIN/VTIME state, cancel timers
48067c478bd9Sstevel@tonic-gate 			 */
48077c478bd9Sstevel@tonic-gate 			vmin_satisfied(q, tp, 0);
48087c478bd9Sstevel@tonic-gate 		} else {
48097c478bd9Sstevel@tonic-gate 			DEBUG4(("CHANGING TO RAW MODE\n"));
48107c478bd9Sstevel@tonic-gate 			optbuf.so_flags = SO_READOPT|SO_MREADON;
48117c478bd9Sstevel@tonic-gate 			optbuf.so_readopt = RNORM;
48127c478bd9Sstevel@tonic-gate 		}
48137c478bd9Sstevel@tonic-gate 	}
48147c478bd9Sstevel@tonic-gate 	if ((oldmodep->c_lflag ^ tp->t_modes.c_lflag) & TOSTOP) {
48157c478bd9Sstevel@tonic-gate 		/*
48167c478bd9Sstevel@tonic-gate 		 * The "stop on background write" bit is changing.
48177c478bd9Sstevel@tonic-gate 		 */
48187c478bd9Sstevel@tonic-gate 		if (tp->t_modes.c_lflag & TOSTOP)
48197c478bd9Sstevel@tonic-gate 			optbuf.so_flags |= SO_TOSTOP;
48207c478bd9Sstevel@tonic-gate 		else
48217c478bd9Sstevel@tonic-gate 			optbuf.so_flags |= SO_TONSTOP;
48227c478bd9Sstevel@tonic-gate 	}
48237c478bd9Sstevel@tonic-gate 	if (optbuf.so_flags != 0) {
48247c478bd9Sstevel@tonic-gate 		if ((bp = allocb(sizeof (struct stroptions), BPRI_HI)) ==
48257c478bd9Sstevel@tonic-gate 		    NULL) {
48267c478bd9Sstevel@tonic-gate 			return (-1);
48277c478bd9Sstevel@tonic-gate 		}
48287c478bd9Sstevel@tonic-gate 		*(struct stroptions *)bp->b_wptr = optbuf;
48297c478bd9Sstevel@tonic-gate 		bp->b_wptr += sizeof (struct stroptions);
48307c478bd9Sstevel@tonic-gate 		bp->b_datap->db_type = M_SETOPTS;
48317c478bd9Sstevel@tonic-gate 		DEBUG4(("M_SETOPTS to stream head\n"));
48327c478bd9Sstevel@tonic-gate 		putnext(q, bp);
48337c478bd9Sstevel@tonic-gate 	}
48347c478bd9Sstevel@tonic-gate 	return (0);
48357c478bd9Sstevel@tonic-gate }
48367c478bd9Sstevel@tonic-gate 
48377c478bd9Sstevel@tonic-gate 
48387c478bd9Sstevel@tonic-gate /*
48397c478bd9Sstevel@tonic-gate  * Called when an M_IOCACK message is seen on the read queue;
48407c478bd9Sstevel@tonic-gate  * modifies the data being returned, if necessary, and passes the
48417c478bd9Sstevel@tonic-gate  * reply up.
48427c478bd9Sstevel@tonic-gate  */
48437c478bd9Sstevel@tonic-gate static void
48447c478bd9Sstevel@tonic-gate ldterm_ioctl_reply(queue_t *q, mblk_t *mp)
48457c478bd9Sstevel@tonic-gate {
48467c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp;
48477c478bd9Sstevel@tonic-gate 	struct iocblk *iocp;
48487c478bd9Sstevel@tonic-gate 
48497c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
48507c478bd9Sstevel@tonic-gate 	tp = (ldtermstd_state_t *)q->q_ptr;
48517c478bd9Sstevel@tonic-gate 
48527c478bd9Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
48537c478bd9Sstevel@tonic-gate 
48547c478bd9Sstevel@tonic-gate 	case TCGETS:
48557c478bd9Sstevel@tonic-gate 		{
48567c478bd9Sstevel@tonic-gate 			/*
48577c478bd9Sstevel@tonic-gate 			 * Get current parameters and return them to
48587c478bd9Sstevel@tonic-gate 			 * stream head eventually.
48597c478bd9Sstevel@tonic-gate 			 */
48607c478bd9Sstevel@tonic-gate 			struct termios *cb =
48617c478bd9Sstevel@tonic-gate 			    (struct termios *)mp->b_cont->b_rptr;
48627c478bd9Sstevel@tonic-gate 
48637c478bd9Sstevel@tonic-gate 			/*
48647c478bd9Sstevel@tonic-gate 			 * cflag has cflags sent upstream by the
48657c478bd9Sstevel@tonic-gate 			 * driver
48667c478bd9Sstevel@tonic-gate 			 */
48677c478bd9Sstevel@tonic-gate 			tcflag_t cflag = cb->c_cflag;
48687c478bd9Sstevel@tonic-gate 
48697c478bd9Sstevel@tonic-gate 			*cb = tp->t_amodes;
48707c478bd9Sstevel@tonic-gate 			if (cflag != 0)
48717c478bd9Sstevel@tonic-gate 				cb->c_cflag = cflag;	/* set by driver */
48727c478bd9Sstevel@tonic-gate 			break;
48737c478bd9Sstevel@tonic-gate 		}
48747c478bd9Sstevel@tonic-gate 
48757c478bd9Sstevel@tonic-gate 	case TCGETA:
48767c478bd9Sstevel@tonic-gate 		{
48777c478bd9Sstevel@tonic-gate 			/*
48787c478bd9Sstevel@tonic-gate 			 * Old-style "ioctl" to get current
48797c478bd9Sstevel@tonic-gate 			 * parameters and return them to stream head
48807c478bd9Sstevel@tonic-gate 			 * eventually.
48817c478bd9Sstevel@tonic-gate 			 */
48827c478bd9Sstevel@tonic-gate 			struct termio *cb =
48837c478bd9Sstevel@tonic-gate 			    (struct termio *)mp->b_cont->b_rptr;
48847c478bd9Sstevel@tonic-gate 
48857c478bd9Sstevel@tonic-gate 			cb->c_iflag = tp->t_amodes.c_iflag; /* all except the */
48867c478bd9Sstevel@tonic-gate 			cb->c_oflag = tp->t_amodes.c_oflag; /* cb->c_cflag */
48877c478bd9Sstevel@tonic-gate 			cb->c_lflag = tp->t_amodes.c_lflag;
48887c478bd9Sstevel@tonic-gate 
48897c478bd9Sstevel@tonic-gate 			if (cb->c_cflag == 0)	/* not set by driver */
48907c478bd9Sstevel@tonic-gate 				cb->c_cflag = tp->t_amodes.c_cflag;
48917c478bd9Sstevel@tonic-gate 
48927c478bd9Sstevel@tonic-gate 			cb->c_line = 0;
48937c478bd9Sstevel@tonic-gate 			bcopy(tp->t_amodes.c_cc, cb->c_cc, NCC);
48947c478bd9Sstevel@tonic-gate 			break;
48957c478bd9Sstevel@tonic-gate 		}
48967c478bd9Sstevel@tonic-gate 	}
48977c478bd9Sstevel@tonic-gate 	putnext(q, mp);
48987c478bd9Sstevel@tonic-gate }
48997c478bd9Sstevel@tonic-gate 
49007c478bd9Sstevel@tonic-gate 
49017c478bd9Sstevel@tonic-gate /*
49027c478bd9Sstevel@tonic-gate  * A VMIN/VTIME request has been satisfied. Cancel outstanding timers
49037c478bd9Sstevel@tonic-gate  * if they exist, clear TS_MREAD state, and send upstream. If a NULL
49047c478bd9Sstevel@tonic-gate  * queue ptr is passed, just reset VMIN/VTIME state.
49057c478bd9Sstevel@tonic-gate  */
49067c478bd9Sstevel@tonic-gate static void
49077c478bd9Sstevel@tonic-gate vmin_satisfied(queue_t *q, ldtermstd_state_t *tp, int sendup)
49087c478bd9Sstevel@tonic-gate {
49097c478bd9Sstevel@tonic-gate 	ASSERT(q);
49107c478bd9Sstevel@tonic-gate 	if (tp->t_vtid != 0)  {
491185bb5f1dSis 		DEBUG4(("vmin_satisfied: cancelled timer id %d\n", tp->t_vtid));
49127c478bd9Sstevel@tonic-gate 		(void) quntimeout(q, tp->t_vtid);
49137c478bd9Sstevel@tonic-gate 		tp->t_vtid = 0;
49147c478bd9Sstevel@tonic-gate 	}
49157c478bd9Sstevel@tonic-gate 	if (sendup) {
49167c478bd9Sstevel@tonic-gate 		if (tp->t_msglen == 0 && V_MIN) {
49177c478bd9Sstevel@tonic-gate 			/* EMPTY */
49187c478bd9Sstevel@tonic-gate 			DEBUG4(("vmin_satisfied: data swiped, msglen = 0\n"));
49197c478bd9Sstevel@tonic-gate 		} else {
49207c478bd9Sstevel@tonic-gate 			if ((!q->q_first) ||
49217c478bd9Sstevel@tonic-gate 			    (q->q_first->b_datap->db_type != M_DATA) ||
49227c478bd9Sstevel@tonic-gate 			    (tp->t_msglen >= LDCHUNK)) {
49237c478bd9Sstevel@tonic-gate 				ldterm_msg_upstream(q, tp);
49247c478bd9Sstevel@tonic-gate 				DEBUG4(("vmin_satisfied: delivering data\n"));
49257c478bd9Sstevel@tonic-gate 			}
49267c478bd9Sstevel@tonic-gate 		}
49277c478bd9Sstevel@tonic-gate 	} else {
49287c478bd9Sstevel@tonic-gate 		/* EMPTY */
49297c478bd9Sstevel@tonic-gate 		DEBUG4(("vmin_satisfied: VMIN/TIME state reset\n"));
49307c478bd9Sstevel@tonic-gate 	}
49317c478bd9Sstevel@tonic-gate 	tp->t_state &= ~TS_MREAD;
49327c478bd9Sstevel@tonic-gate }
49337c478bd9Sstevel@tonic-gate 
49347c478bd9Sstevel@tonic-gate static void
49357c478bd9Sstevel@tonic-gate vmin_settimer(queue_t *q)
49367c478bd9Sstevel@tonic-gate {
49377c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp;
49387c478bd9Sstevel@tonic-gate 
49397c478bd9Sstevel@tonic-gate 	tp = (ldtermstd_state_t *)q->q_ptr;
49407c478bd9Sstevel@tonic-gate 
49417c478bd9Sstevel@tonic-gate 	/*
49427c478bd9Sstevel@tonic-gate 	 * Don't start any time bombs.
49437c478bd9Sstevel@tonic-gate 	 */
49447c478bd9Sstevel@tonic-gate 	if (tp->t_state & TS_CLOSE)
49457c478bd9Sstevel@tonic-gate 		return;
49467c478bd9Sstevel@tonic-gate 
49477c478bd9Sstevel@tonic-gate 	/*
49487c478bd9Sstevel@tonic-gate 	 * tp->t_vtid should NOT be set here unless VMIN > 0 and
49497c478bd9Sstevel@tonic-gate 	 * VTIME > 0.
49507c478bd9Sstevel@tonic-gate 	 */
49517c478bd9Sstevel@tonic-gate 	if (tp->t_vtid) {
49527c478bd9Sstevel@tonic-gate 		if (V_MIN && V_TIME) {
49537c478bd9Sstevel@tonic-gate 			/* EMPTY */
49547c478bd9Sstevel@tonic-gate 			DEBUG4(("vmin_settimer: timer restarted, old tid=%d\n",
49557c478bd9Sstevel@tonic-gate 			    tp->t_vtid));
49567c478bd9Sstevel@tonic-gate 		} else {
49577c478bd9Sstevel@tonic-gate 			/* EMPTY */
49587c478bd9Sstevel@tonic-gate 			DEBUG4(("vmin_settimer: tid = %d was still active!\n",
49597c478bd9Sstevel@tonic-gate 			    tp->t_vtid));
49607c478bd9Sstevel@tonic-gate 		}
49617c478bd9Sstevel@tonic-gate 		(void) quntimeout(q, tp->t_vtid);
49627c478bd9Sstevel@tonic-gate 		tp->t_vtid = 0;
49637c478bd9Sstevel@tonic-gate 	}
49647c478bd9Sstevel@tonic-gate 	tp->t_vtid = qtimeout(q, vmin_timed_out, q,
49657c478bd9Sstevel@tonic-gate 	    (clock_t)(V_TIME * (hz / 10)));
49667c478bd9Sstevel@tonic-gate 	DEBUG4(("vmin_settimer: timer started, tid = %d\n", tp->t_vtid));
49677c478bd9Sstevel@tonic-gate }
49687c478bd9Sstevel@tonic-gate 
49697c478bd9Sstevel@tonic-gate 
49707c478bd9Sstevel@tonic-gate /*
49717c478bd9Sstevel@tonic-gate  * BRRrrringgg!! VTIME was satisfied instead of VMIN
49727c478bd9Sstevel@tonic-gate  */
49737c478bd9Sstevel@tonic-gate static void
49747c478bd9Sstevel@tonic-gate vmin_timed_out(void *arg)
49757c478bd9Sstevel@tonic-gate {
49767c478bd9Sstevel@tonic-gate 	queue_t *q = arg;
49777c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp;
49787c478bd9Sstevel@tonic-gate 
49797c478bd9Sstevel@tonic-gate 	tp = (ldtermstd_state_t *)q->q_ptr;
49807c478bd9Sstevel@tonic-gate 
49817c478bd9Sstevel@tonic-gate 	DEBUG4(("vmin_timed_out: tid = %d\n", tp->t_vtid));
49827c478bd9Sstevel@tonic-gate 	/* don't call untimeout now that we are in the timeout */
49837c478bd9Sstevel@tonic-gate 	tp->t_vtid = 0;
49847c478bd9Sstevel@tonic-gate 	vmin_satisfied(q, tp, 1);
49857c478bd9Sstevel@tonic-gate }
49867c478bd9Sstevel@tonic-gate 
49877c478bd9Sstevel@tonic-gate 
49887c478bd9Sstevel@tonic-gate /*
49897c478bd9Sstevel@tonic-gate  * Routine to adjust termios flags to be processed by the line
49907c478bd9Sstevel@tonic-gate  * discipline. Driver below sends a termios structure, with the flags
49917c478bd9Sstevel@tonic-gate  * the driver intends to process. XOR'ing the driver sent termios
49927c478bd9Sstevel@tonic-gate  * structure with current termios structure with the default values
49937c478bd9Sstevel@tonic-gate  * (or set by ioctls from userland), we come up with a new termios
49947c478bd9Sstevel@tonic-gate  * structrue, the flags of which will be used by the line discipline
49957c478bd9Sstevel@tonic-gate  * in processing input and output. On return from this routine, we
49967c478bd9Sstevel@tonic-gate  * will have the following fields set in tp structure -->
49977c478bd9Sstevel@tonic-gate  * tp->t_modes:	modes the line discipline will process tp->t_amodes:
49987c478bd9Sstevel@tonic-gate  * modes the user process thinks the line discipline is processing
49997c478bd9Sstevel@tonic-gate  */
50007c478bd9Sstevel@tonic-gate 
50017c478bd9Sstevel@tonic-gate static void
50027c478bd9Sstevel@tonic-gate ldterm_adjust_modes(ldtermstd_state_t *tp)
50037c478bd9Sstevel@tonic-gate {
50047c478bd9Sstevel@tonic-gate 
50057c478bd9Sstevel@tonic-gate 	DEBUG6(("original iflag = %o\n", tp->t_modes.c_iflag));
50067c478bd9Sstevel@tonic-gate 	tp->t_modes.c_iflag = tp->t_amodes.c_iflag & ~(tp->t_dmodes.c_iflag);
50077c478bd9Sstevel@tonic-gate 	tp->t_modes.c_oflag = tp->t_amodes.c_oflag & ~(tp->t_dmodes.c_oflag);
50087c478bd9Sstevel@tonic-gate 	tp->t_modes.c_lflag = tp->t_amodes.c_lflag & ~(tp->t_dmodes.c_lflag);
50097c478bd9Sstevel@tonic-gate 	DEBUG6(("driver iflag = %o\n", tp->t_dmodes.c_iflag));
50107c478bd9Sstevel@tonic-gate 	DEBUG6(("apparent iflag = %o\n", tp->t_amodes.c_iflag));
50117c478bd9Sstevel@tonic-gate 	DEBUG6(("effective iflag = %o\n", tp->t_modes.c_iflag));
50127c478bd9Sstevel@tonic-gate 
50137c478bd9Sstevel@tonic-gate 	/* No negotiation of clfags  c_cc array special characters */
50147c478bd9Sstevel@tonic-gate 	/*
50157c478bd9Sstevel@tonic-gate 	 * Copy from amodes to modes already done by TCSETA/TCSETS
50167c478bd9Sstevel@tonic-gate 	 * code
50177c478bd9Sstevel@tonic-gate 	 */
50187c478bd9Sstevel@tonic-gate }
50197c478bd9Sstevel@tonic-gate 
50207c478bd9Sstevel@tonic-gate 
50217c478bd9Sstevel@tonic-gate /*
50227c478bd9Sstevel@tonic-gate  * Erase one multi-byte character.  If TS_MEUC is set AND this
50237c478bd9Sstevel@tonic-gate  * is a multi-byte character, then this should be called instead of
50247c478bd9Sstevel@tonic-gate  * ldterm_erase.  "ldterm_erase" will handle ASCII nicely, thank you.
50257c478bd9Sstevel@tonic-gate  *
50267c478bd9Sstevel@tonic-gate  * We'd better be pointing to the last byte.  If we aren't, it will get
50277c478bd9Sstevel@tonic-gate  * screwed up.
50287c478bd9Sstevel@tonic-gate  */
50297c478bd9Sstevel@tonic-gate static void
50307c478bd9Sstevel@tonic-gate ldterm_csi_erase(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
50317c478bd9Sstevel@tonic-gate {
50327c478bd9Sstevel@tonic-gate 	int i, ung;
50337c478bd9Sstevel@tonic-gate 	uchar_t *p, *bottom;
50347c478bd9Sstevel@tonic-gate 	uchar_t u8[LDTERM_CS_MAX_BYTE_LENGTH];
50357c478bd9Sstevel@tonic-gate 	int c;
50367c478bd9Sstevel@tonic-gate 	int j;
50377c478bd9Sstevel@tonic-gate 	int len;
50387c478bd9Sstevel@tonic-gate 
50397c478bd9Sstevel@tonic-gate 	if (tp->t_eucleft) {
50407c478bd9Sstevel@tonic-gate 		/* XXX Ick.  We're in the middle of an EUC! */
50417c478bd9Sstevel@tonic-gate 		/* What to do now? */
50427c478bd9Sstevel@tonic-gate 		ldterm_eucwarn(tp);
50437c478bd9Sstevel@tonic-gate 		return;		/* ignore it??? */
50447c478bd9Sstevel@tonic-gate 	}
50457c478bd9Sstevel@tonic-gate 	bottom = tp->t_eucp_mp->b_rptr;
50467c478bd9Sstevel@tonic-gate 	p = tp->t_eucp - 1;	/* previous byte */
50477c478bd9Sstevel@tonic-gate 	if (p < bottom)
50487c478bd9Sstevel@tonic-gate 		return;
50497c478bd9Sstevel@tonic-gate 	ung = 1;		/* number of bytes to un-get from buffer */
50507c478bd9Sstevel@tonic-gate 	/*
50517c478bd9Sstevel@tonic-gate 	 * go through the buffer until we find the beginning of the
50527c478bd9Sstevel@tonic-gate 	 * multi-byte char.
50537c478bd9Sstevel@tonic-gate 	 */
50547c478bd9Sstevel@tonic-gate 	while ((*p == 0) && (p > bottom)) {
50557c478bd9Sstevel@tonic-gate 		p--;
50567c478bd9Sstevel@tonic-gate 		++ung;
50577c478bd9Sstevel@tonic-gate 	}
50587c478bd9Sstevel@tonic-gate 
50597c478bd9Sstevel@tonic-gate 	/*
50607c478bd9Sstevel@tonic-gate 	 * Now, "ung" is the number of bytes to unget from the buffer
50617c478bd9Sstevel@tonic-gate 	 * and "*p" is the disp width of it. Fool "ldterm_rubout"
50627c478bd9Sstevel@tonic-gate 	 * into thinking we're rubbing out ASCII characters.  Do that
50637c478bd9Sstevel@tonic-gate 	 * for the display width of the character.
50647c478bd9Sstevel@tonic-gate 	 *
50657c478bd9Sstevel@tonic-gate 	 * Also we accumulate bytes of the character so that if the character
50667c478bd9Sstevel@tonic-gate 	 * is a UTF-8 character, we will get the display width of the UTF-8
50677c478bd9Sstevel@tonic-gate 	 * character.
50687c478bd9Sstevel@tonic-gate 	 */
50697c478bd9Sstevel@tonic-gate 	if (ung >= LDTERM_CS_MAX_BYTE_LENGTH) {
50707c478bd9Sstevel@tonic-gate 		j = len = LDTERM_CS_MAX_BYTE_LENGTH;
50717c478bd9Sstevel@tonic-gate 	} else {
50727c478bd9Sstevel@tonic-gate 		j = len = ung;
50737c478bd9Sstevel@tonic-gate 	}
50747c478bd9Sstevel@tonic-gate 	for (i = 0; i < ung; i++) {	/* remove from buf */
50757c478bd9Sstevel@tonic-gate 		if ((c = ldterm_unget(tp)) != (-1)) {
50767c478bd9Sstevel@tonic-gate 			ldterm_trim(tp);
50777c478bd9Sstevel@tonic-gate 			if (j > 0)
50787c478bd9Sstevel@tonic-gate 				u8[--j] = (uchar_t)c;
50797c478bd9Sstevel@tonic-gate 		}
50807c478bd9Sstevel@tonic-gate 	}
50817c478bd9Sstevel@tonic-gate 	if (*p == UNKNOWN_WIDTH) {
50827c478bd9Sstevel@tonic-gate 		if (tp->t_csdata.codeset_type == LDTERM_CS_TYPE_UTF8) {
50837c478bd9Sstevel@tonic-gate 			*p = ldterm_utf8_width(u8, len);
50847c478bd9Sstevel@tonic-gate 		} else {
50857c478bd9Sstevel@tonic-gate 			*p = 1;
50867c478bd9Sstevel@tonic-gate 		}
50877c478bd9Sstevel@tonic-gate 	}
50887c478bd9Sstevel@tonic-gate 	for (i = 0; i < (int)*p; i++)	/* remove from screen */
50897c478bd9Sstevel@tonic-gate 		ldterm_rubout(' ', q, ebsize, tp);
50907c478bd9Sstevel@tonic-gate 	/*
50917c478bd9Sstevel@tonic-gate 	 * Adjust the parallel array pointer.  Zero out the contents
50927c478bd9Sstevel@tonic-gate 	 * of parallel array for this position, just to make sure...
50937c478bd9Sstevel@tonic-gate 	 */
50947c478bd9Sstevel@tonic-gate 	tp->t_eucp = p;
50957c478bd9Sstevel@tonic-gate 	*p = 0;
50967c478bd9Sstevel@tonic-gate }
50977c478bd9Sstevel@tonic-gate 
50987c478bd9Sstevel@tonic-gate 
50997c478bd9Sstevel@tonic-gate /*
51007c478bd9Sstevel@tonic-gate  * This is kind of a safety valve.  Whenever we see a bad sequence
51017c478bd9Sstevel@tonic-gate  * come up, we call eucwarn.  It just tallies the junk until a
51027c478bd9Sstevel@tonic-gate  * threshold is reached.  Then it prints ONE message on the console
51037c478bd9Sstevel@tonic-gate  * and not any more. Hopefully, we can catch garbage; maybe it will
51047c478bd9Sstevel@tonic-gate  * be useful to somebody.
51057c478bd9Sstevel@tonic-gate  */
51067c478bd9Sstevel@tonic-gate static void
51077c478bd9Sstevel@tonic-gate ldterm_eucwarn(ldtermstd_state_t *tp)
51087c478bd9Sstevel@tonic-gate {
51097c478bd9Sstevel@tonic-gate 	++tp->t_eucwarn;
51107c478bd9Sstevel@tonic-gate #ifdef DEBUG
51117c478bd9Sstevel@tonic-gate 	if ((tp->t_eucwarn > EUC_WARNCNT) && !(tp->t_state & TS_WARNED)) {
51127c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
51137c478bd9Sstevel@tonic-gate 		    "ldterm: tty at addr %p in multi-byte mode --",
51147c478bd9Sstevel@tonic-gate 		    (void *)tp);
51157c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
51167c478bd9Sstevel@tonic-gate 		    "Over %d bad EUC characters this session", EUC_WARNCNT);
51177c478bd9Sstevel@tonic-gate 		tp->t_state |= TS_WARNED;
51187c478bd9Sstevel@tonic-gate 	}
51197c478bd9Sstevel@tonic-gate #endif
51207c478bd9Sstevel@tonic-gate }
51217c478bd9Sstevel@tonic-gate 
51227c478bd9Sstevel@tonic-gate 
51237c478bd9Sstevel@tonic-gate /*
51247c478bd9Sstevel@tonic-gate  * Copy an "eucioc_t" structure.  We use the structure with
51257c478bd9Sstevel@tonic-gate  * incremented values for Codesets 2 & 3.  The specification in
51267c478bd9Sstevel@tonic-gate  * eucioctl is that the sames values as the CSWIDTH definition at
51277c478bd9Sstevel@tonic-gate  * user level are passed to us. When we copy it "in" to ourselves, we
51287c478bd9Sstevel@tonic-gate  * do the increment.  That allows us to avoid treating each character
51297c478bd9Sstevel@tonic-gate  * set separately for "t_eucleft" purposes. When we copy it "out" to
51307c478bd9Sstevel@tonic-gate  * return it to the user, we decrement the values so the user gets
51317c478bd9Sstevel@tonic-gate  * what it expects, and it matches CSWIDTH in the environment (if
51327c478bd9Sstevel@tonic-gate  * things are consistent!).
51337c478bd9Sstevel@tonic-gate  */
51347c478bd9Sstevel@tonic-gate static void
51357c478bd9Sstevel@tonic-gate cp_eucwioc(eucioc_t *from, eucioc_t *to, int dir)
51367c478bd9Sstevel@tonic-gate {
51377c478bd9Sstevel@tonic-gate 	bcopy(from, to, EUCSIZE);
51387c478bd9Sstevel@tonic-gate 	if (dir == EUCOUT) {	/* copying out to user */
51397c478bd9Sstevel@tonic-gate 		if (to->eucw[2])
51407c478bd9Sstevel@tonic-gate 			--to->eucw[2];
51417c478bd9Sstevel@tonic-gate 		if (to->eucw[3])
51427c478bd9Sstevel@tonic-gate 			--to->eucw[3];
51437c478bd9Sstevel@tonic-gate 	} else {		/* copying in */
51447c478bd9Sstevel@tonic-gate 		if (to->eucw[2])
51457c478bd9Sstevel@tonic-gate 			++to->eucw[2];
51467c478bd9Sstevel@tonic-gate 		if (to->eucw[3])
51477c478bd9Sstevel@tonic-gate 			++to->eucw[3];
51487c478bd9Sstevel@tonic-gate 	}
51497c478bd9Sstevel@tonic-gate }
51507c478bd9Sstevel@tonic-gate 
51517c478bd9Sstevel@tonic-gate 
51527c478bd9Sstevel@tonic-gate /*
51537c478bd9Sstevel@tonic-gate  * Take the first byte of a multi-byte, or an ASCII char.  Return its
51547c478bd9Sstevel@tonic-gate  * codeset. If it's NOT the first byte of an EUC, then the return
51557c478bd9Sstevel@tonic-gate  * value may be garbage, as it's probably not SS2 or SS3, and
51567c478bd9Sstevel@tonic-gate  * therefore must be in codeset 1.  Another bizarre catch here is the
51577c478bd9Sstevel@tonic-gate  * fact that we don't do anything about the "C1" control codes.  In
51587c478bd9Sstevel@tonic-gate  * real life, we should; but nobody's come up with a good way of
51597c478bd9Sstevel@tonic-gate  * treating them.
51607c478bd9Sstevel@tonic-gate  */
51617c478bd9Sstevel@tonic-gate 
51627c478bd9Sstevel@tonic-gate static int
51637c478bd9Sstevel@tonic-gate ldterm_codeset(uchar_t codeset_type, uchar_t c)
51647c478bd9Sstevel@tonic-gate {
51657c478bd9Sstevel@tonic-gate 
51667c478bd9Sstevel@tonic-gate 	if (ISASCII(c))
51677c478bd9Sstevel@tonic-gate 		return (0);
51687c478bd9Sstevel@tonic-gate 
51697c478bd9Sstevel@tonic-gate 	if (codeset_type != LDTERM_CS_TYPE_EUC)
51707c478bd9Sstevel@tonic-gate 		return (1);
51717c478bd9Sstevel@tonic-gate 
51727c478bd9Sstevel@tonic-gate 	switch (c) {
51737c478bd9Sstevel@tonic-gate 	case SS2:
51747c478bd9Sstevel@tonic-gate 		return (2);
51757c478bd9Sstevel@tonic-gate 	case SS3:
51767c478bd9Sstevel@tonic-gate 		return (3);
51777c478bd9Sstevel@tonic-gate 	default:
51787c478bd9Sstevel@tonic-gate 		return (1);
51797c478bd9Sstevel@tonic-gate 	}
51807c478bd9Sstevel@tonic-gate }
51817c478bd9Sstevel@tonic-gate 
51827c478bd9Sstevel@tonic-gate /* The following two functions are additional EUC codeset specific methods. */
51837c478bd9Sstevel@tonic-gate /*
51847c478bd9Sstevel@tonic-gate  * ldterm_dispwidth - Take the first byte of an EUC (or ASCII) and
51857c478bd9Sstevel@tonic-gate  * return the display width.  Since this is intended mostly for
51867c478bd9Sstevel@tonic-gate  * multi-byte handling, it returns EUC_TWIDTH for tabs so they can be
51877c478bd9Sstevel@tonic-gate  * differentiated from EUC characters (assumption: EUC require fewer
51887c478bd9Sstevel@tonic-gate  * than 255 columns).  Also, if it's a backspace and !flag, it
51897c478bd9Sstevel@tonic-gate  * returns EUC_BSWIDTH.  Newline & CR also depend on flag.  This
51907c478bd9Sstevel@tonic-gate  * routine SHOULD be cleaner than this, but we have the situation
51917c478bd9Sstevel@tonic-gate  * where we may or may not be counting control characters as having a
51927c478bd9Sstevel@tonic-gate  * column width. Therefore, the computation of ASCII is pretty messy.
51937c478bd9Sstevel@tonic-gate  * The caller will be storing the value, and then switching on it
51947c478bd9Sstevel@tonic-gate  * when it's used.  We really should define the EUC_TWIDTH and other
51957c478bd9Sstevel@tonic-gate  * constants in a header so that the routine could be used in other
51967c478bd9Sstevel@tonic-gate  * modules in the kernel.
51977c478bd9Sstevel@tonic-gate  */
51987c478bd9Sstevel@tonic-gate static int
51997c478bd9Sstevel@tonic-gate __ldterm_dispwidth_euc(uchar_t c, void *p, int mode)
52007c478bd9Sstevel@tonic-gate {
52017c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp = (ldtermstd_state_t *)p;
52027c478bd9Sstevel@tonic-gate 
52037c478bd9Sstevel@tonic-gate 	if (ISASCII(c)) {
52047c478bd9Sstevel@tonic-gate 		if (c <= '\037') {
52057c478bd9Sstevel@tonic-gate 			switch (c) {
52067c478bd9Sstevel@tonic-gate 			case '\t':
52077c478bd9Sstevel@tonic-gate 				return (EUC_TWIDTH);
52087c478bd9Sstevel@tonic-gate 			case '\b':
52097c478bd9Sstevel@tonic-gate 				return (mode ? 2 : EUC_BSWIDTH);
52107c478bd9Sstevel@tonic-gate 			case '\n':
52117c478bd9Sstevel@tonic-gate 				return (EUC_NLWIDTH);
52127c478bd9Sstevel@tonic-gate 			case '\r':
52137c478bd9Sstevel@tonic-gate 				return (mode ? 2 : EUC_CRWIDTH);
52147c478bd9Sstevel@tonic-gate 			default:
52157c478bd9Sstevel@tonic-gate 				return (mode ? 2 : 0);
52167c478bd9Sstevel@tonic-gate 			}
52177c478bd9Sstevel@tonic-gate 		}
52187c478bd9Sstevel@tonic-gate 		return (1);
52197c478bd9Sstevel@tonic-gate 	}
52207c478bd9Sstevel@tonic-gate 	switch (c) {
52217c478bd9Sstevel@tonic-gate 	case SS2:
52227c478bd9Sstevel@tonic-gate 		return (tp->eucwioc.scrw[2]);
52237c478bd9Sstevel@tonic-gate 	case SS3:
52247c478bd9Sstevel@tonic-gate 		return (tp->eucwioc.scrw[3]);
52257c478bd9Sstevel@tonic-gate 	default:
52267c478bd9Sstevel@tonic-gate 		return (tp->eucwioc.scrw[1]);
52277c478bd9Sstevel@tonic-gate 	}
52287c478bd9Sstevel@tonic-gate }
52297c478bd9Sstevel@tonic-gate 
52307c478bd9Sstevel@tonic-gate /*
52317c478bd9Sstevel@tonic-gate  * ldterm_memwidth_euc - Take the first byte of an EUC (or an ASCII char)
52327c478bd9Sstevel@tonic-gate  * and return its memory width.  The routine could have been
52337c478bd9Sstevel@tonic-gate  * implemented to use only the codeset number, but that would require
52347c478bd9Sstevel@tonic-gate  * the caller to have that value available.  Perhaps the user doesn't
52357c478bd9Sstevel@tonic-gate  * want to make the extra call or keep the value of codeset around.
52367c478bd9Sstevel@tonic-gate  * Therefore, we use the actual character with which they're
52377c478bd9Sstevel@tonic-gate  * concerned.  This should never be called with anything but the
52387c478bd9Sstevel@tonic-gate  * first byte of an EUC, otherwise it will return a garbage value.
52397c478bd9Sstevel@tonic-gate  */
52407c478bd9Sstevel@tonic-gate static int
52417c478bd9Sstevel@tonic-gate __ldterm_memwidth_euc(uchar_t c, void *p)
52427c478bd9Sstevel@tonic-gate {
52437c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp = (ldtermstd_state_t *)p;
52447c478bd9Sstevel@tonic-gate 
52457c478bd9Sstevel@tonic-gate 	if (ISASCII(c))
52467c478bd9Sstevel@tonic-gate 		return (1);
52477c478bd9Sstevel@tonic-gate 	switch (c) {
52487c478bd9Sstevel@tonic-gate 	case SS2:
52497c478bd9Sstevel@tonic-gate 		return (tp->eucwioc.eucw[2]);
52507c478bd9Sstevel@tonic-gate 	case SS3:
52517c478bd9Sstevel@tonic-gate 		return (tp->eucwioc.eucw[3]);
52527c478bd9Sstevel@tonic-gate 	default:
52537c478bd9Sstevel@tonic-gate 		return (tp->eucwioc.eucw[1]);
52547c478bd9Sstevel@tonic-gate 	}
52557c478bd9Sstevel@tonic-gate }
52567c478bd9Sstevel@tonic-gate 
52577c478bd9Sstevel@tonic-gate 
52587c478bd9Sstevel@tonic-gate /* The following two functions are PCCS codeset specific methods. */
52597c478bd9Sstevel@tonic-gate static int
52607c478bd9Sstevel@tonic-gate __ldterm_dispwidth_pccs(uchar_t c, void *p, int mode)
52617c478bd9Sstevel@tonic-gate {
52627c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp = (ldtermstd_state_t *)p;
52637c478bd9Sstevel@tonic-gate 	int i;
52647c478bd9Sstevel@tonic-gate 
52657c478bd9Sstevel@tonic-gate 	if (ISASCII(c)) {
52667c478bd9Sstevel@tonic-gate 		if (c <= '\037') {
52677c478bd9Sstevel@tonic-gate 			switch (c) {
52687c478bd9Sstevel@tonic-gate 			case '\t':
52697c478bd9Sstevel@tonic-gate 				return (EUC_TWIDTH);
52707c478bd9Sstevel@tonic-gate 			case '\b':
52717c478bd9Sstevel@tonic-gate 				return (mode ? 2 : EUC_BSWIDTH);
52727c478bd9Sstevel@tonic-gate 			case '\n':
52737c478bd9Sstevel@tonic-gate 				return (EUC_NLWIDTH);
52747c478bd9Sstevel@tonic-gate 			case '\r':
52757c478bd9Sstevel@tonic-gate 				return (mode ? 2 : EUC_CRWIDTH);
52767c478bd9Sstevel@tonic-gate 			default:
52777c478bd9Sstevel@tonic-gate 				return (mode ? 2 : 0);
52787c478bd9Sstevel@tonic-gate 			}
52797c478bd9Sstevel@tonic-gate 		}
52807c478bd9Sstevel@tonic-gate 		return (1);
52817c478bd9Sstevel@tonic-gate 	}
52827c478bd9Sstevel@tonic-gate 
52837c478bd9Sstevel@tonic-gate 	for (i = 0; i < tp->t_csdata.csinfo_num; i++) {
52847c478bd9Sstevel@tonic-gate 		if (c >= tp->t_csdata.eucpc_data[i].msb_start &&
52857c478bd9Sstevel@tonic-gate 		    c <= tp->t_csdata.eucpc_data[i].msb_end)
52867c478bd9Sstevel@tonic-gate 			return (tp->t_csdata.eucpc_data[i].screen_width);
52877c478bd9Sstevel@tonic-gate 	}
52887c478bd9Sstevel@tonic-gate 
52897c478bd9Sstevel@tonic-gate 	/*
52907c478bd9Sstevel@tonic-gate 	 * If this leading byte is not in the range list, either provided
52917c478bd9Sstevel@tonic-gate 	 * locale data is not sufficient or we encountered an invalid
52927c478bd9Sstevel@tonic-gate 	 * character. We return 1 in this case as a fallback value.
52937c478bd9Sstevel@tonic-gate 	 */
52947c478bd9Sstevel@tonic-gate 	return (1);
52957c478bd9Sstevel@tonic-gate }
52967c478bd9Sstevel@tonic-gate 
52977c478bd9Sstevel@tonic-gate static int
52987c478bd9Sstevel@tonic-gate __ldterm_memwidth_pccs(uchar_t c, void *p)
52997c478bd9Sstevel@tonic-gate {
53007c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp = (ldtermstd_state_t *)p;
53017c478bd9Sstevel@tonic-gate 	int i;
53027c478bd9Sstevel@tonic-gate 
53037c478bd9Sstevel@tonic-gate 	for (i = 0; i < tp->t_csdata.csinfo_num; i++) {
53047c478bd9Sstevel@tonic-gate 		if (c >= tp->t_csdata.eucpc_data[i].msb_start &&
53057c478bd9Sstevel@tonic-gate 		    c <= tp->t_csdata.eucpc_data[i].msb_end)
53067c478bd9Sstevel@tonic-gate 			return (tp->t_csdata.eucpc_data[i].byte_length);
53077c478bd9Sstevel@tonic-gate 	}
53087c478bd9Sstevel@tonic-gate 
53097c478bd9Sstevel@tonic-gate 	/*
53107c478bd9Sstevel@tonic-gate 	 * If this leading byte is not in the range list, either provided
53117c478bd9Sstevel@tonic-gate 	 * locale data is not sufficient or we encountered an invalid
53127c478bd9Sstevel@tonic-gate 	 * character. We return 1 in this case as a fallback value.
53137c478bd9Sstevel@tonic-gate 	 */
53147c478bd9Sstevel@tonic-gate 	return (1);
53157c478bd9Sstevel@tonic-gate }
53167c478bd9Sstevel@tonic-gate 
53177c478bd9Sstevel@tonic-gate 
53187c478bd9Sstevel@tonic-gate /* The following two functions are UTF-8 codeset specific methods. */
53197c478bd9Sstevel@tonic-gate static int
53207c478bd9Sstevel@tonic-gate __ldterm_dispwidth_utf8(uchar_t c, void *p, int mode)
53217c478bd9Sstevel@tonic-gate {
53227c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp = (ldtermstd_state_t *)p;
53237c478bd9Sstevel@tonic-gate 
53247c478bd9Sstevel@tonic-gate 	if (ISASCII(c)) {
53257c478bd9Sstevel@tonic-gate 		if (c <= '\037') {
53267c478bd9Sstevel@tonic-gate 			switch (c) {
53277c478bd9Sstevel@tonic-gate 			case '\t':
53287c478bd9Sstevel@tonic-gate 				return (EUC_TWIDTH);
53297c478bd9Sstevel@tonic-gate 			case '\b':
53307c478bd9Sstevel@tonic-gate 				return (mode ? 2 : EUC_BSWIDTH);
53317c478bd9Sstevel@tonic-gate 			case '\n':
53327c478bd9Sstevel@tonic-gate 				return (EUC_NLWIDTH);
53337c478bd9Sstevel@tonic-gate 			case '\r':
53347c478bd9Sstevel@tonic-gate 				return (mode ? 2 : EUC_CRWIDTH);
53357c478bd9Sstevel@tonic-gate 			default:
53367c478bd9Sstevel@tonic-gate 				return (mode ? 2 : 0);
53377c478bd9Sstevel@tonic-gate 			}
53387c478bd9Sstevel@tonic-gate 		}
53397c478bd9Sstevel@tonic-gate 		return (1);
53407c478bd9Sstevel@tonic-gate 	}
53417c478bd9Sstevel@tonic-gate 
53427c478bd9Sstevel@tonic-gate 	/* This is to silence the lint. */
53437c478bd9Sstevel@tonic-gate 	if (tp->t_csdata.codeset_type != LDTERM_CS_TYPE_UTF8)
53447c478bd9Sstevel@tonic-gate 		return (1);
53457c478bd9Sstevel@tonic-gate 
53467c478bd9Sstevel@tonic-gate 	/*
53477c478bd9Sstevel@tonic-gate 	 * If it is a valid leading byte of a UTF-8 character, we set
53487c478bd9Sstevel@tonic-gate 	 * the width as 'UNKNOWN_WIDTH' for now. We need to have all
53497c478bd9Sstevel@tonic-gate 	 * the bytes to figure out the display width.
53507c478bd9Sstevel@tonic-gate 	 */
53517c478bd9Sstevel@tonic-gate 	if (c >= (uchar_t)0xc0 && c <= (uchar_t)0xfd)
53527c478bd9Sstevel@tonic-gate 		return (UNKNOWN_WIDTH);
53537c478bd9Sstevel@tonic-gate 
53547c478bd9Sstevel@tonic-gate 	/*
53557c478bd9Sstevel@tonic-gate 	 * If it is an invalid leading byte, we just do our best by
53567c478bd9Sstevel@tonic-gate 	 * giving the display width of 1.
53577c478bd9Sstevel@tonic-gate 	 */
53587c478bd9Sstevel@tonic-gate 	return (1);
53597c478bd9Sstevel@tonic-gate }
53607c478bd9Sstevel@tonic-gate 
53617c478bd9Sstevel@tonic-gate 
53627c478bd9Sstevel@tonic-gate static int
53637c478bd9Sstevel@tonic-gate __ldterm_memwidth_utf8(uchar_t c, void *p)
53647c478bd9Sstevel@tonic-gate {
53657c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp = (ldtermstd_state_t *)p;
536685bb5f1dSis 	int len;
53677c478bd9Sstevel@tonic-gate 
536885bb5f1dSis 	/*
536985bb5f1dSis 	 * If the codeset type doesn't match, we treat them as
537085bb5f1dSis 	 * an illegal character and return 1.
537185bb5f1dSis 	 */
53727c478bd9Sstevel@tonic-gate 	if (tp->t_csdata.codeset_type != LDTERM_CS_TYPE_UTF8)
53737c478bd9Sstevel@tonic-gate 		return (1);
53747c478bd9Sstevel@tonic-gate 
537585bb5f1dSis 	len = u8_number_of_bytes[c];
537685bb5f1dSis 
537785bb5f1dSis 	/*
537885bb5f1dSis 	 * If this is a start of an illegal character, we treat
537985bb5f1dSis 	 * such as an 1 byte character and screen out.
538085bb5f1dSis 	 */
538185bb5f1dSis 	return ((len <= 0) ? 1 : len);
53827c478bd9Sstevel@tonic-gate }
53837c478bd9Sstevel@tonic-gate 
53847c478bd9Sstevel@tonic-gate static uchar_t
53857c478bd9Sstevel@tonic-gate ldterm_utf8_width(uchar_t *u8, int length)
53867c478bd9Sstevel@tonic-gate {
53877c478bd9Sstevel@tonic-gate 	int i;
53887c478bd9Sstevel@tonic-gate 	int j;
53897c478bd9Sstevel@tonic-gate 	uint_t intcode = 0;
53907c478bd9Sstevel@tonic-gate 
53917c478bd9Sstevel@tonic-gate 	if (length == 0)
53927c478bd9Sstevel@tonic-gate 		return ('\0');
53937c478bd9Sstevel@tonic-gate 
539485bb5f1dSis 	j = u8_number_of_bytes[u8[0]] - 1;
53957c478bd9Sstevel@tonic-gate 
53967c478bd9Sstevel@tonic-gate 	/*
53977c478bd9Sstevel@tonic-gate 	 * If the UTF-8 character is out of UTF-16 code range, or,
53987c478bd9Sstevel@tonic-gate 	 * if it is either an ASCII character or an invalid leading byte for
53997c478bd9Sstevel@tonic-gate 	 * a UTF-8 character, return 1.
54007c478bd9Sstevel@tonic-gate 	 */
540185bb5f1dSis 	if (length > 4 || j <= 0)
54027c478bd9Sstevel@tonic-gate 		return ('\1');
54037c478bd9Sstevel@tonic-gate 
540485bb5f1dSis 	intcode = u8[0] & u8_masks_tbl[j];
54057c478bd9Sstevel@tonic-gate 	for (i = 1; j > 0; j--, i++) {
54067c478bd9Sstevel@tonic-gate 		/*
540785bb5f1dSis 		 * The following additional checking is needed to conform to
540885bb5f1dSis 		 * the "UTF-8 Corrigendum" introduced at the Unicode 3.1 and
540985bb5f1dSis 		 * then updated one more time at the Unicode 3.2.
54107c478bd9Sstevel@tonic-gate 		 */
54117c478bd9Sstevel@tonic-gate 		if (i == 1) {
541285bb5f1dSis 			if (u8[i] < u8_valid_min_2nd_byte[u8[0]] ||
541385bb5f1dSis 			    u8[i] > u8_valid_max_2nd_byte[u8[0]])
54147c478bd9Sstevel@tonic-gate 				return ('\1');
54157c478bd9Sstevel@tonic-gate 		} else if (u8[i] < (uchar_t)LDTERM_CS_TYPE_UTF8_MIN_BYTE ||
54167c478bd9Sstevel@tonic-gate 		    u8[i] > (uchar_t)LDTERM_CS_TYPE_UTF8_MAX_BYTE)
54177c478bd9Sstevel@tonic-gate 			return ('\1');
54187c478bd9Sstevel@tonic-gate 
54197c478bd9Sstevel@tonic-gate 		/*
54207c478bd9Sstevel@tonic-gate 		 * All subsequent bytes of UTF-8 character has the following
54217c478bd9Sstevel@tonic-gate 		 * binary encoding:
54227c478bd9Sstevel@tonic-gate 		 *
54237c478bd9Sstevel@tonic-gate 		 * 10xx xxxx
54247c478bd9Sstevel@tonic-gate 		 *
54257c478bd9Sstevel@tonic-gate 		 * hence left shift six bits to make space and then get
54267c478bd9Sstevel@tonic-gate 		 * six bits from the new byte.
54277c478bd9Sstevel@tonic-gate 		 */
54287c478bd9Sstevel@tonic-gate 		intcode = (intcode << LDTERM_CS_TYPE_UTF8_SHIFT_BITS) |
54297c478bd9Sstevel@tonic-gate 		    (u8[i] & LDTERM_CS_TYPE_UTF8_BIT_MASK);
54307c478bd9Sstevel@tonic-gate 	}
54317c478bd9Sstevel@tonic-gate 
543285bb5f1dSis 	i = 0;
54337c478bd9Sstevel@tonic-gate 	if (intcode <= LDTERM_CS_TYPE_UTF8_MAX_P00) {
54347c478bd9Sstevel@tonic-gate 		/* Basic Multilingual Plane. */
54357c478bd9Sstevel@tonic-gate 		i = intcode / 4;
54367c478bd9Sstevel@tonic-gate 		j = intcode % 4;
54377c478bd9Sstevel@tonic-gate 		switch (j) {
54387c478bd9Sstevel@tonic-gate 		case 0:
543985bb5f1dSis 			i = ldterm_ucode[0][i].u0;
544085bb5f1dSis 			break;
54417c478bd9Sstevel@tonic-gate 		case 1:
544285bb5f1dSis 			i = ldterm_ucode[0][i].u1;
544385bb5f1dSis 			break;
54447c478bd9Sstevel@tonic-gate 		case 2:
544585bb5f1dSis 			i = ldterm_ucode[0][i].u2;
544685bb5f1dSis 			break;
54477c478bd9Sstevel@tonic-gate 		case 3:
544885bb5f1dSis 			i = ldterm_ucode[0][i].u3;
544985bb5f1dSis 			break;
54507c478bd9Sstevel@tonic-gate 		}
54517c478bd9Sstevel@tonic-gate 	} else if (intcode <= LDTERM_CS_TYPE_UTF8_MAX_P01) {
54527c478bd9Sstevel@tonic-gate 		/* Secondary Multilingual Plane. */
54537c478bd9Sstevel@tonic-gate 		intcode = intcode & (uint_t)0xffff;
54547c478bd9Sstevel@tonic-gate 		i = intcode / 4;
54557c478bd9Sstevel@tonic-gate 		j = intcode % 4;
54567c478bd9Sstevel@tonic-gate 		switch (j) {
54577c478bd9Sstevel@tonic-gate 		case 0:
545885bb5f1dSis 			i = ldterm_ucode[1][i].u0;
545985bb5f1dSis 			break;
54607c478bd9Sstevel@tonic-gate 		case 1:
546185bb5f1dSis 			i = ldterm_ucode[1][i].u1;
546285bb5f1dSis 			break;
54637c478bd9Sstevel@tonic-gate 		case 2:
546485bb5f1dSis 			i = ldterm_ucode[1][i].u2;
546585bb5f1dSis 			break;
54667c478bd9Sstevel@tonic-gate 		case 3:
546785bb5f1dSis 			i = ldterm_ucode[1][i].u3;
546885bb5f1dSis 			break;
54697c478bd9Sstevel@tonic-gate 		}
54707c478bd9Sstevel@tonic-gate 	} else if ((intcode >= LDTERM_CS_TYPE_UTF8_MIN_CJKEXTB &&
54717c478bd9Sstevel@tonic-gate 	    intcode <= LDTERM_CS_TYPE_UTF8_MAX_CJKEXTB) ||
54727c478bd9Sstevel@tonic-gate 	    (intcode >= LDTERM_CS_TYPE_UTF8_MIN_CJKCOMP &&
54737c478bd9Sstevel@tonic-gate 	    intcode <= LDTERM_CS_TYPE_UTF8_MAX_CJKCOMP) ||
54747c478bd9Sstevel@tonic-gate 	    (intcode >= LDTERM_CS_TYPE_UTF8_MIN_P15 &&
54757c478bd9Sstevel@tonic-gate 	    intcode <= LDTERM_CS_TYPE_UTF8_MAX_P15) ||
54767c478bd9Sstevel@tonic-gate 	    (intcode >= LDTERM_CS_TYPE_UTF8_MIN_P16 &&
54777c478bd9Sstevel@tonic-gate 	    intcode <= LDTERM_CS_TYPE_UTF8_MAX_P16)) {
54787c478bd9Sstevel@tonic-gate 		/*
54797c478bd9Sstevel@tonic-gate 		 * Supplementary Plane for CJK Ideographs and
54807c478bd9Sstevel@tonic-gate 		 * Private Use Planes.
54817c478bd9Sstevel@tonic-gate 		 */
54827c478bd9Sstevel@tonic-gate 		return ('\2');
54837c478bd9Sstevel@tonic-gate 	} else if ((intcode >= LDTERM_CS_TYPE_UTF8_MIN_P14 &&
54847c478bd9Sstevel@tonic-gate 	    intcode <= LDTERM_CS_TYPE_UTF8_MAX_P14) ||
54857c478bd9Sstevel@tonic-gate 	    (intcode >= LDTERM_CS_TYPE_UTF8_MIN_VARSEL &&
54867c478bd9Sstevel@tonic-gate 	    intcode <= LDTERM_CS_TYPE_UTF8_MAX_VARSEL)) {
548785bb5f1dSis 		/*
548885bb5f1dSis 		 * Some Special Purpose Plane characters:
548985bb5f1dSis 		 * These are like control characters and not printable.
549085bb5f1dSis 		 */
54917c478bd9Sstevel@tonic-gate 		return ('\0');
54927c478bd9Sstevel@tonic-gate 	}
54937c478bd9Sstevel@tonic-gate 
549485bb5f1dSis 	/*
549585bb5f1dSis 	 * We return the display width of 1 for all character code points
549685bb5f1dSis 	 * that we didn't catch from the above logic and also for combining
549785bb5f1dSis 	 * and conjoining characters with width value of zero.
549885bb5f1dSis 	 *
549985bb5f1dSis 	 * In particular, the reason why we are returning 1 for combining
550085bb5f1dSis 	 * and conjoining characters is because the GUI-based terminal
550185bb5f1dSis 	 * emulators are not yet capable of properly handling such characters
550285bb5f1dSis 	 * and in most of the cases, they just treat such characters as if
550385bb5f1dSis 	 * they occupy a display cell. If the terminal emulators are capable of
550485bb5f1dSis 	 * handling the characters correctly, then, this logic of returning
550585bb5f1dSis 	 * 1 should be revisited and changed. See CR 6660526 for more
550685bb5f1dSis 	 * details on this.
550785bb5f1dSis 	 */
550885bb5f1dSis 	return ((i == 0) ? '\1' : (uchar_t)i);
55097c478bd9Sstevel@tonic-gate }
5510