xref: /illumos-gate/usr/src/uts/common/io/ldterm.c (revision 7d8deab2)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
585bb5f1dSis  * Common Development and Distribution License (the "License").
685bb5f1dSis  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
2285bb5f1dSis  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
2424c5c9f4SJohn Levon  * Copyright (c) 2018, Joyent, Inc.
25*7d8deab2SAndy Fiddaman  * Copyright 2020 OmniOS Community Edition (OmniOSce) Association.
267c478bd9Sstevel@tonic-gate  */
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
297c478bd9Sstevel@tonic-gate /* All Rights Reserved					*/
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate /*
327c478bd9Sstevel@tonic-gate  * University Copyright- Copyright (c) 1982, 1986, 1988
337c478bd9Sstevel@tonic-gate  * The Regents of the University of California
347c478bd9Sstevel@tonic-gate  * All Rights Reserved
357c478bd9Sstevel@tonic-gate  *
367c478bd9Sstevel@tonic-gate  * University Acknowledgment- Portions of this document are derived from
377c478bd9Sstevel@tonic-gate  * software developed by the University of California, Berkeley, and its
387c478bd9Sstevel@tonic-gate  * contributors.
397c478bd9Sstevel@tonic-gate  */
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,
3856cfa0a70SAndy Fiddaman 	D_MTQPAIR | D_MP | _D_SINGLE_INSTANCE
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
_init(void)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
_fini(void)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
_info(struct modinfo * modinfop)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 *);
419bf10ed2eSToomas Soome static int	ldtermrput(queue_t *, mblk_t *);
420bf10ed2eSToomas Soome static int	ldtermrsrv(queue_t *);
4217c478bd9Sstevel@tonic-gate static int	ldtermrmsg(queue_t *, mblk_t *);
422bf10ed2eSToomas Soome static int	ldtermwput(queue_t *, mblk_t *);
423bf10ed2eSToomas Soome static int	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 /*
52385bb5f1dSis  * The following tables are from either u8_textprep.c or uconv.c at
52485bb5f1dSis  * usr/src/common/unicode/. The tables are used to figure out corresponding
52585bb5f1dSis  * UTF-8 character byte lengths and also the validity of given character bytes.
5267c478bd9Sstevel@tonic-gate  */
52785bb5f1dSis extern const int8_t u8_number_of_bytes[];
52885bb5f1dSis extern const uchar_t u8_masks_tbl[];
52985bb5f1dSis extern const uint8_t u8_valid_min_2nd_byte[];
53085bb5f1dSis 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,
5702463e920SRichard Lowe 	_TTY_BUFSIZ,
5712463e920SRichard Lowe 	_TTY_BUFSIZ,
5727c478bd9Sstevel@tonic-gate 	LOWAT
5737c478bd9Sstevel@tonic-gate };
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 
5767c478bd9Sstevel@tonic-gate static struct qinit ldtermrinit = {
577bf10ed2eSToomas Soome 	ldtermrput,
578bf10ed2eSToomas Soome 	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 = {
597bf10ed2eSToomas Soome 	ldtermwput,
598bf10ed2eSToomas Soome 	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
dummy_callback(void * arg)6247c478bd9Sstevel@tonic-gate dummy_callback(void *arg)
6257c478bd9Sstevel@tonic-gate {}
6267c478bd9Sstevel@tonic-gate 
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate static mblk_t *
open_ioctl(queue_t * q,uint_t cmd)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 *
open_mblk(queue_t * q,size_t len)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
ldtermopen(queue_t * q,dev_t * devp,int oflag,int sflag,cred_t * crp)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),
68285bb5f1dSis 	    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_csmethods = cs_methods[LDTERM_CS_TYPE_EUC];
732f33b6662SToomas Soome 	tp->t_csdata = default_cs_data;
733f33b6662SToomas Soome 
734f33b6662SToomas Soome 	/*
735f33b6662SToomas Soome 	 * Try to switch to UTF-8 mode by allocating buffer for multibyte
736f33b6662SToomas Soome 	 * chars, keep EUC if allocation fails.
737f33b6662SToomas Soome 	 */
738f33b6662SToomas Soome 	if ((tp->t_eucp_mp = allocb(_TTY_BUFSIZ, BPRI_HI)) != NULL) {
739f33b6662SToomas Soome 		tp->t_eucp = tp->t_eucp_mp->b_rptr;
740f33b6662SToomas Soome 		tp->t_state = TS_MEUC;	/* Multibyte mode. */
741f33b6662SToomas Soome 		tp->t_maxeuc = 4; /* the max len in bytes of an UTF-8 char */
742f33b6662SToomas Soome 		tp->t_csdata.codeset_type = LDTERM_CS_TYPE_UTF8;
743f33b6662SToomas Soome 		tp->t_csdata.csinfo_num = 4;
744f33b6662SToomas Soome 		/* locale_name needs string length with terminating NUL */
745f33b6662SToomas Soome 		tp->t_csdata.locale_name = (char *)kmem_alloc(6, KM_SLEEP);
746f33b6662SToomas Soome 		(void) strcpy(tp->t_csdata.locale_name, "UTF-8");
747f33b6662SToomas Soome 		tp->t_csmethods = cs_methods[LDTERM_CS_TYPE_UTF8];
748f33b6662SToomas Soome 	}
749f33b6662SToomas Soome 	tp->t_eucwarn = 0;	/* no bad chars seen yet */
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate 	qprocson(q);
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate 	/*
7547c478bd9Sstevel@tonic-gate 	 * Find out if the module below us does canonicalization; if
7557c478bd9Sstevel@tonic-gate 	 * so, we won't do it ourselves.
7567c478bd9Sstevel@tonic-gate 	 */
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 	if ((qryp = open_ioctl(q, MC_CANONQUERY)) == NULL)
7597c478bd9Sstevel@tonic-gate 		goto open_abort;
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate 	/*
7627c478bd9Sstevel@tonic-gate 	 * Reformulate as an M_CTL message. The actual data will
7637c478bd9Sstevel@tonic-gate 	 * be in the b_cont field.
7647c478bd9Sstevel@tonic-gate 	 */
7657c478bd9Sstevel@tonic-gate 	qryp->b_datap->db_type = M_CTL;
7667c478bd9Sstevel@tonic-gate 	wq = OTHERQ(q);
7677c478bd9Sstevel@tonic-gate 	putnext(wq, qryp);
7687c478bd9Sstevel@tonic-gate 
7697c478bd9Sstevel@tonic-gate 	/* allocate a TCSBRK ioctl in case we'll need it on close */
7707c478bd9Sstevel@tonic-gate 	if ((qryp = open_ioctl(q, TCSBRK)) == NULL)
7717c478bd9Sstevel@tonic-gate 		goto open_abort;
7727c478bd9Sstevel@tonic-gate 	tp->t_drainmsg = qryp;
7737c478bd9Sstevel@tonic-gate 	if ((bp = open_mblk(q, sizeof (int))) == NULL)
7747c478bd9Sstevel@tonic-gate 		goto open_abort;
7757c478bd9Sstevel@tonic-gate 	qryp->b_cont = bp;
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate 	/*
7787c478bd9Sstevel@tonic-gate 	 * Find out if the underlying driver supports proper POSIX close
7797c478bd9Sstevel@tonic-gate 	 * semantics.  If not, we'll have to approximate it using TCSBRK.  If
7807c478bd9Sstevel@tonic-gate 	 * it does, it will respond with MC_HAS_POSIX, and we'll catch that in
7817c478bd9Sstevel@tonic-gate 	 * the ldtermrput routine.
7827c478bd9Sstevel@tonic-gate 	 *
7837c478bd9Sstevel@tonic-gate 	 * When the ldterm_drain_limit tunable is set to zero, we behave the
7847c478bd9Sstevel@tonic-gate 	 * same as old ldterm: don't send this new message, and always use
7857c478bd9Sstevel@tonic-gate 	 * TCSBRK during close.
7867c478bd9Sstevel@tonic-gate 	 */
7877c478bd9Sstevel@tonic-gate 	if (ldterm_drain_limit != 0) {
7887c478bd9Sstevel@tonic-gate 		if ((qryp = open_ioctl(q, MC_POSIXQUERY)) == NULL)
7897c478bd9Sstevel@tonic-gate 			goto open_abort;
7907c478bd9Sstevel@tonic-gate 		qryp->b_datap->db_type = M_CTL;
7917c478bd9Sstevel@tonic-gate 		putnext(wq, qryp);
7927c478bd9Sstevel@tonic-gate 	}
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 	/* prepare to clear the water marks on close */
7957c478bd9Sstevel@tonic-gate 	if ((bp = open_mblk(q, sizeof (struct stroptions))) == NULL)
7967c478bd9Sstevel@tonic-gate 		goto open_abort;
7977c478bd9Sstevel@tonic-gate 	tp->t_closeopts = bp;
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 	/*
8007c478bd9Sstevel@tonic-gate 	 * Set the high-water and low-water marks on the stream head
8017c478bd9Sstevel@tonic-gate 	 * to values appropriate for a terminal.  Also set the "vmin"
8027c478bd9Sstevel@tonic-gate 	 * and "vtime" values to 1 and 0, turn on message-nondiscard
8037c478bd9Sstevel@tonic-gate 	 * mode (as we're in ICANON mode), and turn on "old-style
8047c478bd9Sstevel@tonic-gate 	 * NODELAY" mode.
8057c478bd9Sstevel@tonic-gate 	 */
8067c478bd9Sstevel@tonic-gate 	if ((bp = open_mblk(q, sizeof (struct stroptions))) == NULL)
8077c478bd9Sstevel@tonic-gate 		goto open_abort;
8087c478bd9Sstevel@tonic-gate 	strop = (struct stroptions *)bp->b_wptr;
8097c478bd9Sstevel@tonic-gate 	strop->so_flags = SO_READOPT|SO_HIWAT|SO_LOWAT|SO_NDELON|SO_ISTTY;
8107c478bd9Sstevel@tonic-gate 	strop->so_readopt = RMSGN;
8112463e920SRichard Lowe 	strop->so_hiwat = _TTY_BUFSIZ;
8127c478bd9Sstevel@tonic-gate 	strop->so_lowat = LOWAT;
8137c478bd9Sstevel@tonic-gate 	bp->b_wptr += sizeof (struct stroptions);
8147c478bd9Sstevel@tonic-gate 	bp->b_datap->db_type = M_SETOPTS;
8157c478bd9Sstevel@tonic-gate 	putnext(q, bp);
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate 	return (0);		/* this can become a controlling TTY */
8187c478bd9Sstevel@tonic-gate 
8197c478bd9Sstevel@tonic-gate open_abort:
8207c478bd9Sstevel@tonic-gate 	qprocsoff(q);
8217c478bd9Sstevel@tonic-gate 	q->q_ptr = NULL;
8227c478bd9Sstevel@tonic-gate 	WR(q)->q_ptr = NULL;
8237c478bd9Sstevel@tonic-gate 	freemsg(tp->t_closeopts);
8247c478bd9Sstevel@tonic-gate 	freemsg(tp->t_drainmsg);
8257c478bd9Sstevel@tonic-gate 	/* Dump the state structure */
8267c478bd9Sstevel@tonic-gate 	kmem_free(tp, sizeof (ldtermstd_state_t));
8277c478bd9Sstevel@tonic-gate 	return (EINTR);
8287c478bd9Sstevel@tonic-gate }
8297c478bd9Sstevel@tonic-gate 
8307c478bd9Sstevel@tonic-gate struct close_timer {
8317c478bd9Sstevel@tonic-gate 	timeout_id_t id;
8327c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp;
8337c478bd9Sstevel@tonic-gate };
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate static void
drain_timed_out(void * arg)8367c478bd9Sstevel@tonic-gate drain_timed_out(void *arg)
8377c478bd9Sstevel@tonic-gate {
8387c478bd9Sstevel@tonic-gate 	struct close_timer *ctp = arg;
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate 	ctp->id = 0;
8417c478bd9Sstevel@tonic-gate 	ctp->tp->t_state &= ~TS_IOCWAIT;
8427c478bd9Sstevel@tonic-gate }
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate /* ARGSUSED2 */
8457c478bd9Sstevel@tonic-gate static int
ldtermclose(queue_t * q,int cflag,cred_t * crp)8467c478bd9Sstevel@tonic-gate ldtermclose(queue_t *q, int cflag, cred_t *crp)
8477c478bd9Sstevel@tonic-gate {
8487c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp = (ldtermstd_state_t *)q->q_ptr;
8497c478bd9Sstevel@tonic-gate 	struct stroptions *strop;
8507c478bd9Sstevel@tonic-gate 	mblk_t *bp;
8517c478bd9Sstevel@tonic-gate 	struct close_timer cltimer;
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate 	/*
8547c478bd9Sstevel@tonic-gate 	 * If we have an outstanding vmin timeout, cancel it.
8557c478bd9Sstevel@tonic-gate 	 */
8567c478bd9Sstevel@tonic-gate 	tp->t_state |= TS_CLOSE;
8577c478bd9Sstevel@tonic-gate 	if (tp->t_vtid != 0)
8587c478bd9Sstevel@tonic-gate 		(void) quntimeout(q, tp->t_vtid);
8597c478bd9Sstevel@tonic-gate 	tp->t_vtid = 0;
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 	/*
8627c478bd9Sstevel@tonic-gate 	 * Cancel outstanding qbufcall request.
8637c478bd9Sstevel@tonic-gate 	 */
8647c478bd9Sstevel@tonic-gate 	if (tp->t_wbufcid != 0)
8657c478bd9Sstevel@tonic-gate 		qunbufcall(q, tp->t_wbufcid);
8667c478bd9Sstevel@tonic-gate 
8677c478bd9Sstevel@tonic-gate 	/*
8687c478bd9Sstevel@tonic-gate 	 * Reset the high-water and low-water marks on the stream
8697c478bd9Sstevel@tonic-gate 	 * head (?), turn on byte-stream mode, and turn off
8707c478bd9Sstevel@tonic-gate 	 * "old-style NODELAY" mode.
8717c478bd9Sstevel@tonic-gate 	 */
8727c478bd9Sstevel@tonic-gate 	bp = tp->t_closeopts;
8737c478bd9Sstevel@tonic-gate 	strop = (struct stroptions *)bp->b_wptr;
8747c478bd9Sstevel@tonic-gate 	strop->so_flags = SO_READOPT|SO_NDELOFF;
8757c478bd9Sstevel@tonic-gate 	strop->so_readopt = RNORM;
8767c478bd9Sstevel@tonic-gate 	bp->b_wptr += sizeof (struct stroptions);
8777c478bd9Sstevel@tonic-gate 	bp->b_datap->db_type = M_SETOPTS;
8787c478bd9Sstevel@tonic-gate 	putnext(q, bp);
8797c478bd9Sstevel@tonic-gate 
8807c478bd9Sstevel@tonic-gate 	if (cflag & (FNDELAY|FNONBLOCK)) {
8817c478bd9Sstevel@tonic-gate 		freemsg(tp->t_drainmsg);
8827c478bd9Sstevel@tonic-gate 	} else if ((bp = tp->t_drainmsg) != NULL) {
8837c478bd9Sstevel@tonic-gate 		struct iocblk *iocb;
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate 		/*
8867c478bd9Sstevel@tonic-gate 		 * If the driver isn't known to have POSIX close semantics,
8877c478bd9Sstevel@tonic-gate 		 * then we have to emulate this the old way.  This is done by
8887c478bd9Sstevel@tonic-gate 		 * sending down TCSBRK,1 to drain the output and waiting for
8897c478bd9Sstevel@tonic-gate 		 * the reply.
8907c478bd9Sstevel@tonic-gate 		 */
8917c478bd9Sstevel@tonic-gate 		iocb = (struct iocblk *)bp->b_rptr;
8927c478bd9Sstevel@tonic-gate 		iocb->ioc_count = sizeof (int);
8937c478bd9Sstevel@tonic-gate 		*(int *)bp->b_cont->b_rptr = 1;
8947c478bd9Sstevel@tonic-gate 		bp->b_cont->b_wptr += sizeof (int);
8957c478bd9Sstevel@tonic-gate 		tp->t_state |= TS_IOCWAIT;
8967c478bd9Sstevel@tonic-gate 		tp->t_iocid = iocb->ioc_id;
8977c478bd9Sstevel@tonic-gate 		if (!putq(WR(q), bp))
8987c478bd9Sstevel@tonic-gate 			putnext(WR(q), bp);
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 		/*
9017c478bd9Sstevel@tonic-gate 		 * If we're not able to receive signals at this point, then
9027c478bd9Sstevel@tonic-gate 		 * launch a timer.  This timer will prevent us from waiting
9037c478bd9Sstevel@tonic-gate 		 * forever for a signal that won't arrive.
9047c478bd9Sstevel@tonic-gate 		 */
9057c478bd9Sstevel@tonic-gate 		cltimer.id = 0;
9067c478bd9Sstevel@tonic-gate 		if (!ddi_can_receive_sig() && ldterm_drain_limit != 0) {
9077c478bd9Sstevel@tonic-gate 			cltimer.tp = tp;
9087c478bd9Sstevel@tonic-gate 			cltimer.id = qtimeout(q, drain_timed_out, &cltimer,
9097c478bd9Sstevel@tonic-gate 			    drv_usectohz(ldterm_drain_limit));
9107c478bd9Sstevel@tonic-gate 		}
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate 		/*
9137c478bd9Sstevel@tonic-gate 		 * Note that the read side of ldterm and the qtimeout are
9147c478bd9Sstevel@tonic-gate 		 * protected by D_MTQPAIR, so no additional locking is needed
9157c478bd9Sstevel@tonic-gate 		 * here.
9167c478bd9Sstevel@tonic-gate 		 */
9177c478bd9Sstevel@tonic-gate 		while (tp->t_state & TS_IOCWAIT) {
9187c478bd9Sstevel@tonic-gate 			if (qwait_sig(q) == 0)
9197c478bd9Sstevel@tonic-gate 				break;
9207c478bd9Sstevel@tonic-gate 		}
9217c478bd9Sstevel@tonic-gate 		if (cltimer.id != 0)
9227c478bd9Sstevel@tonic-gate 			(void) quntimeout(q, cltimer.id);
9237c478bd9Sstevel@tonic-gate 	}
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate 	/*
9267c478bd9Sstevel@tonic-gate 	 * From here to the end, the routine does not sleep and does not
9277c478bd9Sstevel@tonic-gate 	 * reference STREAMS, so it's guaranteed to run to completion.
9287c478bd9Sstevel@tonic-gate 	 */
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate 	qprocsoff(q);
9317c478bd9Sstevel@tonic-gate 
9327c478bd9Sstevel@tonic-gate 	freemsg(tp->t_message);
9337c478bd9Sstevel@tonic-gate 	freemsg(tp->t_eucp_mp);
9347c478bd9Sstevel@tonic-gate 
9357c478bd9Sstevel@tonic-gate 	/* Dump the state structure, then unlink it */
9367c478bd9Sstevel@tonic-gate 	if (tp->t_csdata.locale_name != NULL)
9377c478bd9Sstevel@tonic-gate 		kmem_free(tp->t_csdata.locale_name,
9387c478bd9Sstevel@tonic-gate 		    strlen(tp->t_csdata.locale_name) + 1);
9397c478bd9Sstevel@tonic-gate 	kmem_free(tp, sizeof (ldtermstd_state_t));
9407c478bd9Sstevel@tonic-gate 	q->q_ptr = NULL;
9417c478bd9Sstevel@tonic-gate 	return (0);
9427c478bd9Sstevel@tonic-gate }
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate 
9457c478bd9Sstevel@tonic-gate /*
9467c478bd9Sstevel@tonic-gate  * Put procedure for input from driver end of stream (read queue).
9477c478bd9Sstevel@tonic-gate  */
948bf10ed2eSToomas Soome static int
ldtermrput(queue_t * q,mblk_t * mp)9497c478bd9Sstevel@tonic-gate ldtermrput(queue_t *q, mblk_t *mp)
9507c478bd9Sstevel@tonic-gate {
9517c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp;
9527c478bd9Sstevel@tonic-gate 	unsigned char c;
9537c478bd9Sstevel@tonic-gate 	queue_t *wrq = WR(q);		/* write queue of ldterm mod */
9547c478bd9Sstevel@tonic-gate 	queue_t *nextq = q->q_next;	/* queue below us */
9557c478bd9Sstevel@tonic-gate 	mblk_t *bp;
9567c478bd9Sstevel@tonic-gate 	struct iocblk *qryp;
9577c478bd9Sstevel@tonic-gate 	unsigned char *readp;
9587c478bd9Sstevel@tonic-gate 	unsigned char *writep;
9597c478bd9Sstevel@tonic-gate 	struct termios *emodes;		/* effective modes set by driver */
9607c478bd9Sstevel@tonic-gate 	int dbtype;
9617c478bd9Sstevel@tonic-gate 
9627c478bd9Sstevel@tonic-gate 	tp = (ldtermstd_state_t *)q->q_ptr;
9637c478bd9Sstevel@tonic-gate 	/*
9647c478bd9Sstevel@tonic-gate 	 * We received our ack from the driver saying there is nothing left to
9657c478bd9Sstevel@tonic-gate 	 * shovel out, so wake up the close routine.
9667c478bd9Sstevel@tonic-gate 	 */
9677c478bd9Sstevel@tonic-gate 	dbtype = DB_TYPE(mp);
9687c478bd9Sstevel@tonic-gate 	if ((dbtype == M_IOCACK || dbtype == M_IOCNAK) &&
9697c478bd9Sstevel@tonic-gate 	    (tp->t_state & (TS_CLOSE|TS_IOCWAIT)) == (TS_CLOSE|TS_IOCWAIT)) {
9707c478bd9Sstevel@tonic-gate 		struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
9717c478bd9Sstevel@tonic-gate 
9727c478bd9Sstevel@tonic-gate 		if (iocp->ioc_id == tp->t_iocid) {
9737c478bd9Sstevel@tonic-gate 			tp->t_state &= ~TS_IOCWAIT;
9747c478bd9Sstevel@tonic-gate 			freemsg(mp);
975bf10ed2eSToomas Soome 			return (0);
9767c478bd9Sstevel@tonic-gate 		}
9777c478bd9Sstevel@tonic-gate 	}
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate 	switch (dbtype) {
9807c478bd9Sstevel@tonic-gate 
9817c478bd9Sstevel@tonic-gate 	default:
9827c478bd9Sstevel@tonic-gate 		(void) putq(q, mp);
983bf10ed2eSToomas Soome 		return (0);
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate 		/*
9867c478bd9Sstevel@tonic-gate 		 * Send these up unmolested
9877c478bd9Sstevel@tonic-gate 		 *
9887c478bd9Sstevel@tonic-gate 		 */
9897c478bd9Sstevel@tonic-gate 	case M_PCSIG:
9907c478bd9Sstevel@tonic-gate 	case M_SIG:
9917c478bd9Sstevel@tonic-gate 	case M_IOCNAK:
9927c478bd9Sstevel@tonic-gate 
9937c478bd9Sstevel@tonic-gate 		putnext(q, mp);
994bf10ed2eSToomas Soome 		return (0);
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate 	case M_IOCACK:
9977c478bd9Sstevel@tonic-gate 
9987c478bd9Sstevel@tonic-gate 		ldterm_ioctl_reply(q, mp);
999bf10ed2eSToomas Soome 		return (0);
10007c478bd9Sstevel@tonic-gate 
10017c478bd9Sstevel@tonic-gate 	case M_BREAK:
10027c478bd9Sstevel@tonic-gate 
10037c478bd9Sstevel@tonic-gate 		/*
10047c478bd9Sstevel@tonic-gate 		 * Parity errors are sent up as M_BREAKS with single
10057c478bd9Sstevel@tonic-gate 		 * character data (formerly handled in the driver)
10067c478bd9Sstevel@tonic-gate 		 */
10077c478bd9Sstevel@tonic-gate 		if (mp->b_wptr - mp->b_rptr == 1) {
10087c478bd9Sstevel@tonic-gate 			/*
10097c478bd9Sstevel@tonic-gate 			 * IGNPAR	PARMRK		RESULT
10107c478bd9Sstevel@tonic-gate 			 * off		off		0
10117c478bd9Sstevel@tonic-gate 			 * off		on		3 byte sequence
10127c478bd9Sstevel@tonic-gate 			 * on		either		ignored
10137c478bd9Sstevel@tonic-gate 			 */
10147c478bd9Sstevel@tonic-gate 			if (!(tp->t_amodes.c_iflag & IGNPAR)) {
10157c478bd9Sstevel@tonic-gate 				mp->b_wptr = mp->b_rptr;
10167c478bd9Sstevel@tonic-gate 				if (tp->t_amodes.c_iflag & PARMRK) {
10177c478bd9Sstevel@tonic-gate 					unsigned char c;
10187c478bd9Sstevel@tonic-gate 
10197c478bd9Sstevel@tonic-gate 					c = *mp->b_rptr;
10207c478bd9Sstevel@tonic-gate 					freemsg(mp);
10217c478bd9Sstevel@tonic-gate 					if ((mp = allocb(3, BPRI_HI)) == NULL) {
10227c478bd9Sstevel@tonic-gate 						cmn_err(CE_WARN,
10237c478bd9Sstevel@tonic-gate 						    "ldtermrput: no blocks");
1024bf10ed2eSToomas Soome 						return (0);
10257c478bd9Sstevel@tonic-gate 					}
10267c478bd9Sstevel@tonic-gate 					mp->b_datap->db_type = M_DATA;
10277c478bd9Sstevel@tonic-gate 					*mp->b_wptr++ = (uchar_t)'\377';
10287c478bd9Sstevel@tonic-gate 					*mp->b_wptr++ = '\0';
10297c478bd9Sstevel@tonic-gate 					*mp->b_wptr++ = c;
10307c478bd9Sstevel@tonic-gate 					putnext(q, mp);
10317c478bd9Sstevel@tonic-gate 				} else {
10327c478bd9Sstevel@tonic-gate 					mp->b_datap->db_type = M_DATA;
10337c478bd9Sstevel@tonic-gate 					*mp->b_wptr++ = '\0';
10347c478bd9Sstevel@tonic-gate 					putnext(q, mp);
10357c478bd9Sstevel@tonic-gate 				}
10367c478bd9Sstevel@tonic-gate 			} else {
10377c478bd9Sstevel@tonic-gate 				freemsg(mp);
10387c478bd9Sstevel@tonic-gate 			}
1039bf10ed2eSToomas Soome 			return (0);
10407c478bd9Sstevel@tonic-gate 		}
10417c478bd9Sstevel@tonic-gate 		/*
10427c478bd9Sstevel@tonic-gate 		 * We look at the apparent modes here instead of the
10437c478bd9Sstevel@tonic-gate 		 * effective modes. Effective modes cannot be used if
10447c478bd9Sstevel@tonic-gate 		 * IGNBRK, BRINT and PARMRK have been negotiated to
10457c478bd9Sstevel@tonic-gate 		 * be handled by the driver. Since M_BREAK should be
10467c478bd9Sstevel@tonic-gate 		 * sent upstream only if break processing was not
10477c478bd9Sstevel@tonic-gate 		 * already done, it should be ok to use the apparent
10487c478bd9Sstevel@tonic-gate 		 * modes.
10497c478bd9Sstevel@tonic-gate 		 */
10507c478bd9Sstevel@tonic-gate 
10517c478bd9Sstevel@tonic-gate 		if (!(tp->t_amodes.c_iflag & IGNBRK)) {
10527c478bd9Sstevel@tonic-gate 			if (tp->t_amodes.c_iflag & BRKINT) {
10537c478bd9Sstevel@tonic-gate 				ldterm_dosig(q, SIGINT, '\0', M_PCSIG, FLUSHRW);
10547c478bd9Sstevel@tonic-gate 				freemsg(mp);
10557c478bd9Sstevel@tonic-gate 			} else if (tp->t_amodes.c_iflag & PARMRK) {
10567c478bd9Sstevel@tonic-gate 				/*
10577c478bd9Sstevel@tonic-gate 				 * Send '\377','\0', '\0'.
10587c478bd9Sstevel@tonic-gate 				 */
10597c478bd9Sstevel@tonic-gate 				freemsg(mp);
10607c478bd9Sstevel@tonic-gate 				if ((mp = allocb(3, BPRI_HI)) == NULL) {
10617c478bd9Sstevel@tonic-gate 					cmn_err(CE_WARN,
106285bb5f1dSis 					    "ldtermrput: no blocks");
1063bf10ed2eSToomas Soome 					return (0);
10647c478bd9Sstevel@tonic-gate 				}
10657c478bd9Sstevel@tonic-gate 				mp->b_datap->db_type = M_DATA;
10667c478bd9Sstevel@tonic-gate 				*mp->b_wptr++ = (uchar_t)'\377';
10677c478bd9Sstevel@tonic-gate 				*mp->b_wptr++ = '\0';
10687c478bd9Sstevel@tonic-gate 				*mp->b_wptr++ = '\0';
10697c478bd9Sstevel@tonic-gate 				putnext(q, mp);
10707c478bd9Sstevel@tonic-gate 			} else {
10717c478bd9Sstevel@tonic-gate 				/*
10727c478bd9Sstevel@tonic-gate 				 * Act as if a '\0' came in.
10737c478bd9Sstevel@tonic-gate 				 */
10747c478bd9Sstevel@tonic-gate 				freemsg(mp);
10757c478bd9Sstevel@tonic-gate 				if ((mp = allocb(1, BPRI_HI)) == NULL) {
10767c478bd9Sstevel@tonic-gate 					cmn_err(CE_WARN,
107785bb5f1dSis 					    "ldtermrput: no blocks");
1078bf10ed2eSToomas Soome 					return (0);
10797c478bd9Sstevel@tonic-gate 				}
10807c478bd9Sstevel@tonic-gate 				mp->b_datap->db_type = M_DATA;
10817c478bd9Sstevel@tonic-gate 				*mp->b_wptr++ = '\0';
10827c478bd9Sstevel@tonic-gate 				putnext(q, mp);
10837c478bd9Sstevel@tonic-gate 			}
10847c478bd9Sstevel@tonic-gate 		} else {
10857c478bd9Sstevel@tonic-gate 			freemsg(mp);
10867c478bd9Sstevel@tonic-gate 		}
1087bf10ed2eSToomas Soome 		return (0);
10887c478bd9Sstevel@tonic-gate 
10897c478bd9Sstevel@tonic-gate 	case M_CTL:
10907c478bd9Sstevel@tonic-gate 		DEBUG3(("ldtermrput: M_CTL received\n"));
10917c478bd9Sstevel@tonic-gate 		/*
10927c478bd9Sstevel@tonic-gate 		 * The M_CTL has been standardized to look like an
10937c478bd9Sstevel@tonic-gate 		 * M_IOCTL message.
10947c478bd9Sstevel@tonic-gate 		 */
10957c478bd9Sstevel@tonic-gate 
10967c478bd9Sstevel@tonic-gate 		if ((mp->b_wptr - mp->b_rptr) != sizeof (struct iocblk)) {
10977c478bd9Sstevel@tonic-gate 			DEBUG3((
10987c478bd9Sstevel@tonic-gate 			    "Non standard M_CTL received by ldterm module\n"));
10997c478bd9Sstevel@tonic-gate 			/* May be for someone else; pass it on */
11007c478bd9Sstevel@tonic-gate 			putnext(q, mp);
1101bf10ed2eSToomas Soome 			return (0);
11027c478bd9Sstevel@tonic-gate 		}
11037c478bd9Sstevel@tonic-gate 		qryp = (struct iocblk *)mp->b_rptr;
11047c478bd9Sstevel@tonic-gate 
11057c478bd9Sstevel@tonic-gate 		switch (qryp->ioc_cmd) {
11067c478bd9Sstevel@tonic-gate 
11077c478bd9Sstevel@tonic-gate 		case MC_PART_CANON:
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate 			DEBUG3(("ldtermrput: M_CTL Query Reply\n"));
11107c478bd9Sstevel@tonic-gate 			if (!mp->b_cont) {
11117c478bd9Sstevel@tonic-gate 				DEBUG3(("No information in Query Message\n"));
11127c478bd9Sstevel@tonic-gate 				break;
11137c478bd9Sstevel@tonic-gate 			}
11147c478bd9Sstevel@tonic-gate 			if ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) ==
11157c478bd9Sstevel@tonic-gate 			    sizeof (struct termios)) {
11167c478bd9Sstevel@tonic-gate 				DEBUG3(("ldtermrput: M_CTL GrandScheme\n"));
11177c478bd9Sstevel@tonic-gate 				/* elaborate turning off scheme */
11187c478bd9Sstevel@tonic-gate 				emodes = (struct termios *)mp->b_cont->b_rptr;
11197c478bd9Sstevel@tonic-gate 				bcopy(emodes, &tp->t_dmodes,
11207c478bd9Sstevel@tonic-gate 					sizeof (struct termios));
11217c478bd9Sstevel@tonic-gate 				ldterm_adjust_modes(tp);
11227c478bd9Sstevel@tonic-gate 				break;
11237c478bd9Sstevel@tonic-gate 			} else {
11247c478bd9Sstevel@tonic-gate 				DEBUG3(("Incorrect query replysize\n"));
11257c478bd9Sstevel@tonic-gate 				break;
11267c478bd9Sstevel@tonic-gate 			}
11277c478bd9Sstevel@tonic-gate 
11287c478bd9Sstevel@tonic-gate 		case MC_NO_CANON:
11297c478bd9Sstevel@tonic-gate 			tp->t_state |= TS_NOCANON;
11307c478bd9Sstevel@tonic-gate 			/*
11317c478bd9Sstevel@tonic-gate 			 * Note: this is very nasty.  It's not clear
11327c478bd9Sstevel@tonic-gate 			 * what the right thing to do with a partial
11337c478bd9Sstevel@tonic-gate 			 * message is; We throw it out
11347c478bd9Sstevel@tonic-gate 			 */
11357c478bd9Sstevel@tonic-gate 			if (tp->t_message != NULL) {
11367c478bd9Sstevel@tonic-gate 				freemsg(tp->t_message);
11377c478bd9Sstevel@tonic-gate 				tp->t_message = NULL;
11387c478bd9Sstevel@tonic-gate 				tp->t_endmsg = NULL;
11397c478bd9Sstevel@tonic-gate 				tp->t_msglen = 0;
11407c478bd9Sstevel@tonic-gate 				tp->t_rocount = 0;
11417c478bd9Sstevel@tonic-gate 				tp->t_rocol = 0;
11427c478bd9Sstevel@tonic-gate 				if (tp->t_state & TS_MEUC) {
11437c478bd9Sstevel@tonic-gate 					ASSERT(tp->t_eucp_mp);
11447c478bd9Sstevel@tonic-gate 					tp->t_eucp = tp->t_eucp_mp->b_rptr;
11457c478bd9Sstevel@tonic-gate 					tp->t_codeset = 0;
11467c478bd9Sstevel@tonic-gate 					tp->t_eucleft = 0;
11477c478bd9Sstevel@tonic-gate 				}
11487c478bd9Sstevel@tonic-gate 			}
11497c478bd9Sstevel@tonic-gate 			break;
11507c478bd9Sstevel@tonic-gate 
11517c478bd9Sstevel@tonic-gate 		case MC_DO_CANON:
11527c478bd9Sstevel@tonic-gate 			tp->t_state &= ~TS_NOCANON;
11537c478bd9Sstevel@tonic-gate 			break;
11547c478bd9Sstevel@tonic-gate 
11557c478bd9Sstevel@tonic-gate 		case MC_HAS_POSIX:
11567c478bd9Sstevel@tonic-gate 			/* no longer any reason to drain from ldterm */
11577c478bd9Sstevel@tonic-gate 			if (ldterm_drain_limit != 0) {
11587c478bd9Sstevel@tonic-gate 				freemsg(tp->t_drainmsg);
11597c478bd9Sstevel@tonic-gate 				tp->t_drainmsg = NULL;
11607c478bd9Sstevel@tonic-gate 			}
11617c478bd9Sstevel@tonic-gate 			break;
11627c478bd9Sstevel@tonic-gate 
11637c478bd9Sstevel@tonic-gate 		default:
11647c478bd9Sstevel@tonic-gate 			DEBUG3(("Unknown M_CTL Message\n"));
11657c478bd9Sstevel@tonic-gate 			break;
11667c478bd9Sstevel@tonic-gate 		}
11677c478bd9Sstevel@tonic-gate 		putnext(q, mp);	/* In case anyone else has to see it */
1168bf10ed2eSToomas Soome 		return (0);
11697c478bd9Sstevel@tonic-gate 
11707c478bd9Sstevel@tonic-gate 	case M_FLUSH:
11717c478bd9Sstevel@tonic-gate 		/*
11727c478bd9Sstevel@tonic-gate 		 * Flush everything we haven't looked at yet.
11737c478bd9Sstevel@tonic-gate 		 */
11747c478bd9Sstevel@tonic-gate 
11757c478bd9Sstevel@tonic-gate 		if ((tp->t_state & TS_ISPTSTTY) && (*mp->b_rptr & FLUSHBAND))
11767c478bd9Sstevel@tonic-gate 			flushband(q, *(mp->b_rptr + 1), FLUSHDATA);
11777c478bd9Sstevel@tonic-gate 		else
11787c478bd9Sstevel@tonic-gate 			flushq(q, FLUSHDATA);
11797c478bd9Sstevel@tonic-gate 
11807c478bd9Sstevel@tonic-gate 		/*
11817c478bd9Sstevel@tonic-gate 		 * Flush everything we have looked at.
11827c478bd9Sstevel@tonic-gate 		 */
11837c478bd9Sstevel@tonic-gate 		freemsg(tp->t_message);
11847c478bd9Sstevel@tonic-gate 		tp->t_message = NULL;
11857c478bd9Sstevel@tonic-gate 		tp->t_endmsg = NULL;
11867c478bd9Sstevel@tonic-gate 		tp->t_msglen = 0;
11877c478bd9Sstevel@tonic-gate 		tp->t_rocount = 0;
11887c478bd9Sstevel@tonic-gate 		tp->t_rocol = 0;
11897c478bd9Sstevel@tonic-gate 		if (tp->t_state & TS_MEUC) {	/* EUC multi-byte */
11907c478bd9Sstevel@tonic-gate 			ASSERT(tp->t_eucp_mp);
11917c478bd9Sstevel@tonic-gate 			tp->t_eucp = tp->t_eucp_mp->b_rptr;
11927c478bd9Sstevel@tonic-gate 		}
11937c478bd9Sstevel@tonic-gate 		putnext(q, mp);	/* pass it on */
11947c478bd9Sstevel@tonic-gate 
11957c478bd9Sstevel@tonic-gate 		/*
11967c478bd9Sstevel@tonic-gate 		 * Relieve input flow control
11977c478bd9Sstevel@tonic-gate 		 */
11987c478bd9Sstevel@tonic-gate 		if ((tp->t_modes.c_iflag & IXOFF) &&
11997c478bd9Sstevel@tonic-gate 		    (tp->t_state & TS_TBLOCK) &&
12007c478bd9Sstevel@tonic-gate 		    !(tp->t_state & TS_IFBLOCK) && q->q_count <= TTXOLO) {
12017c478bd9Sstevel@tonic-gate 			tp->t_state &= ~TS_TBLOCK;
12027c478bd9Sstevel@tonic-gate 			(void) putnextctl(wrq, M_STARTI);
12037c478bd9Sstevel@tonic-gate 			DEBUG1(("M_STARTI down\n"));
12047c478bd9Sstevel@tonic-gate 		}
1205bf10ed2eSToomas Soome 		return (0);
12067c478bd9Sstevel@tonic-gate 
12077c478bd9Sstevel@tonic-gate 	case M_DATA:
12087c478bd9Sstevel@tonic-gate 		break;
12097c478bd9Sstevel@tonic-gate 	}
12107c478bd9Sstevel@tonic-gate 	(void) drv_setparm(SYSRAWC, msgdsize(mp));
12117c478bd9Sstevel@tonic-gate 
12127c478bd9Sstevel@tonic-gate 	/*
12137c478bd9Sstevel@tonic-gate 	 * Flow control: send "start input" message if blocked and
12147c478bd9Sstevel@tonic-gate 	 * our queue is below its low water mark.
12157c478bd9Sstevel@tonic-gate 	 */
12167c478bd9Sstevel@tonic-gate 	if ((tp->t_modes.c_iflag & IXOFF) && (tp->t_state & TS_TBLOCK) &&
12177c478bd9Sstevel@tonic-gate 	    !(tp->t_state & TS_IFBLOCK) && q->q_count <= TTXOLO) {
12187c478bd9Sstevel@tonic-gate 		tp->t_state &= ~TS_TBLOCK;
12197c478bd9Sstevel@tonic-gate 		(void) putnextctl(wrq, M_STARTI);
12207c478bd9Sstevel@tonic-gate 		DEBUG1(("M_STARTI down\n"));
12217c478bd9Sstevel@tonic-gate 	}
12227c478bd9Sstevel@tonic-gate 	/*
12237c478bd9Sstevel@tonic-gate 	 * If somebody below us ("intelligent" communications
12247c478bd9Sstevel@tonic-gate 	 * board, pseudo-tty controlled by an editor) is doing
12257c478bd9Sstevel@tonic-gate 	 * canonicalization, don't scan it for special characters.
12267c478bd9Sstevel@tonic-gate 	 */
12277c478bd9Sstevel@tonic-gate 	if (tp->t_state & TS_NOCANON) {
12287c478bd9Sstevel@tonic-gate 		(void) putq(q, mp);
1229bf10ed2eSToomas Soome 		return (0);
12307c478bd9Sstevel@tonic-gate 	}
12317c478bd9Sstevel@tonic-gate 	bp = mp;
12327c478bd9Sstevel@tonic-gate 
12337c478bd9Sstevel@tonic-gate 	do {
12347c478bd9Sstevel@tonic-gate 		readp = bp->b_rptr;
12357c478bd9Sstevel@tonic-gate 		writep = readp;
12367c478bd9Sstevel@tonic-gate 		if (tp->t_modes.c_iflag & (INLCR|IGNCR|ICRNL|IUCLC|IXON) ||
12377c478bd9Sstevel@tonic-gate 		    tp->t_modes.c_lflag & (ISIG|ICANON)) {
12387c478bd9Sstevel@tonic-gate 			/*
12397c478bd9Sstevel@tonic-gate 			 * We're doing some sort of non-trivial
12407c478bd9Sstevel@tonic-gate 			 * processing of input; look at every
12417c478bd9Sstevel@tonic-gate 			 * character.
12427c478bd9Sstevel@tonic-gate 			 */
12437c478bd9Sstevel@tonic-gate 			while (readp < bp->b_wptr) {
12447c478bd9Sstevel@tonic-gate 				c = *readp++;
12457c478bd9Sstevel@tonic-gate 
12467c478bd9Sstevel@tonic-gate 				if (tp->t_modes.c_iflag & ISTRIP)
12477c478bd9Sstevel@tonic-gate 					c &= 0177;
12487c478bd9Sstevel@tonic-gate 
12497c478bd9Sstevel@tonic-gate 				/*
12507c478bd9Sstevel@tonic-gate 				 * First, check that this hasn't been
12517c478bd9Sstevel@tonic-gate 				 * escaped with the "literal next"
12527c478bd9Sstevel@tonic-gate 				 * character.
12537c478bd9Sstevel@tonic-gate 				 */
12547c478bd9Sstevel@tonic-gate 				if (tp->t_state & TS_PLNCH) {
12557c478bd9Sstevel@tonic-gate 					tp->t_state &= ~TS_PLNCH;
12567c478bd9Sstevel@tonic-gate 					tp->t_modes.c_lflag &= ~FLUSHO;
12577c478bd9Sstevel@tonic-gate 					*writep++ = c;
12587c478bd9Sstevel@tonic-gate 					continue;
12597c478bd9Sstevel@tonic-gate 				}
12607c478bd9Sstevel@tonic-gate 				/*
12617c478bd9Sstevel@tonic-gate 				 * Setting a special character to NUL
12627c478bd9Sstevel@tonic-gate 				 * disables it, so if this character
12637c478bd9Sstevel@tonic-gate 				 * is NUL, it should not be compared
12647c478bd9Sstevel@tonic-gate 				 * with any of the special characters.
12657c478bd9Sstevel@tonic-gate 				 * It should, however, restart frozen
12667c478bd9Sstevel@tonic-gate 				 * output if IXON and IXANY are set.
12677c478bd9Sstevel@tonic-gate 				 */
12687c478bd9Sstevel@tonic-gate 				if (c == _POSIX_VDISABLE) {
12697c478bd9Sstevel@tonic-gate 					if (tp->t_modes.c_iflag & IXON &&
12707c478bd9Sstevel@tonic-gate 					    tp->t_state & TS_TTSTOP &&
12717c478bd9Sstevel@tonic-gate 					    tp->t_modes.c_lflag & IEXTEN &&
12727c478bd9Sstevel@tonic-gate 					    tp->t_modes.c_iflag & IXANY) {
12737c478bd9Sstevel@tonic-gate 						tp->t_state &=
12747c478bd9Sstevel@tonic-gate 						    ~(TS_TTSTOP|TS_OFBLOCK);
12757c478bd9Sstevel@tonic-gate 						(void) putnextctl(wrq, M_START);
12767c478bd9Sstevel@tonic-gate 					}
12777c478bd9Sstevel@tonic-gate 					tp->t_modes.c_lflag &= ~FLUSHO;
12787c478bd9Sstevel@tonic-gate 					*writep++ = c;
12797c478bd9Sstevel@tonic-gate 					continue;
12807c478bd9Sstevel@tonic-gate 				}
12817c478bd9Sstevel@tonic-gate 				/*
12827c478bd9Sstevel@tonic-gate 				 * If stopped, start if you can; if
12837c478bd9Sstevel@tonic-gate 				 * running, stop if you must.
12847c478bd9Sstevel@tonic-gate 				 */
12857c478bd9Sstevel@tonic-gate 				if (tp->t_modes.c_iflag & IXON) {
12867c478bd9Sstevel@tonic-gate 					if (tp->t_state & TS_TTSTOP) {
12877c478bd9Sstevel@tonic-gate 						if (c ==
12887c478bd9Sstevel@tonic-gate 						    tp->t_modes.c_cc[VSTART] ||
12897c478bd9Sstevel@tonic-gate 						    (tp->t_modes.c_lflag &
12907c478bd9Sstevel@tonic-gate 						    IEXTEN &&
12917c478bd9Sstevel@tonic-gate 						    tp->t_modes.c_iflag &
12927c478bd9Sstevel@tonic-gate 						    IXANY)) {
12937c478bd9Sstevel@tonic-gate 							tp->t_state &=
129485bb5f1dSis 							    ~(TS_TTSTOP |
129585bb5f1dSis 							    TS_OFBLOCK);
12967c478bd9Sstevel@tonic-gate 							(void) putnextctl(wrq,
12977c478bd9Sstevel@tonic-gate 							    M_START);
12987c478bd9Sstevel@tonic-gate 						}
12997c478bd9Sstevel@tonic-gate 					} else {
13007c478bd9Sstevel@tonic-gate 						if (c ==
13017c478bd9Sstevel@tonic-gate 						    tp->t_modes.c_cc[VSTOP]) {
13027c478bd9Sstevel@tonic-gate 							tp->t_state |=
13037c478bd9Sstevel@tonic-gate 							    TS_TTSTOP;
13047c478bd9Sstevel@tonic-gate 							(void) putnextctl(wrq,
13057c478bd9Sstevel@tonic-gate 							    M_STOP);
13067c478bd9Sstevel@tonic-gate 						}
13077c478bd9Sstevel@tonic-gate 					}
13087c478bd9Sstevel@tonic-gate 					if (c == tp->t_modes.c_cc[VSTOP] ||
13097c478bd9Sstevel@tonic-gate 					    c == tp->t_modes.c_cc[VSTART])
13107c478bd9Sstevel@tonic-gate 						continue;
13117c478bd9Sstevel@tonic-gate 				}
13127c478bd9Sstevel@tonic-gate 				/*
13137c478bd9Sstevel@tonic-gate 				 * Check for "literal next" character
13147c478bd9Sstevel@tonic-gate 				 * and "flush output" character.
13157c478bd9Sstevel@tonic-gate 				 * Note that we omit checks for ISIG
13167c478bd9Sstevel@tonic-gate 				 * and ICANON, since the IEXTEN
13177c478bd9Sstevel@tonic-gate 				 * setting subsumes them.
13187c478bd9Sstevel@tonic-gate 				 */
13197c478bd9Sstevel@tonic-gate 				if (tp->t_modes.c_lflag & IEXTEN) {
13207c478bd9Sstevel@tonic-gate 					if (c == tp->t_modes.c_cc[VLNEXT]) {
13217c478bd9Sstevel@tonic-gate 						/*
13227c478bd9Sstevel@tonic-gate 						 * Remember that we saw a
13237c478bd9Sstevel@tonic-gate 						 * "literal next" while
13247c478bd9Sstevel@tonic-gate 						 * scanning input, but leave
13257c478bd9Sstevel@tonic-gate 						 * leave it in the message so
13267c478bd9Sstevel@tonic-gate 						 * that the service routine
13277c478bd9Sstevel@tonic-gate 						 * can see it too.
13287c478bd9Sstevel@tonic-gate 						 */
13297c478bd9Sstevel@tonic-gate 						tp->t_state |= TS_PLNCH;
13307c478bd9Sstevel@tonic-gate 						tp->t_modes.c_lflag &= ~FLUSHO;
13317c478bd9Sstevel@tonic-gate 						*writep++ = c;
13327c478bd9Sstevel@tonic-gate 						continue;
13337c478bd9Sstevel@tonic-gate 					}
13347c478bd9Sstevel@tonic-gate 					if (c == tp->t_modes.c_cc[VDISCARD]) {
13357c478bd9Sstevel@tonic-gate 						ldterm_flush_output(c, wrq, tp);
13367c478bd9Sstevel@tonic-gate 						continue;
13377c478bd9Sstevel@tonic-gate 					}
13387c478bd9Sstevel@tonic-gate 				}
13397c478bd9Sstevel@tonic-gate 				tp->t_modes.c_lflag &= ~FLUSHO;
13407c478bd9Sstevel@tonic-gate 
13417c478bd9Sstevel@tonic-gate 				/*
13427c478bd9Sstevel@tonic-gate 				 * Check for signal-generating
13437c478bd9Sstevel@tonic-gate 				 * characters.
13447c478bd9Sstevel@tonic-gate 				 */
13457c478bd9Sstevel@tonic-gate 				if (tp->t_modes.c_lflag & ISIG) {
13467c478bd9Sstevel@tonic-gate 					if (c == tp->t_modes.c_cc[VINTR]) {
13477c478bd9Sstevel@tonic-gate 						ldterm_dosig(q, SIGINT, c,
13487c478bd9Sstevel@tonic-gate 						    M_PCSIG, FLUSHRW);
13497c478bd9Sstevel@tonic-gate 						continue;
13507c478bd9Sstevel@tonic-gate 					}
13517c478bd9Sstevel@tonic-gate 					if (c == tp->t_modes.c_cc[VQUIT]) {
13527c478bd9Sstevel@tonic-gate 						ldterm_dosig(q, SIGQUIT, c,
13537c478bd9Sstevel@tonic-gate 						    M_PCSIG, FLUSHRW);
13547c478bd9Sstevel@tonic-gate 						continue;
13557c478bd9Sstevel@tonic-gate 					}
13567c478bd9Sstevel@tonic-gate 					if (c == tp->t_modes.c_cc[VSWTCH]) {
13577c478bd9Sstevel@tonic-gate 						/*
13587c478bd9Sstevel@tonic-gate 						 * Ancient SXT support; discard
13597c478bd9Sstevel@tonic-gate 						 * character without action.
13607c478bd9Sstevel@tonic-gate 						 */
13617c478bd9Sstevel@tonic-gate 						continue;
13627c478bd9Sstevel@tonic-gate 					}
13637c478bd9Sstevel@tonic-gate 					if (c == tp->t_modes.c_cc[VSUSP]) {
13647c478bd9Sstevel@tonic-gate 						ldterm_dosig(q, SIGTSTP, c,
13657c478bd9Sstevel@tonic-gate 						    M_PCSIG, FLUSHRW);
13667c478bd9Sstevel@tonic-gate 						continue;
13677c478bd9Sstevel@tonic-gate 					}
13687c478bd9Sstevel@tonic-gate 					if ((tp->t_modes.c_lflag & IEXTEN) &&
13697c478bd9Sstevel@tonic-gate 					    (c == tp->t_modes.c_cc[VDSUSP])) {
13707c478bd9Sstevel@tonic-gate 						ldterm_dosig(q, SIGTSTP, c,
13717c478bd9Sstevel@tonic-gate 						    M_SIG, 0);
13727c478bd9Sstevel@tonic-gate 						continue;
13737c478bd9Sstevel@tonic-gate 					}
137419d32b9aSRobert Mustacchi 
137519d32b9aSRobert Mustacchi 					/*
137619d32b9aSRobert Mustacchi 					 * Consumers do not expect the ^T to be
137719d32b9aSRobert Mustacchi 					 * echoed out when we generate a
137819d32b9aSRobert Mustacchi 					 * VSTATUS.
137919d32b9aSRobert Mustacchi 					 */
138019d32b9aSRobert Mustacchi 					if (c == tp->t_modes.c_cc[VSTATUS]) {
138119d32b9aSRobert Mustacchi 						ldterm_dosig(q, SIGINFO, '\0',
138219d32b9aSRobert Mustacchi 						    M_PCSIG, FLUSHRW);
138319d32b9aSRobert Mustacchi 						continue;
138419d32b9aSRobert Mustacchi 					}
13857c478bd9Sstevel@tonic-gate 				}
13867c478bd9Sstevel@tonic-gate 				/*
13877c478bd9Sstevel@tonic-gate 				 * Throw away CR if IGNCR set, or
13887c478bd9Sstevel@tonic-gate 				 * turn it into NL if ICRNL set.
13897c478bd9Sstevel@tonic-gate 				 */
13907c478bd9Sstevel@tonic-gate 				if (c == '\r') {
13917c478bd9Sstevel@tonic-gate 					if (tp->t_modes.c_iflag & IGNCR)
13927c478bd9Sstevel@tonic-gate 						continue;
13937c478bd9Sstevel@tonic-gate 					if (tp->t_modes.c_iflag & ICRNL)
13947c478bd9Sstevel@tonic-gate 						c = '\n';
13957c478bd9Sstevel@tonic-gate 				} else {
13967c478bd9Sstevel@tonic-gate 					/*
13977c478bd9Sstevel@tonic-gate 					 * Turn NL into CR if INLCR
13987c478bd9Sstevel@tonic-gate 					 * set.
13997c478bd9Sstevel@tonic-gate 					 */
14007c478bd9Sstevel@tonic-gate 					if (c == '\n' &&
14017c478bd9Sstevel@tonic-gate 					    tp->t_modes.c_iflag & INLCR)
14027c478bd9Sstevel@tonic-gate 						c = '\r';
14037c478bd9Sstevel@tonic-gate 				}
14047c478bd9Sstevel@tonic-gate 
14057c478bd9Sstevel@tonic-gate 				/*
14067c478bd9Sstevel@tonic-gate 				 * Map upper case input to lower case
14077c478bd9Sstevel@tonic-gate 				 * if IUCLC flag set.
14087c478bd9Sstevel@tonic-gate 				 */
14097c478bd9Sstevel@tonic-gate 				if (tp->t_modes.c_iflag & IUCLC &&
14107c478bd9Sstevel@tonic-gate 				    c >= 'A' && c <= 'Z')
14117c478bd9Sstevel@tonic-gate 					c += 'a' - 'A';
14127c478bd9Sstevel@tonic-gate 
14137c478bd9Sstevel@tonic-gate 				/*
14147c478bd9Sstevel@tonic-gate 				 * Put the possibly-transformed
14157c478bd9Sstevel@tonic-gate 				 * character back in the message.
14167c478bd9Sstevel@tonic-gate 				 */
14177c478bd9Sstevel@tonic-gate 				*writep++ = c;
14187c478bd9Sstevel@tonic-gate 			}
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate 			/*
14217c478bd9Sstevel@tonic-gate 			 * If we didn't copy some characters because
14227c478bd9Sstevel@tonic-gate 			 * we were ignoring them, fix the size of the
14237c478bd9Sstevel@tonic-gate 			 * data block by adjusting the write pointer.
14247c478bd9Sstevel@tonic-gate 			 * XXX This may result in a zero-length
14257c478bd9Sstevel@tonic-gate 			 * block; will this cause anybody gastric
14267c478bd9Sstevel@tonic-gate 			 * distress?
14277c478bd9Sstevel@tonic-gate 			 */
14287c478bd9Sstevel@tonic-gate 			bp->b_wptr -= (readp - writep);
14297c478bd9Sstevel@tonic-gate 		} else {
14307c478bd9Sstevel@tonic-gate 			/*
14317c478bd9Sstevel@tonic-gate 			 * We won't be doing anything other than
14327c478bd9Sstevel@tonic-gate 			 * possibly stripping the input.
14337c478bd9Sstevel@tonic-gate 			 */
14347c478bd9Sstevel@tonic-gate 			if (tp->t_modes.c_iflag & ISTRIP) {
14357c478bd9Sstevel@tonic-gate 				while (readp < bp->b_wptr)
14367c478bd9Sstevel@tonic-gate 					*writep++ = *readp++ & 0177;
14377c478bd9Sstevel@tonic-gate 			}
14387c478bd9Sstevel@tonic-gate 			tp->t_modes.c_lflag &= ~FLUSHO;
14397c478bd9Sstevel@tonic-gate 		}
14407c478bd9Sstevel@tonic-gate 
14417c478bd9Sstevel@tonic-gate 	} while ((bp = bp->b_cont) != NULL);	/* next block, if any */
14427c478bd9Sstevel@tonic-gate 
14437c478bd9Sstevel@tonic-gate 	/*
14447c478bd9Sstevel@tonic-gate 	 * Queue the message for service procedure if the
14457c478bd9Sstevel@tonic-gate 	 * queue is not empty or canputnext() fails or
14467c478bd9Sstevel@tonic-gate 	 * tp->t_state & TS_RESCAN is true.
14477c478bd9Sstevel@tonic-gate 	 */
14487c478bd9Sstevel@tonic-gate 
14497c478bd9Sstevel@tonic-gate 	if (q->q_first != NULL || !bcanputnext(q, mp->b_band) ||
145085bb5f1dSis 	    (tp->t_state & TS_RESCAN))
14517c478bd9Sstevel@tonic-gate 		(void) putq(q, mp);
14527c478bd9Sstevel@tonic-gate 	else
14537c478bd9Sstevel@tonic-gate 		(void) ldtermrmsg(q, mp);
14547c478bd9Sstevel@tonic-gate 
14557c478bd9Sstevel@tonic-gate 	/*
14567c478bd9Sstevel@tonic-gate 	 * Flow control: send "stop input" message if our queue is
14577c478bd9Sstevel@tonic-gate 	 * approaching its high-water mark. The message will be
14587c478bd9Sstevel@tonic-gate 	 * dropped on the floor in the service procedure, if we
14597c478bd9Sstevel@tonic-gate 	 * cannot ship it up and we have had it upto our neck!
14607c478bd9Sstevel@tonic-gate 	 *
14617c478bd9Sstevel@tonic-gate 	 * Set QWANTW to ensure that the read queue service procedure
14627c478bd9Sstevel@tonic-gate 	 * gets run when nextq empties up again, so that it can
14637c478bd9Sstevel@tonic-gate 	 * unstop the input.
14647c478bd9Sstevel@tonic-gate 	 */
14657c478bd9Sstevel@tonic-gate 	if ((tp->t_modes.c_iflag & IXOFF) && !(tp->t_state & TS_TBLOCK) &&
14667c478bd9Sstevel@tonic-gate 	    q->q_count >= TTXOHI) {
14677c478bd9Sstevel@tonic-gate 		mutex_enter(QLOCK(nextq));
14687c478bd9Sstevel@tonic-gate 		nextq->q_flag |= QWANTW;
14697c478bd9Sstevel@tonic-gate 		mutex_exit(QLOCK(nextq));
14707c478bd9Sstevel@tonic-gate 		tp->t_state |= TS_TBLOCK;
14717c478bd9Sstevel@tonic-gate 		(void) putnextctl(wrq, M_STOPI);
14727c478bd9Sstevel@tonic-gate 		DEBUG1(("M_STOPI down\n"));
14737c478bd9Sstevel@tonic-gate 	}
1474bf10ed2eSToomas Soome 	return (0);
14757c478bd9Sstevel@tonic-gate }
14767c478bd9Sstevel@tonic-gate 
14777c478bd9Sstevel@tonic-gate 
14787c478bd9Sstevel@tonic-gate /*
14797c478bd9Sstevel@tonic-gate  * Line discipline input server processing.  Erase/kill and escape
14807c478bd9Sstevel@tonic-gate  * ('\') processing, gathering into messages, upper/lower case input
14817c478bd9Sstevel@tonic-gate  * mapping.
14827c478bd9Sstevel@tonic-gate  */
1483bf10ed2eSToomas Soome static int
ldtermrsrv(queue_t * q)14847c478bd9Sstevel@tonic-gate ldtermrsrv(queue_t *q)
14857c478bd9Sstevel@tonic-gate {
14867c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp;
14877c478bd9Sstevel@tonic-gate 	mblk_t *mp;
14887c478bd9Sstevel@tonic-gate 
14897c478bd9Sstevel@tonic-gate 	tp = (ldtermstd_state_t *)q->q_ptr;
14907c478bd9Sstevel@tonic-gate 
14917c478bd9Sstevel@tonic-gate 	if (tp->t_state & TS_RESCAN) {
14927c478bd9Sstevel@tonic-gate 		/*
14937c478bd9Sstevel@tonic-gate 		 * Canonicalization was turned on or off. Put the
14947c478bd9Sstevel@tonic-gate 		 * message being assembled back in the input queue,
14957c478bd9Sstevel@tonic-gate 		 * so that we rescan it.
14967c478bd9Sstevel@tonic-gate 		 */
14977c478bd9Sstevel@tonic-gate 		if (tp->t_message != NULL) {
14987c478bd9Sstevel@tonic-gate 			DEBUG5(("RESCAN WAS SET; put back in q\n"));
14997c478bd9Sstevel@tonic-gate 			if (tp->t_msglen != 0)
15007c478bd9Sstevel@tonic-gate 				(void) putbq(q, tp->t_message);
15017c478bd9Sstevel@tonic-gate 			else
15027c478bd9Sstevel@tonic-gate 				freemsg(tp->t_message);
15037c478bd9Sstevel@tonic-gate 			tp->t_message = NULL;
15047c478bd9Sstevel@tonic-gate 			tp->t_endmsg = NULL;
15057c478bd9Sstevel@tonic-gate 			tp->t_msglen = 0;
15067c478bd9Sstevel@tonic-gate 		}
15077c478bd9Sstevel@tonic-gate 		if (tp->t_state & TS_MEUC) {
15087c478bd9Sstevel@tonic-gate 			ASSERT(tp->t_eucp_mp);
15097c478bd9Sstevel@tonic-gate 			tp->t_eucp = tp->t_eucp_mp->b_rptr;
15107c478bd9Sstevel@tonic-gate 			tp->t_codeset = 0;
15117c478bd9Sstevel@tonic-gate 			tp->t_eucleft = 0;
15127c478bd9Sstevel@tonic-gate 		}
15137c478bd9Sstevel@tonic-gate 		tp->t_state &= ~TS_RESCAN;
15147c478bd9Sstevel@tonic-gate 	}
15157c478bd9Sstevel@tonic-gate 
15167c478bd9Sstevel@tonic-gate 	while ((mp = getq(q)) != NULL) {
15177c478bd9Sstevel@tonic-gate 		if (!ldtermrmsg(q, mp))
15187c478bd9Sstevel@tonic-gate 			break;
15197c478bd9Sstevel@tonic-gate 	}
15207c478bd9Sstevel@tonic-gate 
15217c478bd9Sstevel@tonic-gate 	/*
15227c478bd9Sstevel@tonic-gate 	 * Flow control: send start message if blocked and our queue
15237c478bd9Sstevel@tonic-gate 	 * is below its low water mark.
15247c478bd9Sstevel@tonic-gate 	 */
15257c478bd9Sstevel@tonic-gate 	if ((tp->t_modes.c_iflag & IXOFF) && (tp->t_state & TS_TBLOCK) &&
15267c478bd9Sstevel@tonic-gate 	    !(tp->t_state & TS_IFBLOCK) && q->q_count <= TTXOLO) {
15277c478bd9Sstevel@tonic-gate 		tp->t_state &= ~TS_TBLOCK;
15287c478bd9Sstevel@tonic-gate 		(void) putctl(WR(q), M_STARTI);
15297c478bd9Sstevel@tonic-gate 	}
1530bf10ed2eSToomas Soome 	return (0);
15317c478bd9Sstevel@tonic-gate }
15327c478bd9Sstevel@tonic-gate 
15337c478bd9Sstevel@tonic-gate /*
15347c478bd9Sstevel@tonic-gate  * This routine is called from both ldtermrput and ldtermrsrv to
15357c478bd9Sstevel@tonic-gate  * do the actual work of dealing with mp. Return 1 on sucesss and
15367c478bd9Sstevel@tonic-gate  * 0 on failure.
15377c478bd9Sstevel@tonic-gate  */
15387c478bd9Sstevel@tonic-gate static int
ldtermrmsg(queue_t * q,mblk_t * mp)15397c478bd9Sstevel@tonic-gate ldtermrmsg(queue_t *q, mblk_t *mp)
15407c478bd9Sstevel@tonic-gate {
15417c478bd9Sstevel@tonic-gate 	unsigned char c;
15427c478bd9Sstevel@tonic-gate 	int dofree;
15437c478bd9Sstevel@tonic-gate 	int status = 1;
15447c478bd9Sstevel@tonic-gate 	size_t   ebsize;
15457c478bd9Sstevel@tonic-gate 	mblk_t *bp;
15467c478bd9Sstevel@tonic-gate 	mblk_t *bpt;
15477c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp;
15487c478bd9Sstevel@tonic-gate 
15497c478bd9Sstevel@tonic-gate 	bpt = NULL;
15507c478bd9Sstevel@tonic-gate 
15517c478bd9Sstevel@tonic-gate 	tp = (ldtermstd_state_t *)q->q_ptr;
15527c478bd9Sstevel@tonic-gate 
15537c478bd9Sstevel@tonic-gate 	if (mp->b_datap->db_type <= QPCTL && !bcanputnext(q, mp->b_band)) {
15547c478bd9Sstevel@tonic-gate 		/*
15557c478bd9Sstevel@tonic-gate 		 * Stream head is flow controlled. If echo is
15567c478bd9Sstevel@tonic-gate 		 * turned on, flush the read side or send a
15577c478bd9Sstevel@tonic-gate 		 * bell down the line to stop input and
15587c478bd9Sstevel@tonic-gate 		 * process the current message.
15597c478bd9Sstevel@tonic-gate 		 * Otherwise(putbq) the user will not see any
15607c478bd9Sstevel@tonic-gate 		 * response to to the typed input. Typically
15617c478bd9Sstevel@tonic-gate 		 * happens if there is no reader process.
15627c478bd9Sstevel@tonic-gate 		 * Note that you will loose the data in this
15637c478bd9Sstevel@tonic-gate 		 * case if the data is coming too fast. There
15647c478bd9Sstevel@tonic-gate 		 * is an assumption here that if ECHO is
15657c478bd9Sstevel@tonic-gate 		 * turned on its some user typing the data on
15667c478bd9Sstevel@tonic-gate 		 * a terminal and its not network.
15677c478bd9Sstevel@tonic-gate 		 */
15687c478bd9Sstevel@tonic-gate 		if (tp->t_modes.c_lflag & ECHO) {
15697c478bd9Sstevel@tonic-gate 			if ((tp->t_modes.c_iflag & IMAXBEL) &&
15707c478bd9Sstevel@tonic-gate 			    (tp->t_modes.c_lflag & ICANON)) {
15717c478bd9Sstevel@tonic-gate 				freemsg(mp);
15727c478bd9Sstevel@tonic-gate 				if (canputnext(WR(q)))
15737c478bd9Sstevel@tonic-gate 					ldterm_outchar(CTRL('g'), WR(q), 4, tp);
15747c478bd9Sstevel@tonic-gate 				status = 0;
15757c478bd9Sstevel@tonic-gate 				goto echo;
15767c478bd9Sstevel@tonic-gate 			} else {
15777c478bd9Sstevel@tonic-gate 				(void) putctl1(q, M_FLUSH, FLUSHR);
15787c478bd9Sstevel@tonic-gate 			}
15797c478bd9Sstevel@tonic-gate 		} else {
15807c478bd9Sstevel@tonic-gate 			(void) putbq(q, mp);
15817c478bd9Sstevel@tonic-gate 			status = 0;
15827c478bd9Sstevel@tonic-gate 			goto out;	/* read side is blocked */
15837c478bd9Sstevel@tonic-gate 		}
15847c478bd9Sstevel@tonic-gate 	}
15857c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
15867c478bd9Sstevel@tonic-gate 
15877c478bd9Sstevel@tonic-gate 	default:
15887c478bd9Sstevel@tonic-gate 		putnext(q, mp);	/* pass it on */
15897c478bd9Sstevel@tonic-gate 		goto out;
15907c478bd9Sstevel@tonic-gate 
15917c478bd9Sstevel@tonic-gate 	case M_HANGUP:
15927c478bd9Sstevel@tonic-gate 		/*
15937c478bd9Sstevel@tonic-gate 		 * Flush everything we haven't looked at yet.
15947c478bd9Sstevel@tonic-gate 		 */
15957c478bd9Sstevel@tonic-gate 		flushq(q, FLUSHDATA);
15967c478bd9Sstevel@tonic-gate 
15977c478bd9Sstevel@tonic-gate 		/*
15987c478bd9Sstevel@tonic-gate 		 * Flush everything we have looked at.
15997c478bd9Sstevel@tonic-gate 		 */
16007c478bd9Sstevel@tonic-gate 		freemsg(tp->t_message);
16017c478bd9Sstevel@tonic-gate 		tp->t_message = NULL;
16027c478bd9Sstevel@tonic-gate 		tp->t_endmsg = NULL;
16037c478bd9Sstevel@tonic-gate 		tp->t_msglen = 0;
16047c478bd9Sstevel@tonic-gate 		/*
16057c478bd9Sstevel@tonic-gate 		 * XXX  should we set read request
16067c478bd9Sstevel@tonic-gate 		 * tp->t_rd_request to NULL?
16077c478bd9Sstevel@tonic-gate 		 */
16087c478bd9Sstevel@tonic-gate 		tp->t_rocount = 0;	/* if it hasn't been typed */
16097c478bd9Sstevel@tonic-gate 		tp->t_rocol = 0;	/* it hasn't been echoed :-) */
16107c478bd9Sstevel@tonic-gate 		if (tp->t_state & TS_MEUC) {
16117c478bd9Sstevel@tonic-gate 			ASSERT(tp->t_eucp_mp);
16127c478bd9Sstevel@tonic-gate 			tp->t_eucp = tp->t_eucp_mp->b_rptr;
16137c478bd9Sstevel@tonic-gate 		}
16147c478bd9Sstevel@tonic-gate 		/*
16157c478bd9Sstevel@tonic-gate 		 * Restart output, since it's probably got
16167c478bd9Sstevel@tonic-gate 		 * nowhere to go anyway, and we're probably
16177c478bd9Sstevel@tonic-gate 		 * not going to see another ^Q for a while.
16187c478bd9Sstevel@tonic-gate 		 */
16197c478bd9Sstevel@tonic-gate 		if (tp->t_state & TS_TTSTOP) {
16207c478bd9Sstevel@tonic-gate 			tp->t_state &= ~(TS_TTSTOP|TS_OFBLOCK);
16217c478bd9Sstevel@tonic-gate 			(void) putnextctl(WR(q), M_START);
16227c478bd9Sstevel@tonic-gate 		}
16237c478bd9Sstevel@tonic-gate 		/*
16247c478bd9Sstevel@tonic-gate 		 * This message will travel up the read
16257c478bd9Sstevel@tonic-gate 		 * queue, flushing as it goes, get turned
16267c478bd9Sstevel@tonic-gate 		 * around at the stream head, and travel back
16277c478bd9Sstevel@tonic-gate 		 * down the write queue, flushing as it goes.
16287c478bd9Sstevel@tonic-gate 		 */
16297c478bd9Sstevel@tonic-gate 		(void) putnextctl1(q, M_FLUSH, FLUSHW);
16307c478bd9Sstevel@tonic-gate 
16317c478bd9Sstevel@tonic-gate 		/*
16327c478bd9Sstevel@tonic-gate 		 * This message will travel down the write
16337c478bd9Sstevel@tonic-gate 		 * queue, flushing as it goes, get turned
16347c478bd9Sstevel@tonic-gate 		 * around at the driver, and travel back up
16357c478bd9Sstevel@tonic-gate 		 * the read queue, flushing as it goes.
16367c478bd9Sstevel@tonic-gate 		 */
16377c478bd9Sstevel@tonic-gate 		(void) putctl1(WR(q), M_FLUSH, FLUSHR);
16387c478bd9Sstevel@tonic-gate 
16397c478bd9Sstevel@tonic-gate 		/*
16407c478bd9Sstevel@tonic-gate 		 * Now that that's done, we send a SIGCONT
16417c478bd9Sstevel@tonic-gate 		 * upstream, followed by the M_HANGUP.
16427c478bd9Sstevel@tonic-gate 		 */
16437c478bd9Sstevel@tonic-gate 		/* (void) putnextctl1(q, M_PCSIG, SIGCONT); */
16447c478bd9Sstevel@tonic-gate 		putnext(q, mp);
16457c478bd9Sstevel@tonic-gate 		goto out;
16467c478bd9Sstevel@tonic-gate 
16477c478bd9Sstevel@tonic-gate 	case M_IOCACK:
16487c478bd9Sstevel@tonic-gate 
16497c478bd9Sstevel@tonic-gate 		/*
16507c478bd9Sstevel@tonic-gate 		 * Augment whatever information the driver is
16517c478bd9Sstevel@tonic-gate 		 * returning  with the information we supply.
16527c478bd9Sstevel@tonic-gate 		 */
16537c478bd9Sstevel@tonic-gate 		ldterm_ioctl_reply(q, mp);
16547c478bd9Sstevel@tonic-gate 		goto out;
16557c478bd9Sstevel@tonic-gate 
16567c478bd9Sstevel@tonic-gate 	case M_DATA:
16577c478bd9Sstevel@tonic-gate 		break;
16587c478bd9Sstevel@tonic-gate 	}
16597c478bd9Sstevel@tonic-gate 
16607c478bd9Sstevel@tonic-gate 	/*
16617c478bd9Sstevel@tonic-gate 	 * This is an M_DATA message.
16627c478bd9Sstevel@tonic-gate 	 */
16637c478bd9Sstevel@tonic-gate 
16647c478bd9Sstevel@tonic-gate 	/*
16657c478bd9Sstevel@tonic-gate 	 * If somebody below us ("intelligent" communications
16667c478bd9Sstevel@tonic-gate 	 * board, pseudo-tty controlled by an editor) is
16677c478bd9Sstevel@tonic-gate 	 * doing canonicalization, don't scan it for special
16687c478bd9Sstevel@tonic-gate 	 * characters.
16697c478bd9Sstevel@tonic-gate 	 */
16707c478bd9Sstevel@tonic-gate 	if (tp->t_state & TS_NOCANON) {
16717c478bd9Sstevel@tonic-gate 		putnext(q, mp);
16727c478bd9Sstevel@tonic-gate 		goto out;
16737c478bd9Sstevel@tonic-gate 	}
16747c478bd9Sstevel@tonic-gate 	bp = mp;
16757c478bd9Sstevel@tonic-gate 
16767c478bd9Sstevel@tonic-gate 	if ((bpt = newmsg(tp)) != NULL) {
16777c478bd9Sstevel@tonic-gate 		mblk_t *bcont;
16787c478bd9Sstevel@tonic-gate 
16797c478bd9Sstevel@tonic-gate 		do {
16807c478bd9Sstevel@tonic-gate 			ASSERT(bp->b_wptr >= bp->b_rptr);
16817c478bd9Sstevel@tonic-gate 			ebsize = bp->b_wptr - bp->b_rptr;
16827c478bd9Sstevel@tonic-gate 			if (ebsize > EBSIZE)
16837c478bd9Sstevel@tonic-gate 				ebsize = EBSIZE;
16847c478bd9Sstevel@tonic-gate 			bcont = bp->b_cont;
16857c478bd9Sstevel@tonic-gate 			if (CANON_MODE) {
16867c478bd9Sstevel@tonic-gate 				/*
16877c478bd9Sstevel@tonic-gate 				 * By default, free the message once processed
16887c478bd9Sstevel@tonic-gate 				 */
16897c478bd9Sstevel@tonic-gate 				dofree = 1;
16907c478bd9Sstevel@tonic-gate 
16917c478bd9Sstevel@tonic-gate 				/*
16927c478bd9Sstevel@tonic-gate 				 * update sysinfo canch
16937c478bd9Sstevel@tonic-gate 				 * character. The value of
16947c478bd9Sstevel@tonic-gate 				 * canch may vary as compared
16957c478bd9Sstevel@tonic-gate 				 * to character tty
16967c478bd9Sstevel@tonic-gate 				 * implementation.
16977c478bd9Sstevel@tonic-gate 				 */
16987c478bd9Sstevel@tonic-gate 				while (bp->b_rptr < bp->b_wptr) {
16997c478bd9Sstevel@tonic-gate 					c = *bp->b_rptr++;
17007c478bd9Sstevel@tonic-gate 					if ((bpt = ldterm_docanon(c,
17017c478bd9Sstevel@tonic-gate 					    bpt, ebsize, q, tp, &dofree)) ==
17027c478bd9Sstevel@tonic-gate 					    NULL)
17037c478bd9Sstevel@tonic-gate 						break;
17047c478bd9Sstevel@tonic-gate 				}
17057c478bd9Sstevel@tonic-gate 				/*
17067c478bd9Sstevel@tonic-gate 				 * Release this block or put back on queue.
17077c478bd9Sstevel@tonic-gate 				 */
17087c478bd9Sstevel@tonic-gate 				if (dofree)
17097c478bd9Sstevel@tonic-gate 					freeb(bp);
17107c478bd9Sstevel@tonic-gate 				else {
17117c478bd9Sstevel@tonic-gate 					(void) putbq(q, bp);
17127c478bd9Sstevel@tonic-gate 					break;
17137c478bd9Sstevel@tonic-gate 				}
17147c478bd9Sstevel@tonic-gate 			} else
171585bb5f1dSis 				bpt = ldterm_dononcanon(bp, bpt, ebsize, q, tp);
17167c478bd9Sstevel@tonic-gate 			if (bpt == NULL) {
17177c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
17187c478bd9Sstevel@tonic-gate 				    "ldtermrsrv: out of blocks");
17197c478bd9Sstevel@tonic-gate 				freemsg(bcont);
17207c478bd9Sstevel@tonic-gate 				break;
17217c478bd9Sstevel@tonic-gate 			}
17227c478bd9Sstevel@tonic-gate 		} while ((bp = bcont) != NULL);
17237c478bd9Sstevel@tonic-gate 	}
17247c478bd9Sstevel@tonic-gate echo:
17257c478bd9Sstevel@tonic-gate 	/*
17267c478bd9Sstevel@tonic-gate 	 * Send whatever we echoed downstream.
17277c478bd9Sstevel@tonic-gate 	 */
17287c478bd9Sstevel@tonic-gate 	if (tp->t_echomp != NULL) {
17297c478bd9Sstevel@tonic-gate 		if (canputnext(WR(q)))
17307c478bd9Sstevel@tonic-gate 			putnext(WR(q), tp->t_echomp);
17317c478bd9Sstevel@tonic-gate 		else
17327c478bd9Sstevel@tonic-gate 			freemsg(tp->t_echomp);
17337c478bd9Sstevel@tonic-gate 		tp->t_echomp = NULL;
17347c478bd9Sstevel@tonic-gate 	}
17357c478bd9Sstevel@tonic-gate 
17367c478bd9Sstevel@tonic-gate out:
17377c478bd9Sstevel@tonic-gate 	return (status);
17387c478bd9Sstevel@tonic-gate }
17397c478bd9Sstevel@tonic-gate 
17407c478bd9Sstevel@tonic-gate 
17417c478bd9Sstevel@tonic-gate /*
17427c478bd9Sstevel@tonic-gate  * Do canonical mode input; check whether this character is to be
17437c478bd9Sstevel@tonic-gate  * treated as a special character - if so, check whether it's equal
17447c478bd9Sstevel@tonic-gate  * to any of the special characters and handle it accordingly.
17457c478bd9Sstevel@tonic-gate  * Otherwise, just add it to the current line.
17467c478bd9Sstevel@tonic-gate  */
17477c478bd9Sstevel@tonic-gate static mblk_t *
ldterm_docanon(uchar_t c,mblk_t * bpt,size_t ebsize,queue_t * q,ldtermstd_state_t * tp,int * dofreep)17487c478bd9Sstevel@tonic-gate ldterm_docanon(uchar_t c, mblk_t *bpt, size_t ebsize, queue_t *q,
17497c478bd9Sstevel@tonic-gate     ldtermstd_state_t *tp, int *dofreep)
17507c478bd9Sstevel@tonic-gate {
17517c478bd9Sstevel@tonic-gate 	queue_t *wrq = WR(q);
17527c478bd9Sstevel@tonic-gate 	int i;
17537c478bd9Sstevel@tonic-gate 
17547c478bd9Sstevel@tonic-gate 	/*
17557c478bd9Sstevel@tonic-gate 	 * If the previous character was the "literal next"
17567c478bd9Sstevel@tonic-gate 	 * character, treat this character as regular input.
17577c478bd9Sstevel@tonic-gate 	 */
17587c478bd9Sstevel@tonic-gate 	if (tp->t_state & TS_SLNCH)
17597c478bd9Sstevel@tonic-gate 		goto escaped;
17607c478bd9Sstevel@tonic-gate 
17617c478bd9Sstevel@tonic-gate 	/*
17627c478bd9Sstevel@tonic-gate 	 * Setting a special character to NUL disables it, so if this
17637c478bd9Sstevel@tonic-gate 	 * character is NUL, it should not be compared with any of
17647c478bd9Sstevel@tonic-gate 	 * the special characters.
17657c478bd9Sstevel@tonic-gate 	 */
17667c478bd9Sstevel@tonic-gate 	if (c == _POSIX_VDISABLE) {
17677c478bd9Sstevel@tonic-gate 		tp->t_state &= ~TS_QUOT;
17687c478bd9Sstevel@tonic-gate 		goto escaped;
17697c478bd9Sstevel@tonic-gate 	}
17707c478bd9Sstevel@tonic-gate 	/*
17717c478bd9Sstevel@tonic-gate 	 * If this character is the literal next character, echo it
17727c478bd9Sstevel@tonic-gate 	 * as '^', backspace over it, and record that fact.
17737c478bd9Sstevel@tonic-gate 	 */
17747c478bd9Sstevel@tonic-gate 	if ((tp->t_modes.c_lflag & IEXTEN) && c == tp->t_modes.c_cc[VLNEXT]) {
17757c478bd9Sstevel@tonic-gate 		if (tp->t_modes.c_lflag & ECHO)
17767c478bd9Sstevel@tonic-gate 			ldterm_outstring((unsigned char *)"^\b", 2, wrq,
177785bb5f1dSis 			    ebsize, tp);
17787c478bd9Sstevel@tonic-gate 		tp->t_state |= TS_SLNCH;
17797c478bd9Sstevel@tonic-gate 		goto out;
17807c478bd9Sstevel@tonic-gate 	}
17817c478bd9Sstevel@tonic-gate 	/*
17827c478bd9Sstevel@tonic-gate 	 * Check for the editing character. If the display width of
17837c478bd9Sstevel@tonic-gate 	 * the last byte at the canonical buffer is not one and also
17847c478bd9Sstevel@tonic-gate 	 * smaller than or equal to UNKNOWN_WIDTH, the character at
17857c478bd9Sstevel@tonic-gate 	 * the end of the buffer is a multi-byte and/or multi-column
17867c478bd9Sstevel@tonic-gate 	 * character.
17877c478bd9Sstevel@tonic-gate 	 */
17889a2c4685SToomas Soome 	if (c == tp->t_modes.c_cc[VERASE] || c == tp->t_modes.c_cc[VERASE2]) {
17897c478bd9Sstevel@tonic-gate 		if (tp->t_state & TS_QUOT) {
17907c478bd9Sstevel@tonic-gate 			/*
17917c478bd9Sstevel@tonic-gate 			 * Get rid of the backslash, and put the
17927c478bd9Sstevel@tonic-gate 			 * erase character in its place.
17937c478bd9Sstevel@tonic-gate 			 */
17947c478bd9Sstevel@tonic-gate 			ldterm_erase(wrq, ebsize, tp);
17957c478bd9Sstevel@tonic-gate 			bpt = tp->t_endmsg;
17967c478bd9Sstevel@tonic-gate 			goto escaped;
17977c478bd9Sstevel@tonic-gate 		} else {
17987c478bd9Sstevel@tonic-gate 			if ((tp->t_state & TS_MEUC) && tp->t_msglen &&
17997c478bd9Sstevel@tonic-gate 			    (*(tp->t_eucp - 1) != 1 &&
18007c478bd9Sstevel@tonic-gate 			    *(tp->t_eucp - 1) <= UNKNOWN_WIDTH))
18017c478bd9Sstevel@tonic-gate 				ldterm_csi_erase(wrq, ebsize, tp);
18027c478bd9Sstevel@tonic-gate 			else
18037c478bd9Sstevel@tonic-gate 				ldterm_erase(wrq, ebsize, tp);
18047c478bd9Sstevel@tonic-gate 			bpt = tp->t_endmsg;
18057c478bd9Sstevel@tonic-gate 			goto out;
18067c478bd9Sstevel@tonic-gate 		}
18077c478bd9Sstevel@tonic-gate 	}
18087c478bd9Sstevel@tonic-gate 	if ((tp->t_modes.c_lflag & IEXTEN) && c == tp->t_modes.c_cc[VWERASE]) {
18097c478bd9Sstevel@tonic-gate 		/*
18107c478bd9Sstevel@tonic-gate 		 * Do "ASCII word" or "multibyte character token/chunk" erase.
18117c478bd9Sstevel@tonic-gate 		 */
18127c478bd9Sstevel@tonic-gate 		if (tp->t_state & TS_MEUC)
18137c478bd9Sstevel@tonic-gate 			ldterm_csi_werase(wrq, ebsize, tp);
18147c478bd9Sstevel@tonic-gate 		else
18157c478bd9Sstevel@tonic-gate 			ldterm_werase(wrq, ebsize, tp);
18167c478bd9Sstevel@tonic-gate 		bpt = tp->t_endmsg;
18177c478bd9Sstevel@tonic-gate 		goto out;
18187c478bd9Sstevel@tonic-gate 	}
18197c478bd9Sstevel@tonic-gate 	if (c == tp->t_modes.c_cc[VKILL]) {
18207c478bd9Sstevel@tonic-gate 		if (tp->t_state & TS_QUOT) {
18217c478bd9Sstevel@tonic-gate 			/*
18227c478bd9Sstevel@tonic-gate 			 * Get rid of the backslash, and put the kill
18237c478bd9Sstevel@tonic-gate 			 * character in its place.
18247c478bd9Sstevel@tonic-gate 			 */
18257c478bd9Sstevel@tonic-gate 			ldterm_erase(wrq, ebsize, tp);
18267c478bd9Sstevel@tonic-gate 			bpt = tp->t_endmsg;
18277c478bd9Sstevel@tonic-gate 			goto escaped;
18287c478bd9Sstevel@tonic-gate 		} else {
18297c478bd9Sstevel@tonic-gate 			ldterm_kill(wrq, ebsize, tp);
18307c478bd9Sstevel@tonic-gate 			bpt = tp->t_endmsg;
18317c478bd9Sstevel@tonic-gate 			goto out;
18327c478bd9Sstevel@tonic-gate 		}
18337c478bd9Sstevel@tonic-gate 	}
18347c478bd9Sstevel@tonic-gate 	if ((tp->t_modes.c_lflag & IEXTEN) && c == tp->t_modes.c_cc[VREPRINT]) {
18357c478bd9Sstevel@tonic-gate 		ldterm_reprint(wrq, ebsize, tp);
18367c478bd9Sstevel@tonic-gate 		goto out;
18377c478bd9Sstevel@tonic-gate 	}
18387c478bd9Sstevel@tonic-gate 	/*
18397c478bd9Sstevel@tonic-gate 	 * If the preceding character was a backslash: if the current
18407c478bd9Sstevel@tonic-gate 	 * character is an EOF, get rid of the backslash and treat
18417c478bd9Sstevel@tonic-gate 	 * the EOF as data; if we're in XCASE mode and the current
18427c478bd9Sstevel@tonic-gate 	 * character is part of a backslash-X escape sequence,
18437c478bd9Sstevel@tonic-gate 	 * process it; otherwise, just treat the current character
18447c478bd9Sstevel@tonic-gate 	 * normally.
18457c478bd9Sstevel@tonic-gate 	 */
18467c478bd9Sstevel@tonic-gate 	if (tp->t_state & TS_QUOT) {
18477c478bd9Sstevel@tonic-gate 		tp->t_state &= ~TS_QUOT;
18487c478bd9Sstevel@tonic-gate 		if (c == tp->t_modes.c_cc[VEOF]) {
18497c478bd9Sstevel@tonic-gate 			/*
18507c478bd9Sstevel@tonic-gate 			 * EOF character. Since it's escaped, get rid
18517c478bd9Sstevel@tonic-gate 			 * of the backslash and put the EOF character
18527c478bd9Sstevel@tonic-gate 			 * in its place.
18537c478bd9Sstevel@tonic-gate 			 */
18547c478bd9Sstevel@tonic-gate 			ldterm_erase(wrq, ebsize, tp);
18557c478bd9Sstevel@tonic-gate 			bpt = tp->t_endmsg;
18567c478bd9Sstevel@tonic-gate 		} else {
18577c478bd9Sstevel@tonic-gate 			/*
18587c478bd9Sstevel@tonic-gate 			 * If we're in XCASE mode, and the current
18597c478bd9Sstevel@tonic-gate 			 * character is part of a backslash-X
18607c478bd9Sstevel@tonic-gate 			 * sequence, get rid of the backslash and
18617c478bd9Sstevel@tonic-gate 			 * replace the current character with what
18627c478bd9Sstevel@tonic-gate 			 * that sequence maps to.
18637c478bd9Sstevel@tonic-gate 			 */
18647c478bd9Sstevel@tonic-gate 			if ((tp->t_modes.c_lflag & XCASE) &&
18657c478bd9Sstevel@tonic-gate 			    imaptab[c] != '\0') {
18667c478bd9Sstevel@tonic-gate 				ldterm_erase(wrq, ebsize, tp);
18677c478bd9Sstevel@tonic-gate 				bpt = tp->t_endmsg;
18687c478bd9Sstevel@tonic-gate 				c = imaptab[c];
18697c478bd9Sstevel@tonic-gate 			}
18707c478bd9Sstevel@tonic-gate 		}
18717c478bd9Sstevel@tonic-gate 	} else {
18727c478bd9Sstevel@tonic-gate 		/*
18737c478bd9Sstevel@tonic-gate 		 * Previous character wasn't backslash; check whether
18747c478bd9Sstevel@tonic-gate 		 * this was the EOF character.
18757c478bd9Sstevel@tonic-gate 		 */
18767c478bd9Sstevel@tonic-gate 		if (c == tp->t_modes.c_cc[VEOF]) {
18777c478bd9Sstevel@tonic-gate 			/*
18787c478bd9Sstevel@tonic-gate 			 * EOF character. Don't echo it unless
18797c478bd9Sstevel@tonic-gate 			 * ECHOCTL is set, don't stuff it in the
18807c478bd9Sstevel@tonic-gate 			 * current line, but send the line up the
18817c478bd9Sstevel@tonic-gate 			 * stream.
18827c478bd9Sstevel@tonic-gate 			 */
18837c478bd9Sstevel@tonic-gate 			if ((tp->t_modes.c_lflag & ECHOCTL) &&
18847c478bd9Sstevel@tonic-gate 			    (tp->t_modes.c_lflag & IEXTEN) &&
18857c478bd9Sstevel@tonic-gate 			    (tp->t_modes.c_lflag & ECHO)) {
18867c478bd9Sstevel@tonic-gate 				i = ldterm_echo(c, wrq, ebsize, tp);
18877c478bd9Sstevel@tonic-gate 				while (i > 0) {
18887c478bd9Sstevel@tonic-gate 					ldterm_outchar('\b', wrq, ebsize, tp);
18897c478bd9Sstevel@tonic-gate 					i--;
18907c478bd9Sstevel@tonic-gate 				}
18917c478bd9Sstevel@tonic-gate 			}
18927c478bd9Sstevel@tonic-gate 			bpt->b_datap->db_type = M_DATA;
18937c478bd9Sstevel@tonic-gate 			ldterm_msg_upstream(q, tp);
18947c478bd9Sstevel@tonic-gate 			if (!canputnext(q)) {
18957c478bd9Sstevel@tonic-gate 				bpt = NULL;
18967c478bd9Sstevel@tonic-gate 				*dofreep = 0;
18977c478bd9Sstevel@tonic-gate 			} else {
18987c478bd9Sstevel@tonic-gate 				bpt = newmsg(tp);
18997c478bd9Sstevel@tonic-gate 				*dofreep = 1;
19007c478bd9Sstevel@tonic-gate 			}
19017c478bd9Sstevel@tonic-gate 			goto out;
19027c478bd9Sstevel@tonic-gate 		}
19037c478bd9Sstevel@tonic-gate 	}
19047c478bd9Sstevel@tonic-gate 
19057c478bd9Sstevel@tonic-gate escaped:
19067c478bd9Sstevel@tonic-gate 	/*
19077c478bd9Sstevel@tonic-gate 	 * First, make sure we can fit one WHOLE multi-byte char in the
19087c478bd9Sstevel@tonic-gate 	 * buffer.  This is one place where we have overhead even if
19097c478bd9Sstevel@tonic-gate 	 * not in multi-byte mode; the overhead is subtracting
19107c478bd9Sstevel@tonic-gate 	 * tp->t_maxeuc from MAX_CANON before checking.
19117c478bd9Sstevel@tonic-gate 	 *
19127c478bd9Sstevel@tonic-gate 	 * Allows MAX_CANON bytes in the buffer before throwing awaying
19137c478bd9Sstevel@tonic-gate 	 * the the overflow of characters.
19147c478bd9Sstevel@tonic-gate 	 */
19152463e920SRichard Lowe 	if ((tp->t_msglen > ((_TTY_BUFSIZ + 1) - (int)tp->t_maxeuc)) &&
19167c478bd9Sstevel@tonic-gate 	    !((tp->t_state & TS_MEUC) && tp->t_eucleft)) {
19177c478bd9Sstevel@tonic-gate 
19187c478bd9Sstevel@tonic-gate 		/*
19197c478bd9Sstevel@tonic-gate 		 * Byte will cause line to overflow, or the next EUC
19207c478bd9Sstevel@tonic-gate 		 * won't fit: Ring the bell or discard all input, and
19217c478bd9Sstevel@tonic-gate 		 * don't save the byte away.
19227c478bd9Sstevel@tonic-gate 		 */
19237c478bd9Sstevel@tonic-gate 		if (tp->t_modes.c_iflag & IMAXBEL) {
19247c478bd9Sstevel@tonic-gate 			if (canputnext(wrq))
19257c478bd9Sstevel@tonic-gate 				ldterm_outchar(CTRL('g'), wrq, ebsize, tp);
19267c478bd9Sstevel@tonic-gate 			goto out;
19277c478bd9Sstevel@tonic-gate 		} else {
19287c478bd9Sstevel@tonic-gate 			/*
19297c478bd9Sstevel@tonic-gate 			 * MAX_CANON processing. free everything in
19307c478bd9Sstevel@tonic-gate 			 * the current line and start with the
19317c478bd9Sstevel@tonic-gate 			 * current character as the first character.
19327c478bd9Sstevel@tonic-gate 			 */
19337c478bd9Sstevel@tonic-gate 			DEBUG7(("ldterm_docanon: MAX_CANON processing\n"));
19347c478bd9Sstevel@tonic-gate 			freemsg(tp->t_message);
19357c478bd9Sstevel@tonic-gate 			tp->t_message = NULL;
19367c478bd9Sstevel@tonic-gate 			tp->t_endmsg = NULL;
19377c478bd9Sstevel@tonic-gate 			tp->t_msglen = 0;
19387c478bd9Sstevel@tonic-gate 			tp->t_rocount = 0;	/* if it hasn't been type */
19397c478bd9Sstevel@tonic-gate 			tp->t_rocol = 0;	/* it hasn't been echoed :-) */
19407c478bd9Sstevel@tonic-gate 			if (tp->t_state & TS_MEUC) {
19417c478bd9Sstevel@tonic-gate 				ASSERT(tp->t_eucp_mp);
19427c478bd9Sstevel@tonic-gate 				tp->t_eucp = tp->t_eucp_mp->b_rptr;
19437c478bd9Sstevel@tonic-gate 			}
19447c478bd9Sstevel@tonic-gate 			tp->t_state &= ~TS_SLNCH;
19457c478bd9Sstevel@tonic-gate 			bpt = newmsg(tp);
19467c478bd9Sstevel@tonic-gate 		}
19477c478bd9Sstevel@tonic-gate 	}
19487c478bd9Sstevel@tonic-gate 	/*
19497c478bd9Sstevel@tonic-gate 	 * Add the character to the current line.
19507c478bd9Sstevel@tonic-gate 	 */
19517c478bd9Sstevel@tonic-gate 	if (bpt->b_wptr >= bpt->b_datap->db_lim) {
19527c478bd9Sstevel@tonic-gate 		/*
19537c478bd9Sstevel@tonic-gate 		 * No more room in this mblk; save this one away, and
19547c478bd9Sstevel@tonic-gate 		 * allocate a new one.
19557c478bd9Sstevel@tonic-gate 		 */
19567c478bd9Sstevel@tonic-gate 		bpt->b_datap->db_type = M_DATA;
19577c478bd9Sstevel@tonic-gate 		if ((bpt = allocb(IBSIZE, BPRI_MED)) == NULL)
19587c478bd9Sstevel@tonic-gate 			goto out;
19597c478bd9Sstevel@tonic-gate 
19607c478bd9Sstevel@tonic-gate 		/*
19617c478bd9Sstevel@tonic-gate 		 * Chain the new one to the end of the old one, and
19627c478bd9Sstevel@tonic-gate 		 * mark it as the last block in the current line.
19637c478bd9Sstevel@tonic-gate 		 */
19647c478bd9Sstevel@tonic-gate 		tp->t_endmsg->b_cont = bpt;
19657c478bd9Sstevel@tonic-gate 		tp->t_endmsg = bpt;
19667c478bd9Sstevel@tonic-gate 	}
19677c478bd9Sstevel@tonic-gate 	*bpt->b_wptr++ = c;
19687c478bd9Sstevel@tonic-gate 	tp->t_msglen++;		/* message length in BYTES */
19697c478bd9Sstevel@tonic-gate 
19707c478bd9Sstevel@tonic-gate 	/*
19717c478bd9Sstevel@tonic-gate 	 * In multi-byte mode, we have to keep track of where we are.
19727c478bd9Sstevel@tonic-gate 	 * The first bytes of multi-byte chars get the full count for the
19737c478bd9Sstevel@tonic-gate 	 * whole character.  We don't do any column calculations
19747c478bd9Sstevel@tonic-gate 	 * here, but we need the information for when we do. We could
19757c478bd9Sstevel@tonic-gate 	 * come across cases where we are getting garbage on the
19767c478bd9Sstevel@tonic-gate 	 * line, but we're in multi-byte mode.  In that case, we may
19777c478bd9Sstevel@tonic-gate 	 * see ASCII controls come in the middle of what should have been a
19787c478bd9Sstevel@tonic-gate 	 * multi-byte character.  Call ldterm_eucwarn...eventually, a
19797c478bd9Sstevel@tonic-gate 	 * warning message will be printed about it.
19807c478bd9Sstevel@tonic-gate 	 */
19817c478bd9Sstevel@tonic-gate 	if (tp->t_state & TS_MEUC) {
19827c478bd9Sstevel@tonic-gate 		if (tp->t_eucleft) {	/* if in a multi-byte char already */
19837c478bd9Sstevel@tonic-gate 			--tp->t_eucleft;
19847c478bd9Sstevel@tonic-gate 			*tp->t_eucp++ = 0;	/* is a subsequent byte */
19857c478bd9Sstevel@tonic-gate 			if (c < (uchar_t)0x20)
19867c478bd9Sstevel@tonic-gate 				ldterm_eucwarn(tp);
19877c478bd9Sstevel@tonic-gate 		} else { /* is the first byte of a multi-byte, or is ASCII */
19887c478bd9Sstevel@tonic-gate 			if (ISASCII(c)) {
19897c478bd9Sstevel@tonic-gate 				*tp->t_eucp++ =
199085bb5f1dSis 				    tp->t_csmethods.ldterm_dispwidth(c,
199185bb5f1dSis 				    (void *)tp, tp->t_modes.c_lflag & ECHOCTL);
19927c478bd9Sstevel@tonic-gate 				tp->t_codeset = 0;
19937c478bd9Sstevel@tonic-gate 			} else {
19947c478bd9Sstevel@tonic-gate 				*tp->t_eucp++ =
199585bb5f1dSis 				    tp->t_csmethods.ldterm_dispwidth(c,
199685bb5f1dSis 				    (void *)tp, tp->t_modes.c_lflag & ECHOCTL);
19977c478bd9Sstevel@tonic-gate 				tp->t_eucleft =
199885bb5f1dSis 				    tp->t_csmethods.ldterm_memwidth(c,
199985bb5f1dSis 				    (void *)tp) - 1;
20007c478bd9Sstevel@tonic-gate 				tp->t_codeset = ldterm_codeset(
200185bb5f1dSis 				    tp->t_csdata.codeset_type, c);
20027c478bd9Sstevel@tonic-gate 			}
20037c478bd9Sstevel@tonic-gate 		}
20047c478bd9Sstevel@tonic-gate 	}
20057c478bd9Sstevel@tonic-gate 	/*
20067c478bd9Sstevel@tonic-gate 	 * AT&T is concerned about the following but we aren't since
20077c478bd9Sstevel@tonic-gate 	 * we have already shipped code that works.
20087c478bd9Sstevel@tonic-gate 	 *
20097c478bd9Sstevel@tonic-gate 	 * EOL2/XCASE should be conditioned with IEXTEN to be truly
20107c478bd9Sstevel@tonic-gate 	 * POSIX conformant. This is going to cause problems for
20117c478bd9Sstevel@tonic-gate 	 * pre-SVR4.0 programs that don't know about IEXTEN. Hence
20127c478bd9Sstevel@tonic-gate 	 * EOL2/IEXTEN is not conditioned with IEXTEN.
20137c478bd9Sstevel@tonic-gate 	 */
20147c478bd9Sstevel@tonic-gate 	if (!(tp->t_state & TS_SLNCH) &&
20157c478bd9Sstevel@tonic-gate 	    (c == '\n' || (c != '\0' && (c == tp->t_modes.c_cc[VEOL] ||
20167c478bd9Sstevel@tonic-gate 	    (c == tp->t_modes.c_cc[VEOL2]))))) {
20177c478bd9Sstevel@tonic-gate 		/*
20187c478bd9Sstevel@tonic-gate 		 * || ((tp->t_modes.c_lflag & IEXTEN) && c ==
20197c478bd9Sstevel@tonic-gate 		 * tp->t_modes.c_cc[VEOL2]))))) {
20207c478bd9Sstevel@tonic-gate 		 */
20217c478bd9Sstevel@tonic-gate 		/*
20227c478bd9Sstevel@tonic-gate 		 * It's a line-termination character; send the line
20237c478bd9Sstevel@tonic-gate 		 * up the stream.
20247c478bd9Sstevel@tonic-gate 		 */
20257c478bd9Sstevel@tonic-gate 		bpt->b_datap->db_type = M_DATA;
20267c478bd9Sstevel@tonic-gate 		ldterm_msg_upstream(q, tp);
20277c478bd9Sstevel@tonic-gate 		if (tp->t_state & TS_MEUC) {
20287c478bd9Sstevel@tonic-gate 			ASSERT(tp->t_eucp_mp);
20297c478bd9Sstevel@tonic-gate 			tp->t_eucp = tp->t_eucp_mp->b_rptr;
20307c478bd9Sstevel@tonic-gate 		}
20317c478bd9Sstevel@tonic-gate 		if ((bpt = newmsg(tp)) == NULL)
20327c478bd9Sstevel@tonic-gate 			goto out;
20337c478bd9Sstevel@tonic-gate 	} else {
20347c478bd9Sstevel@tonic-gate 		/*
20357c478bd9Sstevel@tonic-gate 		 * Character was escaped with LNEXT.
20367c478bd9Sstevel@tonic-gate 		 */
20377c478bd9Sstevel@tonic-gate 		if (tp->t_rocount++ == 0)
20387c478bd9Sstevel@tonic-gate 			tp->t_rocol = tp->t_col;
20397c478bd9Sstevel@tonic-gate 		tp->t_state &= ~(TS_SLNCH|TS_QUOT);
20407c478bd9Sstevel@tonic-gate 		/*
20417c478bd9Sstevel@tonic-gate 		 * If the current character is a single byte and single
20427c478bd9Sstevel@tonic-gate 		 * column character and it is the backslash character and
20437c478bd9Sstevel@tonic-gate 		 * IEXTEN, then the state will have TS_QUOT.
20447c478bd9Sstevel@tonic-gate 		 */
20457c478bd9Sstevel@tonic-gate 		if ((c == '\\') && (tp->t_modes.c_lflag & IEXTEN) &&
20467c478bd9Sstevel@tonic-gate 		    (!(tp->t_state & TS_MEUC) ||
20477c478bd9Sstevel@tonic-gate 		    ((tp->t_state & TS_MEUC) && (!tp->t_eucleft))))
20487c478bd9Sstevel@tonic-gate 			tp->t_state |= TS_QUOT;
20497c478bd9Sstevel@tonic-gate 	}
20507c478bd9Sstevel@tonic-gate 
20517c478bd9Sstevel@tonic-gate 	/*
20527c478bd9Sstevel@tonic-gate 	 * Echo it.
20537c478bd9Sstevel@tonic-gate 	 */
20547c478bd9Sstevel@tonic-gate 	if (tp->t_state & TS_ERASE) {
20557c478bd9Sstevel@tonic-gate 		tp->t_state &= ~TS_ERASE;
20567c478bd9Sstevel@tonic-gate 		if (tp->t_modes.c_lflag & ECHO)
20577c478bd9Sstevel@tonic-gate 			ldterm_outchar('/', wrq, ebsize, tp);
20587c478bd9Sstevel@tonic-gate 	}
20597c478bd9Sstevel@tonic-gate 	if (tp->t_modes.c_lflag & ECHO)
20607c478bd9Sstevel@tonic-gate 		(void) ldterm_echo(c, wrq, ebsize, tp);
20617c478bd9Sstevel@tonic-gate 	else {
20627c478bd9Sstevel@tonic-gate 		/*
20637c478bd9Sstevel@tonic-gate 		 * Echo NL when ECHO turned off, if ECHONL flag is
20647c478bd9Sstevel@tonic-gate 		 * set.
20657c478bd9Sstevel@tonic-gate 		 */
20667c478bd9Sstevel@tonic-gate 		if (c == '\n' && (tp->t_modes.c_lflag & ECHONL))
20677c478bd9Sstevel@tonic-gate 			ldterm_outchar(c, wrq, ebsize, tp);
20687c478bd9Sstevel@tonic-gate 	}
20697c478bd9Sstevel@tonic-gate 
20707c478bd9Sstevel@tonic-gate out:
20717c478bd9Sstevel@tonic-gate 
20727c478bd9Sstevel@tonic-gate 	return (bpt);
20737c478bd9Sstevel@tonic-gate }
20747c478bd9Sstevel@tonic-gate 
20757c478bd9Sstevel@tonic-gate 
20767c478bd9Sstevel@tonic-gate static int
ldterm_unget(ldtermstd_state_t * tp)20777c478bd9Sstevel@tonic-gate ldterm_unget(ldtermstd_state_t *tp)
20787c478bd9Sstevel@tonic-gate {
20797c478bd9Sstevel@tonic-gate 	mblk_t *bpt;
20807c478bd9Sstevel@tonic-gate 
20817c478bd9Sstevel@tonic-gate 	if ((bpt = tp->t_endmsg) == NULL)
20827c478bd9Sstevel@tonic-gate 		return (-1);	/* no buffers */
20837c478bd9Sstevel@tonic-gate 	if (bpt->b_rptr == bpt->b_wptr)
20847c478bd9Sstevel@tonic-gate 		return (-1);	/* zero-length record */
20857c478bd9Sstevel@tonic-gate 	tp->t_msglen--;		/* one fewer character */
20867c478bd9Sstevel@tonic-gate 	return (*--bpt->b_wptr);
20877c478bd9Sstevel@tonic-gate }
20887c478bd9Sstevel@tonic-gate 
20897c478bd9Sstevel@tonic-gate 
20907c478bd9Sstevel@tonic-gate static void
ldterm_trim(ldtermstd_state_t * tp)20917c478bd9Sstevel@tonic-gate ldterm_trim(ldtermstd_state_t *tp)
20927c478bd9Sstevel@tonic-gate {
20937c478bd9Sstevel@tonic-gate 	mblk_t *bpt;
20947c478bd9Sstevel@tonic-gate 	mblk_t *bp;
20957c478bd9Sstevel@tonic-gate 
20967c478bd9Sstevel@tonic-gate 	ASSERT(tp->t_endmsg);
20977c478bd9Sstevel@tonic-gate 	bpt = tp->t_endmsg;
20987c478bd9Sstevel@tonic-gate 
20997c478bd9Sstevel@tonic-gate 	if (bpt->b_rptr == bpt->b_wptr) {
21007c478bd9Sstevel@tonic-gate 		/*
21017c478bd9Sstevel@tonic-gate 		 * This mblk is now empty. Find the previous mblk;
21027c478bd9Sstevel@tonic-gate 		 * throw this one away, unless it's the first one.
21037c478bd9Sstevel@tonic-gate 		 */
21047c478bd9Sstevel@tonic-gate 		bp = tp->t_message;
21057c478bd9Sstevel@tonic-gate 		if (bp != bpt) {
21067c478bd9Sstevel@tonic-gate 			while (bp->b_cont != bpt) {
21077c478bd9Sstevel@tonic-gate 				ASSERT(bp->b_cont);
21087c478bd9Sstevel@tonic-gate 				bp = bp->b_cont;
21097c478bd9Sstevel@tonic-gate 			}
21107c478bd9Sstevel@tonic-gate 			bp->b_cont = NULL;
21117c478bd9Sstevel@tonic-gate 			freeb(bpt);
21127c478bd9Sstevel@tonic-gate 			tp->t_endmsg = bp;	/* point to that mblk */
21137c478bd9Sstevel@tonic-gate 		}
21147c478bd9Sstevel@tonic-gate 	}
21157c478bd9Sstevel@tonic-gate }
21167c478bd9Sstevel@tonic-gate 
21177c478bd9Sstevel@tonic-gate 
21187c478bd9Sstevel@tonic-gate /*
21197c478bd9Sstevel@tonic-gate  * Rubout one character from the current line being built for tp as
21207c478bd9Sstevel@tonic-gate  * cleanly as possible.  q is the write queue for tp. Most of this
21217c478bd9Sstevel@tonic-gate  * can't be applied to multi-byte processing.  We do our own thing
21227c478bd9Sstevel@tonic-gate  * for that... See the "ldterm_eucerase" routine.  We never call
21237c478bd9Sstevel@tonic-gate  * ldterm_rubout on a multi-byte or multi-column character.
21247c478bd9Sstevel@tonic-gate  */
21257c478bd9Sstevel@tonic-gate static void
ldterm_rubout(uchar_t c,queue_t * q,size_t ebsize,ldtermstd_state_t * tp)21267c478bd9Sstevel@tonic-gate ldterm_rubout(uchar_t c, queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
21277c478bd9Sstevel@tonic-gate {
21287c478bd9Sstevel@tonic-gate 	int tabcols;
21297c478bd9Sstevel@tonic-gate 	static unsigned char crtrubout[] = "\b \b\b \b";
21307c478bd9Sstevel@tonic-gate #define	RUBOUT1	&crtrubout[3]	/* rub out one position */
21317c478bd9Sstevel@tonic-gate #define	RUBOUT2	&crtrubout[0]	/* rub out two positions */
21327c478bd9Sstevel@tonic-gate 
21337c478bd9Sstevel@tonic-gate 	if (!(tp->t_modes.c_lflag & ECHO))
21347c478bd9Sstevel@tonic-gate 		return;
21357c478bd9Sstevel@tonic-gate 	if (tp->t_modes.c_lflag & ECHOE) {
21367c478bd9Sstevel@tonic-gate 		/*
21377c478bd9Sstevel@tonic-gate 		 * "CRT rubout"; try erasing it from the screen.
21387c478bd9Sstevel@tonic-gate 		 */
21397c478bd9Sstevel@tonic-gate 		if (tp->t_rocount == 0) {
21407c478bd9Sstevel@tonic-gate 			/*
21417c478bd9Sstevel@tonic-gate 			 * After the character being erased was
21427c478bd9Sstevel@tonic-gate 			 * echoed, some data was written to the
21437c478bd9Sstevel@tonic-gate 			 * terminal; we can't erase it cleanly, so we
21447c478bd9Sstevel@tonic-gate 			 * just reprint the whole line as if the user
21457c478bd9Sstevel@tonic-gate 			 * had typed the reprint character.
21467c478bd9Sstevel@tonic-gate 			 */
21477c478bd9Sstevel@tonic-gate 			ldterm_reprint(q, ebsize, tp);
21487c478bd9Sstevel@tonic-gate 			return;
21497c478bd9Sstevel@tonic-gate 		} else {
21507c478bd9Sstevel@tonic-gate 			/*
21517c478bd9Sstevel@tonic-gate 			 * XXX what about escaped characters?
21527c478bd9Sstevel@tonic-gate 			 */
21537c478bd9Sstevel@tonic-gate 			switch (typetab[c]) {
21547c478bd9Sstevel@tonic-gate 
21557c478bd9Sstevel@tonic-gate 			case ORDINARY:
21567c478bd9Sstevel@tonic-gate 				if ((tp->t_modes.c_lflag & XCASE) &&
21577c478bd9Sstevel@tonic-gate 				    omaptab[c])
21587c478bd9Sstevel@tonic-gate 					ldterm_outstring(RUBOUT1, 3, q, ebsize,
215985bb5f1dSis 					    tp);
21607c478bd9Sstevel@tonic-gate 				ldterm_outstring(RUBOUT1, 3, q, ebsize, tp);
21617c478bd9Sstevel@tonic-gate 				break;
21627c478bd9Sstevel@tonic-gate 
21637c478bd9Sstevel@tonic-gate 			case VTAB:
21647c478bd9Sstevel@tonic-gate 			case BACKSPACE:
21657c478bd9Sstevel@tonic-gate 			case CONTROL:
21667c478bd9Sstevel@tonic-gate 			case RETURN:
21677c478bd9Sstevel@tonic-gate 			case NEWLINE:
21687c478bd9Sstevel@tonic-gate 				if ((tp->t_modes.c_lflag & ECHOCTL) &&
21697c478bd9Sstevel@tonic-gate 				    (tp->t_modes.c_lflag & IEXTEN))
21707c478bd9Sstevel@tonic-gate 					ldterm_outstring(RUBOUT2, 6, q, ebsize,
217185bb5f1dSis 					    tp);
21727c478bd9Sstevel@tonic-gate 				break;
21737c478bd9Sstevel@tonic-gate 
21747c478bd9Sstevel@tonic-gate 			case TAB:
21757c478bd9Sstevel@tonic-gate 				if (tp->t_rocount < tp->t_msglen) {
21767c478bd9Sstevel@tonic-gate 					/*
21777c478bd9Sstevel@tonic-gate 					 * While the tab being erased was
21787c478bd9Sstevel@tonic-gate 					 * expanded, some data was written
21797c478bd9Sstevel@tonic-gate 					 * to the terminal; we can't erase
21807c478bd9Sstevel@tonic-gate 					 * it cleanly, so we just reprint
21817c478bd9Sstevel@tonic-gate 					 * the whole line as if the user
21827c478bd9Sstevel@tonic-gate 					 * had typed the reprint character.
21837c478bd9Sstevel@tonic-gate 					 */
21847c478bd9Sstevel@tonic-gate 					ldterm_reprint(q, ebsize, tp);
21857c478bd9Sstevel@tonic-gate 					return;
21867c478bd9Sstevel@tonic-gate 				}
21877c478bd9Sstevel@tonic-gate 				tabcols = ldterm_tabcols(tp);
21887c478bd9Sstevel@tonic-gate 				while (--tabcols >= 0)
21897c478bd9Sstevel@tonic-gate 					ldterm_outchar('\b', q, ebsize, tp);
21907c478bd9Sstevel@tonic-gate 				break;
21917c478bd9Sstevel@tonic-gate 			}
21927c478bd9Sstevel@tonic-gate 		}
21937c478bd9Sstevel@tonic-gate 	} else if ((tp->t_modes.c_lflag & ECHOPRT) &&
219485bb5f1dSis 	    (tp->t_modes.c_lflag & IEXTEN)) {
21957c478bd9Sstevel@tonic-gate 		/*
21967c478bd9Sstevel@tonic-gate 		 * "Printing rubout"; echo it between \ and /.
21977c478bd9Sstevel@tonic-gate 		 */
21987c478bd9Sstevel@tonic-gate 		if (!(tp->t_state & TS_ERASE)) {
21997c478bd9Sstevel@tonic-gate 			ldterm_outchar('\\', q, ebsize, tp);
22007c478bd9Sstevel@tonic-gate 			tp->t_state |= TS_ERASE;
22017c478bd9Sstevel@tonic-gate 		}
22027c478bd9Sstevel@tonic-gate 		(void) ldterm_echo(c, q, ebsize, tp);
22037c478bd9Sstevel@tonic-gate 	} else
22047c478bd9Sstevel@tonic-gate 		(void) ldterm_echo(tp->t_modes.c_cc[VERASE], q, ebsize, tp);
22057c478bd9Sstevel@tonic-gate 	tp->t_rocount--;	/* we "unechoed" this character */
22067c478bd9Sstevel@tonic-gate }
22077c478bd9Sstevel@tonic-gate 
22087c478bd9Sstevel@tonic-gate 
22097c478bd9Sstevel@tonic-gate /*
22107c478bd9Sstevel@tonic-gate  * Find the number of characters the tab we just deleted took up by
22117c478bd9Sstevel@tonic-gate  * zipping through the current line and recomputing the column
22127c478bd9Sstevel@tonic-gate  * number.
22137c478bd9Sstevel@tonic-gate  */
22147c478bd9Sstevel@tonic-gate static int
ldterm_tabcols(ldtermstd_state_t * tp)22157c478bd9Sstevel@tonic-gate ldterm_tabcols(ldtermstd_state_t *tp)
22167c478bd9Sstevel@tonic-gate {
22177c478bd9Sstevel@tonic-gate 	int col;
22187c478bd9Sstevel@tonic-gate 	int i;
22197c478bd9Sstevel@tonic-gate 	mblk_t *bp;
22207c478bd9Sstevel@tonic-gate 	unsigned char *readp, *endp;
22217c478bd9Sstevel@tonic-gate 	unsigned char c;
22227c478bd9Sstevel@tonic-gate 	uchar_t *startp;
22237c478bd9Sstevel@tonic-gate 	char errflg;
22247c478bd9Sstevel@tonic-gate 	uchar_t u8[LDTERM_CS_MAX_BYTE_LENGTH];
22257c478bd9Sstevel@tonic-gate 
22267c478bd9Sstevel@tonic-gate 	col = tp->t_rocol;
22277c478bd9Sstevel@tonic-gate 	/*
22287c478bd9Sstevel@tonic-gate 	 * If we're doing multi-byte stuff, zip through the list of
22297c478bd9Sstevel@tonic-gate 	 * widths to figure out where we are (we've kept track in most
22307c478bd9Sstevel@tonic-gate 	 * cases).
22317c478bd9Sstevel@tonic-gate 	 */
22327c478bd9Sstevel@tonic-gate 	if (tp->t_state & TS_MEUC) {
22337c478bd9Sstevel@tonic-gate 		ASSERT(tp->t_eucp_mp);
22347c478bd9Sstevel@tonic-gate 		bp = tp->t_message;
22357c478bd9Sstevel@tonic-gate 		startp = bp->b_datap->db_base;
22367c478bd9Sstevel@tonic-gate 		readp = tp->t_eucp_mp->b_rptr;
22377c478bd9Sstevel@tonic-gate 		endp = tp->t_eucp;
22387c478bd9Sstevel@tonic-gate 		errflg = (char)0;
22397c478bd9Sstevel@tonic-gate 		while (readp < endp) {
22407c478bd9Sstevel@tonic-gate 			switch (*readp) {
22417c478bd9Sstevel@tonic-gate 			case EUC_TWIDTH:	/* it's a tab */
22427c478bd9Sstevel@tonic-gate 				col |= 07;	/* bump up */
22437c478bd9Sstevel@tonic-gate 				col++;
22447c478bd9Sstevel@tonic-gate 				break;
22457c478bd9Sstevel@tonic-gate 			case EUC_BSWIDTH:	/* backspace */
22467c478bd9Sstevel@tonic-gate 				if (col)
22477c478bd9Sstevel@tonic-gate 					col--;
22487c478bd9Sstevel@tonic-gate 				break;
22497c478bd9Sstevel@tonic-gate 			case EUC_NLWIDTH:	/* newline */
22507c478bd9Sstevel@tonic-gate 				if (tp->t_modes.c_oflag & ONLRET)
22517c478bd9Sstevel@tonic-gate 					col = 0;
22527c478bd9Sstevel@tonic-gate 				break;
22537c478bd9Sstevel@tonic-gate 			case EUC_CRWIDTH:	/* return */
22547c478bd9Sstevel@tonic-gate 				col = 0;
22557c478bd9Sstevel@tonic-gate 				break;
22567c478bd9Sstevel@tonic-gate 			case UNKNOWN_WIDTH:	/* UTF-8 unknown width */
22577c478bd9Sstevel@tonic-gate 				if (tp->t_csdata.codeset_type !=
22587c478bd9Sstevel@tonic-gate 				    LDTERM_CS_TYPE_UTF8 || errflg) {
22597c478bd9Sstevel@tonic-gate 					*readp = 1;
22607c478bd9Sstevel@tonic-gate 					col++;
22617c478bd9Sstevel@tonic-gate 					break;
22627c478bd9Sstevel@tonic-gate 				}
22637c478bd9Sstevel@tonic-gate 				/*
22647c478bd9Sstevel@tonic-gate 				 * Collect the current UTF-8 character bytes
22657c478bd9Sstevel@tonic-gate 				 * from (possibly multiple) data buffers so
22667c478bd9Sstevel@tonic-gate 				 * that we can figure out the display width.
22677c478bd9Sstevel@tonic-gate 				 */
22687c478bd9Sstevel@tonic-gate 				u8[0] = *startp;
22697c478bd9Sstevel@tonic-gate 				for (i = 1; (i < LDTERM_CS_MAX_BYTE_LENGTH) &&
227085bb5f1dSis 				    (*(readp + i) == 0); i++) {
22717c478bd9Sstevel@tonic-gate 					startp++;
22727c478bd9Sstevel@tonic-gate 					if (startp >= bp->b_datap->db_lim) {
22737c478bd9Sstevel@tonic-gate 						if (bp->b_cont) {
22747c478bd9Sstevel@tonic-gate 							bp = bp->b_cont;
22757c478bd9Sstevel@tonic-gate 							startp =
227685bb5f1dSis 							    bp->b_datap->
227785bb5f1dSis 							    db_base;
22787c478bd9Sstevel@tonic-gate 						} else {
22797c478bd9Sstevel@tonic-gate 							*readp = 1;
22807c478bd9Sstevel@tonic-gate 							col++;
22817c478bd9Sstevel@tonic-gate 							break;
22827c478bd9Sstevel@tonic-gate 						}
22837c478bd9Sstevel@tonic-gate 					}
22847c478bd9Sstevel@tonic-gate 					u8[i] = *startp;
22857c478bd9Sstevel@tonic-gate 				}
22867c478bd9Sstevel@tonic-gate 
22877c478bd9Sstevel@tonic-gate 				/* tp->t_eucp_mp contains wrong info?? */
22887c478bd9Sstevel@tonic-gate 				if (*readp == 1)
22897c478bd9Sstevel@tonic-gate 					break;
22907c478bd9Sstevel@tonic-gate 
22917c478bd9Sstevel@tonic-gate 				*readp = ldterm_utf8_width(u8, i);
22927c478bd9Sstevel@tonic-gate 
22937c478bd9Sstevel@tonic-gate 				col += *readp;
22947c478bd9Sstevel@tonic-gate 				readp += (i - 1);
22957c478bd9Sstevel@tonic-gate 				break;
22967c478bd9Sstevel@tonic-gate 			default:
22977c478bd9Sstevel@tonic-gate 				col += *readp;
22987c478bd9Sstevel@tonic-gate 				break;
22997c478bd9Sstevel@tonic-gate 			}
23007c478bd9Sstevel@tonic-gate 			++readp;
23017c478bd9Sstevel@tonic-gate 			++startp;
23027c478bd9Sstevel@tonic-gate 			if (startp >= bp->b_datap->db_lim) {
23037c478bd9Sstevel@tonic-gate 				if (bp->b_cont) {
23047c478bd9Sstevel@tonic-gate 					bp = bp->b_cont;
23057c478bd9Sstevel@tonic-gate 					startp = bp->b_datap->db_base;
23067c478bd9Sstevel@tonic-gate 				} else {
23077c478bd9Sstevel@tonic-gate 					/*
23087c478bd9Sstevel@tonic-gate 					 * This will happen only if
23097c478bd9Sstevel@tonic-gate 					 * tp->t_eucp_mp contains wrong
23107c478bd9Sstevel@tonic-gate 					 * display width info.
23117c478bd9Sstevel@tonic-gate 					 */
23127c478bd9Sstevel@tonic-gate 					errflg = (char)1;
23137c478bd9Sstevel@tonic-gate 					startp--;
23147c478bd9Sstevel@tonic-gate 				}
23157c478bd9Sstevel@tonic-gate 			}
23167c478bd9Sstevel@tonic-gate 		}
23177c478bd9Sstevel@tonic-gate 		goto eucout;	/* finished! */
23187c478bd9Sstevel@tonic-gate 	}
23197c478bd9Sstevel@tonic-gate 	bp = tp->t_message;
23207c478bd9Sstevel@tonic-gate 	do {
23217c478bd9Sstevel@tonic-gate 		readp = bp->b_rptr;
23227c478bd9Sstevel@tonic-gate 		while (readp < bp->b_wptr) {
23237c478bd9Sstevel@tonic-gate 			c = *readp++;
23247c478bd9Sstevel@tonic-gate 			if ((tp->t_modes.c_lflag & ECHOCTL) &&
23257c478bd9Sstevel@tonic-gate 			    (tp->t_modes.c_lflag & IEXTEN)) {
23267c478bd9Sstevel@tonic-gate 				if (c <= 037 && c != '\t' && c != '\n' ||
23277c478bd9Sstevel@tonic-gate 				    c == 0177) {
23287c478bd9Sstevel@tonic-gate 					col += 2;
23297c478bd9Sstevel@tonic-gate 					continue;
23307c478bd9Sstevel@tonic-gate 				}
23317c478bd9Sstevel@tonic-gate 			}
23327c478bd9Sstevel@tonic-gate 			/*
23337c478bd9Sstevel@tonic-gate 			 * Column position calculated here.
23347c478bd9Sstevel@tonic-gate 			 */
23357c478bd9Sstevel@tonic-gate 			switch (typetab[c]) {
23367c478bd9Sstevel@tonic-gate 
23377c478bd9Sstevel@tonic-gate 				/*
23387c478bd9Sstevel@tonic-gate 				 * Ordinary characters; advance by
23397c478bd9Sstevel@tonic-gate 				 * one.
23407c478bd9Sstevel@tonic-gate 				 */
23417c478bd9Sstevel@tonic-gate 			case ORDINARY:
23427c478bd9Sstevel@tonic-gate 				col++;
23437c478bd9Sstevel@tonic-gate 				break;
23447c478bd9Sstevel@tonic-gate 
23457c478bd9Sstevel@tonic-gate 				/*
23467c478bd9Sstevel@tonic-gate 				 * Non-printing characters; nothing
23477c478bd9Sstevel@tonic-gate 				 * happens.
23487c478bd9Sstevel@tonic-gate 				 */
23497c478bd9Sstevel@tonic-gate 			case CONTROL:
23507c478bd9Sstevel@tonic-gate 				break;
23517c478bd9Sstevel@tonic-gate 
23527c478bd9Sstevel@tonic-gate 				/* Backspace */
23537c478bd9Sstevel@tonic-gate 			case BACKSPACE:
23547c478bd9Sstevel@tonic-gate 				if (col != 0)
23557c478bd9Sstevel@tonic-gate 					col--;
23567c478bd9Sstevel@tonic-gate 				break;
23577c478bd9Sstevel@tonic-gate 
23587c478bd9Sstevel@tonic-gate 				/* Newline; column depends on flags. */
23597c478bd9Sstevel@tonic-gate 			case NEWLINE:
23607c478bd9Sstevel@tonic-gate 				if (tp->t_modes.c_oflag & ONLRET)
23617c478bd9Sstevel@tonic-gate 					col = 0;
23627c478bd9Sstevel@tonic-gate 				break;
23637c478bd9Sstevel@tonic-gate 
23647c478bd9Sstevel@tonic-gate 				/* tab */
23657c478bd9Sstevel@tonic-gate 			case TAB:
23667c478bd9Sstevel@tonic-gate 				col |= 07;
23677c478bd9Sstevel@tonic-gate 				col++;
23687c478bd9Sstevel@tonic-gate 				break;
23697c478bd9Sstevel@tonic-gate 
23707c478bd9Sstevel@tonic-gate 				/* vertical motion */
23717c478bd9Sstevel@tonic-gate 			case VTAB:
23727c478bd9Sstevel@tonic-gate 				break;
23737c478bd9Sstevel@tonic-gate 
23747c478bd9Sstevel@tonic-gate 				/* carriage return */
23757c478bd9Sstevel@tonic-gate 			case RETURN:
23767c478bd9Sstevel@tonic-gate 				col = 0;
23777c478bd9Sstevel@tonic-gate 				break;
23787c478bd9Sstevel@tonic-gate 			}
23797c478bd9Sstevel@tonic-gate 		}
23807c478bd9Sstevel@tonic-gate 	} while ((bp = bp->b_cont) != NULL);	/* next block, if any */
23817c478bd9Sstevel@tonic-gate 
23827c478bd9Sstevel@tonic-gate 	/*
23837c478bd9Sstevel@tonic-gate 	 * "col" is now the column number before the tab. "tp->t_col"
23847c478bd9Sstevel@tonic-gate 	 * is still the column number after the tab, since we haven't
23857c478bd9Sstevel@tonic-gate 	 * erased the tab yet. Thus "tp->t_col - col" is the number
23867c478bd9Sstevel@tonic-gate 	 * of positions the tab moved.
23877c478bd9Sstevel@tonic-gate 	 */
23887c478bd9Sstevel@tonic-gate eucout:
23897c478bd9Sstevel@tonic-gate 	col = tp->t_col - col;
23907c478bd9Sstevel@tonic-gate 	if (col > 8)
23917c478bd9Sstevel@tonic-gate 		col = 8;	/* overflow screw */
23927c478bd9Sstevel@tonic-gate 	return (col);
23937c478bd9Sstevel@tonic-gate }
23947c478bd9Sstevel@tonic-gate 
23957c478bd9Sstevel@tonic-gate 
23967c478bd9Sstevel@tonic-gate /*
23977c478bd9Sstevel@tonic-gate  * Erase a single character; We ONLY ONLY deal with ASCII or
23987c478bd9Sstevel@tonic-gate  * single-column single-byte codeset character.  For multi-byte characters,
23997c478bd9Sstevel@tonic-gate  * see "ldterm_csi_erase".
24007c478bd9Sstevel@tonic-gate  */
24017c478bd9Sstevel@tonic-gate static void
ldterm_erase(queue_t * q,size_t ebsize,ldtermstd_state_t * tp)24027c478bd9Sstevel@tonic-gate ldterm_erase(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
24037c478bd9Sstevel@tonic-gate {
24047c478bd9Sstevel@tonic-gate 	int c;
24057c478bd9Sstevel@tonic-gate 
24067c478bd9Sstevel@tonic-gate 	if ((c = ldterm_unget(tp)) != -1) {
24077c478bd9Sstevel@tonic-gate 		ldterm_rubout((unsigned char) c, q, ebsize, tp);
24087c478bd9Sstevel@tonic-gate 		ldterm_trim(tp);
24097c478bd9Sstevel@tonic-gate 		if (tp->t_state & TS_MEUC)
24107c478bd9Sstevel@tonic-gate 			--tp->t_eucp;
24117c478bd9Sstevel@tonic-gate 	}
24127c478bd9Sstevel@tonic-gate }
24137c478bd9Sstevel@tonic-gate 
24147c478bd9Sstevel@tonic-gate 
24157c478bd9Sstevel@tonic-gate /*
24167c478bd9Sstevel@tonic-gate  * Erase an entire word, single-byte EUC only please.
24177c478bd9Sstevel@tonic-gate  */
24187c478bd9Sstevel@tonic-gate static void
ldterm_werase(queue_t * q,size_t ebsize,ldtermstd_state_t * tp)24197c478bd9Sstevel@tonic-gate ldterm_werase(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
24207c478bd9Sstevel@tonic-gate {
24217c478bd9Sstevel@tonic-gate 	int c;
24227c478bd9Sstevel@tonic-gate 
24237c478bd9Sstevel@tonic-gate 	/*
24247c478bd9Sstevel@tonic-gate 	 * Erase trailing white space, if any.
24257c478bd9Sstevel@tonic-gate 	 */
24267c478bd9Sstevel@tonic-gate 	while ((c = ldterm_unget(tp)) == ' ' || c == '\t') {
24277c478bd9Sstevel@tonic-gate 		ldterm_rubout((unsigned char) c, q, ebsize, tp);
24287c478bd9Sstevel@tonic-gate 		ldterm_trim(tp);
24297c478bd9Sstevel@tonic-gate 	}
24307c478bd9Sstevel@tonic-gate 
24317c478bd9Sstevel@tonic-gate 	/*
24327c478bd9Sstevel@tonic-gate 	 * Erase non-white-space characters, if any.
24337c478bd9Sstevel@tonic-gate 	 */
24347c478bd9Sstevel@tonic-gate 	while (c != -1 && c != ' ' && c != '\t') {
24357c478bd9Sstevel@tonic-gate 		ldterm_rubout((unsigned char) c, q, ebsize, tp);
24367c478bd9Sstevel@tonic-gate 		ldterm_trim(tp);
24377c478bd9Sstevel@tonic-gate 		c = ldterm_unget(tp);
24387c478bd9Sstevel@tonic-gate 	}
24397c478bd9Sstevel@tonic-gate 	if (c != -1) {
24407c478bd9Sstevel@tonic-gate 		/*
24417c478bd9Sstevel@tonic-gate 		 * We removed one too many characters; put the last
24427c478bd9Sstevel@tonic-gate 		 * one back.
24437c478bd9Sstevel@tonic-gate 		 */
24447c478bd9Sstevel@tonic-gate 		tp->t_endmsg->b_wptr++;	/* put 'c' back */
24457c478bd9Sstevel@tonic-gate 		tp->t_msglen++;
24467c478bd9Sstevel@tonic-gate 	}
24477c478bd9Sstevel@tonic-gate }
24487c478bd9Sstevel@tonic-gate 
24497c478bd9Sstevel@tonic-gate 
24507c478bd9Sstevel@tonic-gate /*
24517c478bd9Sstevel@tonic-gate  * ldterm_csi_werase - This is multi-byte equivalent of "word erase".
24527c478bd9Sstevel@tonic-gate  * "Word erase" only makes sense in languages which space between words,
24537c478bd9Sstevel@tonic-gate  * and it's presumptuous for us to attempt "word erase" when we don't
24547c478bd9Sstevel@tonic-gate  * know anything about what's really going on.  It makes no sense for
24557c478bd9Sstevel@tonic-gate  * many languages, as the criteria for defining words and tokens may
24567c478bd9Sstevel@tonic-gate  * be completely different.
24577c478bd9Sstevel@tonic-gate  *
24587c478bd9Sstevel@tonic-gate  * In the TS_MEUC case (which is how we got here), we define a token to
24597c478bd9Sstevel@tonic-gate  * be space- or tab-delimited, and erase one of them.  It helps to
24607c478bd9Sstevel@tonic-gate  * have this for command lines, but it's otherwise useless for text
24617c478bd9Sstevel@tonic-gate  * editing applications; you need more sophistication than we can
24627c478bd9Sstevel@tonic-gate  * provide here.
24637c478bd9Sstevel@tonic-gate  */
24647c478bd9Sstevel@tonic-gate static void
ldterm_csi_werase(queue_t * q,size_t ebsize,ldtermstd_state_t * tp)24657c478bd9Sstevel@tonic-gate ldterm_csi_werase(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
24667c478bd9Sstevel@tonic-gate {
24677c478bd9Sstevel@tonic-gate 	int c, i;
24687c478bd9Sstevel@tonic-gate 	int len;
24697c478bd9Sstevel@tonic-gate 	uchar_t *ip;
24707c478bd9Sstevel@tonic-gate 	uchar_t	u8[LDTERM_CS_MAX_BYTE_LENGTH];
24717c478bd9Sstevel@tonic-gate 	uchar_t	u8_2[LDTERM_CS_MAX_BYTE_LENGTH];
24727c478bd9Sstevel@tonic-gate 
24737c478bd9Sstevel@tonic-gate 	/*
24747c478bd9Sstevel@tonic-gate 	 * ip points to the width of the actual bytes.  t_eucp points
24757c478bd9Sstevel@tonic-gate 	 * one byte beyond, where the next thing will be inserted.
24767c478bd9Sstevel@tonic-gate 	 */
24777c478bd9Sstevel@tonic-gate 	ip = tp->t_eucp - 1;
24787c478bd9Sstevel@tonic-gate 	/*
24797c478bd9Sstevel@tonic-gate 	 * Erase trailing white space, if any.
24807c478bd9Sstevel@tonic-gate 	 */
24817c478bd9Sstevel@tonic-gate 	while ((c = ldterm_unget(tp)) == ' ' || c == '\t') {
24827c478bd9Sstevel@tonic-gate 		tp->t_eucp--;
24837c478bd9Sstevel@tonic-gate 		ldterm_rubout((unsigned char) c, q, ebsize, tp);
24847c478bd9Sstevel@tonic-gate 		ldterm_trim(tp);
24857c478bd9Sstevel@tonic-gate 		--ip;
24867c478bd9Sstevel@tonic-gate 	}
24877c478bd9Sstevel@tonic-gate 
24887c478bd9Sstevel@tonic-gate 	/*
24897c478bd9Sstevel@tonic-gate 	 * Erase non-white-space characters, if any.  The outer loop
24907c478bd9Sstevel@tonic-gate 	 * bops through each byte in the buffer. Multi-byte is removed, as
24917c478bd9Sstevel@tonic-gate 	 * is ASCII, one byte at a time. The inner loop (for) is only
24927c478bd9Sstevel@tonic-gate 	 * executed for first bytes of multi-byte.  The inner loop erases
24937c478bd9Sstevel@tonic-gate 	 * the number of columns required for the multi-byte char.  We check
24947c478bd9Sstevel@tonic-gate 	 * for ASCII first, and ldterm_rubout knows about ASCII.
24957c478bd9Sstevel@tonic-gate 	 */
24967c478bd9Sstevel@tonic-gate 	len = 0;
24977c478bd9Sstevel@tonic-gate 	while (c != -1 && c != ' ' && c != '\t') {
24987c478bd9Sstevel@tonic-gate 		tp->t_eucp--;
24997c478bd9Sstevel@tonic-gate 		if (len < LDTERM_CS_MAX_BYTE_LENGTH) {
25007c478bd9Sstevel@tonic-gate 			u8[len++] = (uchar_t)c;
25017c478bd9Sstevel@tonic-gate 		}
25027c478bd9Sstevel@tonic-gate 		/*
25037c478bd9Sstevel@tonic-gate 		 * Unlike EUC, except the leading byte, some bytes of
25047c478bd9Sstevel@tonic-gate 		 * a non-EUC multi-byte characters are in the ASCII code
25057c478bd9Sstevel@tonic-gate 		 * range, esp., 0x41 ~ 0x7a. Thus, we cannot simply check
25067c478bd9Sstevel@tonic-gate 		 * ISASCII().
25077c478bd9Sstevel@tonic-gate 		 * Checking the (*ip == 1 || *ip == 2 || *ip > UNKNOWN_WIDTH)
25087c478bd9Sstevel@tonic-gate 		 * will ensure that it is a single byte character (even though
25097c478bd9Sstevel@tonic-gate 		 * it is on display width not byte length) and can be further
25107c478bd9Sstevel@tonic-gate 		 * checked whether it is an ASCII character or not.
25117c478bd9Sstevel@tonic-gate 		 *
25127c478bd9Sstevel@tonic-gate 		 * When ECHOCTL is on and 'c' is an ASCII control character,
25137c478bd9Sstevel@tonic-gate 		 * *ip == 2 happens.
25147c478bd9Sstevel@tonic-gate 		 */
25157c478bd9Sstevel@tonic-gate 		if ((*ip == 1 || *ip == 2 || *ip > UNKNOWN_WIDTH) &&
25167c478bd9Sstevel@tonic-gate 		    ISASCII(c)) {
25177c478bd9Sstevel@tonic-gate 			ldterm_rubout((unsigned char) c, q, ebsize, tp);
25187c478bd9Sstevel@tonic-gate 			len = 0;
25197c478bd9Sstevel@tonic-gate 		} else if (*ip) {
25207c478bd9Sstevel@tonic-gate 			if (*ip == UNKNOWN_WIDTH) {
25217c478bd9Sstevel@tonic-gate 				if (tp->t_csdata.codeset_type ==
25227c478bd9Sstevel@tonic-gate 				    LDTERM_CS_TYPE_UTF8) {
25237c478bd9Sstevel@tonic-gate 					for (i = 0; i < len; i++)
25247c478bd9Sstevel@tonic-gate 						u8_2[i] = u8[len - i - 1];
25257c478bd9Sstevel@tonic-gate 					*ip = ldterm_utf8_width(u8_2, len);
25267c478bd9Sstevel@tonic-gate 				} else {
25277c478bd9Sstevel@tonic-gate 					*ip = 1;
25287c478bd9Sstevel@tonic-gate 				}
25297c478bd9Sstevel@tonic-gate 			}
25307c478bd9Sstevel@tonic-gate 			/*
25317c478bd9Sstevel@tonic-gate 			 * erase for number of columns required for
25327c478bd9Sstevel@tonic-gate 			 * this multi-byte character. Hopefully, matches
25337c478bd9Sstevel@tonic-gate 			 * ldterm_dispwidth!
25347c478bd9Sstevel@tonic-gate 			 */
25357c478bd9Sstevel@tonic-gate 			for (i = 0; i < (int)*ip; i++)
25367c478bd9Sstevel@tonic-gate 				ldterm_rubout(' ', q, ebsize, tp);
25377c478bd9Sstevel@tonic-gate 			len = 0;
25387c478bd9Sstevel@tonic-gate 		}
25397c478bd9Sstevel@tonic-gate 		ldterm_trim(tp);
25407c478bd9Sstevel@tonic-gate 		--ip;
25417c478bd9Sstevel@tonic-gate 		c = ldterm_unget(tp);
25427c478bd9Sstevel@tonic-gate 	}
25437c478bd9Sstevel@tonic-gate 	if (c != -1) {
25447c478bd9Sstevel@tonic-gate 		/*
25457c478bd9Sstevel@tonic-gate 		 * We removed one too many characters; put the last
25467c478bd9Sstevel@tonic-gate 		 * one back.
25477c478bd9Sstevel@tonic-gate 		 */
25487c478bd9Sstevel@tonic-gate 		tp->t_endmsg->b_wptr++;	/* put 'c' back */
25497c478bd9Sstevel@tonic-gate 		tp->t_msglen++;
25507c478bd9Sstevel@tonic-gate 	}
25517c478bd9Sstevel@tonic-gate }
25527c478bd9Sstevel@tonic-gate 
25537c478bd9Sstevel@tonic-gate 
25547c478bd9Sstevel@tonic-gate /*
25557c478bd9Sstevel@tonic-gate  * Kill an entire line, erasing each character one-by-one (if ECHOKE
25567c478bd9Sstevel@tonic-gate  * is set) or just echoing the kill character, followed by a newline
25577c478bd9Sstevel@tonic-gate  * (if ECHOK is set).  Multi-byte processing is included here.
25587c478bd9Sstevel@tonic-gate  */
25597c478bd9Sstevel@tonic-gate 
25607c478bd9Sstevel@tonic-gate static void
ldterm_kill(queue_t * q,size_t ebsize,ldtermstd_state_t * tp)25617c478bd9Sstevel@tonic-gate ldterm_kill(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
25627c478bd9Sstevel@tonic-gate {
25637c478bd9Sstevel@tonic-gate 	int c, i;
25647c478bd9Sstevel@tonic-gate 	int len;
25657c478bd9Sstevel@tonic-gate 	uchar_t *ip;
25667c478bd9Sstevel@tonic-gate 	uchar_t u8[LDTERM_CS_MAX_BYTE_LENGTH];
25677c478bd9Sstevel@tonic-gate 	uchar_t u8_2[LDTERM_CS_MAX_BYTE_LENGTH];
25687c478bd9Sstevel@tonic-gate 
25697c478bd9Sstevel@tonic-gate 	if ((tp->t_modes.c_lflag & ECHOKE) &&
25707c478bd9Sstevel@tonic-gate 	    (tp->t_modes.c_lflag & IEXTEN) &&
25717c478bd9Sstevel@tonic-gate 	    (tp->t_msglen == tp->t_rocount)) {
25727c478bd9Sstevel@tonic-gate 		if (tp->t_state & TS_MEUC) {
25737c478bd9Sstevel@tonic-gate 			ip = tp->t_eucp - 1;
25747c478bd9Sstevel@tonic-gate 			/*
25757c478bd9Sstevel@tonic-gate 			 * This loop similar to "ldterm_csi_werase" above.
25767c478bd9Sstevel@tonic-gate 			 */
25777c478bd9Sstevel@tonic-gate 			len = 0;
25787c478bd9Sstevel@tonic-gate 			while ((c = ldterm_unget(tp)) != (-1)) {
25797c478bd9Sstevel@tonic-gate 				tp->t_eucp--;
25807c478bd9Sstevel@tonic-gate 				if (len < LDTERM_CS_MAX_BYTE_LENGTH) {
25817c478bd9Sstevel@tonic-gate 					u8[len++] = (uchar_t)c;
25827c478bd9Sstevel@tonic-gate 				}
25837c478bd9Sstevel@tonic-gate 				if ((*ip == 1 || *ip == 2 ||
25847c478bd9Sstevel@tonic-gate 				    *ip > UNKNOWN_WIDTH) && ISASCII(c)) {
25857c478bd9Sstevel@tonic-gate 					ldterm_rubout((unsigned char) c, q,
258685bb5f1dSis 					    ebsize, tp);
25877c478bd9Sstevel@tonic-gate 					len = 0;
25887c478bd9Sstevel@tonic-gate 				} else if (*ip) {
25897c478bd9Sstevel@tonic-gate 					if (*ip == UNKNOWN_WIDTH) {
25907c478bd9Sstevel@tonic-gate 						if (tp->t_csdata.codeset_type
25917c478bd9Sstevel@tonic-gate 						    == LDTERM_CS_TYPE_UTF8) {
25927c478bd9Sstevel@tonic-gate 							for (i = 0; i < len;
25937c478bd9Sstevel@tonic-gate 							    i++)
25947c478bd9Sstevel@tonic-gate 								u8_2[i] =
25957c478bd9Sstevel@tonic-gate 								    u8[len-i-1];
25967c478bd9Sstevel@tonic-gate 							*ip = ldterm_utf8_width(
259785bb5f1dSis 							    u8_2, len);
25987c478bd9Sstevel@tonic-gate 						} else {
25997c478bd9Sstevel@tonic-gate 							*ip = 1;
26007c478bd9Sstevel@tonic-gate 						}
26017c478bd9Sstevel@tonic-gate 					}
26027c478bd9Sstevel@tonic-gate 					for (i = 0; i < (int)*ip; i++)
26037c478bd9Sstevel@tonic-gate 						ldterm_rubout(' ', q, ebsize,
26047c478bd9Sstevel@tonic-gate 						    tp);
26057c478bd9Sstevel@tonic-gate 					len = 0;
26067c478bd9Sstevel@tonic-gate 				}
26077c478bd9Sstevel@tonic-gate 				ldterm_trim(tp);
26087c478bd9Sstevel@tonic-gate 				--ip;
26097c478bd9Sstevel@tonic-gate 			}
26107c478bd9Sstevel@tonic-gate 		} else {
26117c478bd9Sstevel@tonic-gate 			while ((c = ldterm_unget(tp)) != -1) {
26127c478bd9Sstevel@tonic-gate 				ldterm_rubout((unsigned char) c, q, ebsize, tp);
26137c478bd9Sstevel@tonic-gate 				ldterm_trim(tp);
26147c478bd9Sstevel@tonic-gate 			}
26157c478bd9Sstevel@tonic-gate 		}
26167c478bd9Sstevel@tonic-gate 	} else {
26177c478bd9Sstevel@tonic-gate 		(void) ldterm_echo(tp->t_modes.c_cc[VKILL], q, ebsize, tp);
26187c478bd9Sstevel@tonic-gate 		if (tp->t_modes.c_lflag & ECHOK)
26197c478bd9Sstevel@tonic-gate 			(void) ldterm_echo('\n', q, ebsize, tp);
26207c478bd9Sstevel@tonic-gate 		while (ldterm_unget(tp) != -1) {
26217c478bd9Sstevel@tonic-gate 			if (tp->t_state & TS_MEUC)
26227c478bd9Sstevel@tonic-gate 				--tp->t_eucp;
26237c478bd9Sstevel@tonic-gate 			ldterm_trim(tp);
26247c478bd9Sstevel@tonic-gate 		}
26257c478bd9Sstevel@tonic-gate 		tp->t_rocount = 0;
26267c478bd9Sstevel@tonic-gate 		if (tp->t_state & TS_MEUC)
26277c478bd9Sstevel@tonic-gate 			tp->t_eucp = tp->t_eucp_mp->b_rptr;
26287c478bd9Sstevel@tonic-gate 	}
26297c478bd9Sstevel@tonic-gate 	tp->t_state &= ~(TS_QUOT|TS_ERASE|TS_SLNCH);
26307c478bd9Sstevel@tonic-gate }
26317c478bd9Sstevel@tonic-gate 
26327c478bd9Sstevel@tonic-gate 
26337c478bd9Sstevel@tonic-gate /*
26347c478bd9Sstevel@tonic-gate  * Reprint the current input line. We assume c_cc has already been
26357c478bd9Sstevel@tonic-gate  * checked. XXX just the current line, not the whole queue? What
26367c478bd9Sstevel@tonic-gate  * about DEFECHO mode?
26377c478bd9Sstevel@tonic-gate  */
26387c478bd9Sstevel@tonic-gate static void
ldterm_reprint(queue_t * q,size_t ebsize,ldtermstd_state_t * tp)26397c478bd9Sstevel@tonic-gate ldterm_reprint(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
26407c478bd9Sstevel@tonic-gate {
26417c478bd9Sstevel@tonic-gate 	mblk_t *bp;
26427c478bd9Sstevel@tonic-gate 	unsigned char *readp;
26437c478bd9Sstevel@tonic-gate 
26447c478bd9Sstevel@tonic-gate 	if (tp->t_modes.c_cc[VREPRINT] != (unsigned char) 0)
26457c478bd9Sstevel@tonic-gate 		(void) ldterm_echo(tp->t_modes.c_cc[VREPRINT], q, ebsize, tp);
26467c478bd9Sstevel@tonic-gate 	ldterm_outchar('\n', q, ebsize, tp);
26477c478bd9Sstevel@tonic-gate 
26487c478bd9Sstevel@tonic-gate 	bp = tp->t_message;
26497c478bd9Sstevel@tonic-gate 	do {
26507c478bd9Sstevel@tonic-gate 		readp = bp->b_rptr;
26517c478bd9Sstevel@tonic-gate 		while (readp < bp->b_wptr)
26527c478bd9Sstevel@tonic-gate 			(void) ldterm_echo(*readp++, q, ebsize, tp);
26537c478bd9Sstevel@tonic-gate 	} while ((bp = bp->b_cont) != NULL);	/* next block, if any */
26547c478bd9Sstevel@tonic-gate 
26557c478bd9Sstevel@tonic-gate 	tp->t_state &= ~TS_ERASE;
26567c478bd9Sstevel@tonic-gate 	tp->t_rocount = tp->t_msglen;	/* we reechoed the entire line */
26577c478bd9Sstevel@tonic-gate 	tp->t_rocol = 0;
26587c478bd9Sstevel@tonic-gate }
26597c478bd9Sstevel@tonic-gate 
26607c478bd9Sstevel@tonic-gate 
26617c478bd9Sstevel@tonic-gate /*
26627c478bd9Sstevel@tonic-gate  * Non canonical processing. Called with q locked from  ldtermrsrv.
26637c478bd9Sstevel@tonic-gate  *
26647c478bd9Sstevel@tonic-gate  */
26657c478bd9Sstevel@tonic-gate static mblk_t *
ldterm_dononcanon(mblk_t * bp,mblk_t * bpt,size_t ebsize,queue_t * q,ldtermstd_state_t * tp)26667c478bd9Sstevel@tonic-gate ldterm_dononcanon(mblk_t *bp, mblk_t *bpt, size_t ebsize, queue_t *q,
26677c478bd9Sstevel@tonic-gate     ldtermstd_state_t *tp)
26687c478bd9Sstevel@tonic-gate {
26697c478bd9Sstevel@tonic-gate 	queue_t *wrq = WR(q);
26707c478bd9Sstevel@tonic-gate 	unsigned char *rptr;
26717c478bd9Sstevel@tonic-gate 	size_t bytes_in_bp;
26727c478bd9Sstevel@tonic-gate 	size_t roomleft;
26737c478bd9Sstevel@tonic-gate 	size_t bytes_to_move;
26747c478bd9Sstevel@tonic-gate 	int free_flag = 0;
26757c478bd9Sstevel@tonic-gate 
26767c478bd9Sstevel@tonic-gate 	if (tp->t_modes.c_lflag & (ECHO|ECHONL|IEXTEN)) {
26777c478bd9Sstevel@tonic-gate 		unsigned char *wptr;
26787c478bd9Sstevel@tonic-gate 		unsigned char c;
26797c478bd9Sstevel@tonic-gate 
26807c478bd9Sstevel@tonic-gate 		/*
26817c478bd9Sstevel@tonic-gate 		 * Either we must echo the characters, or we must
26827c478bd9Sstevel@tonic-gate 		 * echo NL, or we must check for VLNEXT. Process
26837c478bd9Sstevel@tonic-gate 		 * characters one at a time.
26847c478bd9Sstevel@tonic-gate 		 */
26857c478bd9Sstevel@tonic-gate 		rptr = bp->b_rptr;
26867c478bd9Sstevel@tonic-gate 		wptr = bp->b_rptr;
26877c478bd9Sstevel@tonic-gate 		while (rptr < bp->b_wptr) {
26887c478bd9Sstevel@tonic-gate 			c = *rptr++;
26897c478bd9Sstevel@tonic-gate 			/*
26907c478bd9Sstevel@tonic-gate 			 * If this character is the literal next
26917c478bd9Sstevel@tonic-gate 			 * character, echo it as '^' and backspace
26927c478bd9Sstevel@tonic-gate 			 * over it if echoing is enabled, indicate
26937c478bd9Sstevel@tonic-gate 			 * that the next character is to be treated
26947c478bd9Sstevel@tonic-gate 			 * literally, and remove the LNEXT from the
26957c478bd9Sstevel@tonic-gate 			 * input stream.
26967c478bd9Sstevel@tonic-gate 			 *
26977c478bd9Sstevel@tonic-gate 			 * If the *previous* character was the literal
26987c478bd9Sstevel@tonic-gate 			 * next character, don't check whether this
26997c478bd9Sstevel@tonic-gate 			 * is a literal next or not.
27007c478bd9Sstevel@tonic-gate 			 */
27017c478bd9Sstevel@tonic-gate 			if ((tp->t_modes.c_lflag & IEXTEN) &&
27027c478bd9Sstevel@tonic-gate 			    !(tp->t_state & TS_SLNCH) &&
27037c478bd9Sstevel@tonic-gate 			    c != _POSIX_VDISABLE &&
27047c478bd9Sstevel@tonic-gate 			    c == tp->t_modes.c_cc[VLNEXT]) {
27057c478bd9Sstevel@tonic-gate 				if (tp->t_modes.c_lflag & ECHO)
27067c478bd9Sstevel@tonic-gate 					ldterm_outstring(
27077c478bd9Sstevel@tonic-gate 					    (unsigned char *)"^\b",
270885bb5f1dSis 					    2, wrq, ebsize, tp);
27097c478bd9Sstevel@tonic-gate 				tp->t_state |= TS_SLNCH;
27107c478bd9Sstevel@tonic-gate 				continue;	/* and ignore it */
27117c478bd9Sstevel@tonic-gate 			}
27127c478bd9Sstevel@tonic-gate 			/*
27137c478bd9Sstevel@tonic-gate 			 * Not a "literal next" character, so it
27147c478bd9Sstevel@tonic-gate 			 * should show up as input. If it was
27157c478bd9Sstevel@tonic-gate 			 * literal-nexted, turn off the literal-next
27167c478bd9Sstevel@tonic-gate 			 * flag.
27177c478bd9Sstevel@tonic-gate 			 */
27187c478bd9Sstevel@tonic-gate 			tp->t_state &= ~TS_SLNCH;
27197c478bd9Sstevel@tonic-gate 			*wptr++ = c;
27207c478bd9Sstevel@tonic-gate 			if (tp->t_modes.c_lflag & ECHO) {
27217c478bd9Sstevel@tonic-gate 				/*
27227c478bd9Sstevel@tonic-gate 				 * Echo the character.
27237c478bd9Sstevel@tonic-gate 				 */
27247c478bd9Sstevel@tonic-gate 				(void) ldterm_echo(c, wrq, ebsize, tp);
27257c478bd9Sstevel@tonic-gate 			} else if (tp->t_modes.c_lflag & ECHONL) {
27267c478bd9Sstevel@tonic-gate 				/*
27277c478bd9Sstevel@tonic-gate 				 * Echo NL, even though ECHO is not
27287c478bd9Sstevel@tonic-gate 				 * set.
27297c478bd9Sstevel@tonic-gate 				 */
27307c478bd9Sstevel@tonic-gate 				if (c == '\n')
273185bb5f1dSis 					ldterm_outchar('\n', wrq, 1, tp);
27327c478bd9Sstevel@tonic-gate 			}
27337c478bd9Sstevel@tonic-gate 		}
27347c478bd9Sstevel@tonic-gate 		bp->b_wptr = wptr;
27357c478bd9Sstevel@tonic-gate 	} else {
27367c478bd9Sstevel@tonic-gate 		/*
27377c478bd9Sstevel@tonic-gate 		 * If there are any characters in this buffer, and
27387c478bd9Sstevel@tonic-gate 		 * the first of them was literal-nexted, turn off the
27397c478bd9Sstevel@tonic-gate 		 * literal-next flag.
27407c478bd9Sstevel@tonic-gate 		 */
27417c478bd9Sstevel@tonic-gate 		if (bp->b_rptr != bp->b_wptr)
27427c478bd9Sstevel@tonic-gate 			tp->t_state &= ~TS_SLNCH;
27437c478bd9Sstevel@tonic-gate 	}
27447c478bd9Sstevel@tonic-gate 
27457c478bd9Sstevel@tonic-gate 	ASSERT(bp->b_wptr >= bp->b_rptr);
27467c478bd9Sstevel@tonic-gate 	bytes_in_bp = bp->b_wptr - bp->b_rptr;
27477c478bd9Sstevel@tonic-gate 	rptr = bp->b_rptr;
27487c478bd9Sstevel@tonic-gate 	while (bytes_in_bp != 0) {
27497c478bd9Sstevel@tonic-gate 		roomleft = bpt->b_datap->db_lim - bpt->b_wptr;
27507c478bd9Sstevel@tonic-gate 		if (roomleft == 0) {
27517c478bd9Sstevel@tonic-gate 			/*
27527c478bd9Sstevel@tonic-gate 			 * No more room in this mblk; save this one
27537c478bd9Sstevel@tonic-gate 			 * away, and allocate a new one.
27547c478bd9Sstevel@tonic-gate 			 */
27557c478bd9Sstevel@tonic-gate 			if ((bpt = allocb(IBSIZE, BPRI_MED)) == NULL) {
27567c478bd9Sstevel@tonic-gate 				freeb(bp);
27577c478bd9Sstevel@tonic-gate 				DEBUG4(("ldterm_do_noncanon: allcob failed\n"));
27587c478bd9Sstevel@tonic-gate 				return (bpt);
27597c478bd9Sstevel@tonic-gate 			}
27607c478bd9Sstevel@tonic-gate 			/*
27617c478bd9Sstevel@tonic-gate 			 * Chain the new one to the end of the old
27627c478bd9Sstevel@tonic-gate 			 * one, and mark it as the last block in the
27637c478bd9Sstevel@tonic-gate 			 * current lump.
27647c478bd9Sstevel@tonic-gate 			 */
27657c478bd9Sstevel@tonic-gate 			tp->t_endmsg->b_cont = bpt;
27667c478bd9Sstevel@tonic-gate 			tp->t_endmsg = bpt;
27677c478bd9Sstevel@tonic-gate 			roomleft = IBSIZE;
27687c478bd9Sstevel@tonic-gate 		}
27697c478bd9Sstevel@tonic-gate 		DEBUG5(("roomleft=%d, bytes_in_bp=%d, tp->t_rd_request=%d\n",
277085bb5f1dSis 		    roomleft, bytes_in_bp, tp->t_rd_request));
27717c478bd9Sstevel@tonic-gate 		/*
27727c478bd9Sstevel@tonic-gate 		 * if there is a read pending before this data got
27737c478bd9Sstevel@tonic-gate 		 * here move bytes according to the minimum of room
27747c478bd9Sstevel@tonic-gate 		 * left in this buffer, bytes in the message and byte
27757c478bd9Sstevel@tonic-gate 		 * count requested in the read. If there is no read
27767c478bd9Sstevel@tonic-gate 		 * pending, move the minimum of the first two
27777c478bd9Sstevel@tonic-gate 		 */
27787c478bd9Sstevel@tonic-gate 		if (tp->t_rd_request == 0)
27797c478bd9Sstevel@tonic-gate 			bytes_to_move = MIN(roomleft, bytes_in_bp);
27807c478bd9Sstevel@tonic-gate 		else
27817c478bd9Sstevel@tonic-gate 			bytes_to_move =
27827c478bd9Sstevel@tonic-gate 			    MIN(MIN(roomleft, bytes_in_bp), tp->t_rd_request);
27837c478bd9Sstevel@tonic-gate 		DEBUG5(("Bytes to move = %lu\n", bytes_to_move));
27847c478bd9Sstevel@tonic-gate 		if (bytes_to_move == 0)
27857c478bd9Sstevel@tonic-gate 			break;
27867c478bd9Sstevel@tonic-gate 		bcopy(rptr, bpt->b_wptr, bytes_to_move);
27877c478bd9Sstevel@tonic-gate 		bpt->b_wptr += bytes_to_move;
27887c478bd9Sstevel@tonic-gate 		rptr += bytes_to_move;
27897c478bd9Sstevel@tonic-gate 		tp->t_msglen += bytes_to_move;
27907c478bd9Sstevel@tonic-gate 		bytes_in_bp -= bytes_to_move;
27917c478bd9Sstevel@tonic-gate 	}
27927c478bd9Sstevel@tonic-gate 	if (bytes_in_bp == 0) {
27937c478bd9Sstevel@tonic-gate 		DEBUG4(("bytes_in_bp is zero\n"));
27947c478bd9Sstevel@tonic-gate 		freeb(bp);
27957c478bd9Sstevel@tonic-gate 	} else
27967c478bd9Sstevel@tonic-gate 		free_flag = 1;	/* for debugging olny */
27977c478bd9Sstevel@tonic-gate 
27987c478bd9Sstevel@tonic-gate 	DEBUG4(("ldterm_do_noncanon: VMIN = %d, VTIME = %d, msglen = %d, \
27997c478bd9Sstevel@tonic-gate 		tid = %d\n", V_MIN, V_TIME, tp->t_msglen, tp->t_vtid));
28007c478bd9Sstevel@tonic-gate 	/*
28017c478bd9Sstevel@tonic-gate 	 * If there is a pending read request at the stream head we
28027c478bd9Sstevel@tonic-gate 	 * need to do VMIN/VTIME processing. The four possible cases
28037c478bd9Sstevel@tonic-gate 	 * are:
28047c478bd9Sstevel@tonic-gate 	 *	MIN = 0, TIME > 0
28057c478bd9Sstevel@tonic-gate 	 *	MIN = >, TIME = 0
28067c478bd9Sstevel@tonic-gate 	 *	MIN > 0, TIME > 0
28077c478bd9Sstevel@tonic-gate 	 *	MIN = 0, TIME = 0
28087c478bd9Sstevel@tonic-gate 	 * If we can satisfy VMIN, send it up, and start a new
28097c478bd9Sstevel@tonic-gate 	 * timer if necessary.  These four cases of VMIN/VTIME
28107c478bd9Sstevel@tonic-gate 	 * are also dealt with in the write side put routine
28117c478bd9Sstevel@tonic-gate 	 * when the M_READ is first seen.
28127c478bd9Sstevel@tonic-gate 	 */
28137c478bd9Sstevel@tonic-gate 
28147c478bd9Sstevel@tonic-gate 	DEBUG4(("Incoming data while M_READ'ing\n"));
28157c478bd9Sstevel@tonic-gate 	/*
28167c478bd9Sstevel@tonic-gate 	 * Case 1:  Any data will satisfy the read, so send
28177c478bd9Sstevel@tonic-gate 	 * it upstream.
28187c478bd9Sstevel@tonic-gate 	 */
28197c478bd9Sstevel@tonic-gate 	if (V_MIN == 0 && V_TIME > 0) {
28207c478bd9Sstevel@tonic-gate 		if (tp->t_msglen)
28217c478bd9Sstevel@tonic-gate 			vmin_satisfied(q, tp, 1);
28227c478bd9Sstevel@tonic-gate 		else {
28237c478bd9Sstevel@tonic-gate 			/* EMPTY */
28247c478bd9Sstevel@tonic-gate 			DEBUG4(("ldterm_do_noncanon called, but no data!\n"));
28257c478bd9Sstevel@tonic-gate 		}
28267c478bd9Sstevel@tonic-gate 		/*
28277c478bd9Sstevel@tonic-gate 		 * Case 2:  This should never time out, so
28287c478bd9Sstevel@tonic-gate 		 * until there's enough data, do nothing.
28297c478bd9Sstevel@tonic-gate 		 */
28307c478bd9Sstevel@tonic-gate 	} else if (V_MIN > 0 && V_TIME == 0) {
28317c478bd9Sstevel@tonic-gate 		if (tp->t_msglen >= (int)V_MIN)
28327c478bd9Sstevel@tonic-gate 			vmin_satisfied(q, tp, 1);
28337c478bd9Sstevel@tonic-gate 
28347c478bd9Sstevel@tonic-gate 		/*
28357c478bd9Sstevel@tonic-gate 		 * Case 3:  If MIN is satisfied, send it up.
28367c478bd9Sstevel@tonic-gate 		 * Also, remember to start a new timer *every*
28377c478bd9Sstevel@tonic-gate 		 * time we see something if MIN isn't
28387c478bd9Sstevel@tonic-gate 		 * safisfied
28397c478bd9Sstevel@tonic-gate 		 */
28407c478bd9Sstevel@tonic-gate 	} else if (V_MIN > 0 && V_TIME > 0) {
28417c478bd9Sstevel@tonic-gate 		if (tp->t_msglen >= (int)V_MIN)
28427c478bd9Sstevel@tonic-gate 			vmin_satisfied(q, tp, 1);
28437c478bd9Sstevel@tonic-gate 		else
28447c478bd9Sstevel@tonic-gate 			vmin_settimer(q);
28457c478bd9Sstevel@tonic-gate 		/*
28467c478bd9Sstevel@tonic-gate 		 * Case 4:  Not possible.  This request
28477c478bd9Sstevel@tonic-gate 		 * should always be satisfied from the write
28487c478bd9Sstevel@tonic-gate 		 * side, left here for debugging.
28497c478bd9Sstevel@tonic-gate 		 */
28507c478bd9Sstevel@tonic-gate 	} else {	/* V_MIN == 0 && V_TIME == 0 */
28517c478bd9Sstevel@tonic-gate 			vmin_satisfied(q, tp, 1);
28527c478bd9Sstevel@tonic-gate 	}
28537c478bd9Sstevel@tonic-gate 
28547c478bd9Sstevel@tonic-gate 	if (free_flag) {
28557c478bd9Sstevel@tonic-gate 		/* EMPTY */
28567c478bd9Sstevel@tonic-gate 		DEBUG4(("CAUTION message block not freed\n"));
28577c478bd9Sstevel@tonic-gate 	}
28587c478bd9Sstevel@tonic-gate 	return (newmsg(tp));
28597c478bd9Sstevel@tonic-gate }
28607c478bd9Sstevel@tonic-gate 
28617c478bd9Sstevel@tonic-gate 
28627c478bd9Sstevel@tonic-gate /*
28637c478bd9Sstevel@tonic-gate  * Echo a typed byte to the terminal.  Returns the number of bytes
28647c478bd9Sstevel@tonic-gate  * printed. Bytes of EUC characters drop through the ECHOCTL stuff
28657c478bd9Sstevel@tonic-gate  * and are just output as themselves.
28667c478bd9Sstevel@tonic-gate  */
28677c478bd9Sstevel@tonic-gate static int
ldterm_echo(uchar_t c,queue_t * q,size_t ebsize,ldtermstd_state_t * tp)28687c478bd9Sstevel@tonic-gate ldterm_echo(uchar_t c, queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
28697c478bd9Sstevel@tonic-gate {
28707c478bd9Sstevel@tonic-gate 	int i;
28717c478bd9Sstevel@tonic-gate 
28727c478bd9Sstevel@tonic-gate 	if (!(tp->t_modes.c_lflag & ECHO))
28737c478bd9Sstevel@tonic-gate 		return (0);
28747c478bd9Sstevel@tonic-gate 	i = 0;
28757c478bd9Sstevel@tonic-gate 
28767c478bd9Sstevel@tonic-gate 	/*
28777c478bd9Sstevel@tonic-gate 	 * Echo control characters (c <= 37) only if the ECHOCTRL
28787c478bd9Sstevel@tonic-gate 	 * flag is set as ^X.
28797c478bd9Sstevel@tonic-gate 	 */
28807c478bd9Sstevel@tonic-gate 
28817c478bd9Sstevel@tonic-gate 	if ((tp->t_modes.c_lflag & ECHOCTL) &&
28827c478bd9Sstevel@tonic-gate 	    (tp->t_modes.c_lflag & IEXTEN)) {
28837c478bd9Sstevel@tonic-gate 		if (c <= 037 && c != '\t' && c != '\n') {
28847c478bd9Sstevel@tonic-gate 			ldterm_outchar('^', q, ebsize, tp);
28857c478bd9Sstevel@tonic-gate 			i++;
28867c478bd9Sstevel@tonic-gate 			if (tp->t_modes.c_oflag & OLCUC)
28877c478bd9Sstevel@tonic-gate 				c += 'a' - 1;
28887c478bd9Sstevel@tonic-gate 			else
28897c478bd9Sstevel@tonic-gate 				c += 'A' - 1;
28907c478bd9Sstevel@tonic-gate 		} else if (c == 0177) {
28917c478bd9Sstevel@tonic-gate 			ldterm_outchar('^', q, ebsize, tp);
28927c478bd9Sstevel@tonic-gate 			i++;
28937c478bd9Sstevel@tonic-gate 			c = '?';
28947c478bd9Sstevel@tonic-gate 		}
28957c478bd9Sstevel@tonic-gate 		ldterm_outchar(c, q, ebsize, tp);
28967c478bd9Sstevel@tonic-gate 		return (i + 1);
28977c478bd9Sstevel@tonic-gate 		/* echo only special control character and the Bell */
28987c478bd9Sstevel@tonic-gate 	} else if ((c > 037 && c != 0177) || c == '\t' || c == '\n' ||
289985bb5f1dSis 	    c == '\r' || c == '\b' || c == 007 ||
290085bb5f1dSis 	    c == tp->t_modes.c_cc[VKILL]) {
29017c478bd9Sstevel@tonic-gate 		ldterm_outchar(c, q, ebsize, tp);
29027c478bd9Sstevel@tonic-gate 		return (i + 1);
29037c478bd9Sstevel@tonic-gate 	}
29047c478bd9Sstevel@tonic-gate 	return (i);
29057c478bd9Sstevel@tonic-gate }
29067c478bd9Sstevel@tonic-gate 
29077c478bd9Sstevel@tonic-gate 
29087c478bd9Sstevel@tonic-gate /*
29097c478bd9Sstevel@tonic-gate  * Put a character on the output queue.
29107c478bd9Sstevel@tonic-gate  */
29117c478bd9Sstevel@tonic-gate static void
ldterm_outchar(uchar_t c,queue_t * q,size_t bsize,ldtermstd_state_t * tp)29127c478bd9Sstevel@tonic-gate ldterm_outchar(uchar_t c, queue_t *q, size_t bsize, ldtermstd_state_t *tp)
29137c478bd9Sstevel@tonic-gate {
29147c478bd9Sstevel@tonic-gate 	mblk_t *curbp;
29157c478bd9Sstevel@tonic-gate 
29167c478bd9Sstevel@tonic-gate 	/*
29177c478bd9Sstevel@tonic-gate 	 * Don't even look at the characters unless we have something
29187c478bd9Sstevel@tonic-gate 	 * useful to do with them.
29197c478bd9Sstevel@tonic-gate 	 */
29207c478bd9Sstevel@tonic-gate 	if ((tp->t_modes.c_oflag & OPOST) ||
29217c478bd9Sstevel@tonic-gate 	    ((tp->t_modes.c_lflag & XCASE) &&
29227c478bd9Sstevel@tonic-gate 	    (tp->t_modes.c_lflag & ICANON))) {
29237c478bd9Sstevel@tonic-gate 		mblk_t *mp;
29247c478bd9Sstevel@tonic-gate 
29257c478bd9Sstevel@tonic-gate 		if ((mp = allocb(4, BPRI_HI)) == NULL) {
29267c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
29277c478bd9Sstevel@tonic-gate 			    "ldterm: (ldterm_outchar) out of blocks");
29287c478bd9Sstevel@tonic-gate 			return;
29297c478bd9Sstevel@tonic-gate 		}
29307c478bd9Sstevel@tonic-gate 		*mp->b_wptr++ = c;
29317c478bd9Sstevel@tonic-gate 		mp = ldterm_output_msg(q, mp, &tp->t_echomp, tp, bsize, 1);
29327c478bd9Sstevel@tonic-gate 		if (mp != NULL)
29337c478bd9Sstevel@tonic-gate 			freemsg(mp);
29347c478bd9Sstevel@tonic-gate 
29357c478bd9Sstevel@tonic-gate 	} else {
29367c478bd9Sstevel@tonic-gate 		if ((curbp = tp->t_echomp) != NULL) {
29377c478bd9Sstevel@tonic-gate 			while (curbp->b_cont != NULL)
29387c478bd9Sstevel@tonic-gate 				curbp = curbp->b_cont;
29397c478bd9Sstevel@tonic-gate 			if (curbp->b_datap->db_lim == curbp->b_wptr) {
29407c478bd9Sstevel@tonic-gate 				mblk_t *newbp;
29417c478bd9Sstevel@tonic-gate 
29427c478bd9Sstevel@tonic-gate 				if ((newbp = allocb(bsize, BPRI_HI)) == NULL) {
29437c478bd9Sstevel@tonic-gate 					cmn_err(CE_WARN,
29447c478bd9Sstevel@tonic-gate 					    "ldterm_outchar: out of blocks");
29457c478bd9Sstevel@tonic-gate 					return;
29467c478bd9Sstevel@tonic-gate 				}
29477c478bd9Sstevel@tonic-gate 				curbp->b_cont = newbp;
29487c478bd9Sstevel@tonic-gate 				curbp = newbp;
29497c478bd9Sstevel@tonic-gate 			}
29507c478bd9Sstevel@tonic-gate 		} else {
29517c478bd9Sstevel@tonic-gate 			if ((curbp = allocb(bsize, BPRI_HI)) == NULL) {
29527c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
29537c478bd9Sstevel@tonic-gate 				    "ldterm_outchar: out of blocks");
29547c478bd9Sstevel@tonic-gate 				return;
29557c478bd9Sstevel@tonic-gate 			}
29567c478bd9Sstevel@tonic-gate 			tp->t_echomp = curbp;
29577c478bd9Sstevel@tonic-gate 		}
29587c478bd9Sstevel@tonic-gate 		*curbp->b_wptr++ = c;
29597c478bd9Sstevel@tonic-gate 	}
29607c478bd9Sstevel@tonic-gate }
29617c478bd9Sstevel@tonic-gate 
29627c478bd9Sstevel@tonic-gate 
29637c478bd9Sstevel@tonic-gate /*
29647c478bd9Sstevel@tonic-gate  * Copy a string, of length len, to the output queue.
29657c478bd9Sstevel@tonic-gate  */
29667c478bd9Sstevel@tonic-gate static void
ldterm_outstring(uchar_t * cp,int len,queue_t * q,size_t bsize,ldtermstd_state_t * tp)29677c478bd9Sstevel@tonic-gate ldterm_outstring(uchar_t *cp, int len, queue_t *q, size_t bsize,
29687c478bd9Sstevel@tonic-gate     ldtermstd_state_t *tp)
29697c478bd9Sstevel@tonic-gate {
29707c478bd9Sstevel@tonic-gate 	while (len > 0) {
29717c478bd9Sstevel@tonic-gate 		ldterm_outchar(*cp++, q, bsize, tp);
29727c478bd9Sstevel@tonic-gate 		len--;
29737c478bd9Sstevel@tonic-gate 	}
29747c478bd9Sstevel@tonic-gate }
29757c478bd9Sstevel@tonic-gate 
29767c478bd9Sstevel@tonic-gate 
29777c478bd9Sstevel@tonic-gate static mblk_t *
newmsg(ldtermstd_state_t * tp)29787c478bd9Sstevel@tonic-gate newmsg(ldtermstd_state_t *tp)
29797c478bd9Sstevel@tonic-gate {
29807c478bd9Sstevel@tonic-gate 	mblk_t *bp;
29817c478bd9Sstevel@tonic-gate 
29827c478bd9Sstevel@tonic-gate 	/*
29837c478bd9Sstevel@tonic-gate 	 * If no current message, allocate a block for it.
29847c478bd9Sstevel@tonic-gate 	 */
29857c478bd9Sstevel@tonic-gate 	if ((bp = tp->t_endmsg) == NULL) {
29867c478bd9Sstevel@tonic-gate 		if ((bp = allocb(IBSIZE, BPRI_MED)) == NULL) {
29877c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
29887c478bd9Sstevel@tonic-gate 			    "ldterm: (ldtermrsrv/newmsg) out of blocks");
29897c478bd9Sstevel@tonic-gate 			return (bp);
29907c478bd9Sstevel@tonic-gate 		}
29917c478bd9Sstevel@tonic-gate 		tp->t_message = bp;
29927c478bd9Sstevel@tonic-gate 		tp->t_endmsg = bp;
29937c478bd9Sstevel@tonic-gate 	}
29947c478bd9Sstevel@tonic-gate 	return (bp);
29957c478bd9Sstevel@tonic-gate }
29967c478bd9Sstevel@tonic-gate 
29977c478bd9Sstevel@tonic-gate 
29987c478bd9Sstevel@tonic-gate static void
ldterm_msg_upstream(queue_t * q,ldtermstd_state_t * tp)29997c478bd9Sstevel@tonic-gate ldterm_msg_upstream(queue_t *q, ldtermstd_state_t *tp)
30007c478bd9Sstevel@tonic-gate {
30017c478bd9Sstevel@tonic-gate 	ssize_t s;
30027c478bd9Sstevel@tonic-gate 	mblk_t *bp;
30037c478bd9Sstevel@tonic-gate 
30047c478bd9Sstevel@tonic-gate 	bp = tp->t_message;
30057c478bd9Sstevel@tonic-gate 	s = msgdsize(bp);
30067c478bd9Sstevel@tonic-gate 	if (bp)
30077c478bd9Sstevel@tonic-gate 		putnext(q, tp->t_message);
30087c478bd9Sstevel@tonic-gate 
30097c478bd9Sstevel@tonic-gate 	/*
30107c478bd9Sstevel@tonic-gate 	 * update sysinfo canch character.
30117c478bd9Sstevel@tonic-gate 	 */
30127c478bd9Sstevel@tonic-gate 	if (CANON_MODE)
30137c478bd9Sstevel@tonic-gate 		(void) drv_setparm(SYSCANC, s);
30147c478bd9Sstevel@tonic-gate 	tp->t_message = NULL;
30157c478bd9Sstevel@tonic-gate 	tp->t_endmsg = NULL;
30167c478bd9Sstevel@tonic-gate 	tp->t_msglen = 0;
30177c478bd9Sstevel@tonic-gate 	tp->t_rocount = 0;
30187c478bd9Sstevel@tonic-gate 	tp->t_rd_request = 0;
30197c478bd9Sstevel@tonic-gate 	if (tp->t_state & TS_MEUC) {
30207c478bd9Sstevel@tonic-gate 		ASSERT(tp->t_eucp_mp);
30217c478bd9Sstevel@tonic-gate 		tp->t_eucp = tp->t_eucp_mp->b_rptr;
30227c478bd9Sstevel@tonic-gate 		/* can't reset everything, as we may have other input */
30237c478bd9Sstevel@tonic-gate 	}
30247c478bd9Sstevel@tonic-gate }
30257c478bd9Sstevel@tonic-gate 
30267c478bd9Sstevel@tonic-gate 
30277c478bd9Sstevel@tonic-gate /*
30287c478bd9Sstevel@tonic-gate  * Re-enable the write-side service procedure.  When an allocation
30297c478bd9Sstevel@tonic-gate  * failure causes write-side processing to stall, we disable the
30307c478bd9Sstevel@tonic-gate  * write side and arrange to call this function when allocation once
30317c478bd9Sstevel@tonic-gate  * again becomes possible.
30327c478bd9Sstevel@tonic-gate  */
30337c478bd9Sstevel@tonic-gate static void
ldterm_wenable(void * addr)30347c478bd9Sstevel@tonic-gate ldterm_wenable(void *addr)
30357c478bd9Sstevel@tonic-gate {
30367c478bd9Sstevel@tonic-gate 	queue_t *q = addr;
30377c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp;
30387c478bd9Sstevel@tonic-gate 
30397c478bd9Sstevel@tonic-gate 	tp = (ldtermstd_state_t *)q->q_ptr;
30407c478bd9Sstevel@tonic-gate 	/*
30417c478bd9Sstevel@tonic-gate 	 * The bufcall is no longer pending.
30427c478bd9Sstevel@tonic-gate 	 */
30437c478bd9Sstevel@tonic-gate 	tp->t_wbufcid = 0;
30447c478bd9Sstevel@tonic-gate 	enableok(q);
30457c478bd9Sstevel@tonic-gate 	qenable(q);
30467c478bd9Sstevel@tonic-gate }
30477c478bd9Sstevel@tonic-gate 
30487c478bd9Sstevel@tonic-gate 
30497c478bd9Sstevel@tonic-gate /*
30507c478bd9Sstevel@tonic-gate  * Line discipline output queue put procedure.  Attempts to process
30517c478bd9Sstevel@tonic-gate  * the message directly and send it on downstream, queueing it only
30527c478bd9Sstevel@tonic-gate  * if there's already something pending or if its downstream neighbor
30537c478bd9Sstevel@tonic-gate  * is clogged.
30547c478bd9Sstevel@tonic-gate  */
3055bf10ed2eSToomas Soome static int
ldtermwput(queue_t * q,mblk_t * mp)30567c478bd9Sstevel@tonic-gate ldtermwput(queue_t *q, mblk_t *mp)
30577c478bd9Sstevel@tonic-gate {
30587c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp;
30597c478bd9Sstevel@tonic-gate 	unsigned char type = mp->b_datap->db_type;
30607c478bd9Sstevel@tonic-gate 
30617c478bd9Sstevel@tonic-gate 	tp = (ldtermstd_state_t *)q->q_ptr;
30627c478bd9Sstevel@tonic-gate 
30637c478bd9Sstevel@tonic-gate 	/*
30647c478bd9Sstevel@tonic-gate 	 * Always process priority messages, regardless of whether or
30657c478bd9Sstevel@tonic-gate 	 * not our queue is nonempty.
30667c478bd9Sstevel@tonic-gate 	 */
30677c478bd9Sstevel@tonic-gate 	if (type >= QPCTL) {
30687c478bd9Sstevel@tonic-gate 		switch (type) {
30697c478bd9Sstevel@tonic-gate 
30707c478bd9Sstevel@tonic-gate 		case M_FLUSH:
30717c478bd9Sstevel@tonic-gate 			/*
30727c478bd9Sstevel@tonic-gate 			 * Get rid of it, see comment in
30737c478bd9Sstevel@tonic-gate 			 * ldterm_dosig().
30747c478bd9Sstevel@tonic-gate 			 */
30757c478bd9Sstevel@tonic-gate 			if ((tp->t_state & TS_FLUSHWAIT) &&
30767c478bd9Sstevel@tonic-gate 			    (*mp->b_rptr == FLUSHW)) {
30777c478bd9Sstevel@tonic-gate 				tp->t_state &= ~TS_FLUSHWAIT;
30787c478bd9Sstevel@tonic-gate 				freemsg(mp);
3079bf10ed2eSToomas Soome 				return (0);
30807c478bd9Sstevel@tonic-gate 			}
30817c478bd9Sstevel@tonic-gate 			/*
30827c478bd9Sstevel@tonic-gate 			 * This is coming from above, so we only
30837c478bd9Sstevel@tonic-gate 			 * handle the write queue here.  If FLUSHR is
30847c478bd9Sstevel@tonic-gate 			 * set, it will get turned around at the
30857c478bd9Sstevel@tonic-gate 			 * driver, and the read procedure will see it
30867c478bd9Sstevel@tonic-gate 			 * eventually.
30877c478bd9Sstevel@tonic-gate 			 */
30887c478bd9Sstevel@tonic-gate 			if (*mp->b_rptr & FLUSHW) {
308985bb5f1dSis 				if ((tp->t_state & TS_ISPTSTTY) &&
309085bb5f1dSis 				    (*mp->b_rptr & FLUSHBAND))
309185bb5f1dSis 					flushband(q, *(mp->b_rptr + 1),
309285bb5f1dSis 					    FLUSHDATA);
309385bb5f1dSis 				else
309485bb5f1dSis 					flushq(q, FLUSHDATA);
30957c478bd9Sstevel@tonic-gate 			}
30967c478bd9Sstevel@tonic-gate 
30977c478bd9Sstevel@tonic-gate 			putnext(q, mp);
30987c478bd9Sstevel@tonic-gate 			/*
30997c478bd9Sstevel@tonic-gate 			 * If a timed read is interrupted, there is
31007c478bd9Sstevel@tonic-gate 			 * no way to cancel an existing M_READ
31017c478bd9Sstevel@tonic-gate 			 * request.  We kludge by allowing a flush to
31027c478bd9Sstevel@tonic-gate 			 * do so.
31037c478bd9Sstevel@tonic-gate 			 */
31047c478bd9Sstevel@tonic-gate 			if (tp->t_state & TS_MREAD)
31057c478bd9Sstevel@tonic-gate 				vmin_satisfied(RD(q), tp, 0);
31067c478bd9Sstevel@tonic-gate 			break;
31077c478bd9Sstevel@tonic-gate 
31087c478bd9Sstevel@tonic-gate 		case M_READ:
31097c478bd9Sstevel@tonic-gate 			DEBUG1(("ldtermwmsg:M_READ RECEIVED\n"));
31107c478bd9Sstevel@tonic-gate 			/*
31117c478bd9Sstevel@tonic-gate 			 * Stream head needs data to satisfy timed
31127c478bd9Sstevel@tonic-gate 			 * read. Has meaning only if ICANON flag is
31137c478bd9Sstevel@tonic-gate 			 * off indicating raw mode
31147c478bd9Sstevel@tonic-gate 			 */
31157c478bd9Sstevel@tonic-gate 
31167c478bd9Sstevel@tonic-gate 			DEBUG4((
31177c478bd9Sstevel@tonic-gate 			    "M_READ: RAW_MODE=%d, CNT=%d, VMIN=%d, VTIME=%d\n",
31187c478bd9Sstevel@tonic-gate 			    RAW_MODE, *(unsigned int *)mp->b_rptr, V_MIN,
31197c478bd9Sstevel@tonic-gate 			    V_TIME));
31207c478bd9Sstevel@tonic-gate 
31217c478bd9Sstevel@tonic-gate 			tp->t_rd_request = *(unsigned int *)mp->b_rptr;
31227c478bd9Sstevel@tonic-gate 
31237c478bd9Sstevel@tonic-gate 			if (RAW_MODE) {
31247c478bd9Sstevel@tonic-gate 				if (newmsg(tp) != NULL) {
31257c478bd9Sstevel@tonic-gate 					/*
31267c478bd9Sstevel@tonic-gate 					 * VMIN/VTIME processing...
31277c478bd9Sstevel@tonic-gate 					 * The four possible cases are:
31287c478bd9Sstevel@tonic-gate 					 *	MIN = 0, TIME > 0
31297c478bd9Sstevel@tonic-gate 					 *	MIN = >, TIME = 0
31307c478bd9Sstevel@tonic-gate 					 *	MIN > 0, TIME > 0
31317c478bd9Sstevel@tonic-gate 					 *	MIN = 0, TIME = 0
31327c478bd9Sstevel@tonic-gate 					 * These four conditions must be dealt
31337c478bd9Sstevel@tonic-gate 					 * with on the read side as well in
31347c478bd9Sstevel@tonic-gate 					 * ldterm_do_noncanon(). Set TS_MREAD
31357c478bd9Sstevel@tonic-gate 					 * so that the read side will know
31367c478bd9Sstevel@tonic-gate 					 * there is a pending read request
31377c478bd9Sstevel@tonic-gate 					 * waiting at the stream head.  If we
31387c478bd9Sstevel@tonic-gate 					 * can satisfy MIN do it here, rather
31397c478bd9Sstevel@tonic-gate 					 * than on the read side.  If we can't,
31407c478bd9Sstevel@tonic-gate 					 * start timers if necessary and let
31417c478bd9Sstevel@tonic-gate 					 * the other side deal with it.
31427c478bd9Sstevel@tonic-gate 					 *
31437c478bd9Sstevel@tonic-gate 					 * We got another M_READ before the
31447c478bd9Sstevel@tonic-gate 					 * pending one completed, cancel any
31457c478bd9Sstevel@tonic-gate 					 * existing timeout.
31467c478bd9Sstevel@tonic-gate 					 */
31477c478bd9Sstevel@tonic-gate 					if (tp->t_state & TS_MREAD) {
31487c478bd9Sstevel@tonic-gate 						vmin_satisfied(RD(q),
31497c478bd9Sstevel@tonic-gate 						    tp, 0);
31507c478bd9Sstevel@tonic-gate 					}
31517c478bd9Sstevel@tonic-gate 					tp->t_state |= TS_MREAD;
31527c478bd9Sstevel@tonic-gate 					/*
31537c478bd9Sstevel@tonic-gate 					 * Case 1:  Any data will
31547c478bd9Sstevel@tonic-gate 					 * satisfy read, otherwise
31557c478bd9Sstevel@tonic-gate 					 * start timer
31567c478bd9Sstevel@tonic-gate 					 */
31577c478bd9Sstevel@tonic-gate 					if (V_MIN == 0 && V_TIME > 0) {
31587c478bd9Sstevel@tonic-gate 						if (tp->t_msglen)
31597c478bd9Sstevel@tonic-gate 							vmin_satisfied(RD(q),
31607c478bd9Sstevel@tonic-gate 							    tp, 1);
31617c478bd9Sstevel@tonic-gate 						else
31627c478bd9Sstevel@tonic-gate 							vmin_settimer(RD(q));
31637c478bd9Sstevel@tonic-gate 
31647c478bd9Sstevel@tonic-gate 						/*
31657c478bd9Sstevel@tonic-gate 						 * Case 2:  If we have enough
31667c478bd9Sstevel@tonic-gate 						 * data, send up now.
31677c478bd9Sstevel@tonic-gate 						 * Otherwise, the read side
31687c478bd9Sstevel@tonic-gate 						 * should wait forever until MIN
31697c478bd9Sstevel@tonic-gate 						 * is satisified.
31707c478bd9Sstevel@tonic-gate 						 */
31717c478bd9Sstevel@tonic-gate 					} else if (V_MIN > 0 && V_TIME == 0) {
31727c478bd9Sstevel@tonic-gate 						if (tp->t_msglen >= (int)V_MIN)
31737c478bd9Sstevel@tonic-gate 							vmin_satisfied(RD(q),
31747c478bd9Sstevel@tonic-gate 							    tp, 1);
31757c478bd9Sstevel@tonic-gate 
31767c478bd9Sstevel@tonic-gate 						/*
31777c478bd9Sstevel@tonic-gate 						 * Case 3:  If we can satisfy
31787c478bd9Sstevel@tonic-gate 						 * the read, send it up. If we
31797c478bd9Sstevel@tonic-gate 						 * don't have enough data, but
31807c478bd9Sstevel@tonic-gate 						 * there is at least one char,
31817c478bd9Sstevel@tonic-gate 						 * start a timer.  Otherwise,
31827c478bd9Sstevel@tonic-gate 						 * let the read side start
31837c478bd9Sstevel@tonic-gate 						 * the timer.
31847c478bd9Sstevel@tonic-gate 						 */
31857c478bd9Sstevel@tonic-gate 					} else if (V_MIN > 0 && V_TIME > 0) {
31867c478bd9Sstevel@tonic-gate 						if (tp->t_msglen >= (int)V_MIN)
31877c478bd9Sstevel@tonic-gate 							vmin_satisfied(RD(q),
31887c478bd9Sstevel@tonic-gate 							    tp, 1);
31897c478bd9Sstevel@tonic-gate 						else if (tp->t_msglen)
31907c478bd9Sstevel@tonic-gate 							vmin_settimer(RD(q));
31917c478bd9Sstevel@tonic-gate 						/*
31927c478bd9Sstevel@tonic-gate 						 * Case 4:  Read returns
31937c478bd9Sstevel@tonic-gate 						 * whatever data is available
31947c478bd9Sstevel@tonic-gate 						 * or zero if none.
31957c478bd9Sstevel@tonic-gate 						 */
31967c478bd9Sstevel@tonic-gate 					} else { /* V_MIN == 0 && V_TIME == 0 */
31977c478bd9Sstevel@tonic-gate 						vmin_satisfied(RD(q), tp, 1);
31987c478bd9Sstevel@tonic-gate 					}
31997c478bd9Sstevel@tonic-gate 
32007c478bd9Sstevel@tonic-gate 				} else	/* should do bufcall, really! */
32017c478bd9Sstevel@tonic-gate 					cmn_err(CE_WARN,
32027c478bd9Sstevel@tonic-gate 					    "ldtermwmsg: out of blocks");
32037c478bd9Sstevel@tonic-gate 			}
32047c478bd9Sstevel@tonic-gate 			/*
32057c478bd9Sstevel@tonic-gate 			 * pass M_READ down
32067c478bd9Sstevel@tonic-gate 			 */
32077c478bd9Sstevel@tonic-gate 			putnext(q, mp);
32087c478bd9Sstevel@tonic-gate 			break;
32097c478bd9Sstevel@tonic-gate 
32107c478bd9Sstevel@tonic-gate 		default:
32117c478bd9Sstevel@tonic-gate 			/* Pass it through unmolested. */
32127c478bd9Sstevel@tonic-gate 			putnext(q, mp);
32137c478bd9Sstevel@tonic-gate 			break;
32147c478bd9Sstevel@tonic-gate 		}
3215bf10ed2eSToomas Soome 		return (0);
32167c478bd9Sstevel@tonic-gate 	}
32177c478bd9Sstevel@tonic-gate 	/*
32187c478bd9Sstevel@tonic-gate 	 * If our queue is nonempty or there's a traffic jam
32197c478bd9Sstevel@tonic-gate 	 * downstream, this message must get in line.
32207c478bd9Sstevel@tonic-gate 	 */
32217c478bd9Sstevel@tonic-gate 	if (q->q_first != NULL || !bcanputnext(q, mp->b_band)) {
32227c478bd9Sstevel@tonic-gate 		/*
32237c478bd9Sstevel@tonic-gate 		 * Exception: ioctls, except for those defined to
32247c478bd9Sstevel@tonic-gate 		 * take effect after output has drained, should be
32257c478bd9Sstevel@tonic-gate 		 * processed immediately.
32267c478bd9Sstevel@tonic-gate 		 */
32277c478bd9Sstevel@tonic-gate 		if (type == M_IOCTL) {
32287c478bd9Sstevel@tonic-gate 			struct iocblk *iocp;
32297c478bd9Sstevel@tonic-gate 
32307c478bd9Sstevel@tonic-gate 			iocp = (struct iocblk *)mp->b_rptr;
32317c478bd9Sstevel@tonic-gate 			switch (iocp->ioc_cmd) {
32327c478bd9Sstevel@tonic-gate 
32337c478bd9Sstevel@tonic-gate 				/*
32347c478bd9Sstevel@tonic-gate 				 * Queue these.
32357c478bd9Sstevel@tonic-gate 				 */
32367c478bd9Sstevel@tonic-gate 			case TCSETSW:
32377c478bd9Sstevel@tonic-gate 			case TCSETSF:
32387c478bd9Sstevel@tonic-gate 			case TCSETAW:
32397c478bd9Sstevel@tonic-gate 			case TCSETAF:
32407c478bd9Sstevel@tonic-gate 			case TCSBRK:
32417c478bd9Sstevel@tonic-gate 				break;
32427c478bd9Sstevel@tonic-gate 
32437c478bd9Sstevel@tonic-gate 				/*
32447c478bd9Sstevel@tonic-gate 				 * Handle all others immediately.
32457c478bd9Sstevel@tonic-gate 				 */
32467c478bd9Sstevel@tonic-gate 			default:
32477c478bd9Sstevel@tonic-gate 				(void) ldtermwmsg(q, mp);
3248bf10ed2eSToomas Soome 				return (0);
32497c478bd9Sstevel@tonic-gate 			}
32507c478bd9Sstevel@tonic-gate 		}
32517c478bd9Sstevel@tonic-gate 		(void) putq(q, mp);
3252bf10ed2eSToomas Soome 		return (0);
32537c478bd9Sstevel@tonic-gate 	}
32547c478bd9Sstevel@tonic-gate 	/*
32557c478bd9Sstevel@tonic-gate 	 * We can take the fast path through, by simply calling
32567c478bd9Sstevel@tonic-gate 	 * ldtermwmsg to dispose of mp.
32577c478bd9Sstevel@tonic-gate 	 */
32587c478bd9Sstevel@tonic-gate 	(void) ldtermwmsg(q, mp);
3259bf10ed2eSToomas Soome 	return (0);
32607c478bd9Sstevel@tonic-gate }
32617c478bd9Sstevel@tonic-gate 
32627c478bd9Sstevel@tonic-gate 
32637c478bd9Sstevel@tonic-gate /*
32647c478bd9Sstevel@tonic-gate  * Line discipline output queue service procedure.
32657c478bd9Sstevel@tonic-gate  */
3266bf10ed2eSToomas Soome static int
ldtermwsrv(queue_t * q)32677c478bd9Sstevel@tonic-gate ldtermwsrv(queue_t *q)
32687c478bd9Sstevel@tonic-gate {
32697c478bd9Sstevel@tonic-gate 	mblk_t *mp;
32707c478bd9Sstevel@tonic-gate 
32717c478bd9Sstevel@tonic-gate 	/*
32727c478bd9Sstevel@tonic-gate 	 * We expect this loop to iterate at most once, but must be
32737c478bd9Sstevel@tonic-gate 	 * prepared for more in case our upstream neighbor isn't
32747c478bd9Sstevel@tonic-gate 	 * paying strict attention to what canput tells it.
32757c478bd9Sstevel@tonic-gate 	 */
32767c478bd9Sstevel@tonic-gate 	while ((mp = getq(q)) != NULL) {
32777c478bd9Sstevel@tonic-gate 		/*
32787c478bd9Sstevel@tonic-gate 		 * N.B.: ldtermwput has already handled high-priority
32797c478bd9Sstevel@tonic-gate 		 * messages, so we don't have to worry about them
32807c478bd9Sstevel@tonic-gate 		 * here. Hence, the putbq call is safe.
32817c478bd9Sstevel@tonic-gate 		 */
32827c478bd9Sstevel@tonic-gate 		if (!bcanputnext(q, mp->b_band)) {
32837c478bd9Sstevel@tonic-gate 			(void) putbq(q, mp);
32847c478bd9Sstevel@tonic-gate 			break;
32857c478bd9Sstevel@tonic-gate 		}
32867c478bd9Sstevel@tonic-gate 		if (!ldtermwmsg(q, mp)) {
32877c478bd9Sstevel@tonic-gate 			/*
32887c478bd9Sstevel@tonic-gate 			 * Couldn't handle the whole thing; give up
32897c478bd9Sstevel@tonic-gate 			 * for now and wait to be rescheduled.
32907c478bd9Sstevel@tonic-gate 			 */
32917c478bd9Sstevel@tonic-gate 			break;
32927c478bd9Sstevel@tonic-gate 		}
32937c478bd9Sstevel@tonic-gate 	}
3294bf10ed2eSToomas Soome 	return (0);
32957c478bd9Sstevel@tonic-gate }
32967c478bd9Sstevel@tonic-gate 
32977c478bd9Sstevel@tonic-gate 
32987c478bd9Sstevel@tonic-gate /*
32997c478bd9Sstevel@tonic-gate  * Process the write-side message denoted by mp.  If mp can't be
33007c478bd9Sstevel@tonic-gate  * processed completely (due to allocation failures), put the
33017c478bd9Sstevel@tonic-gate  * residual unprocessed part on the front of the write queue, disable
33027c478bd9Sstevel@tonic-gate  * the queue, and schedule a qbufcall to arrange to complete its
33037c478bd9Sstevel@tonic-gate  * processing later.
33047c478bd9Sstevel@tonic-gate  *
33057c478bd9Sstevel@tonic-gate  * Return 1 if the message was processed completely and 0 if not.
33067c478bd9Sstevel@tonic-gate  *
33077c478bd9Sstevel@tonic-gate  * This routine is called from both ldtermwput and ldtermwsrv to do the
33087c478bd9Sstevel@tonic-gate  * actual work of dealing with mp.  ldtermwput will have already
33097c478bd9Sstevel@tonic-gate  * dealt with high priority messages.
33107c478bd9Sstevel@tonic-gate  */
33117c478bd9Sstevel@tonic-gate static int
ldtermwmsg(queue_t * q,mblk_t * mp)33127c478bd9Sstevel@tonic-gate ldtermwmsg(queue_t *q, mblk_t *mp)
33137c478bd9Sstevel@tonic-gate {
33147c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp;
33157c478bd9Sstevel@tonic-gate 	mblk_t *residmp = NULL;
33167c478bd9Sstevel@tonic-gate 	size_t size;
33177c478bd9Sstevel@tonic-gate 
33187c478bd9Sstevel@tonic-gate 	tp = (ldtermstd_state_t *)q->q_ptr;
33197c478bd9Sstevel@tonic-gate 
33207c478bd9Sstevel@tonic-gate 	switch (mp->b_datap->db_type) {
33217c478bd9Sstevel@tonic-gate 
33227c478bd9Sstevel@tonic-gate 	case M_IOCTL:
33237c478bd9Sstevel@tonic-gate 		ldterm_do_ioctl(q, mp);
33247c478bd9Sstevel@tonic-gate 		break;
33257c478bd9Sstevel@tonic-gate 
33267c478bd9Sstevel@tonic-gate 	case M_DATA:
33277c478bd9Sstevel@tonic-gate 		{
33287c478bd9Sstevel@tonic-gate 			mblk_t *omp = NULL;
33297c478bd9Sstevel@tonic-gate 
33307c478bd9Sstevel@tonic-gate 			if ((tp->t_modes.c_lflag & FLUSHO) &&
33317c478bd9Sstevel@tonic-gate 			    (tp->t_modes.c_lflag & IEXTEN)) {
33327c478bd9Sstevel@tonic-gate 				freemsg(mp);	/* drop on floor */
33337c478bd9Sstevel@tonic-gate 				break;
33347c478bd9Sstevel@tonic-gate 			}
33357c478bd9Sstevel@tonic-gate 			tp->t_rocount = 0;
33367c478bd9Sstevel@tonic-gate 			/*
33377c478bd9Sstevel@tonic-gate 			 * Don't even look at the characters unless
33387c478bd9Sstevel@tonic-gate 			 * we have something useful to do with them.
33397c478bd9Sstevel@tonic-gate 			 */
33407c478bd9Sstevel@tonic-gate 			if (((tp->t_modes.c_oflag & OPOST) ||
33417c478bd9Sstevel@tonic-gate 			    ((tp->t_modes.c_lflag & XCASE) &&
33427c478bd9Sstevel@tonic-gate 			    (tp->t_modes.c_lflag & ICANON))) &&
33437c478bd9Sstevel@tonic-gate 			    (msgdsize(mp) || !(tp->t_state & TS_ISPTSTTY))) {
33447c478bd9Sstevel@tonic-gate 				unsigned char band = mp->b_band;
33457c478bd9Sstevel@tonic-gate 				short flag = mp->b_flag;
33467c478bd9Sstevel@tonic-gate 
33477c478bd9Sstevel@tonic-gate 				residmp = ldterm_output_msg(q, mp, &omp,
334885bb5f1dSis 				    tp, OBSIZE, 0);
33497c478bd9Sstevel@tonic-gate 				if ((mp = omp) == NULL)
33507c478bd9Sstevel@tonic-gate 					break;
33517c478bd9Sstevel@tonic-gate 				mp->b_band |= band;
33527c478bd9Sstevel@tonic-gate 				mp->b_flag |= flag;
33537c478bd9Sstevel@tonic-gate 			}
33547c478bd9Sstevel@tonic-gate 			/* Update sysinfo outch */
33557c478bd9Sstevel@tonic-gate 			(void) drv_setparm(SYSOUTC, msgdsize(mp));
33567c478bd9Sstevel@tonic-gate 			putnext(q, mp);
33577c478bd9Sstevel@tonic-gate 			break;
33587c478bd9Sstevel@tonic-gate 		}
33597c478bd9Sstevel@tonic-gate 
33607c478bd9Sstevel@tonic-gate 	default:
33617c478bd9Sstevel@tonic-gate 		putnext(q, mp);	/* pass it through unmolested */
33627c478bd9Sstevel@tonic-gate 		break;
33637c478bd9Sstevel@tonic-gate 	}
33647c478bd9Sstevel@tonic-gate 
33657c478bd9Sstevel@tonic-gate 	if (residmp == NULL)
33667c478bd9Sstevel@tonic-gate 		return (1);
33677c478bd9Sstevel@tonic-gate 
33687c478bd9Sstevel@tonic-gate 	/*
33697c478bd9Sstevel@tonic-gate 	 * An allocation failure occurred that prevented the message
33707c478bd9Sstevel@tonic-gate 	 * from being completely processed.  First, disable our
33717c478bd9Sstevel@tonic-gate 	 * queue, since it's pointless to attempt further processing
33727c478bd9Sstevel@tonic-gate 	 * until the allocation situation is resolved.  (This must
33737c478bd9Sstevel@tonic-gate 	 * precede the putbq call below, which would otherwise mark
33747c478bd9Sstevel@tonic-gate 	 * the queue to be serviced.)
33757c478bd9Sstevel@tonic-gate 	 */
33767c478bd9Sstevel@tonic-gate 	noenable(q);
33777c478bd9Sstevel@tonic-gate 	/*
33787c478bd9Sstevel@tonic-gate 	 * Stuff the remnant on our write queue so that we can
33797c478bd9Sstevel@tonic-gate 	 * complete it later when times become less lean.  Note that
33807c478bd9Sstevel@tonic-gate 	 * this sets QFULL, so that our upstream neighbor will be
33817c478bd9Sstevel@tonic-gate 	 * blocked by flow control.
33827c478bd9Sstevel@tonic-gate 	 */
33837c478bd9Sstevel@tonic-gate 	(void) putbq(q, residmp);
33847c478bd9Sstevel@tonic-gate 	/*
33857c478bd9Sstevel@tonic-gate 	 * Schedule a qbufcall to re-enable the queue.  The failure
33867c478bd9Sstevel@tonic-gate 	 * won't have been for an allocation of more than OBSIZE
33877c478bd9Sstevel@tonic-gate 	 * bytes, so don't ask for more than that from bufcall.
33887c478bd9Sstevel@tonic-gate 	 */
33897c478bd9Sstevel@tonic-gate 	size = msgdsize(residmp);
33907c478bd9Sstevel@tonic-gate 	if (size > OBSIZE)
33917c478bd9Sstevel@tonic-gate 		size = OBSIZE;
33927c478bd9Sstevel@tonic-gate 	if (tp->t_wbufcid)
33937c478bd9Sstevel@tonic-gate 		qunbufcall(q, tp->t_wbufcid);
33947c478bd9Sstevel@tonic-gate 	tp->t_wbufcid = qbufcall(q, size, BPRI_MED, ldterm_wenable, q);
33957c478bd9Sstevel@tonic-gate 
33967c478bd9Sstevel@tonic-gate 	return (0);
33977c478bd9Sstevel@tonic-gate }
33987c478bd9Sstevel@tonic-gate 
33997c478bd9Sstevel@tonic-gate 
34007c478bd9Sstevel@tonic-gate /*
34017c478bd9Sstevel@tonic-gate  * Perform output processing on a message, accumulating the output
34027c478bd9Sstevel@tonic-gate  * characters in a new message.
34037c478bd9Sstevel@tonic-gate  */
34047c478bd9Sstevel@tonic-gate static mblk_t *
ldterm_output_msg(queue_t * q,mblk_t * imp,mblk_t ** omp,ldtermstd_state_t * tp,size_t bsize,int echoing)34057c478bd9Sstevel@tonic-gate ldterm_output_msg(queue_t *q, mblk_t *imp, mblk_t **omp,
34067c478bd9Sstevel@tonic-gate     ldtermstd_state_t *tp, size_t bsize, int echoing)
34077c478bd9Sstevel@tonic-gate {
34087c478bd9Sstevel@tonic-gate 	mblk_t *ibp;		/* block we're examining from input message */
34097c478bd9Sstevel@tonic-gate 	mblk_t *obp;		/* block we're filling in output message */
34107c478bd9Sstevel@tonic-gate 	mblk_t *cbp;		/* continuation block */
34117c478bd9Sstevel@tonic-gate 	mblk_t *oobp;		/* old value of obp; valid if NEW_BLOCK fails */
34127c478bd9Sstevel@tonic-gate 	mblk_t **contpp;	/* where to stuff ptr to newly-allocated blk */
34137c478bd9Sstevel@tonic-gate 	unsigned char c, n;
34147c478bd9Sstevel@tonic-gate 	int count, ctype;
34157c478bd9Sstevel@tonic-gate 	ssize_t bytes_left;
34167c478bd9Sstevel@tonic-gate 
34177c478bd9Sstevel@tonic-gate 	mblk_t *bp;		/* block to stuff an M_DELAY message in */
34187c478bd9Sstevel@tonic-gate 
34197c478bd9Sstevel@tonic-gate 
34207c478bd9Sstevel@tonic-gate 	/*
34217c478bd9Sstevel@tonic-gate 	 * Allocate a new block into which to put bytes. If we can't,
34227c478bd9Sstevel@tonic-gate 	 * we just drop the rest of the message on the floor. If x is
34237c478bd9Sstevel@tonic-gate 	 * non-zero, just fall thru; failure requires cleanup before
34247c478bd9Sstevel@tonic-gate 	 * going out
34257c478bd9Sstevel@tonic-gate 	 */
34267c478bd9Sstevel@tonic-gate 
34277c478bd9Sstevel@tonic-gate #define	NEW_BLOCK(x) \
34287c478bd9Sstevel@tonic-gate 	{ \
34297c478bd9Sstevel@tonic-gate 		oobp = obp; \
34307c478bd9Sstevel@tonic-gate 		if ((obp = allocb(bsize, BPRI_MED)) == NULL) { \
34317c478bd9Sstevel@tonic-gate 			if (x == 0) \
34327c478bd9Sstevel@tonic-gate 				goto outofbufs; \
34337c478bd9Sstevel@tonic-gate 		} else { \
34347c478bd9Sstevel@tonic-gate 			*contpp = obp; \
34357c478bd9Sstevel@tonic-gate 			contpp = &obp->b_cont; \
34367c478bd9Sstevel@tonic-gate 			bytes_left = obp->b_datap->db_lim - obp->b_wptr; \
34377c478bd9Sstevel@tonic-gate 		} \
34387c478bd9Sstevel@tonic-gate 	}
34397c478bd9Sstevel@tonic-gate 
34407c478bd9Sstevel@tonic-gate 	ibp = imp;
34417c478bd9Sstevel@tonic-gate 
34427c478bd9Sstevel@tonic-gate 	/*
34437c478bd9Sstevel@tonic-gate 	 * When we allocate the first block of a message, we should
34447c478bd9Sstevel@tonic-gate 	 * stuff the pointer to it in "*omp".  All subsequent blocks
34457c478bd9Sstevel@tonic-gate 	 * should have the pointer to them stuffed into the "b_cont"
34467c478bd9Sstevel@tonic-gate 	 * field of the previous block.  "contpp" points to the place
34477c478bd9Sstevel@tonic-gate 	 * where we should stuff the pointer.
34487c478bd9Sstevel@tonic-gate 	 *
34497c478bd9Sstevel@tonic-gate 	 * If we already have a message we're filling in, continue doing
34507c478bd9Sstevel@tonic-gate 	 * so.
34517c478bd9Sstevel@tonic-gate 	 */
34527c478bd9Sstevel@tonic-gate 	if ((obp = *omp) != NULL) {
34537c478bd9Sstevel@tonic-gate 		while (obp->b_cont != NULL)
34547c478bd9Sstevel@tonic-gate 			obp = obp->b_cont;
34557c478bd9Sstevel@tonic-gate 		contpp = &obp->b_cont;
34567c478bd9Sstevel@tonic-gate 		bytes_left = obp->b_datap->db_lim - obp->b_wptr;
34577c478bd9Sstevel@tonic-gate 	} else {
34587c478bd9Sstevel@tonic-gate 		contpp = omp;
34597c478bd9Sstevel@tonic-gate 		bytes_left = 0;
34607c478bd9Sstevel@tonic-gate 	}
34617c478bd9Sstevel@tonic-gate 
34627c478bd9Sstevel@tonic-gate 	do {
34637c478bd9Sstevel@tonic-gate 		while (ibp->b_rptr < ibp->b_wptr) {
34647c478bd9Sstevel@tonic-gate 			/*
34657c478bd9Sstevel@tonic-gate 			 * Make sure there's room for one more
34667c478bd9Sstevel@tonic-gate 			 * character.  At most, we'll need "t_maxeuc"
34677c478bd9Sstevel@tonic-gate 			 * bytes.
34687c478bd9Sstevel@tonic-gate 			 */
34697c478bd9Sstevel@tonic-gate 			if ((bytes_left < (int)tp->t_maxeuc)) {
34707c478bd9Sstevel@tonic-gate 				/* LINTED */
34717c478bd9Sstevel@tonic-gate 				NEW_BLOCK(0);
34727c478bd9Sstevel@tonic-gate 			}
34737c478bd9Sstevel@tonic-gate 			/*
34747c478bd9Sstevel@tonic-gate 			 * If doing XCASE processing (not very
34757c478bd9Sstevel@tonic-gate 			 * likely, in this day and age), look at each
34767c478bd9Sstevel@tonic-gate 			 * character individually.
34777c478bd9Sstevel@tonic-gate 			 */
34787c478bd9Sstevel@tonic-gate 			if ((tp->t_modes.c_lflag & XCASE) &&
34797c478bd9Sstevel@tonic-gate 			    (tp->t_modes.c_lflag & ICANON)) {
34807c478bd9Sstevel@tonic-gate 				c = *ibp->b_rptr++;
34817c478bd9Sstevel@tonic-gate 
34827c478bd9Sstevel@tonic-gate 				/*
34837c478bd9Sstevel@tonic-gate 				 * We need to make sure that this is not
34847c478bd9Sstevel@tonic-gate 				 * a following byte of a multibyte character
34857c478bd9Sstevel@tonic-gate 				 * before applying an XCASE processing.
34867c478bd9Sstevel@tonic-gate 				 *
34877c478bd9Sstevel@tonic-gate 				 * tp->t_eucign will be 0 if and only
34887c478bd9Sstevel@tonic-gate 				 * if the current 'c' is an ASCII character
34897c478bd9Sstevel@tonic-gate 				 * and also a byte. Otherwise, it will have
34907c478bd9Sstevel@tonic-gate 				 * the byte length of a multibyte character.
34917c478bd9Sstevel@tonic-gate 				 */
34927c478bd9Sstevel@tonic-gate 				if ((tp->t_state & TS_MEUC) &&
34937c478bd9Sstevel@tonic-gate 				    tp->t_eucign == 0 && NOTASCII(c)) {
34947c478bd9Sstevel@tonic-gate 					tp->t_eucign =
349585bb5f1dSis 					    tp->t_csmethods.ldterm_memwidth(
349685bb5f1dSis 					    c, (void *)tp);
34977c478bd9Sstevel@tonic-gate 					tp->t_scratch_len = tp->t_eucign;
34987c478bd9Sstevel@tonic-gate 
34997c478bd9Sstevel@tonic-gate 					if (tp->t_csdata.codeset_type !=
35007c478bd9Sstevel@tonic-gate 					    LDTERM_CS_TYPE_UTF8) {
35017c478bd9Sstevel@tonic-gate 						tp->t_col +=
350285bb5f1dSis 						    tp->
350385bb5f1dSis 						    t_csmethods.
350485bb5f1dSis 						    ldterm_dispwidth(c,
350585bb5f1dSis 						    (void *)tp,
350685bb5f1dSis 						    tp->t_modes.c_lflag &
350785bb5f1dSis 						    ECHOCTL);
35087c478bd9Sstevel@tonic-gate 					}
35097c478bd9Sstevel@tonic-gate 				}
35107c478bd9Sstevel@tonic-gate 
35117c478bd9Sstevel@tonic-gate 				/*
35127c478bd9Sstevel@tonic-gate 				 * If character is mapped on output,
35137c478bd9Sstevel@tonic-gate 				 * put out a backslash followed by
35147c478bd9Sstevel@tonic-gate 				 * what it is mapped to.
35157c478bd9Sstevel@tonic-gate 				 */
35167c478bd9Sstevel@tonic-gate 				if (tp->t_eucign == 0 && omaptab[c] != 0 &&
35177c478bd9Sstevel@tonic-gate 				    (!echoing || c != '\\')) {
35187c478bd9Sstevel@tonic-gate 					/* backslash is an ordinary character */
35197c478bd9Sstevel@tonic-gate 					tp->t_col++;
35207c478bd9Sstevel@tonic-gate 					*obp->b_wptr++ = '\\';
35217c478bd9Sstevel@tonic-gate 					bytes_left--;
35227c478bd9Sstevel@tonic-gate 					if (bytes_left == 0) {
35237c478bd9Sstevel@tonic-gate 						/* LINTED */
35247c478bd9Sstevel@tonic-gate 						NEW_BLOCK(1);
35257c478bd9Sstevel@tonic-gate 					}
35267c478bd9Sstevel@tonic-gate 					/*
35277c478bd9Sstevel@tonic-gate 					 * Allocation failed, make
35287c478bd9Sstevel@tonic-gate 					 * state consistent before
35297c478bd9Sstevel@tonic-gate 					 * returning
35307c478bd9Sstevel@tonic-gate 					 */
35317c478bd9Sstevel@tonic-gate 					if (obp == NULL) {
35327c478bd9Sstevel@tonic-gate 						ibp->b_rptr--;
35337c478bd9Sstevel@tonic-gate 						tp->t_col--;
35347c478bd9Sstevel@tonic-gate 						oobp->b_wptr--;
35357c478bd9Sstevel@tonic-gate 						goto outofbufs;
35367c478bd9Sstevel@tonic-gate 					}
35377c478bd9Sstevel@tonic-gate 					c = omaptab[c];
35387c478bd9Sstevel@tonic-gate 				}
35397c478bd9Sstevel@tonic-gate 				/*
35407c478bd9Sstevel@tonic-gate 				 * If no other output processing is
35417c478bd9Sstevel@tonic-gate 				 * required, push the character into
35427c478bd9Sstevel@tonic-gate 				 * the block and get another.
35437c478bd9Sstevel@tonic-gate 				 */
35447c478bd9Sstevel@tonic-gate 				if (!(tp->t_modes.c_oflag & OPOST)) {
35457c478bd9Sstevel@tonic-gate 					if (tp->t_eucign > 0) {
35467c478bd9Sstevel@tonic-gate 						--tp->t_eucign;
35477c478bd9Sstevel@tonic-gate 					} else {
35487c478bd9Sstevel@tonic-gate 						tp->t_col++;
35497c478bd9Sstevel@tonic-gate 					}
35507c478bd9Sstevel@tonic-gate 					*obp->b_wptr++ = c;
35517c478bd9Sstevel@tonic-gate 					bytes_left--;
35527c478bd9Sstevel@tonic-gate 					continue;
35537c478bd9Sstevel@tonic-gate 				}
35547c478bd9Sstevel@tonic-gate 				/*
35557c478bd9Sstevel@tonic-gate 				 * OPOST output flag is set. Map
35567c478bd9Sstevel@tonic-gate 				 * lower case to upper case if OLCUC
35577c478bd9Sstevel@tonic-gate 				 * flag is set and the 'c' is a lowercase
35587c478bd9Sstevel@tonic-gate 				 * ASCII character.
35597c478bd9Sstevel@tonic-gate 				 */
35607c478bd9Sstevel@tonic-gate 				if (tp->t_eucign == 0 &&
35617c478bd9Sstevel@tonic-gate 				    (tp->t_modes.c_oflag & OLCUC) &&
35627c478bd9Sstevel@tonic-gate 				    c >= 'a' && c <= 'z')
35637c478bd9Sstevel@tonic-gate 					c -= 'a' - 'A';
35647c478bd9Sstevel@tonic-gate 			} else {
35657c478bd9Sstevel@tonic-gate 				/*
35667c478bd9Sstevel@tonic-gate 				 * Copy all the ORDINARY characters,
35677c478bd9Sstevel@tonic-gate 				 * possibly mapping upper case to
35687c478bd9Sstevel@tonic-gate 				 * lower case.  We use "movtuc",
35697c478bd9Sstevel@tonic-gate 				 * STOPPING when we can't move some
35707c478bd9Sstevel@tonic-gate 				 * character. For multi-byte or
35717c478bd9Sstevel@tonic-gate 				 * multi-column EUC, we can't depend
35727c478bd9Sstevel@tonic-gate 				 * on the regular tables. Rather than
35737c478bd9Sstevel@tonic-gate 				 * just drop through to the "big
35747c478bd9Sstevel@tonic-gate 				 * switch" for all characters, it
35757c478bd9Sstevel@tonic-gate 				 * _might_ be faster to let "movtuc"
35767c478bd9Sstevel@tonic-gate 				 * move a bunch of characters.
35777c478bd9Sstevel@tonic-gate 				 * Chances are, even in multi-byte
35787c478bd9Sstevel@tonic-gate 				 * mode we'll have lots of ASCII
35797c478bd9Sstevel@tonic-gate 				 * going through. We check the flag
35807c478bd9Sstevel@tonic-gate 				 * once, and call movtuc with the
35817c478bd9Sstevel@tonic-gate 				 * appropriate table as an argument.
35827c478bd9Sstevel@tonic-gate 				 *
35837c478bd9Sstevel@tonic-gate 				 * "movtuc will work for all codeset
35847c478bd9Sstevel@tonic-gate 				 * types since it stops at the beginning
35857c478bd9Sstevel@tonic-gate 				 * byte of a multibyte character.
35867c478bd9Sstevel@tonic-gate 				 */
35877c478bd9Sstevel@tonic-gate 				size_t bytes_to_move;
35887c478bd9Sstevel@tonic-gate 				size_t bytes_moved;
35897c478bd9Sstevel@tonic-gate 
35907c478bd9Sstevel@tonic-gate 				ASSERT(ibp->b_wptr >= ibp->b_rptr);
35917c478bd9Sstevel@tonic-gate 				bytes_to_move = ibp->b_wptr - ibp->b_rptr;
35927c478bd9Sstevel@tonic-gate 				if (bytes_to_move > bytes_left)
35937c478bd9Sstevel@tonic-gate 					bytes_to_move = bytes_left;
35947c478bd9Sstevel@tonic-gate 				if (tp->t_state & TS_MEUC) {
35957c478bd9Sstevel@tonic-gate 					bytes_moved = movtuc(bytes_to_move,
359685bb5f1dSis 					    ibp->b_rptr, obp->b_wptr,
359785bb5f1dSis 					    (tp->t_modes.c_oflag & OLCUC ?
359885bb5f1dSis 					    elcuctab : enotrantab));
35997c478bd9Sstevel@tonic-gate 				} else {
36007c478bd9Sstevel@tonic-gate 					bytes_moved = movtuc(bytes_to_move,
36017c478bd9Sstevel@tonic-gate 					    ibp->b_rptr, obp->b_wptr,
36027c478bd9Sstevel@tonic-gate 					    (tp->t_modes.c_oflag & OLCUC ?
36037c478bd9Sstevel@tonic-gate 					    lcuctab : notrantab));
36047c478bd9Sstevel@tonic-gate 				}
36057c478bd9Sstevel@tonic-gate 				/*
36067c478bd9Sstevel@tonic-gate 				 * We're save to just do this column
36077c478bd9Sstevel@tonic-gate 				 * calculation, because if TS_MEUC is
36087c478bd9Sstevel@tonic-gate 				 * set, we used the proper EUC
36097c478bd9Sstevel@tonic-gate 				 * tables, and won't have copied any
36107c478bd9Sstevel@tonic-gate 				 * EUC bytes.
36117c478bd9Sstevel@tonic-gate 				 */
36127c478bd9Sstevel@tonic-gate 				tp->t_col += bytes_moved;
36137c478bd9Sstevel@tonic-gate 				ibp->b_rptr += bytes_moved;
36147c478bd9Sstevel@tonic-gate 				obp->b_wptr += bytes_moved;
36157c478bd9Sstevel@tonic-gate 				bytes_left -= bytes_moved;
36167c478bd9Sstevel@tonic-gate 				if (ibp->b_rptr >= ibp->b_wptr)
36177c478bd9Sstevel@tonic-gate 					continue;	/* moved all of block */
36187c478bd9Sstevel@tonic-gate 				if (bytes_left == 0) {
36197c478bd9Sstevel@tonic-gate 					/* LINTED */
36207c478bd9Sstevel@tonic-gate 					NEW_BLOCK(0);
36217c478bd9Sstevel@tonic-gate 				}
36227c478bd9Sstevel@tonic-gate 				c = *ibp->b_rptr++;	/* stopper */
36237c478bd9Sstevel@tonic-gate 			}
36247c478bd9Sstevel@tonic-gate 
36257c478bd9Sstevel@tonic-gate 			/*
36267c478bd9Sstevel@tonic-gate 			 * Again, we need to make sure that this is not
36277c478bd9Sstevel@tonic-gate 			 * a following byte of a multibyte character at
36287c478bd9Sstevel@tonic-gate 			 * here.
36297c478bd9Sstevel@tonic-gate 			 *
36307c478bd9Sstevel@tonic-gate 			 * 'tp->t_eucign' will be 0 iff the current 'c' is
36317c478bd9Sstevel@tonic-gate 			 * an ASCII character. Otherwise, it will have
36327c478bd9Sstevel@tonic-gate 			 * the byte length of a multibyte character.
36337c478bd9Sstevel@tonic-gate 			 * We also add the display width to 'tp->t_col' if
36347c478bd9Sstevel@tonic-gate 			 * the current codeset is not UTF-8 since this is
36357c478bd9Sstevel@tonic-gate 			 * a leading byte of a multibyte character.
36367c478bd9Sstevel@tonic-gate 			 * For UTF-8 codeset type, we add the display width
36377c478bd9Sstevel@tonic-gate 			 * when we get the last byte of a character.
36387c478bd9Sstevel@tonic-gate 			 */
36397c478bd9Sstevel@tonic-gate 			if ((tp->t_state & TS_MEUC) && tp->t_eucign == 0 &&
36407c478bd9Sstevel@tonic-gate 			    NOTASCII(c)) {
36417c478bd9Sstevel@tonic-gate 				tp->t_eucign = tp->t_csmethods.ldterm_memwidth(
364285bb5f1dSis 				    c, (void *)tp);
36437c478bd9Sstevel@tonic-gate 				tp->t_scratch_len = tp->t_eucign;
36447c478bd9Sstevel@tonic-gate 
36457c478bd9Sstevel@tonic-gate 				if (tp->t_csdata.codeset_type !=
36467c478bd9Sstevel@tonic-gate 				    LDTERM_CS_TYPE_UTF8) {
36477c478bd9Sstevel@tonic-gate 					tp->t_col +=
36487c478bd9Sstevel@tonic-gate 					    tp->t_csmethods.ldterm_dispwidth(c,
364985bb5f1dSis 					    (void *)tp,
365085bb5f1dSis 					    tp->t_modes.c_lflag & ECHOCTL);
36517c478bd9Sstevel@tonic-gate 				}
36527c478bd9Sstevel@tonic-gate 			}
36537c478bd9Sstevel@tonic-gate 
36547c478bd9Sstevel@tonic-gate 			/*
36557c478bd9Sstevel@tonic-gate 			 * If the driver has requested, don't process
36567c478bd9Sstevel@tonic-gate 			 * output flags.  However, if we're in
36577c478bd9Sstevel@tonic-gate 			 * multi-byte mode, we HAVE to look at
36587c478bd9Sstevel@tonic-gate 			 * EVERYTHING going out to maintain column
36597c478bd9Sstevel@tonic-gate 			 * position properly. Therefore IF the driver
36607c478bd9Sstevel@tonic-gate 			 * says don't AND we're not doing multi-byte,
36617c478bd9Sstevel@tonic-gate 			 * then don't do it.  Otherwise, do it.
36627c478bd9Sstevel@tonic-gate 			 *
36637c478bd9Sstevel@tonic-gate 			 * NOTE:  Hardware USUALLY doesn't expand tabs
36647c478bd9Sstevel@tonic-gate 			 * properly for multi-byte situations anyway;
36657c478bd9Sstevel@tonic-gate 			 * that's a known problem with the 3B2
36667c478bd9Sstevel@tonic-gate 			 * "PORTS" board firmware, and any other
36677c478bd9Sstevel@tonic-gate 			 * hardware that doesn't ACTUALLY know about
36687c478bd9Sstevel@tonic-gate 			 * the current EUC mapping that WE are using
36697c478bd9Sstevel@tonic-gate 			 * at this very moment.  The problem is that
36707c478bd9Sstevel@tonic-gate 			 * memory width is INDEPENDENT of screen
36717c478bd9Sstevel@tonic-gate 			 * width - no relation - so WE know how wide
36727c478bd9Sstevel@tonic-gate 			 * the characters are, but an off-the-host
36737c478bd9Sstevel@tonic-gate 			 * board probably doesn't.  So, until we're
36747c478bd9Sstevel@tonic-gate 			 * SURE that the hardware below us can
36757c478bd9Sstevel@tonic-gate 			 * correctly expand tabs in a
36767c478bd9Sstevel@tonic-gate 			 * multi-byte/multi-column EUC situation, we
36777c478bd9Sstevel@tonic-gate 			 * do it ourselves.
36787c478bd9Sstevel@tonic-gate 			 */
36797c478bd9Sstevel@tonic-gate 			/*
36807c478bd9Sstevel@tonic-gate 			 * Map <CR>to<NL> on output if OCRNL flag
36817c478bd9Sstevel@tonic-gate 			 * set. ONLCR processing is not done if OCRNL
36827c478bd9Sstevel@tonic-gate 			 * is set.
36837c478bd9Sstevel@tonic-gate 			 */
36847c478bd9Sstevel@tonic-gate 			if (c == '\r' && (tp->t_modes.c_oflag & OCRNL)) {
36857c478bd9Sstevel@tonic-gate 				c = '\n';
36867c478bd9Sstevel@tonic-gate 				ctype = typetab[c];
36877c478bd9Sstevel@tonic-gate 				goto jocrnl;
36887c478bd9Sstevel@tonic-gate 			}
36897c478bd9Sstevel@tonic-gate 
36907c478bd9Sstevel@tonic-gate 			if (tp->t_csdata.codeset_type == LDTERM_CS_TYPE_EUC) {
36917c478bd9Sstevel@tonic-gate 				ctype = typetab[c];
36927c478bd9Sstevel@tonic-gate 			} else {
36937c478bd9Sstevel@tonic-gate 				/*
36947c478bd9Sstevel@tonic-gate 				 * In other codeset types, we safely assume
36957c478bd9Sstevel@tonic-gate 				 * any byte of a multibyte character will have
36967c478bd9Sstevel@tonic-gate 				 * 'ORDINARY' type. For ASCII characters, we
36977c478bd9Sstevel@tonic-gate 				 * still use the typetab[].
36987c478bd9Sstevel@tonic-gate 				 */
36997c478bd9Sstevel@tonic-gate 				if (tp->t_eucign == 0)
37007c478bd9Sstevel@tonic-gate 					ctype = typetab[c];
37017c478bd9Sstevel@tonic-gate 				else
37027c478bd9Sstevel@tonic-gate 					ctype = ORDINARY;
37037c478bd9Sstevel@tonic-gate 			}
37047c478bd9Sstevel@tonic-gate 
37057c478bd9Sstevel@tonic-gate 			/*
37067c478bd9Sstevel@tonic-gate 			 * Map <NL> to <CR><NL> on output if ONLCR
37077c478bd9Sstevel@tonic-gate 			 * flag is set.
37087c478bd9Sstevel@tonic-gate 			 */
37097c478bd9Sstevel@tonic-gate 			if (c == '\n' && (tp->t_modes.c_oflag & ONLCR)) {
37107c478bd9Sstevel@tonic-gate 				if (!(tp->t_state & TS_TTCR)) {
37117c478bd9Sstevel@tonic-gate 					tp->t_state |= TS_TTCR;
37127c478bd9Sstevel@tonic-gate 					c = '\r';
37137c478bd9Sstevel@tonic-gate 					ctype = typetab['\r'];
37147c478bd9Sstevel@tonic-gate 					--ibp->b_rptr;
37157c478bd9Sstevel@tonic-gate 				} else
37167c478bd9Sstevel@tonic-gate 					tp->t_state &= ~TS_TTCR;
37177c478bd9Sstevel@tonic-gate 			}
37187c478bd9Sstevel@tonic-gate 			/*
37197c478bd9Sstevel@tonic-gate 			 * Delay values and column position
37207c478bd9Sstevel@tonic-gate 			 * calculated here.  For EUC chars in
37217c478bd9Sstevel@tonic-gate 			 * multi-byte mode, we use "t_eucign" to help
37227c478bd9Sstevel@tonic-gate 			 * calculate columns.  When we see the first
37237c478bd9Sstevel@tonic-gate 			 * byte of an EUC, we set t_eucign to the
37247c478bd9Sstevel@tonic-gate 			 * number of bytes that will FOLLOW it, and
37257c478bd9Sstevel@tonic-gate 			 * we add the screen width of the WHOLE EUC
37267c478bd9Sstevel@tonic-gate 			 * character to the column position.  In
37277c478bd9Sstevel@tonic-gate 			 * particular, we can't count SS2 or SS3 as
37287c478bd9Sstevel@tonic-gate 			 * printing characters.  Remember, folks, the
37297c478bd9Sstevel@tonic-gate 			 * screen width and memory width are
37307c478bd9Sstevel@tonic-gate 			 * independent - no relation. We could have
37317c478bd9Sstevel@tonic-gate 			 * dropped through for ASCII, but we want to
37327c478bd9Sstevel@tonic-gate 			 * catch any bad characters (i.e., t_eucign
37337c478bd9Sstevel@tonic-gate 			 * set and an ASCII char received) and
37347c478bd9Sstevel@tonic-gate 			 * possibly report the garbage situation.
37357c478bd9Sstevel@tonic-gate 			 */
37367c478bd9Sstevel@tonic-gate 	jocrnl:
37377c478bd9Sstevel@tonic-gate 
37387c478bd9Sstevel@tonic-gate 			count = 0;
37397c478bd9Sstevel@tonic-gate 			switch (ctype) {
37407c478bd9Sstevel@tonic-gate 
37417c478bd9Sstevel@tonic-gate 			case T_SS2:
37427c478bd9Sstevel@tonic-gate 			case T_SS3:
37437c478bd9Sstevel@tonic-gate 			case ORDINARY:
37447c478bd9Sstevel@tonic-gate 				if (tp->t_state & TS_MEUC) {
37457c478bd9Sstevel@tonic-gate 					if (tp->t_eucign) {
37467c478bd9Sstevel@tonic-gate 						*obp->b_wptr++ = c;
37477c478bd9Sstevel@tonic-gate 						bytes_left--;
37487c478bd9Sstevel@tonic-gate 
37497c478bd9Sstevel@tonic-gate 						tp->t_scratch[tp->t_scratch_len
37507c478bd9Sstevel@tonic-gate 						    - tp->t_eucign] = c;
37517c478bd9Sstevel@tonic-gate 
37527c478bd9Sstevel@tonic-gate 						--tp->t_eucign;
37537c478bd9Sstevel@tonic-gate 
37547c478bd9Sstevel@tonic-gate 						if (tp->t_csdata.codeset_type
37557c478bd9Sstevel@tonic-gate 						    == LDTERM_CS_TYPE_UTF8 &&
37567c478bd9Sstevel@tonic-gate 						    tp->t_eucign <= 0) {
37577c478bd9Sstevel@tonic-gate 							tp->t_col +=
37587c478bd9Sstevel@tonic-gate 							    ldterm_utf8_width(
37597c478bd9Sstevel@tonic-gate 							    tp->t_scratch,
37607c478bd9Sstevel@tonic-gate 							    tp->t_scratch_len);
37617c478bd9Sstevel@tonic-gate 						}
37627c478bd9Sstevel@tonic-gate 					} else {
37637c478bd9Sstevel@tonic-gate 						if (tp->t_modes.c_oflag & OLCUC)
37647c478bd9Sstevel@tonic-gate 							n = elcuctab[c];
37657c478bd9Sstevel@tonic-gate 						else
37667c478bd9Sstevel@tonic-gate 							n = enotrantab[c];
37677c478bd9Sstevel@tonic-gate 						if (n)
37687c478bd9Sstevel@tonic-gate 							c = n;
37697c478bd9Sstevel@tonic-gate 						tp->t_col++;
37707c478bd9Sstevel@tonic-gate 						*obp->b_wptr++ = c;
37717c478bd9Sstevel@tonic-gate 						bytes_left--;
37727c478bd9Sstevel@tonic-gate 					}
37737c478bd9Sstevel@tonic-gate 				} else {	/* ho hum, ASCII mode... */
37747c478bd9Sstevel@tonic-gate 					if (tp->t_modes.c_oflag & OLCUC)
37757c478bd9Sstevel@tonic-gate 						n = lcuctab[c];
37767c478bd9Sstevel@tonic-gate 					else
37777c478bd9Sstevel@tonic-gate 						n = notrantab[c];
37787c478bd9Sstevel@tonic-gate 					if (n)
37797c478bd9Sstevel@tonic-gate 						c = n;
37807c478bd9Sstevel@tonic-gate 					tp->t_col++;
37817c478bd9Sstevel@tonic-gate 					*obp->b_wptr++ = c;
37827c478bd9Sstevel@tonic-gate 					bytes_left--;
37837c478bd9Sstevel@tonic-gate 				}
37847c478bd9Sstevel@tonic-gate 				break;
37857c478bd9Sstevel@tonic-gate 
37867c478bd9Sstevel@tonic-gate 				/*
37877c478bd9Sstevel@tonic-gate 				 * If we're doing ECHOCTL, we've
37887c478bd9Sstevel@tonic-gate 				 * already mapped the thing during
37897c478bd9Sstevel@tonic-gate 				 * the process of canonising.  Don't
37907c478bd9Sstevel@tonic-gate 				 * bother here, as it's not one that
37917c478bd9Sstevel@tonic-gate 				 * we did.
37927c478bd9Sstevel@tonic-gate 				 */
37937c478bd9Sstevel@tonic-gate 			case CONTROL:
37947c478bd9Sstevel@tonic-gate 				*obp->b_wptr++ = c;
37957c478bd9Sstevel@tonic-gate 				bytes_left--;
37967c478bd9Sstevel@tonic-gate 				break;
37977c478bd9Sstevel@tonic-gate 
37987c478bd9Sstevel@tonic-gate 				/*
37997c478bd9Sstevel@tonic-gate 				 * This is probably a backspace
38007c478bd9Sstevel@tonic-gate 				 * received, not one that we're
38017c478bd9Sstevel@tonic-gate 				 * echoing.  Let it go as a
38027c478bd9Sstevel@tonic-gate 				 * single-column backspace.
38037c478bd9Sstevel@tonic-gate 				 */
38047c478bd9Sstevel@tonic-gate 			case BACKSPACE:
38057c478bd9Sstevel@tonic-gate 				if (tp->t_col)
38067c478bd9Sstevel@tonic-gate 					tp->t_col--;
38077c478bd9Sstevel@tonic-gate 				if (tp->t_modes.c_oflag & BSDLY) {
38087c478bd9Sstevel@tonic-gate 					if (tp->t_modes.c_oflag & OFILL)
38097c478bd9Sstevel@tonic-gate 						count = 1;
38107c478bd9Sstevel@tonic-gate 				}
38117c478bd9Sstevel@tonic-gate 				*obp->b_wptr++ = c;
38127c478bd9Sstevel@tonic-gate 				bytes_left--;
38137c478bd9Sstevel@tonic-gate 				break;
38147c478bd9Sstevel@tonic-gate 
38157c478bd9Sstevel@tonic-gate 			case NEWLINE:
38167c478bd9Sstevel@tonic-gate 				if (tp->t_modes.c_oflag & ONLRET)
38177c478bd9Sstevel@tonic-gate 					goto cr;
38187c478bd9Sstevel@tonic-gate 				if ((tp->t_modes.c_oflag & NLDLY) == NL1)
38197c478bd9Sstevel@tonic-gate 					count = 2;
38207c478bd9Sstevel@tonic-gate 				*obp->b_wptr++ = c;
38217c478bd9Sstevel@tonic-gate 				bytes_left--;
38227c478bd9Sstevel@tonic-gate 				break;
38237c478bd9Sstevel@tonic-gate 
38247c478bd9Sstevel@tonic-gate 			case TAB:
38257c478bd9Sstevel@tonic-gate 				/*
38267c478bd9Sstevel@tonic-gate 				 * Map '\t' to spaces if XTABS flag
38277c478bd9Sstevel@tonic-gate 				 * is set.  The calculation of
38287c478bd9Sstevel@tonic-gate 				 * "t_eucign" has probably insured
38297c478bd9Sstevel@tonic-gate 				 * that column will be correct, as we
38307c478bd9Sstevel@tonic-gate 				 * bumped t_col by the DISP width,
38317c478bd9Sstevel@tonic-gate 				 * not the memory width.
38327c478bd9Sstevel@tonic-gate 				 */
38337c478bd9Sstevel@tonic-gate 				if ((tp->t_modes.c_oflag & TABDLY) == XTABS) {
38347c478bd9Sstevel@tonic-gate 					for (;;) {
38357c478bd9Sstevel@tonic-gate 						*obp->b_wptr++ = ' ';
38367c478bd9Sstevel@tonic-gate 						bytes_left--;
38377c478bd9Sstevel@tonic-gate 						tp->t_col++;
38387c478bd9Sstevel@tonic-gate 						if ((tp->t_col & 07) == 0)
38397c478bd9Sstevel@tonic-gate 							break;	/* every 8th */
38407c478bd9Sstevel@tonic-gate 						/*
38417c478bd9Sstevel@tonic-gate 						 * If we don't have
38427c478bd9Sstevel@tonic-gate 						 * room to fully
38437c478bd9Sstevel@tonic-gate 						 * expand this tab in
38447c478bd9Sstevel@tonic-gate 						 * this block, back
38457c478bd9Sstevel@tonic-gate 						 * up to continue
38467c478bd9Sstevel@tonic-gate 						 * expanding it into
38477c478bd9Sstevel@tonic-gate 						 * the next block.
38487c478bd9Sstevel@tonic-gate 						 */
38497c478bd9Sstevel@tonic-gate 						if (obp->b_wptr >=
38507c478bd9Sstevel@tonic-gate 						    obp->b_datap->db_lim) {
38517c478bd9Sstevel@tonic-gate 							ibp->b_rptr--;
38527c478bd9Sstevel@tonic-gate 							break;
38537c478bd9Sstevel@tonic-gate 						}
38547c478bd9Sstevel@tonic-gate 					}
38557c478bd9Sstevel@tonic-gate 				} else {
38567c478bd9Sstevel@tonic-gate 					tp->t_col |= 07;
38577c478bd9Sstevel@tonic-gate 					tp->t_col++;
38587c478bd9Sstevel@tonic-gate 					if (tp->t_modes.c_oflag & OFILL) {
38597c478bd9Sstevel@tonic-gate 						if (tp->t_modes.c_oflag &
38607c478bd9Sstevel@tonic-gate 						    TABDLY)
38617c478bd9Sstevel@tonic-gate 							count = 2;
38627c478bd9Sstevel@tonic-gate 					} else {
38637c478bd9Sstevel@tonic-gate 						switch (tp->t_modes.c_oflag &
38647c478bd9Sstevel@tonic-gate 						    TABDLY) {
38657c478bd9Sstevel@tonic-gate 						case TAB2:
38667c478bd9Sstevel@tonic-gate 							count = 6;
38677c478bd9Sstevel@tonic-gate 							break;
38687c478bd9Sstevel@tonic-gate 
38697c478bd9Sstevel@tonic-gate 						case TAB1:
38707c478bd9Sstevel@tonic-gate 							count = 1 + (tp->t_col |
38717c478bd9Sstevel@tonic-gate 							    ~07);
38727c478bd9Sstevel@tonic-gate 							if (count < 5)
38737c478bd9Sstevel@tonic-gate 								count = 0;
38747c478bd9Sstevel@tonic-gate 							break;
38757c478bd9Sstevel@tonic-gate 						}
38767c478bd9Sstevel@tonic-gate 					}
38777c478bd9Sstevel@tonic-gate 					*obp->b_wptr++ = c;
38787c478bd9Sstevel@tonic-gate 					bytes_left--;
38797c478bd9Sstevel@tonic-gate 				}
38807c478bd9Sstevel@tonic-gate 				break;
38817c478bd9Sstevel@tonic-gate 
38827c478bd9Sstevel@tonic-gate 			case VTAB:
38837c478bd9Sstevel@tonic-gate 				if ((tp->t_modes.c_oflag & VTDLY) &&
38847c478bd9Sstevel@tonic-gate 				    !(tp->t_modes.c_oflag & OFILL))
38857c478bd9Sstevel@tonic-gate 					count = 127;
38867c478bd9Sstevel@tonic-gate 				*obp->b_wptr++ = c;
38877c478bd9Sstevel@tonic-gate 				bytes_left--;
38887c478bd9Sstevel@tonic-gate 				break;
38897c478bd9Sstevel@tonic-gate 
38907c478bd9Sstevel@tonic-gate 			case RETURN:
38917c478bd9Sstevel@tonic-gate 				/*
38927c478bd9Sstevel@tonic-gate 				 * Ignore <CR> in column 0 if ONOCR
38937c478bd9Sstevel@tonic-gate 				 * flag set.
38947c478bd9Sstevel@tonic-gate 				 */
38957c478bd9Sstevel@tonic-gate 				if (tp->t_col == 0 &&
38967c478bd9Sstevel@tonic-gate 				    (tp->t_modes.c_oflag & ONOCR))
38977c478bd9Sstevel@tonic-gate 					break;
38987c478bd9Sstevel@tonic-gate 
38997c478bd9Sstevel@tonic-gate 		cr:
39007c478bd9Sstevel@tonic-gate 				switch (tp->t_modes.c_oflag & CRDLY) {
39017c478bd9Sstevel@tonic-gate 
39027c478bd9Sstevel@tonic-gate 				case CR1:
39037c478bd9Sstevel@tonic-gate 					if (tp->t_modes.c_oflag & OFILL)
39047c478bd9Sstevel@tonic-gate 						count = 2;
39057c478bd9Sstevel@tonic-gate 					else
39067c478bd9Sstevel@tonic-gate 						count = tp->t_col % 2;
39077c478bd9Sstevel@tonic-gate 					break;
39087c478bd9Sstevel@tonic-gate 
39097c478bd9Sstevel@tonic-gate 				case CR2:
39107c478bd9Sstevel@tonic-gate 					if (tp->t_modes.c_oflag & OFILL)
39117c478bd9Sstevel@tonic-gate 						count = 4;
39127c478bd9Sstevel@tonic-gate 					else
39137c478bd9Sstevel@tonic-gate 						count = 6;
39147c478bd9Sstevel@tonic-gate 					break;
39157c478bd9Sstevel@tonic-gate 
39167c478bd9Sstevel@tonic-gate 				case CR3:
39177c478bd9Sstevel@tonic-gate 					if (tp->t_modes.c_oflag & OFILL)
39187c478bd9Sstevel@tonic-gate 						count = 0;
39197c478bd9Sstevel@tonic-gate 					else
39207c478bd9Sstevel@tonic-gate 						count = 9;
39217c478bd9Sstevel@tonic-gate 					break;
39227c478bd9Sstevel@tonic-gate 				}
39237c478bd9Sstevel@tonic-gate 				tp->t_col = 0;
39247c478bd9Sstevel@tonic-gate 				*obp->b_wptr++ = c;
39257c478bd9Sstevel@tonic-gate 				bytes_left--;
39267c478bd9Sstevel@tonic-gate 				break;
39277c478bd9Sstevel@tonic-gate 			}
39287c478bd9Sstevel@tonic-gate 
39297c478bd9Sstevel@tonic-gate 			if (count != 0) {
39307c478bd9Sstevel@tonic-gate 				if (tp->t_modes.c_oflag & OFILL) {
39317c478bd9Sstevel@tonic-gate 					do {
39327c478bd9Sstevel@tonic-gate 						if (bytes_left == 0) {
39337c478bd9Sstevel@tonic-gate 							/* LINTED */
39347c478bd9Sstevel@tonic-gate 							NEW_BLOCK(0);
39357c478bd9Sstevel@tonic-gate 						}
39367c478bd9Sstevel@tonic-gate 						if (tp->t_modes.c_oflag & OFDEL)
39377c478bd9Sstevel@tonic-gate 							*obp->b_wptr++ = CDEL;
39387c478bd9Sstevel@tonic-gate 						else
39397c478bd9Sstevel@tonic-gate 							*obp->b_wptr++ = CNUL;
39407c478bd9Sstevel@tonic-gate 						bytes_left--;
39417c478bd9Sstevel@tonic-gate 					} while (--count != 0);
39427c478bd9Sstevel@tonic-gate 				} else {
39437c478bd9Sstevel@tonic-gate 					if ((tp->t_modes.c_lflag & FLUSHO) &&
39447c478bd9Sstevel@tonic-gate 					    (tp->t_modes.c_lflag & IEXTEN)) {
39457c478bd9Sstevel@tonic-gate 						/* drop on floor */
39467c478bd9Sstevel@tonic-gate 						freemsg(*omp);
39477c478bd9Sstevel@tonic-gate 					} else {
39487c478bd9Sstevel@tonic-gate 						/*
39497c478bd9Sstevel@tonic-gate 						 * Update sysinfo
39507c478bd9Sstevel@tonic-gate 						 * outch
39517c478bd9Sstevel@tonic-gate 						 */
39527c478bd9Sstevel@tonic-gate 						(void) drv_setparm(SYSOUTC,
39537c478bd9Sstevel@tonic-gate 						    msgdsize(*omp));
39547c478bd9Sstevel@tonic-gate 						putnext(q, *omp);
39557c478bd9Sstevel@tonic-gate 						/*
39567c478bd9Sstevel@tonic-gate 						 * Send M_DELAY
39577c478bd9Sstevel@tonic-gate 						 * downstream
39587c478bd9Sstevel@tonic-gate 						 */
39597c478bd9Sstevel@tonic-gate 						if ((bp =
39607c478bd9Sstevel@tonic-gate 						    allocb(1, BPRI_MED)) !=
39617c478bd9Sstevel@tonic-gate 						    NULL) {
39627c478bd9Sstevel@tonic-gate 							bp->b_datap->db_type =
39637c478bd9Sstevel@tonic-gate 							    M_DELAY;
39647c478bd9Sstevel@tonic-gate 							*bp->b_wptr++ =
396585bb5f1dSis 							    (uchar_t)count;
39667c478bd9Sstevel@tonic-gate 							putnext(q, bp);
39677c478bd9Sstevel@tonic-gate 						}
39687c478bd9Sstevel@tonic-gate 					}
39697c478bd9Sstevel@tonic-gate 					bytes_left = 0;
39707c478bd9Sstevel@tonic-gate 					/*
39717c478bd9Sstevel@tonic-gate 					 * We have to start a new
39727c478bd9Sstevel@tonic-gate 					 * message; the delay
39737c478bd9Sstevel@tonic-gate 					 * introduces a break between
39747c478bd9Sstevel@tonic-gate 					 * messages.
39757c478bd9Sstevel@tonic-gate 					 */
39767c478bd9Sstevel@tonic-gate 					*omp = NULL;
39777c478bd9Sstevel@tonic-gate 					contpp = omp;
39787c478bd9Sstevel@tonic-gate 				}
39797c478bd9Sstevel@tonic-gate 			}
39807c478bd9Sstevel@tonic-gate 		}
39817c478bd9Sstevel@tonic-gate 		cbp = ibp->b_cont;
39827c478bd9Sstevel@tonic-gate 		freeb(ibp);
39837c478bd9Sstevel@tonic-gate 	} while ((ibp = cbp) != NULL);	/* next block, if any */
39847c478bd9Sstevel@tonic-gate 
39857c478bd9Sstevel@tonic-gate outofbufs:
39867c478bd9Sstevel@tonic-gate 	return (ibp);
39877c478bd9Sstevel@tonic-gate #undef NEW_BLOCK
39887c478bd9Sstevel@tonic-gate }
39897c478bd9Sstevel@tonic-gate 
39907c478bd9Sstevel@tonic-gate 
39917c478bd9Sstevel@tonic-gate #if !defined(__sparc)
39927c478bd9Sstevel@tonic-gate int
movtuc(size_t size,unsigned char * from,unsigned char * origto,unsigned char * table)39937c478bd9Sstevel@tonic-gate movtuc(size_t size, unsigned char *from, unsigned char *origto,
39949a2c4685SToomas Soome     unsigned char *table)
39957c478bd9Sstevel@tonic-gate {
39967c478bd9Sstevel@tonic-gate 	unsigned char *to = origto;
39977c478bd9Sstevel@tonic-gate 	unsigned char c;
39987c478bd9Sstevel@tonic-gate 
39997c478bd9Sstevel@tonic-gate 	while (size != 0 && (c = table[*from++]) != 0) {
40007c478bd9Sstevel@tonic-gate 		*to++ = c;
40017c478bd9Sstevel@tonic-gate 		size--;
40027c478bd9Sstevel@tonic-gate 	}
40037c478bd9Sstevel@tonic-gate 	return (to - origto);
40047c478bd9Sstevel@tonic-gate }
40057c478bd9Sstevel@tonic-gate #endif
40067c478bd9Sstevel@tonic-gate 
40077c478bd9Sstevel@tonic-gate static void
ldterm_flush_output(uchar_t c,queue_t * q,ldtermstd_state_t * tp)40087c478bd9Sstevel@tonic-gate ldterm_flush_output(uchar_t c, queue_t *q, ldtermstd_state_t *tp)
40097c478bd9Sstevel@tonic-gate {
40107c478bd9Sstevel@tonic-gate 	/* Already conditioned with IEXTEN during VDISCARD processing */
40117c478bd9Sstevel@tonic-gate 	if (tp->t_modes.c_lflag & FLUSHO)
40127c478bd9Sstevel@tonic-gate 		tp->t_modes.c_lflag &= ~FLUSHO;
40137c478bd9Sstevel@tonic-gate 	else {
40147c478bd9Sstevel@tonic-gate 		flushq(q, FLUSHDATA);	/* flush our write queue */
40157c478bd9Sstevel@tonic-gate 		/* flush ones below us */
40167c478bd9Sstevel@tonic-gate 		(void) putnextctl1(q, M_FLUSH, FLUSHW);
40177c478bd9Sstevel@tonic-gate 		if ((tp->t_echomp = allocb(EBSIZE, BPRI_HI)) != NULL) {
40187c478bd9Sstevel@tonic-gate 			(void) ldterm_echo(c, q, 1, tp);
40197c478bd9Sstevel@tonic-gate 			if (tp->t_msglen != 0)
40207c478bd9Sstevel@tonic-gate 				ldterm_reprint(q, EBSIZE, tp);
40217c478bd9Sstevel@tonic-gate 			if (tp->t_echomp != NULL) {
40227c478bd9Sstevel@tonic-gate 				putnext(q, tp->t_echomp);
40237c478bd9Sstevel@tonic-gate 				tp->t_echomp = NULL;
40247c478bd9Sstevel@tonic-gate 			}
40257c478bd9Sstevel@tonic-gate 		}
40267c478bd9Sstevel@tonic-gate 		tp->t_modes.c_lflag |= FLUSHO;
40277c478bd9Sstevel@tonic-gate 	}
40287c478bd9Sstevel@tonic-gate }
40297c478bd9Sstevel@tonic-gate 
40307c478bd9Sstevel@tonic-gate 
40317c478bd9Sstevel@tonic-gate /*
40327c478bd9Sstevel@tonic-gate  * Signal generated by the reader: M_PCSIG and M_FLUSH messages sent.
40337c478bd9Sstevel@tonic-gate  */
40347c478bd9Sstevel@tonic-gate static void
ldterm_dosig(queue_t * q,int sig,uchar_t c,int mtype,int mode)40357c478bd9Sstevel@tonic-gate ldterm_dosig(queue_t *q, int sig, uchar_t c, int mtype, int mode)
40367c478bd9Sstevel@tonic-gate {
40377c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp = (ldtermstd_state_t *)q->q_ptr;
40387c478bd9Sstevel@tonic-gate 	int sndsig = 0;
40397c478bd9Sstevel@tonic-gate 
40407c478bd9Sstevel@tonic-gate 	/*
40417c478bd9Sstevel@tonic-gate 	 * c == \0 is brk case; need to flush on BRKINT even if
40427c478bd9Sstevel@tonic-gate 	 * noflsh is set.
40437c478bd9Sstevel@tonic-gate 	 */
40447c478bd9Sstevel@tonic-gate 	if ((!(tp->t_modes.c_lflag & NOFLSH)) || (c == '\0')) {
40457c478bd9Sstevel@tonic-gate 		if (mode) {
40467c478bd9Sstevel@tonic-gate 			if (tp->t_state & TS_TTSTOP) {
40477c478bd9Sstevel@tonic-gate 				sndsig = 1;
40487c478bd9Sstevel@tonic-gate 				(void) putnextctl1(q, mtype, sig);
40497c478bd9Sstevel@tonic-gate 			}
40507c478bd9Sstevel@tonic-gate 			/*
40517c478bd9Sstevel@tonic-gate 			 * Flush read or write side.
40527c478bd9Sstevel@tonic-gate 			 * Restart the input or output.
40537c478bd9Sstevel@tonic-gate 			 */
40547c478bd9Sstevel@tonic-gate 			if (mode & FLUSHR) {
40557c478bd9Sstevel@tonic-gate 				flushq(q, FLUSHDATA);
40567c478bd9Sstevel@tonic-gate 				(void) putnextctl1(WR(q), M_FLUSH, mode);
40577c478bd9Sstevel@tonic-gate 				if (tp->t_state & (TS_TBLOCK|TS_IFBLOCK)) {
40587c478bd9Sstevel@tonic-gate 					(void) putnextctl(WR(q), M_STARTI);
40597c478bd9Sstevel@tonic-gate 					tp->t_state &= ~(TS_TBLOCK|TS_IFBLOCK);
40607c478bd9Sstevel@tonic-gate 				}
40617c478bd9Sstevel@tonic-gate 			}
40627c478bd9Sstevel@tonic-gate 			if (mode & FLUSHW) {
40637c478bd9Sstevel@tonic-gate 				flushq(WR(q), FLUSHDATA);
40647c478bd9Sstevel@tonic-gate 				/*
40657c478bd9Sstevel@tonic-gate 				 * XXX This is extremely gross.
40667c478bd9Sstevel@tonic-gate 				 * Since we can't be sure our M_FLUSH
40677c478bd9Sstevel@tonic-gate 				 * will have run its course by the
40687c478bd9Sstevel@tonic-gate 				 * time we do the echo below, we set
40697c478bd9Sstevel@tonic-gate 				 * state and toss it in the write put
40707c478bd9Sstevel@tonic-gate 				 * routine to prevent flushing our
40717c478bd9Sstevel@tonic-gate 				 * own data.  Note that downstream
40727c478bd9Sstevel@tonic-gate 				 * modules on the write side will be
40737c478bd9Sstevel@tonic-gate 				 * flushed by the M_FLUSH sent above.
40747c478bd9Sstevel@tonic-gate 				 */
40757c478bd9Sstevel@tonic-gate 				tp->t_state |= TS_FLUSHWAIT;
40767c478bd9Sstevel@tonic-gate 				(void) putnextctl1(q, M_FLUSH, FLUSHW);
40777c478bd9Sstevel@tonic-gate 				if (tp->t_state & TS_TTSTOP) {
40787c478bd9Sstevel@tonic-gate 					(void) putnextctl(WR(q), M_START);
40797c478bd9Sstevel@tonic-gate 					tp->t_state &= ~(TS_TTSTOP|TS_OFBLOCK);
40807c478bd9Sstevel@tonic-gate 				}
40817c478bd9Sstevel@tonic-gate 			}
40827c478bd9Sstevel@tonic-gate 		}
40837c478bd9Sstevel@tonic-gate 	}
40847c478bd9Sstevel@tonic-gate 	tp->t_state &= ~TS_QUOT;
40857c478bd9Sstevel@tonic-gate 	if (sndsig == 0)
40867c478bd9Sstevel@tonic-gate 		(void) putnextctl1(q, mtype, sig);
40877c478bd9Sstevel@tonic-gate 
40887c478bd9Sstevel@tonic-gate 	if (c != '\0') {
40897c478bd9Sstevel@tonic-gate 		if ((tp->t_echomp = allocb(4, BPRI_HI)) != NULL) {
4090*7d8deab2SAndy Fiddaman 			if (ldterm_echo(c, WR(q), 4, tp) > 0 ||
4091*7d8deab2SAndy Fiddaman 			    (tp->t_state & TS_ISPTSTTY))
4092cfad0651SAndy Fiddaman 				putnext(WR(q), tp->t_echomp);
4093cfad0651SAndy Fiddaman 			else
4094cfad0651SAndy Fiddaman 				freemsg(tp->t_echomp);
40957c478bd9Sstevel@tonic-gate 			tp->t_echomp = NULL;
40967c478bd9Sstevel@tonic-gate 		}
40977c478bd9Sstevel@tonic-gate 	}
40987c478bd9Sstevel@tonic-gate }
40997c478bd9Sstevel@tonic-gate 
41007c478bd9Sstevel@tonic-gate 
41017c478bd9Sstevel@tonic-gate /*
41027c478bd9Sstevel@tonic-gate  * Called when an M_IOCTL message is seen on the write queue; does
41037c478bd9Sstevel@tonic-gate  * whatever we're supposed to do with it, and either replies
41047c478bd9Sstevel@tonic-gate  * immediately or passes it to the next module down.
41057c478bd9Sstevel@tonic-gate  */
41067c478bd9Sstevel@tonic-gate static void
ldterm_do_ioctl(queue_t * q,mblk_t * mp)41077c478bd9Sstevel@tonic-gate ldterm_do_ioctl(queue_t *q, mblk_t *mp)
41087c478bd9Sstevel@tonic-gate {
41097c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp;
41107c478bd9Sstevel@tonic-gate 	struct iocblk *iocp;
41117c478bd9Sstevel@tonic-gate 	struct eucioc *euciocp;	/* needed for EUC ioctls */
41127c478bd9Sstevel@tonic-gate 	ldterm_cs_data_user_t *csdp;
41137c478bd9Sstevel@tonic-gate 	int i;
41147c478bd9Sstevel@tonic-gate 	int locale_name_sz;
41157c478bd9Sstevel@tonic-gate 	uchar_t maxbytelen;
41167c478bd9Sstevel@tonic-gate 	uchar_t maxscreenlen;
41177c478bd9Sstevel@tonic-gate 	int error;
41187c478bd9Sstevel@tonic-gate 
41197c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
41207c478bd9Sstevel@tonic-gate 	tp = (ldtermstd_state_t *)q->q_ptr;
41217c478bd9Sstevel@tonic-gate 
41227c478bd9Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
41237c478bd9Sstevel@tonic-gate 
41247c478bd9Sstevel@tonic-gate 	case TCSETS:
41257c478bd9Sstevel@tonic-gate 	case TCSETSW:
41267c478bd9Sstevel@tonic-gate 	case TCSETSF:
41277c478bd9Sstevel@tonic-gate 		{
41287c478bd9Sstevel@tonic-gate 			/*
41297c478bd9Sstevel@tonic-gate 			 * Set current parameters and special
41307c478bd9Sstevel@tonic-gate 			 * characters.
41317c478bd9Sstevel@tonic-gate 			 */
41327c478bd9Sstevel@tonic-gate 			struct termios *cb;
41337c478bd9Sstevel@tonic-gate 			struct termios oldmodes;
41347c478bd9Sstevel@tonic-gate 
41357c478bd9Sstevel@tonic-gate 			error = miocpullup(mp, sizeof (struct termios));
41367c478bd9Sstevel@tonic-gate 			if (error != 0) {
41377c478bd9Sstevel@tonic-gate 				miocnak(q, mp, 0, error);
41387c478bd9Sstevel@tonic-gate 				return;
41397c478bd9Sstevel@tonic-gate 			}
41407c478bd9Sstevel@tonic-gate 
41417c478bd9Sstevel@tonic-gate 			cb = (struct termios *)mp->b_cont->b_rptr;
41427c478bd9Sstevel@tonic-gate 
41437c478bd9Sstevel@tonic-gate 			oldmodes = tp->t_amodes;
41447c478bd9Sstevel@tonic-gate 			tp->t_amodes = *cb;
41457c478bd9Sstevel@tonic-gate 			if ((tp->t_amodes.c_lflag & PENDIN) &&
41467c478bd9Sstevel@tonic-gate 			    (tp->t_modes.c_lflag & IEXTEN)) {
41477c478bd9Sstevel@tonic-gate 				/*
41487c478bd9Sstevel@tonic-gate 				 * Yuk.  The C shell file completion
41497c478bd9Sstevel@tonic-gate 				 * code actually uses this "feature",
41507c478bd9Sstevel@tonic-gate 				 * so we have to support it.
41517c478bd9Sstevel@tonic-gate 				 */
41527c478bd9Sstevel@tonic-gate 				if (tp->t_message != NULL) {
41537c478bd9Sstevel@tonic-gate 					tp->t_state |= TS_RESCAN;
41547c478bd9Sstevel@tonic-gate 					qenable(RD(q));
41557c478bd9Sstevel@tonic-gate 				}
41567c478bd9Sstevel@tonic-gate 				tp->t_amodes.c_lflag &= ~PENDIN;
41577c478bd9Sstevel@tonic-gate 			}
41587c478bd9Sstevel@tonic-gate 			bcopy(tp->t_amodes.c_cc, tp->t_modes.c_cc, NCCS);
41597c478bd9Sstevel@tonic-gate 
41607c478bd9Sstevel@tonic-gate 			/*
41617c478bd9Sstevel@tonic-gate 			 * ldterm_adjust_modes does not deal with
41627c478bd9Sstevel@tonic-gate 			 * cflags
41637c478bd9Sstevel@tonic-gate 			 */
41647c478bd9Sstevel@tonic-gate 			tp->t_modes.c_cflag = tp->t_amodes.c_cflag;
41657c478bd9Sstevel@tonic-gate 
41667c478bd9Sstevel@tonic-gate 			ldterm_adjust_modes(tp);
41677c478bd9Sstevel@tonic-gate 			if (chgstropts(&oldmodes, tp, RD(q)) == (-1)) {
41687c478bd9Sstevel@tonic-gate 				miocnak(q, mp, 0, EAGAIN);
41697c478bd9Sstevel@tonic-gate 				return;
41707c478bd9Sstevel@tonic-gate 			}
41717c478bd9Sstevel@tonic-gate 			/*
41727c478bd9Sstevel@tonic-gate 			 * The driver may want to know about the
41737c478bd9Sstevel@tonic-gate 			 * following iflags: IGNBRK, BRKINT, IGNPAR,
41747c478bd9Sstevel@tonic-gate 			 * PARMRK, INPCK, IXON, IXANY.
41757c478bd9Sstevel@tonic-gate 			 */
41767c478bd9Sstevel@tonic-gate 			break;
41777c478bd9Sstevel@tonic-gate 		}
41787c478bd9Sstevel@tonic-gate 
41797c478bd9Sstevel@tonic-gate 	case TCSETA:
41807c478bd9Sstevel@tonic-gate 	case TCSETAW:
41817c478bd9Sstevel@tonic-gate 	case TCSETAF:
41827c478bd9Sstevel@tonic-gate 		{
41837c478bd9Sstevel@tonic-gate 			/*
41847c478bd9Sstevel@tonic-gate 			 * Old-style "ioctl" to set current
41857c478bd9Sstevel@tonic-gate 			 * parameters and special characters. Don't
41867c478bd9Sstevel@tonic-gate 			 * clear out the unset portions, leave them
41877c478bd9Sstevel@tonic-gate 			 * as they are.
41887c478bd9Sstevel@tonic-gate 			 */
41897c478bd9Sstevel@tonic-gate 			struct termio *cb;
41907c478bd9Sstevel@tonic-gate 			struct termios oldmodes;
41917c478bd9Sstevel@tonic-gate 
41927c478bd9Sstevel@tonic-gate 			error = miocpullup(mp, sizeof (struct termio));
41937c478bd9Sstevel@tonic-gate 			if (error != 0) {
41947c478bd9Sstevel@tonic-gate 				miocnak(q, mp, 0, error);
41957c478bd9Sstevel@tonic-gate 				return;
41967c478bd9Sstevel@tonic-gate 			}
41977c478bd9Sstevel@tonic-gate 
41987c478bd9Sstevel@tonic-gate 			cb = (struct termio *)mp->b_cont->b_rptr;
41997c478bd9Sstevel@tonic-gate 
42007c478bd9Sstevel@tonic-gate 			oldmodes = tp->t_amodes;
42017c478bd9Sstevel@tonic-gate 			tp->t_amodes.c_iflag =
420285bb5f1dSis 			    (tp->t_amodes.c_iflag & 0xffff0000 | cb->c_iflag);
42037c478bd9Sstevel@tonic-gate 			tp->t_amodes.c_oflag =
420485bb5f1dSis 			    (tp->t_amodes.c_oflag & 0xffff0000 | cb->c_oflag);
42057c478bd9Sstevel@tonic-gate 			tp->t_amodes.c_cflag =
420685bb5f1dSis 			    (tp->t_amodes.c_cflag & 0xffff0000 | cb->c_cflag);
42077c478bd9Sstevel@tonic-gate 			tp->t_amodes.c_lflag =
420885bb5f1dSis 			    (tp->t_amodes.c_lflag & 0xffff0000 | cb->c_lflag);
42097c478bd9Sstevel@tonic-gate 
42107c478bd9Sstevel@tonic-gate 			bcopy(cb->c_cc, tp->t_modes.c_cc, NCC);
42117c478bd9Sstevel@tonic-gate 			/* TCGETS returns amodes, so update that too */
42127c478bd9Sstevel@tonic-gate 			bcopy(cb->c_cc, tp->t_amodes.c_cc, NCC);
42137c478bd9Sstevel@tonic-gate 
42147c478bd9Sstevel@tonic-gate 			/* ldterm_adjust_modes does not deal with cflags */
42157c478bd9Sstevel@tonic-gate 
42167c478bd9Sstevel@tonic-gate 			tp->t_modes.c_cflag = tp->t_amodes.c_cflag;
42177c478bd9Sstevel@tonic-gate 
42187c478bd9Sstevel@tonic-gate 			ldterm_adjust_modes(tp);
42197c478bd9Sstevel@tonic-gate 			if (chgstropts(&oldmodes, tp, RD(q)) == (-1)) {
42207c478bd9Sstevel@tonic-gate 				miocnak(q, mp, 0, EAGAIN);
42217c478bd9Sstevel@tonic-gate 				return;
42227c478bd9Sstevel@tonic-gate 			}
42237c478bd9Sstevel@tonic-gate 			/*
42247c478bd9Sstevel@tonic-gate 			 * The driver may want to know about the
42257c478bd9Sstevel@tonic-gate 			 * following iflags: IGNBRK, BRKINT, IGNPAR,
42267c478bd9Sstevel@tonic-gate 			 * PARMRK, INPCK, IXON, IXANY.
42277c478bd9Sstevel@tonic-gate 			 */
42287c478bd9Sstevel@tonic-gate 			break;
42297c478bd9Sstevel@tonic-gate 		}
42307c478bd9Sstevel@tonic-gate 
42317c478bd9Sstevel@tonic-gate 	case TCFLSH:
42327c478bd9Sstevel@tonic-gate 		/*
42337c478bd9Sstevel@tonic-gate 		 * Do the flush on the write queue immediately, and
42347c478bd9Sstevel@tonic-gate 		 * queue up any flush on the read queue for the
42357c478bd9Sstevel@tonic-gate 		 * service procedure to see.  Then turn it into the
42367c478bd9Sstevel@tonic-gate 		 * appropriate M_FLUSH message, so that the module
42377c478bd9Sstevel@tonic-gate 		 * below us doesn't have to know about TCFLSH.
42387c478bd9Sstevel@tonic-gate 		 */
42397c478bd9Sstevel@tonic-gate 		error = miocpullup(mp, sizeof (int));
42407c478bd9Sstevel@tonic-gate 		if (error != 0) {
42417c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, error);
42427c478bd9Sstevel@tonic-gate 			return;
42437c478bd9Sstevel@tonic-gate 		}
42447c478bd9Sstevel@tonic-gate 
42457c478bd9Sstevel@tonic-gate 		ASSERT(mp->b_datap != NULL);
42467c478bd9Sstevel@tonic-gate 		if (*(int *)mp->b_cont->b_rptr == 0) {
42477c478bd9Sstevel@tonic-gate 			ASSERT(mp->b_datap != NULL);
42487c478bd9Sstevel@tonic-gate 			(void) putnextctl1(q, M_FLUSH, FLUSHR);
42497c478bd9Sstevel@tonic-gate 			(void) putctl1(RD(q), M_FLUSH, FLUSHR);
42507c478bd9Sstevel@tonic-gate 		} else if (*(int *)mp->b_cont->b_rptr == 1) {
42517c478bd9Sstevel@tonic-gate 			flushq(q, FLUSHDATA);
42527c478bd9Sstevel@tonic-gate 			ASSERT(mp->b_datap != NULL);
42537c478bd9Sstevel@tonic-gate 			tp->t_state |= TS_FLUSHWAIT;
42547c478bd9Sstevel@tonic-gate 			(void) putnextctl1(RD(q), M_FLUSH, FLUSHW);
42557c478bd9Sstevel@tonic-gate 			(void) putnextctl1(q, M_FLUSH, FLUSHW);
42567c478bd9Sstevel@tonic-gate 		} else if (*(int *)mp->b_cont->b_rptr == 2) {
42577c478bd9Sstevel@tonic-gate 			flushq(q, FLUSHDATA);
42587c478bd9Sstevel@tonic-gate 			ASSERT(mp->b_datap != NULL);
42597c478bd9Sstevel@tonic-gate 			(void) putnextctl1(q, M_FLUSH, FLUSHRW);
42607c478bd9Sstevel@tonic-gate 			tp->t_state |= TS_FLUSHWAIT;
42617c478bd9Sstevel@tonic-gate 			(void) putnextctl1(RD(q), M_FLUSH, FLUSHRW);
42627c478bd9Sstevel@tonic-gate 		} else {
42637c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, EINVAL);
42647c478bd9Sstevel@tonic-gate 			return;
42657c478bd9Sstevel@tonic-gate 		}
42667c478bd9Sstevel@tonic-gate 		ASSERT(mp->b_datap != NULL);
42677c478bd9Sstevel@tonic-gate 		iocp->ioc_rval = 0;
42687c478bd9Sstevel@tonic-gate 		miocack(q, mp, 0, 0);
42697c478bd9Sstevel@tonic-gate 		return;
42707c478bd9Sstevel@tonic-gate 
42717c478bd9Sstevel@tonic-gate 	case TCXONC:
42727c478bd9Sstevel@tonic-gate 		error = miocpullup(mp, sizeof (int));
42737c478bd9Sstevel@tonic-gate 		if (error != 0) {
42747c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, error);
42757c478bd9Sstevel@tonic-gate 			return;
42767c478bd9Sstevel@tonic-gate 		}
42777c478bd9Sstevel@tonic-gate 
42787c478bd9Sstevel@tonic-gate 		switch (*(int *)mp->b_cont->b_rptr) {
42797c478bd9Sstevel@tonic-gate 		case 0:
42807c478bd9Sstevel@tonic-gate 			if (!(tp->t_state & TS_TTSTOP)) {
42817c478bd9Sstevel@tonic-gate 				(void) putnextctl(q, M_STOP);
42827c478bd9Sstevel@tonic-gate 				tp->t_state |= (TS_TTSTOP|TS_OFBLOCK);
42837c478bd9Sstevel@tonic-gate 			}
42847c478bd9Sstevel@tonic-gate 			break;
42857c478bd9Sstevel@tonic-gate 
42867c478bd9Sstevel@tonic-gate 		case 1:
42877c478bd9Sstevel@tonic-gate 			if (tp->t_state & TS_TTSTOP) {
42887c478bd9Sstevel@tonic-gate 				(void) putnextctl(q, M_START);
42897c478bd9Sstevel@tonic-gate 				tp->t_state &= ~(TS_TTSTOP|TS_OFBLOCK);
42907c478bd9Sstevel@tonic-gate 			}
42917c478bd9Sstevel@tonic-gate 			break;
42927c478bd9Sstevel@tonic-gate 
42937c478bd9Sstevel@tonic-gate 		case 2:
42947c478bd9Sstevel@tonic-gate 			(void) putnextctl(q, M_STOPI);
42957c478bd9Sstevel@tonic-gate 			tp->t_state |= (TS_TBLOCK|TS_IFBLOCK);
42967c478bd9Sstevel@tonic-gate 			break;
42977c478bd9Sstevel@tonic-gate 
42987c478bd9Sstevel@tonic-gate 		case 3:
42997c478bd9Sstevel@tonic-gate 			(void) putnextctl(q, M_STARTI);
43007c478bd9Sstevel@tonic-gate 			tp->t_state &= ~(TS_TBLOCK|TS_IFBLOCK);
43017c478bd9Sstevel@tonic-gate 			break;
43027c478bd9Sstevel@tonic-gate 
43037c478bd9Sstevel@tonic-gate 		default:
43047c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, EINVAL);
43057c478bd9Sstevel@tonic-gate 			return;
43067c478bd9Sstevel@tonic-gate 		}
43077c478bd9Sstevel@tonic-gate 		ASSERT(mp->b_datap != NULL);
43087c478bd9Sstevel@tonic-gate 		iocp->ioc_rval = 0;
43097c478bd9Sstevel@tonic-gate 		miocack(q, mp, 0, 0);
43107c478bd9Sstevel@tonic-gate 		return;
43117c478bd9Sstevel@tonic-gate 		/*
43127c478bd9Sstevel@tonic-gate 		 * TCSBRK is expected to be handled by the driver.
43137c478bd9Sstevel@tonic-gate 		 * The reason its left for the driver is that when
43147c478bd9Sstevel@tonic-gate 		 * the argument to TCSBRK is zero driver has to drain
43157c478bd9Sstevel@tonic-gate 		 * the data and sending a M_IOCACK from LDTERM before
43167c478bd9Sstevel@tonic-gate 		 * the driver drains the data is going to cause
43177c478bd9Sstevel@tonic-gate 		 * problems.
43187c478bd9Sstevel@tonic-gate 		 */
43197c478bd9Sstevel@tonic-gate 
43207c478bd9Sstevel@tonic-gate 		/*
43217c478bd9Sstevel@tonic-gate 		 * The following are EUC related ioctls.  For
43227c478bd9Sstevel@tonic-gate 		 * EUC_WSET, we have to pass the information on, even
43237c478bd9Sstevel@tonic-gate 		 * though we ACK the call.  It's vital in the EUC
43247c478bd9Sstevel@tonic-gate 		 * environment that everybody downstream knows about
43257c478bd9Sstevel@tonic-gate 		 * the EUC codeset widths currently in use; we
43267c478bd9Sstevel@tonic-gate 		 * therefore pass down the information in an M_CTL
43277c478bd9Sstevel@tonic-gate 		 * message.  It will bottom out in the driver.
43287c478bd9Sstevel@tonic-gate 		 */
43297c478bd9Sstevel@tonic-gate 	case EUC_WSET:
43307c478bd9Sstevel@tonic-gate 		{
43317c478bd9Sstevel@tonic-gate 
43327c478bd9Sstevel@tonic-gate 			/* only needed for EUC_WSET */
43337c478bd9Sstevel@tonic-gate 			struct iocblk *riocp;
43347c478bd9Sstevel@tonic-gate 
43357c478bd9Sstevel@tonic-gate 			mblk_t *dmp, *dmp_cont;
43367c478bd9Sstevel@tonic-gate 
43377c478bd9Sstevel@tonic-gate 			/*
43387c478bd9Sstevel@tonic-gate 			 * If the user didn't supply any information,
43397c478bd9Sstevel@tonic-gate 			 * NAK it.
43407c478bd9Sstevel@tonic-gate 			 */
43417c478bd9Sstevel@tonic-gate 			error = miocpullup(mp, sizeof (struct eucioc));
43427c478bd9Sstevel@tonic-gate 			if (error != 0) {
43437c478bd9Sstevel@tonic-gate 				miocnak(q, mp, 0, error);
43447c478bd9Sstevel@tonic-gate 				return;
43457c478bd9Sstevel@tonic-gate 			}
43467c478bd9Sstevel@tonic-gate 
43477c478bd9Sstevel@tonic-gate 			euciocp = (struct eucioc *)mp->b_cont->b_rptr;
43487c478bd9Sstevel@tonic-gate 			/*
43497c478bd9Sstevel@tonic-gate 			 * Check here for something reasonable.  If
43507c478bd9Sstevel@tonic-gate 			 * anything will take more than EUC_MAXW
43517c478bd9Sstevel@tonic-gate 			 * columns or more than EUC_MAXW bytes
43527c478bd9Sstevel@tonic-gate 			 * following SS2 or SS3, then just reject it
43537c478bd9Sstevel@tonic-gate 			 * out of hand. It's not impossible for us to
43547c478bd9Sstevel@tonic-gate 			 * do it, it just isn't reasonable.  So far,
43557c478bd9Sstevel@tonic-gate 			 * in the world, we've seen the absolute max
43567c478bd9Sstevel@tonic-gate 			 * columns to be 2 and the max number of
43577c478bd9Sstevel@tonic-gate 			 * bytes to be 3.  This allows room for some
43587c478bd9Sstevel@tonic-gate 			 * expansion of that, but it probably won't
43597c478bd9Sstevel@tonic-gate 			 * even be necessary. At the moment, we
43607c478bd9Sstevel@tonic-gate 			 * return a "range" error.  If you really
43617c478bd9Sstevel@tonic-gate 			 * need to, you can push EUC_MAXW up to over
43627c478bd9Sstevel@tonic-gate 			 * 200; it doesn't make sense, though, with
43637c478bd9Sstevel@tonic-gate 			 * only a CANBSIZ sized input limit (usually
43647c478bd9Sstevel@tonic-gate 			 * 256)!
43657c478bd9Sstevel@tonic-gate 			 */
43667c478bd9Sstevel@tonic-gate 			for (i = 0; i < 4; i++) {
43677c478bd9Sstevel@tonic-gate 				if ((euciocp->eucw[i] > EUC_MAXW) ||
43687c478bd9Sstevel@tonic-gate 				    (euciocp->scrw[i] > EUC_MAXW)) {
43697c478bd9Sstevel@tonic-gate 					miocnak(q, mp, 0, ERANGE);
43707c478bd9Sstevel@tonic-gate 					return;
43717c478bd9Sstevel@tonic-gate 				}
43727c478bd9Sstevel@tonic-gate 			}
43737c478bd9Sstevel@tonic-gate 			/*
43747c478bd9Sstevel@tonic-gate 			 * Otherwise, save the information in tp,
43757c478bd9Sstevel@tonic-gate 			 * force codeset 0 (ASCII) to be one byte,
43767c478bd9Sstevel@tonic-gate 			 * one column.
43777c478bd9Sstevel@tonic-gate 			 */
43787c478bd9Sstevel@tonic-gate 			cp_eucwioc(euciocp, &tp->eucwioc, EUCIN);
43797c478bd9Sstevel@tonic-gate 			tp->eucwioc.eucw[0] = tp->eucwioc.scrw[0] = 1;
43807c478bd9Sstevel@tonic-gate 			/*
43817c478bd9Sstevel@tonic-gate 			 * Now, check out whether we're doing
43827c478bd9Sstevel@tonic-gate 			 * multibyte processing. if we are, we need
43837c478bd9Sstevel@tonic-gate 			 * to allocate a block to hold the parallel
43847c478bd9Sstevel@tonic-gate 			 * array. By convention, we've been passed
43857c478bd9Sstevel@tonic-gate 			 * what amounts to a CSWIDTH definition.  We
43867c478bd9Sstevel@tonic-gate 			 * actually NEED the number of bytes for
43877c478bd9Sstevel@tonic-gate 			 * Codesets 2 & 3.
43887c478bd9Sstevel@tonic-gate 			 */
43897c478bd9Sstevel@tonic-gate 			tp->t_maxeuc = 0;	/* reset to say we're NOT */
43907c478bd9Sstevel@tonic-gate 
43917c478bd9Sstevel@tonic-gate 			tp->t_state &= ~TS_MEUC;
43927c478bd9Sstevel@tonic-gate 			/*
43937c478bd9Sstevel@tonic-gate 			 * We'll set TS_MEUC if we're doing
43947c478bd9Sstevel@tonic-gate 			 * multi-column OR multi- byte OR both.  It
43957c478bd9Sstevel@tonic-gate 			 * makes things easier...  NOTE:  If we fail
43967c478bd9Sstevel@tonic-gate 			 * to get the buffer we need to hold display
43977c478bd9Sstevel@tonic-gate 			 * widths, then DON'T let the TS_MEUC bit get
43987c478bd9Sstevel@tonic-gate 			 * set!
43997c478bd9Sstevel@tonic-gate 			 */
44007c478bd9Sstevel@tonic-gate 			for (i = 0; i < 4; i++) {
44017c478bd9Sstevel@tonic-gate 				if (tp->eucwioc.eucw[i] > tp->t_maxeuc)
44027c478bd9Sstevel@tonic-gate 					tp->t_maxeuc = tp->eucwioc.eucw[i];
44037c478bd9Sstevel@tonic-gate 				if (tp->eucwioc.scrw[i] > 1)
44047c478bd9Sstevel@tonic-gate 					tp->t_state |= TS_MEUC;
44057c478bd9Sstevel@tonic-gate 			}
44067c478bd9Sstevel@tonic-gate 			if ((tp->t_maxeuc > 1) || (tp->t_state & TS_MEUC)) {
44077c478bd9Sstevel@tonic-gate 				if (!tp->t_eucp_mp) {
44082463e920SRichard Lowe 					if ((tp->t_eucp_mp = allocb(_TTY_BUFSIZ,
44092463e920SRichard Lowe 					    BPRI_HI)) == NULL) {
44107c478bd9Sstevel@tonic-gate 						tp->t_maxeuc = 1;
44117c478bd9Sstevel@tonic-gate 						tp->t_state &= ~TS_MEUC;
44127c478bd9Sstevel@tonic-gate 						cmn_err(CE_WARN,
44137c478bd9Sstevel@tonic-gate 						    "Can't allocate eucp_mp");
44147c478bd9Sstevel@tonic-gate 						miocnak(q, mp, 0, ENOSR);
44157c478bd9Sstevel@tonic-gate 						return;
44167c478bd9Sstevel@tonic-gate 					}
44177c478bd9Sstevel@tonic-gate 					/*
44187c478bd9Sstevel@tonic-gate 					 * here, if there's junk in
44197c478bd9Sstevel@tonic-gate 					 * the canonical buffer, then
44207c478bd9Sstevel@tonic-gate 					 * move the eucp pointer past
44217c478bd9Sstevel@tonic-gate 					 * it, so we don't run off
44227c478bd9Sstevel@tonic-gate 					 * the beginning.  This is a
44237c478bd9Sstevel@tonic-gate 					 * total botch, but will
44247c478bd9Sstevel@tonic-gate 					 * hopefully keep stuff from
44257c478bd9Sstevel@tonic-gate 					 * getting too messed up
44267c478bd9Sstevel@tonic-gate 					 * until the user flushes
44277c478bd9Sstevel@tonic-gate 					 * this line!
44287c478bd9Sstevel@tonic-gate 					 */
44297c478bd9Sstevel@tonic-gate 					if (tp->t_msglen) {
443085bb5f1dSis 						tp->t_eucp =
443185bb5f1dSis 						    tp->t_eucp_mp->b_rptr;
44327c478bd9Sstevel@tonic-gate 						for (i = tp->t_msglen; i; i--)
44337c478bd9Sstevel@tonic-gate 							*tp->t_eucp++ = 1;
443485bb5f1dSis 					} else {
443585bb5f1dSis 						tp->t_eucp =
443685bb5f1dSis 						    tp->t_eucp_mp->b_rptr;
443785bb5f1dSis 					}
44387c478bd9Sstevel@tonic-gate 				}
44397c478bd9Sstevel@tonic-gate 				/* doing multi-byte handling */
44407c478bd9Sstevel@tonic-gate 				tp->t_state |= TS_MEUC;
44417c478bd9Sstevel@tonic-gate 
44427c478bd9Sstevel@tonic-gate 			} else if (tp->t_eucp_mp) {
44437c478bd9Sstevel@tonic-gate 				freemsg(tp->t_eucp_mp);
44447c478bd9Sstevel@tonic-gate 				tp->t_eucp_mp = NULL;
44457c478bd9Sstevel@tonic-gate 				tp->t_eucp = NULL;
44467c478bd9Sstevel@tonic-gate 			}
44477c478bd9Sstevel@tonic-gate 
44487c478bd9Sstevel@tonic-gate 			/*
44497c478bd9Sstevel@tonic-gate 			 * Save the EUC width data we have at
44507c478bd9Sstevel@tonic-gate 			 * the t_csdata, set t_csdata.codeset_type to
44517c478bd9Sstevel@tonic-gate 			 * EUC one, and, switch the codeset methods at
44527c478bd9Sstevel@tonic-gate 			 * t_csmethods.
44537c478bd9Sstevel@tonic-gate 			 */
44547c478bd9Sstevel@tonic-gate 			bzero(&tp->t_csdata.eucpc_data,
44557c478bd9Sstevel@tonic-gate 			    (sizeof (ldterm_eucpc_data_t) *
445685bb5f1dSis 			    LDTERM_CS_MAX_CODESETS));
44577c478bd9Sstevel@tonic-gate 			tp->t_csdata.eucpc_data[0].byte_length =
445885bb5f1dSis 			    tp->eucwioc.eucw[1];
44597c478bd9Sstevel@tonic-gate 			tp->t_csdata.eucpc_data[0].screen_width =
446085bb5f1dSis 			    tp->eucwioc.scrw[1];
44617c478bd9Sstevel@tonic-gate 			tp->t_csdata.eucpc_data[1].byte_length =
446285bb5f1dSis 			    tp->eucwioc.eucw[2];
44637c478bd9Sstevel@tonic-gate 			tp->t_csdata.eucpc_data[1].screen_width =
446485bb5f1dSis 			    tp->eucwioc.scrw[2];
44657c478bd9Sstevel@tonic-gate 			tp->t_csdata.eucpc_data[2].byte_length =
446685bb5f1dSis 			    tp->eucwioc.eucw[3];
44677c478bd9Sstevel@tonic-gate 			tp->t_csdata.eucpc_data[2].screen_width =
446885bb5f1dSis 			    tp->eucwioc.scrw[3];
44697c478bd9Sstevel@tonic-gate 			tp->t_csdata.version = LDTERM_DATA_VERSION;
44707c478bd9Sstevel@tonic-gate 			tp->t_csdata.codeset_type = LDTERM_CS_TYPE_EUC;
44717c478bd9Sstevel@tonic-gate 			/*
44727c478bd9Sstevel@tonic-gate 			 * We are not using the 'csinfo_num' anyway if the
44737c478bd9Sstevel@tonic-gate 			 * current codeset type is EUC. So, set it to
44747c478bd9Sstevel@tonic-gate 			 * the maximum possible.
44757c478bd9Sstevel@tonic-gate 			 */
44767c478bd9Sstevel@tonic-gate 			tp->t_csdata.csinfo_num =
447785bb5f1dSis 			    LDTERM_CS_TYPE_EUC_MAX_SUBCS;
44787c478bd9Sstevel@tonic-gate 			if (tp->t_csdata.locale_name != (char *)NULL) {
44797c478bd9Sstevel@tonic-gate 				kmem_free(tp->t_csdata.locale_name,
44807c478bd9Sstevel@tonic-gate 				    strlen(tp->t_csdata.locale_name) + 1);
44817c478bd9Sstevel@tonic-gate 				tp->t_csdata.locale_name = (char *)NULL;
44827c478bd9Sstevel@tonic-gate 			}
44837c478bd9Sstevel@tonic-gate 			tp->t_csmethods = cs_methods[LDTERM_CS_TYPE_EUC];
44847c478bd9Sstevel@tonic-gate 
44857c478bd9Sstevel@tonic-gate 			/*
44867c478bd9Sstevel@tonic-gate 			 * If we are able to allocate two blocks (the
44877c478bd9Sstevel@tonic-gate 			 * iocblk and the associated data), then pass
44887c478bd9Sstevel@tonic-gate 			 * it downstream, otherwise we'll need to NAK
44897c478bd9Sstevel@tonic-gate 			 * it, and drop whatever we WERE able to
44907c478bd9Sstevel@tonic-gate 			 * allocate.
44917c478bd9Sstevel@tonic-gate 			 */
44927c478bd9Sstevel@tonic-gate 			if ((dmp = mkiocb(EUC_WSET)) == NULL) {
44937c478bd9Sstevel@tonic-gate 				miocnak(q, mp, 0, ENOSR);
44947c478bd9Sstevel@tonic-gate 				return;
44957c478bd9Sstevel@tonic-gate 			}
44967c478bd9Sstevel@tonic-gate 			if ((dmp_cont = allocb(EUCSIZE, BPRI_HI)) == NULL) {
44977c478bd9Sstevel@tonic-gate 				freemsg(dmp);
44987c478bd9Sstevel@tonic-gate 				miocnak(q, mp, 0, ENOSR);
44997c478bd9Sstevel@tonic-gate 				return;
45007c478bd9Sstevel@tonic-gate 			}
45017c478bd9Sstevel@tonic-gate 
45027c478bd9Sstevel@tonic-gate 			/*
45037c478bd9Sstevel@tonic-gate 			 * We got both buffers.  Copy out the EUC
45047c478bd9Sstevel@tonic-gate 			 * information (as we received it, not what
45057c478bd9Sstevel@tonic-gate 			 * we're using!) & pass it on.
45067c478bd9Sstevel@tonic-gate 			 */
45077c478bd9Sstevel@tonic-gate 			bcopy(mp->b_cont->b_rptr, dmp_cont->b_rptr, EUCSIZE);
45087c478bd9Sstevel@tonic-gate 			dmp_cont->b_wptr += EUCSIZE;
45097c478bd9Sstevel@tonic-gate 			dmp->b_cont = dmp_cont;
45107c478bd9Sstevel@tonic-gate 			dmp->b_datap->db_type = M_CTL;
45117c478bd9Sstevel@tonic-gate 			dmp_cont->b_datap->db_type = M_DATA;
45127c478bd9Sstevel@tonic-gate 			riocp = (struct iocblk *)dmp->b_rptr;
45137c478bd9Sstevel@tonic-gate 			riocp->ioc_count = EUCSIZE;
45147c478bd9Sstevel@tonic-gate 			putnext(q, dmp);
45157c478bd9Sstevel@tonic-gate 
45167c478bd9Sstevel@tonic-gate 			/*
45177c478bd9Sstevel@tonic-gate 			 * Now ACK the ioctl.
45187c478bd9Sstevel@tonic-gate 			 */
45197c478bd9Sstevel@tonic-gate 			iocp->ioc_rval = 0;
45207c478bd9Sstevel@tonic-gate 			miocack(q, mp, 0, 0);
45217c478bd9Sstevel@tonic-gate 			return;
45227c478bd9Sstevel@tonic-gate 		}
45237c478bd9Sstevel@tonic-gate 
45247c478bd9Sstevel@tonic-gate 	case EUC_WGET:
45257c478bd9Sstevel@tonic-gate 		error = miocpullup(mp, sizeof (struct eucioc));
45267c478bd9Sstevel@tonic-gate 		if (error != 0) {
45277c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, error);
45287c478bd9Sstevel@tonic-gate 			return;
45297c478bd9Sstevel@tonic-gate 		}
45307c478bd9Sstevel@tonic-gate 		euciocp = (struct eucioc *)mp->b_cont->b_rptr;
45317c478bd9Sstevel@tonic-gate 		cp_eucwioc(&tp->eucwioc, euciocp, EUCOUT);
45327c478bd9Sstevel@tonic-gate 		iocp->ioc_rval = 0;
45337c478bd9Sstevel@tonic-gate 		miocack(q, mp, EUCSIZE, 0);
45347c478bd9Sstevel@tonic-gate 		return;
45357c478bd9Sstevel@tonic-gate 
45367c478bd9Sstevel@tonic-gate 	case CSDATA_SET:
45377c478bd9Sstevel@tonic-gate 		error = miocpullup(mp, sizeof (ldterm_cs_data_user_t));
45387c478bd9Sstevel@tonic-gate 		if (error != 0) {
45397c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, error);
45407c478bd9Sstevel@tonic-gate 			return;
45417c478bd9Sstevel@tonic-gate 		}
45427c478bd9Sstevel@tonic-gate 
45437c478bd9Sstevel@tonic-gate 		csdp = (ldterm_cs_data_user_t *)mp->b_cont->b_rptr;
45447c478bd9Sstevel@tonic-gate 
45457c478bd9Sstevel@tonic-gate 		/* Validate the codeset data provided. */
45467c478bd9Sstevel@tonic-gate 		if (csdp->version > LDTERM_DATA_VERSION ||
45477c478bd9Sstevel@tonic-gate 		    csdp->codeset_type < LDTERM_CS_TYPE_MIN ||
45487c478bd9Sstevel@tonic-gate 		    csdp->codeset_type > LDTERM_CS_TYPE_MAX) {
45497c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, ERANGE);
45507c478bd9Sstevel@tonic-gate 			return;
45517c478bd9Sstevel@tonic-gate 		}
45527c478bd9Sstevel@tonic-gate 
45537c478bd9Sstevel@tonic-gate 		if ((csdp->codeset_type == LDTERM_CS_TYPE_EUC &&
455485bb5f1dSis 		    csdp->csinfo_num > LDTERM_CS_TYPE_EUC_MAX_SUBCS) ||
45557c478bd9Sstevel@tonic-gate 		    (csdp->codeset_type == LDTERM_CS_TYPE_PCCS &&
455685bb5f1dSis 		    (csdp->csinfo_num < LDTERM_CS_TYPE_PCCS_MIN_SUBCS ||
455785bb5f1dSis 		    csdp->csinfo_num > LDTERM_CS_TYPE_PCCS_MAX_SUBCS))) {
45587c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, ERANGE);
45597c478bd9Sstevel@tonic-gate 			return;
45607c478bd9Sstevel@tonic-gate 		}
45617c478bd9Sstevel@tonic-gate 
45627c478bd9Sstevel@tonic-gate 		maxbytelen = maxscreenlen = 0;
45637c478bd9Sstevel@tonic-gate 		if (csdp->codeset_type == LDTERM_CS_TYPE_EUC) {
45647c478bd9Sstevel@tonic-gate 			for (i = 0; i < LDTERM_CS_TYPE_EUC_MAX_SUBCS; i++) {
45657c478bd9Sstevel@tonic-gate 				if (csdp->eucpc_data[i].byte_length >
45667c478bd9Sstevel@tonic-gate 				    EUC_MAXW ||
45677c478bd9Sstevel@tonic-gate 				    csdp->eucpc_data[i].screen_width >
45687c478bd9Sstevel@tonic-gate 				    EUC_MAXW) {
45697c478bd9Sstevel@tonic-gate 					miocnak(q, mp, 0, ERANGE);
45707c478bd9Sstevel@tonic-gate 					return;
45717c478bd9Sstevel@tonic-gate 				}
45727c478bd9Sstevel@tonic-gate 
45737c478bd9Sstevel@tonic-gate 				if (csdp->eucpc_data[i].byte_length >
45747c478bd9Sstevel@tonic-gate 				    maxbytelen)
45757c478bd9Sstevel@tonic-gate 					maxbytelen =
45767c478bd9Sstevel@tonic-gate 					    csdp->eucpc_data[i].byte_length;
45777c478bd9Sstevel@tonic-gate 				if (csdp->eucpc_data[i].screen_width >
45787c478bd9Sstevel@tonic-gate 				    maxscreenlen)
45797c478bd9Sstevel@tonic-gate 					maxscreenlen =
45807c478bd9Sstevel@tonic-gate 					    csdp->eucpc_data[i].screen_width;
45817c478bd9Sstevel@tonic-gate 			}
45827c478bd9Sstevel@tonic-gate 			/* POSIX/C locale? */
45837c478bd9Sstevel@tonic-gate 			if (maxbytelen == 0 && maxscreenlen == 0)
45847c478bd9Sstevel@tonic-gate 				maxbytelen = maxscreenlen = 1;
45857c478bd9Sstevel@tonic-gate 		} else if (csdp->codeset_type == LDTERM_CS_TYPE_PCCS) {
45867c478bd9Sstevel@tonic-gate 			for (i = 0; i < LDTERM_CS_MAX_CODESETS; i++) {
45877c478bd9Sstevel@tonic-gate 				if (csdp->eucpc_data[i].byte_length >
45887c478bd9Sstevel@tonic-gate 				    LDTERM_CS_MAX_BYTE_LENGTH) {
45897c478bd9Sstevel@tonic-gate 					miocnak(q, mp, 0, ERANGE);
45907c478bd9Sstevel@tonic-gate 					return;
45917c478bd9Sstevel@tonic-gate 				}
45927c478bd9Sstevel@tonic-gate 				if (csdp->eucpc_data[i].byte_length >
45937c478bd9Sstevel@tonic-gate 				    maxbytelen)
45947c478bd9Sstevel@tonic-gate 					maxbytelen =
45957c478bd9Sstevel@tonic-gate 					    csdp->eucpc_data[i].byte_length;
45967c478bd9Sstevel@tonic-gate 				if (csdp->eucpc_data[i].screen_width >
45977c478bd9Sstevel@tonic-gate 				    maxscreenlen)
45987c478bd9Sstevel@tonic-gate 					maxscreenlen =
45997c478bd9Sstevel@tonic-gate 					    csdp->eucpc_data[i].screen_width;
46007c478bd9Sstevel@tonic-gate 			}
46017c478bd9Sstevel@tonic-gate 		} else if (csdp->codeset_type == LDTERM_CS_TYPE_UTF8) {
46027c478bd9Sstevel@tonic-gate 			maxbytelen = 4;
46037c478bd9Sstevel@tonic-gate 			maxscreenlen = 2;
46047c478bd9Sstevel@tonic-gate 		}
46057c478bd9Sstevel@tonic-gate 
46067c478bd9Sstevel@tonic-gate 		locale_name_sz = 0;
46077c478bd9Sstevel@tonic-gate 
460824c5c9f4SJohn Levon 		for (i = 0; i < MAXNAMELEN; i++)
460924c5c9f4SJohn Levon 			if (csdp->locale_name[i] == '\0')
461024c5c9f4SJohn Levon 				break;
461124c5c9f4SJohn Levon 		/*
461224c5c9f4SJohn Levon 		 * We cannot have any string that is not NULL byte
461324c5c9f4SJohn Levon 		 * terminated.
461424c5c9f4SJohn Levon 		 */
461524c5c9f4SJohn Levon 		if (i >= MAXNAMELEN) {
461624c5c9f4SJohn Levon 			miocnak(q, mp, 0, ERANGE);
461724c5c9f4SJohn Levon 			return;
46187c478bd9Sstevel@tonic-gate 		}
46197c478bd9Sstevel@tonic-gate 
462024c5c9f4SJohn Levon 		locale_name_sz = i + 1;
462124c5c9f4SJohn Levon 
46227c478bd9Sstevel@tonic-gate 		/*
46237c478bd9Sstevel@tonic-gate 		 * As the final check, if there was invalid codeset_type
46247c478bd9Sstevel@tonic-gate 		 * given, or invalid byte_length was specified, it's an error.
46257c478bd9Sstevel@tonic-gate 		 */
46267c478bd9Sstevel@tonic-gate 		if (maxbytelen <= 0 || maxscreenlen <= 0) {
46277c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, ERANGE);
46287c478bd9Sstevel@tonic-gate 			return;
46297c478bd9Sstevel@tonic-gate 		}
46307c478bd9Sstevel@tonic-gate 
46317c478bd9Sstevel@tonic-gate 		/* Do the switching. */
46327c478bd9Sstevel@tonic-gate 		tp->t_maxeuc = maxbytelen;
46337c478bd9Sstevel@tonic-gate 		tp->t_state &= ~TS_MEUC;
46347c478bd9Sstevel@tonic-gate 		if (maxbytelen > 1 || maxscreenlen > 1) {
46357c478bd9Sstevel@tonic-gate 			if (!tp->t_eucp_mp) {
46362463e920SRichard Lowe 				if (!(tp->t_eucp_mp = allocb(_TTY_BUFSIZ,
46377c478bd9Sstevel@tonic-gate 				    BPRI_HI))) {
46387c478bd9Sstevel@tonic-gate 					cmn_err(CE_WARN,
463985bb5f1dSis 					    "Can't allocate eucp_mp");
46407c478bd9Sstevel@tonic-gate 					miocnak(q, mp, 0, ENOSR);
46417c478bd9Sstevel@tonic-gate 					return;
46427c478bd9Sstevel@tonic-gate 				}
46437c478bd9Sstevel@tonic-gate 				/*
46447c478bd9Sstevel@tonic-gate 				 * If there's junk in the canonical buffer,
46457c478bd9Sstevel@tonic-gate 				 * then move the eucp pointer past it,
46467c478bd9Sstevel@tonic-gate 				 * so we don't run off the beginning. This is
46477c478bd9Sstevel@tonic-gate 				 * a total botch, but will hopefully keep
46487c478bd9Sstevel@tonic-gate 				 * stuff from getting too messed up until
46497c478bd9Sstevel@tonic-gate 				 * the user flushes this line!
46507c478bd9Sstevel@tonic-gate 				 */
46517c478bd9Sstevel@tonic-gate 				if (tp->t_msglen) {
46527c478bd9Sstevel@tonic-gate 					tp->t_eucp = tp->t_eucp_mp->b_rptr;
46537c478bd9Sstevel@tonic-gate 					for (i = tp->t_msglen; i; i--)
46547c478bd9Sstevel@tonic-gate 						*tp->t_eucp++ = 1;
46557c478bd9Sstevel@tonic-gate 				} else {
46567c478bd9Sstevel@tonic-gate 					tp->t_eucp = tp->t_eucp_mp->b_rptr;
46577c478bd9Sstevel@tonic-gate 				}
46587c478bd9Sstevel@tonic-gate 			}
46597c478bd9Sstevel@tonic-gate 
46607c478bd9Sstevel@tonic-gate 			/*
46617c478bd9Sstevel@tonic-gate 			 * We only set TS_MEUC for a multibyte/multi-column
46627c478bd9Sstevel@tonic-gate 			 * codeset.
46637c478bd9Sstevel@tonic-gate 			 */
46647c478bd9Sstevel@tonic-gate 			tp->t_state |= TS_MEUC;
46657c478bd9Sstevel@tonic-gate 
46667c478bd9Sstevel@tonic-gate 			tp->t_csdata.version = csdp->version;
46677c478bd9Sstevel@tonic-gate 			tp->t_csdata.codeset_type = csdp->codeset_type;
46687c478bd9Sstevel@tonic-gate 			tp->t_csdata.csinfo_num = csdp->csinfo_num;
46697c478bd9Sstevel@tonic-gate 			bcopy(csdp->eucpc_data, tp->t_csdata.eucpc_data,
467085bb5f1dSis 			    sizeof (ldterm_eucpc_data_t) *
467185bb5f1dSis 			    LDTERM_CS_MAX_CODESETS);
46727c478bd9Sstevel@tonic-gate 			tp->t_csmethods = cs_methods[csdp->codeset_type];
46737c478bd9Sstevel@tonic-gate 
46747c478bd9Sstevel@tonic-gate 			if (csdp->codeset_type == LDTERM_CS_TYPE_EUC) {
46757c478bd9Sstevel@tonic-gate 				tp->eucwioc.eucw[0] = 1;
46767c478bd9Sstevel@tonic-gate 				tp->eucwioc.scrw[0] = 1;
46777c478bd9Sstevel@tonic-gate 
46787c478bd9Sstevel@tonic-gate 				tp->eucwioc.eucw[1] =
467985bb5f1dSis 				    csdp->eucpc_data[0].byte_length;
46807c478bd9Sstevel@tonic-gate 				tp->eucwioc.scrw[1] =
468185bb5f1dSis 				    csdp->eucpc_data[0].screen_width;
46827c478bd9Sstevel@tonic-gate 
46837c478bd9Sstevel@tonic-gate 				tp->eucwioc.eucw[2] =
468485bb5f1dSis 				    csdp->eucpc_data[1].byte_length + 1;
46857c478bd9Sstevel@tonic-gate 				tp->eucwioc.scrw[2] =
468685bb5f1dSis 				    csdp->eucpc_data[1].screen_width;
46877c478bd9Sstevel@tonic-gate 
46887c478bd9Sstevel@tonic-gate 				tp->eucwioc.eucw[3] =
468985bb5f1dSis 				    csdp->eucpc_data[2].byte_length + 1;
46907c478bd9Sstevel@tonic-gate 				tp->eucwioc.scrw[3] =
469185bb5f1dSis 				    csdp->eucpc_data[2].screen_width;
46927c478bd9Sstevel@tonic-gate 			} else {
46937c478bd9Sstevel@tonic-gate 				/*
46947c478bd9Sstevel@tonic-gate 				 * We are not going to use this data
46957c478bd9Sstevel@tonic-gate 				 * structure. So, clear it. Also, stty(1) will
46967c478bd9Sstevel@tonic-gate 				 * make use of the cleared tp->eucwioc when
46977c478bd9Sstevel@tonic-gate 				 * it prints out codeset width setting.
46987c478bd9Sstevel@tonic-gate 				 */
46997c478bd9Sstevel@tonic-gate 				bzero(&tp->eucwioc, EUCSIZE);
47007c478bd9Sstevel@tonic-gate 			}
47017c478bd9Sstevel@tonic-gate 		} else {
47027c478bd9Sstevel@tonic-gate 			/*
47037c478bd9Sstevel@tonic-gate 			 * If this codeset is a single byte codeset that
47047c478bd9Sstevel@tonic-gate 			 * requires only single display column for all
47057c478bd9Sstevel@tonic-gate 			 * characters, we switch to default EUC codeset
47067c478bd9Sstevel@tonic-gate 			 * methods and data setting.
47077c478bd9Sstevel@tonic-gate 			 */
47087c478bd9Sstevel@tonic-gate 
47097c478bd9Sstevel@tonic-gate 			if (tp->t_eucp_mp) {
47107c478bd9Sstevel@tonic-gate 				freemsg(tp->t_eucp_mp);
47117c478bd9Sstevel@tonic-gate 				tp->t_eucp_mp = NULL;
47127c478bd9Sstevel@tonic-gate 				tp->t_eucp = NULL;
47137c478bd9Sstevel@tonic-gate 			}
47147c478bd9Sstevel@tonic-gate 
47157c478bd9Sstevel@tonic-gate 			bzero(&tp->eucwioc, EUCSIZE);
47167c478bd9Sstevel@tonic-gate 			tp->eucwioc.eucw[0] = 1;
47177c478bd9Sstevel@tonic-gate 			tp->eucwioc.scrw[0] = 1;
47187c478bd9Sstevel@tonic-gate 			if (tp->t_csdata.locale_name != (char *)NULL) {
47197c478bd9Sstevel@tonic-gate 				kmem_free(tp->t_csdata.locale_name,
47207c478bd9Sstevel@tonic-gate 				    strlen(tp->t_csdata.locale_name) + 1);
47217c478bd9Sstevel@tonic-gate 			}
47227c478bd9Sstevel@tonic-gate 			tp->t_csdata = default_cs_data;
47237c478bd9Sstevel@tonic-gate 			tp->t_csmethods = cs_methods[LDTERM_CS_TYPE_EUC];
47247c478bd9Sstevel@tonic-gate 		}
47257c478bd9Sstevel@tonic-gate 
47267c478bd9Sstevel@tonic-gate 		/* Copy over locale_name. */
47277c478bd9Sstevel@tonic-gate 		if (tp->t_csdata.locale_name != (char *)NULL) {
47287c478bd9Sstevel@tonic-gate 			kmem_free(tp->t_csdata.locale_name,
47297c478bd9Sstevel@tonic-gate 			    strlen(tp->t_csdata.locale_name) + 1);
47307c478bd9Sstevel@tonic-gate 		}
47317c478bd9Sstevel@tonic-gate 		if (locale_name_sz > 1) {
47327c478bd9Sstevel@tonic-gate 			tp->t_csdata.locale_name = (char *)kmem_alloc(
473385bb5f1dSis 			    locale_name_sz, KM_SLEEP);
47347c478bd9Sstevel@tonic-gate 			(void) strcpy(tp->t_csdata.locale_name,
47357c478bd9Sstevel@tonic-gate 			    csdp->locale_name);
47367c478bd9Sstevel@tonic-gate 		} else {
47377c478bd9Sstevel@tonic-gate 			tp->t_csdata.locale_name = (char *)NULL;
47387c478bd9Sstevel@tonic-gate 		}
47397c478bd9Sstevel@tonic-gate 
47407c478bd9Sstevel@tonic-gate 		/*
47417c478bd9Sstevel@tonic-gate 		 * Now ACK the ioctl.
47427c478bd9Sstevel@tonic-gate 		 */
47437c478bd9Sstevel@tonic-gate 		iocp->ioc_rval = 0;
47447c478bd9Sstevel@tonic-gate 		miocack(q, mp, 0, 0);
47457c478bd9Sstevel@tonic-gate 		return;
47467c478bd9Sstevel@tonic-gate 
47477c478bd9Sstevel@tonic-gate 	case CSDATA_GET:
47487c478bd9Sstevel@tonic-gate 		error = miocpullup(mp, sizeof (ldterm_cs_data_user_t));
47497c478bd9Sstevel@tonic-gate 		if (error != 0) {
47507c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, error);
47517c478bd9Sstevel@tonic-gate 			return;
47527c478bd9Sstevel@tonic-gate 		}
47537c478bd9Sstevel@tonic-gate 
47547c478bd9Sstevel@tonic-gate 		csdp = (ldterm_cs_data_user_t *)mp->b_cont->b_rptr;
47557c478bd9Sstevel@tonic-gate 
47567c478bd9Sstevel@tonic-gate 		csdp->version = tp->t_csdata.version;
47577c478bd9Sstevel@tonic-gate 		csdp->codeset_type = tp->t_csdata.codeset_type;
47587c478bd9Sstevel@tonic-gate 		csdp->csinfo_num = tp->t_csdata.csinfo_num;
47597c478bd9Sstevel@tonic-gate 		csdp->pad = tp->t_csdata.pad;
47607c478bd9Sstevel@tonic-gate 		if (tp->t_csdata.locale_name) {
47617c478bd9Sstevel@tonic-gate 			(void) strcpy(csdp->locale_name,
476285bb5f1dSis 			    tp->t_csdata.locale_name);
47637c478bd9Sstevel@tonic-gate 		} else {
47647c478bd9Sstevel@tonic-gate 			csdp->locale_name[0] = '\0';
47657c478bd9Sstevel@tonic-gate 		}
47667c478bd9Sstevel@tonic-gate 		bcopy(tp->t_csdata.eucpc_data, csdp->eucpc_data,
476785bb5f1dSis 		    sizeof (ldterm_eucpc_data_t) * LDTERM_CS_MAX_CODESETS);
47687c478bd9Sstevel@tonic-gate 		/*
47697c478bd9Sstevel@tonic-gate 		 * If the codeset is an EUC codeset and if it has 2nd and/or
47707c478bd9Sstevel@tonic-gate 		 * 3rd supplementary codesets, we subtract one from each
47717c478bd9Sstevel@tonic-gate 		 * byte length of the supplementary codesets. This is
47727c478bd9Sstevel@tonic-gate 		 * because single shift characters, SS2 and SS3, are not
47737c478bd9Sstevel@tonic-gate 		 * included in the byte lengths in the user space.
47747c478bd9Sstevel@tonic-gate 		 */
47757c478bd9Sstevel@tonic-gate 		if (csdp->codeset_type == LDTERM_CS_TYPE_EUC) {
47767c478bd9Sstevel@tonic-gate 			if (csdp->eucpc_data[1].byte_length)
47777c478bd9Sstevel@tonic-gate 				csdp->eucpc_data[1].byte_length -= 1;
47787c478bd9Sstevel@tonic-gate 			if (csdp->eucpc_data[2].byte_length)
47797c478bd9Sstevel@tonic-gate 				csdp->eucpc_data[2].byte_length -= 1;
47807c478bd9Sstevel@tonic-gate 		}
47817c478bd9Sstevel@tonic-gate 		iocp->ioc_rval = 0;
47827c478bd9Sstevel@tonic-gate 		miocack(q, mp, sizeof (ldterm_cs_data_user_t), 0);
47837c478bd9Sstevel@tonic-gate 		return;
47847c478bd9Sstevel@tonic-gate 
47857c478bd9Sstevel@tonic-gate 	case PTSSTTY:
47867c478bd9Sstevel@tonic-gate 		tp->t_state |= TS_ISPTSTTY;
47877c478bd9Sstevel@tonic-gate 		break;
47887c478bd9Sstevel@tonic-gate 
47897c478bd9Sstevel@tonic-gate 	}
47907c478bd9Sstevel@tonic-gate 
47917c478bd9Sstevel@tonic-gate 	putnext(q, mp);
47927c478bd9Sstevel@tonic-gate }
47937c478bd9Sstevel@tonic-gate 
47947c478bd9Sstevel@tonic-gate 
47957c478bd9Sstevel@tonic-gate /*
47967c478bd9Sstevel@tonic-gate  * Send an M_SETOPTS message upstream if any mode changes are being
47977c478bd9Sstevel@tonic-gate  * made that affect the stream head options. returns -1 if allocb
47987c478bd9Sstevel@tonic-gate  * fails, else returns 0.
47997c478bd9Sstevel@tonic-gate  */
48007c478bd9Sstevel@tonic-gate static int
chgstropts(struct termios * oldmodep,ldtermstd_state_t * tp,queue_t * q)48017c478bd9Sstevel@tonic-gate chgstropts(struct termios *oldmodep, ldtermstd_state_t *tp, queue_t *q)
48027c478bd9Sstevel@tonic-gate {
48037c478bd9Sstevel@tonic-gate 	struct stroptions optbuf;
48047c478bd9Sstevel@tonic-gate 	mblk_t *bp;
48057c478bd9Sstevel@tonic-gate 
48067c478bd9Sstevel@tonic-gate 	optbuf.so_flags = 0;
48077c478bd9Sstevel@tonic-gate 	if ((oldmodep->c_lflag ^ tp->t_modes.c_lflag) & ICANON) {
48087c478bd9Sstevel@tonic-gate 		/*
48097c478bd9Sstevel@tonic-gate 		 * Canonical mode is changing state; switch the
48107c478bd9Sstevel@tonic-gate 		 * stream head to message-nondiscard or byte-stream
48117c478bd9Sstevel@tonic-gate 		 * mode.  Also, rerun the service procedure so it can
48127c478bd9Sstevel@tonic-gate 		 * change its mind about whether to send data
48137c478bd9Sstevel@tonic-gate 		 * upstream or not.
48147c478bd9Sstevel@tonic-gate 		 */
48157c478bd9Sstevel@tonic-gate 		if (tp->t_modes.c_lflag & ICANON) {
48167c478bd9Sstevel@tonic-gate 			DEBUG4(("CHANGING TO CANON MODE\n"));
48177c478bd9Sstevel@tonic-gate 			optbuf.so_flags = SO_READOPT|SO_MREADOFF;
48187c478bd9Sstevel@tonic-gate 			optbuf.so_readopt = RMSGN;
48197c478bd9Sstevel@tonic-gate 
48207c478bd9Sstevel@tonic-gate 			/*
48217c478bd9Sstevel@tonic-gate 			 * if there is a pending raw mode timeout,
48227c478bd9Sstevel@tonic-gate 			 * clear it
48237c478bd9Sstevel@tonic-gate 			 */
48247c478bd9Sstevel@tonic-gate 
48257c478bd9Sstevel@tonic-gate 			/*
48267c478bd9Sstevel@tonic-gate 			 * Clear VMIN/VTIME state, cancel timers
48277c478bd9Sstevel@tonic-gate 			 */
48287c478bd9Sstevel@tonic-gate 			vmin_satisfied(q, tp, 0);
48297c478bd9Sstevel@tonic-gate 		} else {
48307c478bd9Sstevel@tonic-gate 			DEBUG4(("CHANGING TO RAW MODE\n"));
48317c478bd9Sstevel@tonic-gate 			optbuf.so_flags = SO_READOPT|SO_MREADON;
48327c478bd9Sstevel@tonic-gate 			optbuf.so_readopt = RNORM;
48337c478bd9Sstevel@tonic-gate 		}
48347c478bd9Sstevel@tonic-gate 	}
48357c478bd9Sstevel@tonic-gate 	if ((oldmodep->c_lflag ^ tp->t_modes.c_lflag) & TOSTOP) {
48367c478bd9Sstevel@tonic-gate 		/*
48377c478bd9Sstevel@tonic-gate 		 * The "stop on background write" bit is changing.
48387c478bd9Sstevel@tonic-gate 		 */
48397c478bd9Sstevel@tonic-gate 		if (tp->t_modes.c_lflag & TOSTOP)
48407c478bd9Sstevel@tonic-gate 			optbuf.so_flags |= SO_TOSTOP;
48417c478bd9Sstevel@tonic-gate 		else
48427c478bd9Sstevel@tonic-gate 			optbuf.so_flags |= SO_TONSTOP;
48437c478bd9Sstevel@tonic-gate 	}
48447c478bd9Sstevel@tonic-gate 	if (optbuf.so_flags != 0) {
48457c478bd9Sstevel@tonic-gate 		if ((bp = allocb(sizeof (struct stroptions), BPRI_HI)) ==
48467c478bd9Sstevel@tonic-gate 		    NULL) {
48477c478bd9Sstevel@tonic-gate 			return (-1);
48487c478bd9Sstevel@tonic-gate 		}
48497c478bd9Sstevel@tonic-gate 		*(struct stroptions *)bp->b_wptr = optbuf;
48507c478bd9Sstevel@tonic-gate 		bp->b_wptr += sizeof (struct stroptions);
48517c478bd9Sstevel@tonic-gate 		bp->b_datap->db_type = M_SETOPTS;
48527c478bd9Sstevel@tonic-gate 		DEBUG4(("M_SETOPTS to stream head\n"));
48537c478bd9Sstevel@tonic-gate 		putnext(q, bp);
48547c478bd9Sstevel@tonic-gate 	}
48557c478bd9Sstevel@tonic-gate 	return (0);
48567c478bd9Sstevel@tonic-gate }
48577c478bd9Sstevel@tonic-gate 
48587c478bd9Sstevel@tonic-gate 
48597c478bd9Sstevel@tonic-gate /*
48607c478bd9Sstevel@tonic-gate  * Called when an M_IOCACK message is seen on the read queue;
48617c478bd9Sstevel@tonic-gate  * modifies the data being returned, if necessary, and passes the
48627c478bd9Sstevel@tonic-gate  * reply up.
48637c478bd9Sstevel@tonic-gate  */
48647c478bd9Sstevel@tonic-gate static void
ldterm_ioctl_reply(queue_t * q,mblk_t * mp)48657c478bd9Sstevel@tonic-gate ldterm_ioctl_reply(queue_t *q, mblk_t *mp)
48667c478bd9Sstevel@tonic-gate {
48677c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp;
48687c478bd9Sstevel@tonic-gate 	struct iocblk *iocp;
48697c478bd9Sstevel@tonic-gate 
48707c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
48717c478bd9Sstevel@tonic-gate 	tp = (ldtermstd_state_t *)q->q_ptr;
48727c478bd9Sstevel@tonic-gate 
48737c478bd9Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
48747c478bd9Sstevel@tonic-gate 
48757c478bd9Sstevel@tonic-gate 	case TCGETS:
48767c478bd9Sstevel@tonic-gate 		{
48777c478bd9Sstevel@tonic-gate 			/*
48787c478bd9Sstevel@tonic-gate 			 * Get current parameters and return them to
48797c478bd9Sstevel@tonic-gate 			 * stream head eventually.
48807c478bd9Sstevel@tonic-gate 			 */
48817c478bd9Sstevel@tonic-gate 			struct termios *cb =
488285bb5f1dSis 			    (struct termios *)mp->b_cont->b_rptr;
48837c478bd9Sstevel@tonic-gate 
48847c478bd9Sstevel@tonic-gate 			/*
48857c478bd9Sstevel@tonic-gate 			 * cflag has cflags sent upstream by the
48867c478bd9Sstevel@tonic-gate 			 * driver
48877c478bd9Sstevel@tonic-gate 			 */
48887c478bd9Sstevel@tonic-gate 			tcflag_t cflag = cb->c_cflag;
48897c478bd9Sstevel@tonic-gate 
48907c478bd9Sstevel@tonic-gate 			*cb = tp->t_amodes;
48917c478bd9Sstevel@tonic-gate 			if (cflag != 0)
48927c478bd9Sstevel@tonic-gate 				cb->c_cflag = cflag;	/* set by driver */
48937c478bd9Sstevel@tonic-gate 			break;
48947c478bd9Sstevel@tonic-gate 		}
48957c478bd9Sstevel@tonic-gate 
48967c478bd9Sstevel@tonic-gate 	case TCGETA:
48977c478bd9Sstevel@tonic-gate 		{
48987c478bd9Sstevel@tonic-gate 			/*
48997c478bd9Sstevel@tonic-gate 			 * Old-style "ioctl" to get current
49007c478bd9Sstevel@tonic-gate 			 * parameters and return them to stream head
49017c478bd9Sstevel@tonic-gate 			 * eventually.
49027c478bd9Sstevel@tonic-gate 			 */
49037c478bd9Sstevel@tonic-gate 			struct termio *cb =
490485bb5f1dSis 			    (struct termio *)mp->b_cont->b_rptr;
49057c478bd9Sstevel@tonic-gate 
49067c478bd9Sstevel@tonic-gate 			cb->c_iflag = tp->t_amodes.c_iflag; /* all except the */
49077c478bd9Sstevel@tonic-gate 			cb->c_oflag = tp->t_amodes.c_oflag; /* cb->c_cflag */
49087c478bd9Sstevel@tonic-gate 			cb->c_lflag = tp->t_amodes.c_lflag;
49097c478bd9Sstevel@tonic-gate 
49107c478bd9Sstevel@tonic-gate 			if (cb->c_cflag == 0)	/* not set by driver */
49117c478bd9Sstevel@tonic-gate 				cb->c_cflag = tp->t_amodes.c_cflag;
49127c478bd9Sstevel@tonic-gate 
49137c478bd9Sstevel@tonic-gate 			cb->c_line = 0;
49147c478bd9Sstevel@tonic-gate 			bcopy(tp->t_amodes.c_cc, cb->c_cc, NCC);
49157c478bd9Sstevel@tonic-gate 			break;
49167c478bd9Sstevel@tonic-gate 		}
49177c478bd9Sstevel@tonic-gate 	}
49187c478bd9Sstevel@tonic-gate 	putnext(q, mp);
49197c478bd9Sstevel@tonic-gate }
49207c478bd9Sstevel@tonic-gate 
49217c478bd9Sstevel@tonic-gate 
49227c478bd9Sstevel@tonic-gate /*
49237c478bd9Sstevel@tonic-gate  * A VMIN/VTIME request has been satisfied. Cancel outstanding timers
49247c478bd9Sstevel@tonic-gate  * if they exist, clear TS_MREAD state, and send upstream. If a NULL
49257c478bd9Sstevel@tonic-gate  * queue ptr is passed, just reset VMIN/VTIME state.
49267c478bd9Sstevel@tonic-gate  */
49277c478bd9Sstevel@tonic-gate static void
vmin_satisfied(queue_t * q,ldtermstd_state_t * tp,int sendup)49287c478bd9Sstevel@tonic-gate vmin_satisfied(queue_t *q, ldtermstd_state_t *tp, int sendup)
49297c478bd9Sstevel@tonic-gate {
49307c478bd9Sstevel@tonic-gate 	ASSERT(q);
49317c478bd9Sstevel@tonic-gate 	if (tp->t_vtid != 0)  {
493285bb5f1dSis 		DEBUG4(("vmin_satisfied: cancelled timer id %d\n", tp->t_vtid));
49337c478bd9Sstevel@tonic-gate 		(void) quntimeout(q, tp->t_vtid);
49347c478bd9Sstevel@tonic-gate 		tp->t_vtid = 0;
49357c478bd9Sstevel@tonic-gate 	}
49367c478bd9Sstevel@tonic-gate 	if (sendup) {
49377c478bd9Sstevel@tonic-gate 		if (tp->t_msglen == 0 && V_MIN) {
49387c478bd9Sstevel@tonic-gate 			/* EMPTY */
49397c478bd9Sstevel@tonic-gate 			DEBUG4(("vmin_satisfied: data swiped, msglen = 0\n"));
49407c478bd9Sstevel@tonic-gate 		} else {
49417c478bd9Sstevel@tonic-gate 			if ((!q->q_first) ||
49427c478bd9Sstevel@tonic-gate 			    (q->q_first->b_datap->db_type != M_DATA) ||
49437c478bd9Sstevel@tonic-gate 			    (tp->t_msglen >= LDCHUNK)) {
49447c478bd9Sstevel@tonic-gate 				ldterm_msg_upstream(q, tp);
49457c478bd9Sstevel@tonic-gate 				DEBUG4(("vmin_satisfied: delivering data\n"));
49467c478bd9Sstevel@tonic-gate 			}
49477c478bd9Sstevel@tonic-gate 		}
49487c478bd9Sstevel@tonic-gate 	} else {
49497c478bd9Sstevel@tonic-gate 		/* EMPTY */
49507c478bd9Sstevel@tonic-gate 		DEBUG4(("vmin_satisfied: VMIN/TIME state reset\n"));
49517c478bd9Sstevel@tonic-gate 	}
49527c478bd9Sstevel@tonic-gate 	tp->t_state &= ~TS_MREAD;
49537c478bd9Sstevel@tonic-gate }
49547c478bd9Sstevel@tonic-gate 
49557c478bd9Sstevel@tonic-gate static void
vmin_settimer(queue_t * q)49567c478bd9Sstevel@tonic-gate vmin_settimer(queue_t *q)
49577c478bd9Sstevel@tonic-gate {
49587c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp;
49597c478bd9Sstevel@tonic-gate 
49607c478bd9Sstevel@tonic-gate 	tp = (ldtermstd_state_t *)q->q_ptr;
49617c478bd9Sstevel@tonic-gate 
49627c478bd9Sstevel@tonic-gate 	/*
49637c478bd9Sstevel@tonic-gate 	 * Don't start any time bombs.
49647c478bd9Sstevel@tonic-gate 	 */
49657c478bd9Sstevel@tonic-gate 	if (tp->t_state & TS_CLOSE)
49667c478bd9Sstevel@tonic-gate 		return;
49677c478bd9Sstevel@tonic-gate 
49687c478bd9Sstevel@tonic-gate 	/*
49697c478bd9Sstevel@tonic-gate 	 * tp->t_vtid should NOT be set here unless VMIN > 0 and
49707c478bd9Sstevel@tonic-gate 	 * VTIME > 0.
49717c478bd9Sstevel@tonic-gate 	 */
49727c478bd9Sstevel@tonic-gate 	if (tp->t_vtid) {
49737c478bd9Sstevel@tonic-gate 		if (V_MIN && V_TIME) {
49747c478bd9Sstevel@tonic-gate 			/* EMPTY */
49757c478bd9Sstevel@tonic-gate 			DEBUG4(("vmin_settimer: timer restarted, old tid=%d\n",
497685bb5f1dSis 			    tp->t_vtid));
49777c478bd9Sstevel@tonic-gate 		} else {
49787c478bd9Sstevel@tonic-gate 			/* EMPTY */
49797c478bd9Sstevel@tonic-gate 			DEBUG4(("vmin_settimer: tid = %d was still active!\n",
498085bb5f1dSis 			    tp->t_vtid));
49817c478bd9Sstevel@tonic-gate 		}
49827c478bd9Sstevel@tonic-gate 		(void) quntimeout(q, tp->t_vtid);
49837c478bd9Sstevel@tonic-gate 		tp->t_vtid = 0;
49847c478bd9Sstevel@tonic-gate 	}
49857c478bd9Sstevel@tonic-gate 	tp->t_vtid = qtimeout(q, vmin_timed_out, q,
49867c478bd9Sstevel@tonic-gate 	    (clock_t)(V_TIME * (hz / 10)));
49877c478bd9Sstevel@tonic-gate 	DEBUG4(("vmin_settimer: timer started, tid = %d\n", tp->t_vtid));
49887c478bd9Sstevel@tonic-gate }
49897c478bd9Sstevel@tonic-gate 
49907c478bd9Sstevel@tonic-gate 
49917c478bd9Sstevel@tonic-gate /*
49927c478bd9Sstevel@tonic-gate  * BRRrrringgg!! VTIME was satisfied instead of VMIN
49937c478bd9Sstevel@tonic-gate  */
49947c478bd9Sstevel@tonic-gate static void
vmin_timed_out(void * arg)49957c478bd9Sstevel@tonic-gate vmin_timed_out(void *arg)
49967c478bd9Sstevel@tonic-gate {
49977c478bd9Sstevel@tonic-gate 	queue_t *q = arg;
49987c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp;
49997c478bd9Sstevel@tonic-gate 
50007c478bd9Sstevel@tonic-gate 	tp = (ldtermstd_state_t *)q->q_ptr;
50017c478bd9Sstevel@tonic-gate 
50027c478bd9Sstevel@tonic-gate 	DEBUG4(("vmin_timed_out: tid = %d\n", tp->t_vtid));
50037c478bd9Sstevel@tonic-gate 	/* don't call untimeout now that we are in the timeout */
50047c478bd9Sstevel@tonic-gate 	tp->t_vtid = 0;
50057c478bd9Sstevel@tonic-gate 	vmin_satisfied(q, tp, 1);
50067c478bd9Sstevel@tonic-gate }
50077c478bd9Sstevel@tonic-gate 
50087c478bd9Sstevel@tonic-gate 
50097c478bd9Sstevel@tonic-gate /*
50107c478bd9Sstevel@tonic-gate  * Routine to adjust termios flags to be processed by the line
50117c478bd9Sstevel@tonic-gate  * discipline. Driver below sends a termios structure, with the flags
50127c478bd9Sstevel@tonic-gate  * the driver intends to process. XOR'ing the driver sent termios
50137c478bd9Sstevel@tonic-gate  * structure with current termios structure with the default values
50147c478bd9Sstevel@tonic-gate  * (or set by ioctls from userland), we come up with a new termios
50157c478bd9Sstevel@tonic-gate  * structrue, the flags of which will be used by the line discipline
50167c478bd9Sstevel@tonic-gate  * in processing input and output. On return from this routine, we
50177c478bd9Sstevel@tonic-gate  * will have the following fields set in tp structure -->
50187c478bd9Sstevel@tonic-gate  * tp->t_modes:	modes the line discipline will process tp->t_amodes:
50197c478bd9Sstevel@tonic-gate  * modes the user process thinks the line discipline is processing
50207c478bd9Sstevel@tonic-gate  */
50217c478bd9Sstevel@tonic-gate 
50227c478bd9Sstevel@tonic-gate static void
ldterm_adjust_modes(ldtermstd_state_t * tp)50237c478bd9Sstevel@tonic-gate ldterm_adjust_modes(ldtermstd_state_t *tp)
50247c478bd9Sstevel@tonic-gate {
50257c478bd9Sstevel@tonic-gate 
50267c478bd9Sstevel@tonic-gate 	DEBUG6(("original iflag = %o\n", tp->t_modes.c_iflag));
50277c478bd9Sstevel@tonic-gate 	tp->t_modes.c_iflag = tp->t_amodes.c_iflag & ~(tp->t_dmodes.c_iflag);
50287c478bd9Sstevel@tonic-gate 	tp->t_modes.c_oflag = tp->t_amodes.c_oflag & ~(tp->t_dmodes.c_oflag);
50297c478bd9Sstevel@tonic-gate 	tp->t_modes.c_lflag = tp->t_amodes.c_lflag & ~(tp->t_dmodes.c_lflag);
50307c478bd9Sstevel@tonic-gate 	DEBUG6(("driver iflag = %o\n", tp->t_dmodes.c_iflag));
50317c478bd9Sstevel@tonic-gate 	DEBUG6(("apparent iflag = %o\n", tp->t_amodes.c_iflag));
50327c478bd9Sstevel@tonic-gate 	DEBUG6(("effective iflag = %o\n", tp->t_modes.c_iflag));
50337c478bd9Sstevel@tonic-gate 
50347c478bd9Sstevel@tonic-gate 	/* No negotiation of clfags  c_cc array special characters */
50357c478bd9Sstevel@tonic-gate 	/*
50367c478bd9Sstevel@tonic-gate 	 * Copy from amodes to modes already done by TCSETA/TCSETS
50377c478bd9Sstevel@tonic-gate 	 * code
50387c478bd9Sstevel@tonic-gate 	 */
50397c478bd9Sstevel@tonic-gate }
50407c478bd9Sstevel@tonic-gate 
50417c478bd9Sstevel@tonic-gate 
50427c478bd9Sstevel@tonic-gate /*
50437c478bd9Sstevel@tonic-gate  * Erase one multi-byte character.  If TS_MEUC is set AND this
50447c478bd9Sstevel@tonic-gate  * is a multi-byte character, then this should be called instead of
50457c478bd9Sstevel@tonic-gate  * ldterm_erase.  "ldterm_erase" will handle ASCII nicely, thank you.
50467c478bd9Sstevel@tonic-gate  *
50477c478bd9Sstevel@tonic-gate  * We'd better be pointing to the last byte.  If we aren't, it will get
50487c478bd9Sstevel@tonic-gate  * screwed up.
50497c478bd9Sstevel@tonic-gate  */
50507c478bd9Sstevel@tonic-gate static void
ldterm_csi_erase(queue_t * q,size_t ebsize,ldtermstd_state_t * tp)50517c478bd9Sstevel@tonic-gate ldterm_csi_erase(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
50527c478bd9Sstevel@tonic-gate {
50537c478bd9Sstevel@tonic-gate 	int i, ung;
50547c478bd9Sstevel@tonic-gate 	uchar_t *p, *bottom;
50557c478bd9Sstevel@tonic-gate 	uchar_t u8[LDTERM_CS_MAX_BYTE_LENGTH];
50567c478bd9Sstevel@tonic-gate 	int c;
50577c478bd9Sstevel@tonic-gate 	int j;
50587c478bd9Sstevel@tonic-gate 	int len;
50597c478bd9Sstevel@tonic-gate 
50607c478bd9Sstevel@tonic-gate 	if (tp->t_eucleft) {
50617c478bd9Sstevel@tonic-gate 		/* XXX Ick.  We're in the middle of an EUC! */
50627c478bd9Sstevel@tonic-gate 		/* What to do now? */
50637c478bd9Sstevel@tonic-gate 		ldterm_eucwarn(tp);
50647c478bd9Sstevel@tonic-gate 		return;		/* ignore it??? */
50657c478bd9Sstevel@tonic-gate 	}
50667c478bd9Sstevel@tonic-gate 	bottom = tp->t_eucp_mp->b_rptr;
50677c478bd9Sstevel@tonic-gate 	p = tp->t_eucp - 1;	/* previous byte */
50687c478bd9Sstevel@tonic-gate 	if (p < bottom)
50697c478bd9Sstevel@tonic-gate 		return;
50707c478bd9Sstevel@tonic-gate 	ung = 1;		/* number of bytes to un-get from buffer */
50717c478bd9Sstevel@tonic-gate 	/*
50727c478bd9Sstevel@tonic-gate 	 * go through the buffer until we find the beginning of the
50737c478bd9Sstevel@tonic-gate 	 * multi-byte char.
50747c478bd9Sstevel@tonic-gate 	 */
50757c478bd9Sstevel@tonic-gate 	while ((*p == 0) && (p > bottom)) {
50767c478bd9Sstevel@tonic-gate 		p--;
50777c478bd9Sstevel@tonic-gate 		++ung;
50787c478bd9Sstevel@tonic-gate 	}
50797c478bd9Sstevel@tonic-gate 
50807c478bd9Sstevel@tonic-gate 	/*
50817c478bd9Sstevel@tonic-gate 	 * Now, "ung" is the number of bytes to unget from the buffer
50827c478bd9Sstevel@tonic-gate 	 * and "*p" is the disp width of it. Fool "ldterm_rubout"
50837c478bd9Sstevel@tonic-gate 	 * into thinking we're rubbing out ASCII characters.  Do that
50847c478bd9Sstevel@tonic-gate 	 * for the display width of the character.
50857c478bd9Sstevel@tonic-gate 	 *
50867c478bd9Sstevel@tonic-gate 	 * Also we accumulate bytes of the character so that if the character
50877c478bd9Sstevel@tonic-gate 	 * is a UTF-8 character, we will get the display width of the UTF-8
50887c478bd9Sstevel@tonic-gate 	 * character.
50897c478bd9Sstevel@tonic-gate 	 */
50907c478bd9Sstevel@tonic-gate 	if (ung >= LDTERM_CS_MAX_BYTE_LENGTH) {
50917c478bd9Sstevel@tonic-gate 		j = len = LDTERM_CS_MAX_BYTE_LENGTH;
50927c478bd9Sstevel@tonic-gate 	} else {
50937c478bd9Sstevel@tonic-gate 		j = len = ung;
50947c478bd9Sstevel@tonic-gate 	}
50957c478bd9Sstevel@tonic-gate 	for (i = 0; i < ung; i++) {	/* remove from buf */
50967c478bd9Sstevel@tonic-gate 		if ((c = ldterm_unget(tp)) != (-1)) {
50977c478bd9Sstevel@tonic-gate 			ldterm_trim(tp);
50987c478bd9Sstevel@tonic-gate 			if (j > 0)
50997c478bd9Sstevel@tonic-gate 				u8[--j] = (uchar_t)c;
51007c478bd9Sstevel@tonic-gate 		}
51017c478bd9Sstevel@tonic-gate 	}
51027c478bd9Sstevel@tonic-gate 	if (*p == UNKNOWN_WIDTH) {
51037c478bd9Sstevel@tonic-gate 		if (tp->t_csdata.codeset_type == LDTERM_CS_TYPE_UTF8) {
51047c478bd9Sstevel@tonic-gate 			*p = ldterm_utf8_width(u8, len);
51057c478bd9Sstevel@tonic-gate 		} else {
51067c478bd9Sstevel@tonic-gate 			*p = 1;
51077c478bd9Sstevel@tonic-gate 		}
51087c478bd9Sstevel@tonic-gate 	}
51097c478bd9Sstevel@tonic-gate 	for (i = 0; i < (int)*p; i++)	/* remove from screen */
51107c478bd9Sstevel@tonic-gate 		ldterm_rubout(' ', q, ebsize, tp);
51117c478bd9Sstevel@tonic-gate 	/*
51127c478bd9Sstevel@tonic-gate 	 * Adjust the parallel array pointer.  Zero out the contents
51137c478bd9Sstevel@tonic-gate 	 * of parallel array for this position, just to make sure...
51147c478bd9Sstevel@tonic-gate 	 */
51157c478bd9Sstevel@tonic-gate 	tp->t_eucp = p;
51167c478bd9Sstevel@tonic-gate 	*p = 0;
51177c478bd9Sstevel@tonic-gate }
51187c478bd9Sstevel@tonic-gate 
51197c478bd9Sstevel@tonic-gate 
51207c478bd9Sstevel@tonic-gate /*
51217c478bd9Sstevel@tonic-gate  * This is kind of a safety valve.  Whenever we see a bad sequence
51227c478bd9Sstevel@tonic-gate  * come up, we call eucwarn.  It just tallies the junk until a
51237c478bd9Sstevel@tonic-gate  * threshold is reached.  Then it prints ONE message on the console
51247c478bd9Sstevel@tonic-gate  * and not any more. Hopefully, we can catch garbage; maybe it will
51257c478bd9Sstevel@tonic-gate  * be useful to somebody.
51267c478bd9Sstevel@tonic-gate  */
51277c478bd9Sstevel@tonic-gate static void
ldterm_eucwarn(ldtermstd_state_t * tp)51287c478bd9Sstevel@tonic-gate ldterm_eucwarn(ldtermstd_state_t *tp)
51297c478bd9Sstevel@tonic-gate {
51307c478bd9Sstevel@tonic-gate 	++tp->t_eucwarn;
51317c478bd9Sstevel@tonic-gate #ifdef DEBUG
51327c478bd9Sstevel@tonic-gate 	if ((tp->t_eucwarn > EUC_WARNCNT) && !(tp->t_state & TS_WARNED)) {
51337c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
51347c478bd9Sstevel@tonic-gate 		    "ldterm: tty at addr %p in multi-byte mode --",
51357c478bd9Sstevel@tonic-gate 		    (void *)tp);
51367c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
51377c478bd9Sstevel@tonic-gate 		    "Over %d bad EUC characters this session", EUC_WARNCNT);
51387c478bd9Sstevel@tonic-gate 		tp->t_state |= TS_WARNED;
51397c478bd9Sstevel@tonic-gate 	}
51407c478bd9Sstevel@tonic-gate #endif
51417c478bd9Sstevel@tonic-gate }
51427c478bd9Sstevel@tonic-gate 
51437c478bd9Sstevel@tonic-gate 
51447c478bd9Sstevel@tonic-gate /*
51457c478bd9Sstevel@tonic-gate  * Copy an "eucioc_t" structure.  We use the structure with
51467c478bd9Sstevel@tonic-gate  * incremented values for Codesets 2 & 3.  The specification in
51477c478bd9Sstevel@tonic-gate  * eucioctl is that the sames values as the CSWIDTH definition at
51487c478bd9Sstevel@tonic-gate  * user level are passed to us. When we copy it "in" to ourselves, we
51497c478bd9Sstevel@tonic-gate  * do the increment.  That allows us to avoid treating each character
51507c478bd9Sstevel@tonic-gate  * set separately for "t_eucleft" purposes. When we copy it "out" to
51517c478bd9Sstevel@tonic-gate  * return it to the user, we decrement the values so the user gets
51527c478bd9Sstevel@tonic-gate  * what it expects, and it matches CSWIDTH in the environment (if
51537c478bd9Sstevel@tonic-gate  * things are consistent!).
51547c478bd9Sstevel@tonic-gate  */
51557c478bd9Sstevel@tonic-gate static void
cp_eucwioc(eucioc_t * from,eucioc_t * to,int dir)51567c478bd9Sstevel@tonic-gate cp_eucwioc(eucioc_t *from, eucioc_t *to, int dir)
51577c478bd9Sstevel@tonic-gate {
51587c478bd9Sstevel@tonic-gate 	bcopy(from, to, EUCSIZE);
51597c478bd9Sstevel@tonic-gate 	if (dir == EUCOUT) {	/* copying out to user */
51607c478bd9Sstevel@tonic-gate 		if (to->eucw[2])
51617c478bd9Sstevel@tonic-gate 			--to->eucw[2];
51627c478bd9Sstevel@tonic-gate 		if (to->eucw[3])
51637c478bd9Sstevel@tonic-gate 			--to->eucw[3];
51647c478bd9Sstevel@tonic-gate 	} else {		/* copying in */
51657c478bd9Sstevel@tonic-gate 		if (to->eucw[2])
51667c478bd9Sstevel@tonic-gate 			++to->eucw[2];
51677c478bd9Sstevel@tonic-gate 		if (to->eucw[3])
51687c478bd9Sstevel@tonic-gate 			++to->eucw[3];
51697c478bd9Sstevel@tonic-gate 	}
51707c478bd9Sstevel@tonic-gate }
51717c478bd9Sstevel@tonic-gate 
51727c478bd9Sstevel@tonic-gate 
51737c478bd9Sstevel@tonic-gate /*
51747c478bd9Sstevel@tonic-gate  * Take the first byte of a multi-byte, or an ASCII char.  Return its
51757c478bd9Sstevel@tonic-gate  * codeset. If it's NOT the first byte of an EUC, then the return
51767c478bd9Sstevel@tonic-gate  * value may be garbage, as it's probably not SS2 or SS3, and
51777c478bd9Sstevel@tonic-gate  * therefore must be in codeset 1.  Another bizarre catch here is the
51787c478bd9Sstevel@tonic-gate  * fact that we don't do anything about the "C1" control codes.  In
51797c478bd9Sstevel@tonic-gate  * real life, we should; but nobody's come up with a good way of
51807c478bd9Sstevel@tonic-gate  * treating them.
51817c478bd9Sstevel@tonic-gate  */
51827c478bd9Sstevel@tonic-gate 
51837c478bd9Sstevel@tonic-gate static int
ldterm_codeset(uchar_t codeset_type,uchar_t c)51847c478bd9Sstevel@tonic-gate ldterm_codeset(uchar_t codeset_type, uchar_t c)
51857c478bd9Sstevel@tonic-gate {
51867c478bd9Sstevel@tonic-gate 
51877c478bd9Sstevel@tonic-gate 	if (ISASCII(c))
51887c478bd9Sstevel@tonic-gate 		return (0);
51897c478bd9Sstevel@tonic-gate 
51907c478bd9Sstevel@tonic-gate 	if (codeset_type != LDTERM_CS_TYPE_EUC)
51917c478bd9Sstevel@tonic-gate 		return (1);
51927c478bd9Sstevel@tonic-gate 
51937c478bd9Sstevel@tonic-gate 	switch (c) {
51947c478bd9Sstevel@tonic-gate 	case SS2:
51957c478bd9Sstevel@tonic-gate 		return (2);
51967c478bd9Sstevel@tonic-gate 	case SS3:
51977c478bd9Sstevel@tonic-gate 		return (3);
51987c478bd9Sstevel@tonic-gate 	default:
51997c478bd9Sstevel@tonic-gate 		return (1);
52007c478bd9Sstevel@tonic-gate 	}
52017c478bd9Sstevel@tonic-gate }
52027c478bd9Sstevel@tonic-gate 
52037c478bd9Sstevel@tonic-gate /* The following two functions are additional EUC codeset specific methods. */
52047c478bd9Sstevel@tonic-gate /*
52057c478bd9Sstevel@tonic-gate  * ldterm_dispwidth - Take the first byte of an EUC (or ASCII) and
52067c478bd9Sstevel@tonic-gate  * return the display width.  Since this is intended mostly for
52077c478bd9Sstevel@tonic-gate  * multi-byte handling, it returns EUC_TWIDTH for tabs so they can be
52087c478bd9Sstevel@tonic-gate  * differentiated from EUC characters (assumption: EUC require fewer
52097c478bd9Sstevel@tonic-gate  * than 255 columns).  Also, if it's a backspace and !flag, it
52107c478bd9Sstevel@tonic-gate  * returns EUC_BSWIDTH.  Newline & CR also depend on flag.  This
52117c478bd9Sstevel@tonic-gate  * routine SHOULD be cleaner than this, but we have the situation
52127c478bd9Sstevel@tonic-gate  * where we may or may not be counting control characters as having a
52137c478bd9Sstevel@tonic-gate  * column width. Therefore, the computation of ASCII is pretty messy.
52147c478bd9Sstevel@tonic-gate  * The caller will be storing the value, and then switching on it
52157c478bd9Sstevel@tonic-gate  * when it's used.  We really should define the EUC_TWIDTH and other
52167c478bd9Sstevel@tonic-gate  * constants in a header so that the routine could be used in other
52177c478bd9Sstevel@tonic-gate  * modules in the kernel.
52187c478bd9Sstevel@tonic-gate  */
52197c478bd9Sstevel@tonic-gate static int
__ldterm_dispwidth_euc(uchar_t c,void * p,int mode)52207c478bd9Sstevel@tonic-gate __ldterm_dispwidth_euc(uchar_t c, void *p, int mode)
52217c478bd9Sstevel@tonic-gate {
52227c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp = (ldtermstd_state_t *)p;
52237c478bd9Sstevel@tonic-gate 
52247c478bd9Sstevel@tonic-gate 	if (ISASCII(c)) {
52257c478bd9Sstevel@tonic-gate 		if (c <= '\037') {
52267c478bd9Sstevel@tonic-gate 			switch (c) {
52277c478bd9Sstevel@tonic-gate 			case '\t':
52287c478bd9Sstevel@tonic-gate 				return (EUC_TWIDTH);
52297c478bd9Sstevel@tonic-gate 			case '\b':
52307c478bd9Sstevel@tonic-gate 				return (mode ? 2 : EUC_BSWIDTH);
52317c478bd9Sstevel@tonic-gate 			case '\n':
52327c478bd9Sstevel@tonic-gate 				return (EUC_NLWIDTH);
52337c478bd9Sstevel@tonic-gate 			case '\r':
52347c478bd9Sstevel@tonic-gate 				return (mode ? 2 : EUC_CRWIDTH);
52357c478bd9Sstevel@tonic-gate 			default:
52367c478bd9Sstevel@tonic-gate 				return (mode ? 2 : 0);
52377c478bd9Sstevel@tonic-gate 			}
52387c478bd9Sstevel@tonic-gate 		}
52397c478bd9Sstevel@tonic-gate 		return (1);
52407c478bd9Sstevel@tonic-gate 	}
52417c478bd9Sstevel@tonic-gate 	switch (c) {
52427c478bd9Sstevel@tonic-gate 	case SS2:
52437c478bd9Sstevel@tonic-gate 		return (tp->eucwioc.scrw[2]);
52447c478bd9Sstevel@tonic-gate 	case SS3:
52457c478bd9Sstevel@tonic-gate 		return (tp->eucwioc.scrw[3]);
52467c478bd9Sstevel@tonic-gate 	default:
52477c478bd9Sstevel@tonic-gate 		return (tp->eucwioc.scrw[1]);
52487c478bd9Sstevel@tonic-gate 	}
52497c478bd9Sstevel@tonic-gate }
52507c478bd9Sstevel@tonic-gate 
52517c478bd9Sstevel@tonic-gate /*
52527c478bd9Sstevel@tonic-gate  * ldterm_memwidth_euc - Take the first byte of an EUC (or an ASCII char)
52537c478bd9Sstevel@tonic-gate  * and return its memory width.  The routine could have been
52547c478bd9Sstevel@tonic-gate  * implemented to use only the codeset number, but that would require
52557c478bd9Sstevel@tonic-gate  * the caller to have that value available.  Perhaps the user doesn't
52567c478bd9Sstevel@tonic-gate  * want to make the extra call or keep the value of codeset around.
52577c478bd9Sstevel@tonic-gate  * Therefore, we use the actual character with which they're
52587c478bd9Sstevel@tonic-gate  * concerned.  This should never be called with anything but the
52597c478bd9Sstevel@tonic-gate  * first byte of an EUC, otherwise it will return a garbage value.
52607c478bd9Sstevel@tonic-gate  */
52617c478bd9Sstevel@tonic-gate static int
__ldterm_memwidth_euc(uchar_t c,void * p)52627c478bd9Sstevel@tonic-gate __ldterm_memwidth_euc(uchar_t c, void *p)
52637c478bd9Sstevel@tonic-gate {
52647c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp = (ldtermstd_state_t *)p;
52657c478bd9Sstevel@tonic-gate 
52667c478bd9Sstevel@tonic-gate 	if (ISASCII(c))
52677c478bd9Sstevel@tonic-gate 		return (1);
52687c478bd9Sstevel@tonic-gate 	switch (c) {
52697c478bd9Sstevel@tonic-gate 	case SS2:
52707c478bd9Sstevel@tonic-gate 		return (tp->eucwioc.eucw[2]);
52717c478bd9Sstevel@tonic-gate 	case SS3:
52727c478bd9Sstevel@tonic-gate 		return (tp->eucwioc.eucw[3]);
52737c478bd9Sstevel@tonic-gate 	default:
52747c478bd9Sstevel@tonic-gate 		return (tp->eucwioc.eucw[1]);
52757c478bd9Sstevel@tonic-gate 	}
52767c478bd9Sstevel@tonic-gate }
52777c478bd9Sstevel@tonic-gate 
52787c478bd9Sstevel@tonic-gate 
52797c478bd9Sstevel@tonic-gate /* The following two functions are PCCS codeset specific methods. */
52807c478bd9Sstevel@tonic-gate static int
__ldterm_dispwidth_pccs(uchar_t c,void * p,int mode)52817c478bd9Sstevel@tonic-gate __ldterm_dispwidth_pccs(uchar_t c, void *p, int mode)
52827c478bd9Sstevel@tonic-gate {
52837c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp = (ldtermstd_state_t *)p;
52847c478bd9Sstevel@tonic-gate 	int i;
52857c478bd9Sstevel@tonic-gate 
52867c478bd9Sstevel@tonic-gate 	if (ISASCII(c)) {
52877c478bd9Sstevel@tonic-gate 		if (c <= '\037') {
52887c478bd9Sstevel@tonic-gate 			switch (c) {
52897c478bd9Sstevel@tonic-gate 			case '\t':
52907c478bd9Sstevel@tonic-gate 				return (EUC_TWIDTH);
52917c478bd9Sstevel@tonic-gate 			case '\b':
52927c478bd9Sstevel@tonic-gate 				return (mode ? 2 : EUC_BSWIDTH);
52937c478bd9Sstevel@tonic-gate 			case '\n':
52947c478bd9Sstevel@tonic-gate 				return (EUC_NLWIDTH);
52957c478bd9Sstevel@tonic-gate 			case '\r':
52967c478bd9Sstevel@tonic-gate 				return (mode ? 2 : EUC_CRWIDTH);
52977c478bd9Sstevel@tonic-gate 			default:
52987c478bd9Sstevel@tonic-gate 				return (mode ? 2 : 0);
52997c478bd9Sstevel@tonic-gate 			}
53007c478bd9Sstevel@tonic-gate 		}
53017c478bd9Sstevel@tonic-gate 		return (1);
53027c478bd9Sstevel@tonic-gate 	}
53037c478bd9Sstevel@tonic-gate 
53047c478bd9Sstevel@tonic-gate 	for (i = 0; i < tp->t_csdata.csinfo_num; i++) {
53057c478bd9Sstevel@tonic-gate 		if (c >= tp->t_csdata.eucpc_data[i].msb_start &&
53067c478bd9Sstevel@tonic-gate 		    c <= tp->t_csdata.eucpc_data[i].msb_end)
53077c478bd9Sstevel@tonic-gate 			return (tp->t_csdata.eucpc_data[i].screen_width);
53087c478bd9Sstevel@tonic-gate 	}
53097c478bd9Sstevel@tonic-gate 
53107c478bd9Sstevel@tonic-gate 	/*
53117c478bd9Sstevel@tonic-gate 	 * If this leading byte is not in the range list, either provided
53127c478bd9Sstevel@tonic-gate 	 * locale data is not sufficient or we encountered an invalid
53137c478bd9Sstevel@tonic-gate 	 * character. We return 1 in this case as a fallback value.
53147c478bd9Sstevel@tonic-gate 	 */
53157c478bd9Sstevel@tonic-gate 	return (1);
53167c478bd9Sstevel@tonic-gate }
53177c478bd9Sstevel@tonic-gate 
53187c478bd9Sstevel@tonic-gate static int
__ldterm_memwidth_pccs(uchar_t c,void * p)53197c478bd9Sstevel@tonic-gate __ldterm_memwidth_pccs(uchar_t c, void *p)
53207c478bd9Sstevel@tonic-gate {
53217c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp = (ldtermstd_state_t *)p;
53227c478bd9Sstevel@tonic-gate 	int i;
53237c478bd9Sstevel@tonic-gate 
53247c478bd9Sstevel@tonic-gate 	for (i = 0; i < tp->t_csdata.csinfo_num; i++) {
53257c478bd9Sstevel@tonic-gate 		if (c >= tp->t_csdata.eucpc_data[i].msb_start &&
53267c478bd9Sstevel@tonic-gate 		    c <= tp->t_csdata.eucpc_data[i].msb_end)
53277c478bd9Sstevel@tonic-gate 			return (tp->t_csdata.eucpc_data[i].byte_length);
53287c478bd9Sstevel@tonic-gate 	}
53297c478bd9Sstevel@tonic-gate 
53307c478bd9Sstevel@tonic-gate 	/*
53317c478bd9Sstevel@tonic-gate 	 * If this leading byte is not in the range list, either provided
53327c478bd9Sstevel@tonic-gate 	 * locale data is not sufficient or we encountered an invalid
53337c478bd9Sstevel@tonic-gate 	 * character. We return 1 in this case as a fallback value.
53347c478bd9Sstevel@tonic-gate 	 */
53357c478bd9Sstevel@tonic-gate 	return (1);
53367c478bd9Sstevel@tonic-gate }
53377c478bd9Sstevel@tonic-gate 
53387c478bd9Sstevel@tonic-gate 
53397c478bd9Sstevel@tonic-gate /* The following two functions are UTF-8 codeset specific methods. */
53407c478bd9Sstevel@tonic-gate static int
__ldterm_dispwidth_utf8(uchar_t c,void * p,int mode)53417c478bd9Sstevel@tonic-gate __ldterm_dispwidth_utf8(uchar_t c, void *p, int mode)
53427c478bd9Sstevel@tonic-gate {
53437c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp = (ldtermstd_state_t *)p;
53447c478bd9Sstevel@tonic-gate 
53457c478bd9Sstevel@tonic-gate 	if (ISASCII(c)) {
53467c478bd9Sstevel@tonic-gate 		if (c <= '\037') {
53477c478bd9Sstevel@tonic-gate 			switch (c) {
53487c478bd9Sstevel@tonic-gate 			case '\t':
53497c478bd9Sstevel@tonic-gate 				return (EUC_TWIDTH);
53507c478bd9Sstevel@tonic-gate 			case '\b':
53517c478bd9Sstevel@tonic-gate 				return (mode ? 2 : EUC_BSWIDTH);
53527c478bd9Sstevel@tonic-gate 			case '\n':
53537c478bd9Sstevel@tonic-gate 				return (EUC_NLWIDTH);
53547c478bd9Sstevel@tonic-gate 			case '\r':
53557c478bd9Sstevel@tonic-gate 				return (mode ? 2 : EUC_CRWIDTH);
53567c478bd9Sstevel@tonic-gate 			default:
53577c478bd9Sstevel@tonic-gate 				return (mode ? 2 : 0);
53587c478bd9Sstevel@tonic-gate 			}
53597c478bd9Sstevel@tonic-gate 		}
53607c478bd9Sstevel@tonic-gate 		return (1);
53617c478bd9Sstevel@tonic-gate 	}
53627c478bd9Sstevel@tonic-gate 
53637c478bd9Sstevel@tonic-gate 	/* This is to silence the lint. */
53647c478bd9Sstevel@tonic-gate 	if (tp->t_csdata.codeset_type != LDTERM_CS_TYPE_UTF8)
53657c478bd9Sstevel@tonic-gate 		return (1);
53667c478bd9Sstevel@tonic-gate 
53677c478bd9Sstevel@tonic-gate 	/*
53687c478bd9Sstevel@tonic-gate 	 * If it is a valid leading byte of a UTF-8 character, we set
53697c478bd9Sstevel@tonic-gate 	 * the width as 'UNKNOWN_WIDTH' for now. We need to have all
53707c478bd9Sstevel@tonic-gate 	 * the bytes to figure out the display width.
53717c478bd9Sstevel@tonic-gate 	 */
53727c478bd9Sstevel@tonic-gate 	if (c >= (uchar_t)0xc0 && c <= (uchar_t)0xfd)
53737c478bd9Sstevel@tonic-gate 		return (UNKNOWN_WIDTH);
53747c478bd9Sstevel@tonic-gate 
53757c478bd9Sstevel@tonic-gate 	/*
53767c478bd9Sstevel@tonic-gate 	 * If it is an invalid leading byte, we just do our best by
53777c478bd9Sstevel@tonic-gate 	 * giving the display width of 1.
53787c478bd9Sstevel@tonic-gate 	 */
53797c478bd9Sstevel@tonic-gate 	return (1);
53807c478bd9Sstevel@tonic-gate }
53817c478bd9Sstevel@tonic-gate 
53827c478bd9Sstevel@tonic-gate 
53837c478bd9Sstevel@tonic-gate static int
__ldterm_memwidth_utf8(uchar_t c,void * p)53847c478bd9Sstevel@tonic-gate __ldterm_memwidth_utf8(uchar_t c, void *p)
53857c478bd9Sstevel@tonic-gate {
53867c478bd9Sstevel@tonic-gate 	ldtermstd_state_t *tp = (ldtermstd_state_t *)p;
538785bb5f1dSis 	int len;
53887c478bd9Sstevel@tonic-gate 
538985bb5f1dSis 	/*
539085bb5f1dSis 	 * If the codeset type doesn't match, we treat them as
539185bb5f1dSis 	 * an illegal character and return 1.
539285bb5f1dSis 	 */
53937c478bd9Sstevel@tonic-gate 	if (tp->t_csdata.codeset_type != LDTERM_CS_TYPE_UTF8)
53947c478bd9Sstevel@tonic-gate 		return (1);
53957c478bd9Sstevel@tonic-gate 
539685bb5f1dSis 	len = u8_number_of_bytes[c];
539785bb5f1dSis 
539885bb5f1dSis 	/*
539985bb5f1dSis 	 * If this is a start of an illegal character, we treat
540085bb5f1dSis 	 * such as an 1 byte character and screen out.
540185bb5f1dSis 	 */
540285bb5f1dSis 	return ((len <= 0) ? 1 : len);
54037c478bd9Sstevel@tonic-gate }
54047c478bd9Sstevel@tonic-gate 
54057c478bd9Sstevel@tonic-gate static uchar_t
ldterm_utf8_width(uchar_t * u8,int length)54067c478bd9Sstevel@tonic-gate ldterm_utf8_width(uchar_t *u8, int length)
54077c478bd9Sstevel@tonic-gate {
54087c478bd9Sstevel@tonic-gate 	int i;
54097c478bd9Sstevel@tonic-gate 	int j;
54107c478bd9Sstevel@tonic-gate 	uint_t intcode = 0;
54117c478bd9Sstevel@tonic-gate 
54127c478bd9Sstevel@tonic-gate 	if (length == 0)
54137c478bd9Sstevel@tonic-gate 		return ('\0');
54147c478bd9Sstevel@tonic-gate 
541585bb5f1dSis 	j = u8_number_of_bytes[u8[0]] - 1;
54167c478bd9Sstevel@tonic-gate 
54177c478bd9Sstevel@tonic-gate 	/*
54187c478bd9Sstevel@tonic-gate 	 * If the UTF-8 character is out of UTF-16 code range, or,
54197c478bd9Sstevel@tonic-gate 	 * if it is either an ASCII character or an invalid leading byte for
54207c478bd9Sstevel@tonic-gate 	 * a UTF-8 character, return 1.
54217c478bd9Sstevel@tonic-gate 	 */
542285bb5f1dSis 	if (length > 4 || j <= 0)
54237c478bd9Sstevel@tonic-gate 		return ('\1');
54247c478bd9Sstevel@tonic-gate 
542585bb5f1dSis 	intcode = u8[0] & u8_masks_tbl[j];
54267c478bd9Sstevel@tonic-gate 	for (i = 1; j > 0; j--, i++) {
54277c478bd9Sstevel@tonic-gate 		/*
542885bb5f1dSis 		 * The following additional checking is needed to conform to
542985bb5f1dSis 		 * the "UTF-8 Corrigendum" introduced at the Unicode 3.1 and
543085bb5f1dSis 		 * then updated one more time at the Unicode 3.2.
54317c478bd9Sstevel@tonic-gate 		 */
54327c478bd9Sstevel@tonic-gate 		if (i == 1) {
543385bb5f1dSis 			if (u8[i] < u8_valid_min_2nd_byte[u8[0]] ||
543485bb5f1dSis 			    u8[i] > u8_valid_max_2nd_byte[u8[0]])
54357c478bd9Sstevel@tonic-gate 				return ('\1');
54367c478bd9Sstevel@tonic-gate 		} else if (u8[i] < (uchar_t)LDTERM_CS_TYPE_UTF8_MIN_BYTE ||
543785bb5f1dSis 		    u8[i] > (uchar_t)LDTERM_CS_TYPE_UTF8_MAX_BYTE)
54387c478bd9Sstevel@tonic-gate 			return ('\1');
54397c478bd9Sstevel@tonic-gate 
54407c478bd9Sstevel@tonic-gate 		/*
54417c478bd9Sstevel@tonic-gate 		 * All subsequent bytes of UTF-8 character has the following
54427c478bd9Sstevel@tonic-gate 		 * binary encoding:
54437c478bd9Sstevel@tonic-gate 		 *
54447c478bd9Sstevel@tonic-gate 		 * 10xx xxxx
54457c478bd9Sstevel@tonic-gate 		 *
54467c478bd9Sstevel@tonic-gate 		 * hence left shift six bits to make space and then get
54477c478bd9Sstevel@tonic-gate 		 * six bits from the new byte.
54487c478bd9Sstevel@tonic-gate 		 */
54497c478bd9Sstevel@tonic-gate 		intcode = (intcode << LDTERM_CS_TYPE_UTF8_SHIFT_BITS) |
545085bb5f1dSis 		    (u8[i] & LDTERM_CS_TYPE_UTF8_BIT_MASK);
54517c478bd9Sstevel@tonic-gate 	}
54527c478bd9Sstevel@tonic-gate 
545385bb5f1dSis 	i = 0;
54547c478bd9Sstevel@tonic-gate 	if (intcode <= LDTERM_CS_TYPE_UTF8_MAX_P00) {
54557c478bd9Sstevel@tonic-gate 		/* Basic Multilingual Plane. */
54567c478bd9Sstevel@tonic-gate 		i = intcode / 4;
54577c478bd9Sstevel@tonic-gate 		j = intcode % 4;
54587c478bd9Sstevel@tonic-gate 		switch (j) {
54597c478bd9Sstevel@tonic-gate 		case 0:
546085bb5f1dSis 			i = ldterm_ucode[0][i].u0;
546185bb5f1dSis 			break;
54627c478bd9Sstevel@tonic-gate 		case 1:
546385bb5f1dSis 			i = ldterm_ucode[0][i].u1;
546485bb5f1dSis 			break;
54657c478bd9Sstevel@tonic-gate 		case 2:
546685bb5f1dSis 			i = ldterm_ucode[0][i].u2;
546785bb5f1dSis 			break;
54687c478bd9Sstevel@tonic-gate 		case 3:
546985bb5f1dSis 			i = ldterm_ucode[0][i].u3;
547085bb5f1dSis 			break;
54717c478bd9Sstevel@tonic-gate 		}
54727c478bd9Sstevel@tonic-gate 	} else if (intcode <= LDTERM_CS_TYPE_UTF8_MAX_P01) {
54737c478bd9Sstevel@tonic-gate 		/* Secondary Multilingual Plane. */
54747c478bd9Sstevel@tonic-gate 		intcode = intcode & (uint_t)0xffff;
54757c478bd9Sstevel@tonic-gate 		i = intcode / 4;
54767c478bd9Sstevel@tonic-gate 		j = intcode % 4;
54777c478bd9Sstevel@tonic-gate 		switch (j) {
54787c478bd9Sstevel@tonic-gate 		case 0:
547985bb5f1dSis 			i = ldterm_ucode[1][i].u0;
548085bb5f1dSis 			break;
54817c478bd9Sstevel@tonic-gate 		case 1:
548285bb5f1dSis 			i = ldterm_ucode[1][i].u1;
548385bb5f1dSis 			break;
54847c478bd9Sstevel@tonic-gate 		case 2:
548585bb5f1dSis 			i = ldterm_ucode[1][i].u2;
548685bb5f1dSis 			break;
54877c478bd9Sstevel@tonic-gate 		case 3:
548885bb5f1dSis 			i = ldterm_ucode[1][i].u3;
548985bb5f1dSis 			break;
54907c478bd9Sstevel@tonic-gate 		}
54917c478bd9Sstevel@tonic-gate 	} else if ((intcode >= LDTERM_CS_TYPE_UTF8_MIN_CJKEXTB &&
549285bb5f1dSis 	    intcode <= LDTERM_CS_TYPE_UTF8_MAX_CJKEXTB) ||
549385bb5f1dSis 	    (intcode >= LDTERM_CS_TYPE_UTF8_MIN_CJKCOMP &&
549485bb5f1dSis 	    intcode <= LDTERM_CS_TYPE_UTF8_MAX_CJKCOMP) ||
549585bb5f1dSis 	    (intcode >= LDTERM_CS_TYPE_UTF8_MIN_P15 &&
549685bb5f1dSis 	    intcode <= LDTERM_CS_TYPE_UTF8_MAX_P15) ||
549785bb5f1dSis 	    (intcode >= LDTERM_CS_TYPE_UTF8_MIN_P16 &&
549885bb5f1dSis 	    intcode <= LDTERM_CS_TYPE_UTF8_MAX_P16)) {
54997c478bd9Sstevel@tonic-gate 		/*
55007c478bd9Sstevel@tonic-gate 		 * Supplementary Plane for CJK Ideographs and
55017c478bd9Sstevel@tonic-gate 		 * Private Use Planes.
55027c478bd9Sstevel@tonic-gate 		 */
55037c478bd9Sstevel@tonic-gate 		return ('\2');
55047c478bd9Sstevel@tonic-gate 	} else if ((intcode >= LDTERM_CS_TYPE_UTF8_MIN_P14 &&
550585bb5f1dSis 	    intcode <= LDTERM_CS_TYPE_UTF8_MAX_P14) ||
550685bb5f1dSis 	    (intcode >= LDTERM_CS_TYPE_UTF8_MIN_VARSEL &&
550785bb5f1dSis 	    intcode <= LDTERM_CS_TYPE_UTF8_MAX_VARSEL)) {
550885bb5f1dSis 		/*
550985bb5f1dSis 		 * Some Special Purpose Plane characters:
551085bb5f1dSis 		 * These are like control characters and not printable.
551185bb5f1dSis 		 */
55127c478bd9Sstevel@tonic-gate 		return ('\0');
55137c478bd9Sstevel@tonic-gate 	}
55147c478bd9Sstevel@tonic-gate 
551585bb5f1dSis 	/*
551685bb5f1dSis 	 * We return the display width of 1 for all character code points
551785bb5f1dSis 	 * that we didn't catch from the above logic and also for combining
551885bb5f1dSis 	 * and conjoining characters with width value of zero.
551985bb5f1dSis 	 *
552085bb5f1dSis 	 * In particular, the reason why we are returning 1 for combining
552185bb5f1dSis 	 * and conjoining characters is because the GUI-based terminal
552285bb5f1dSis 	 * emulators are not yet capable of properly handling such characters
552385bb5f1dSis 	 * and in most of the cases, they just treat such characters as if
552485bb5f1dSis 	 * they occupy a display cell. If the terminal emulators are capable of
552585bb5f1dSis 	 * handling the characters correctly, then, this logic of returning
552685bb5f1dSis 	 * 1 should be revisited and changed. See CR 6660526 for more
552785bb5f1dSis 	 * details on this.
552885bb5f1dSis 	 */
552985bb5f1dSis 	return ((i == 0) ? '\1' : (uchar_t)i);
55307c478bd9Sstevel@tonic-gate }
5531