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