xref: /illumos-gate/usr/src/uts/common/io/ldterm.c (revision 0627591eb8261c55a48bc3b17ff3dfe0d0568939)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  * Copyright (c) 2018, Joyent, Inc.
25  * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
26  */
27 
28 /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
29 /* All Rights Reserved					*/
30 
31 /*
32  * University Copyright- Copyright (c) 1982, 1986, 1988
33  * The Regents of the University of California
34  * All Rights Reserved
35  *
36  * University Acknowledgment- Portions of this document are derived from
37  * software developed by the University of California, Berkeley, and its
38  * contributors.
39  */
40 
41 /*
42  * Standard Streams Terminal Line Discipline module.
43  */
44 
45 #include <sys/param.h>
46 #include <sys/types.h>
47 #include <sys/termio.h>
48 #include <sys/stream.h>
49 #include <sys/conf.h>
50 #include <sys/stropts.h>
51 #include <sys/strsubr.h>
52 #include <sys/strsun.h>
53 #include <sys/strtty.h>
54 #include <sys/signal.h>
55 #include <sys/file.h>
56 #include <sys/errno.h>
57 #include <sys/debug.h>
58 #include <sys/cmn_err.h>
59 #include <sys/euc.h>
60 #include <sys/eucioctl.h>
61 #include <sys/csiioctl.h>
62 #include <sys/ptms.h>
63 #include <sys/ldterm.h>
64 #include <sys/cred.h>
65 #include <sys/ddi.h>
66 #include <sys/sunddi.h>
67 #include <sys/kmem.h>
68 #include <sys/modctl.h>
69 
70 /* Time limit when draining during a close(9E) invoked by exit(2) */
71 /* Can be set to zero to emulate the old, broken behavior */
72 int ldterm_drain_limit = 15000000;
73 
74 /*
75  * Character types.
76  */
77 #define	ORDINARY	0
78 #define	CONTROL		1
79 #define	BACKSPACE	2
80 #define	NEWLINE		3
81 #define	TAB		4
82 #define	VTAB		5
83 #define	RETURN		6
84 
85 /*
86  * The following for EUC handling:
87  */
88 #define	T_SS2		7
89 #define	T_SS3		8
90 
91 /*
92  * Table indicating character classes to tty driver.  In particular,
93  * if the class is ORDINARY, then the character needs no special
94  * processing on output.
95  *
96  * Characters in the C1 set are all considered CONTROL; this will
97  * work with terminals that properly use the ANSI/ISO extensions,
98  * but might cause distress with terminals that put graphics in
99  * the range 0200-0237.  On the other hand, characters in that
100  * range cause even greater distress to other UNIX terminal drivers....
101  */
102 
103 static char typetab[256] = {
104 /* 000 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
105 /* 004 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
106 /* 010 */	BACKSPACE,	TAB,		NEWLINE,	CONTROL,
107 /* 014 */	VTAB,		RETURN,		CONTROL,	CONTROL,
108 /* 020 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
109 /* 024 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
110 /* 030 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
111 /* 034 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
112 /* 040 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
113 /* 044 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
114 /* 050 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
115 /* 054 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
116 /* 060 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
117 /* 064 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
118 /* 070 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
119 /* 074 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
120 /* 100 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
121 /* 104 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
122 /* 110 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
123 /* 114 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
124 /* 120 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
125 /* 124 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
126 /* 130 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
127 /* 134 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
128 /* 140 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
129 /* 144 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
130 /* 150 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
131 /* 154 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
132 /* 160 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
133 /* 164 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
134 /* 170 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
135 /* 174 */	ORDINARY,	ORDINARY,	ORDINARY,	CONTROL,
136 /* 200 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
137 /* 204 */	CONTROL,	CONTROL,	T_SS2,		T_SS3,
138 /* 210 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
139 /* 214 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
140 /* 220 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
141 /* 224 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
142 /* 230 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
143 /* 234 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
144 /* 240 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
145 /* 244 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
146 /* 250 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
147 /* 254 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
148 /* 260 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
149 /* 264 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
150 /* 270 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
151 /* 274 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
152 /* 300 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
153 /* 304 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
154 /* 310 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
155 /* 314 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
156 /* 320 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
157 /* 324 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
158 /* 330 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
159 /* 334 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
160 /* 340 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
161 /* 344 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
162 /* 350 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
163 /* 354 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
164 /* 360 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
165 /* 364 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
166 /* 370 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
167 /*
168  * WARNING:  For EUC, 0xFF must be an ordinary character.  It is used with
169  * single-byte EUC in some of the "ISO Latin Alphabet" codesets, and occupies
170  * a screen position; in those ISO sets where that position isn't used, it
171  * shouldn't make any difference.
172  */
173 /* 374 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
174 };
175 
176 /*
177  * Translation table for output without OLCUC.  All ORDINARY-class characters
178  * translate to themselves.  All other characters have a zero in the table,
179  * which stops the copying.
180  */
181 static unsigned char notrantab[256] = {
182 /* 000 */	0,	0,	0,	0,	0,	0,	0,	0,
183 /* 010 */	0,	0,	0,	0,	0,	0,	0,	0,
184 /* 020 */	0,	0,	0,	0,	0,	0,	0,	0,
185 /* 030 */	0,	0,	0,	0,	0,	0,	0,	0,
186 /* 040 */	' ',	'!',	'"',	'#',	'$',	'%',	'&',	'\'',
187 /* 050 */	'(',	')',	'*',	'+',	',',	'-',	'.',	'/',
188 /* 060 */	'0',	'1',	'2',	'3',	'4',	'5',	'6',	'7',
189 /* 070 */	'8',	'9',	':',	';',	'<',	'=',	'>',	'?',
190 /* 100 */	'@',	'A',	'B',	'C',	'D',	'E',	'F',	'G',
191 /* 110 */	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
192 /* 120 */	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
193 /* 130 */	'X',	'Y',	'Z',	'[',	'\\',	']',	'^',	'_',
194 /* 140 */	'`',	'a',	'b',	'c',	'd',	'e',	'f',	'g',
195 /* 150 */	'h',	'i',	'j',	'k',	'l',	'm',	'n',	'o',
196 /* 160 */	'p',	'q',	'r',	's',	't',	'u',	'v',	'w',
197 /* 170 */	'x',	'y',	'z',	'{',	'|',	'}',	'~',	0,
198 /* 200 */	0,	0,	0,	0,	0,	0,	0,	0,
199 /* 210 */	0,	0,	0,	0,	0,	0,	0,	0,
200 /* 220 */	0,	0,	0,	0,	0,	0,	0,	0,
201 /* 230 */	0,	0,	0,	0,	0,	0,	0,	0,
202 /* 240 */	0240,	0241,	0242,	0243,	0244,	0245,	0246,	0247,
203 /* 250 */	0250,	0251,	0252,	0253,	0254,	0255,	0256,	0257,
204 /* 260 */	0260,	0261,	0262,	0263,	0264,	0265,	0266,	0267,
205 /* 270 */	0270,	0271,	0272,	0273,	0274,	0275,	0276,	0277,
206 /* 300 */	0300,	0301,	0302,	0303,	0304,	0305,	0306,	0307,
207 /* 310 */	0310,	0311,	0312,	0313,	0314,	0315,	0316,	0317,
208 /* 320 */	0320,	0321,	0322,	0323,	0324,	0325,	0326,	0327,
209 /* 330 */	0330,	0331,	0332,	0333,	0334,	0335,	0336,	0337,
210 /* 340 */	0340,	0341,	0342,	0343,	0344,	0345,	0346,	0347,
211 /* 350 */	0350,	0351,	0352,	0353,	0354,	0355,	0356,	0357,
212 /* 360 */	0360,	0361,	0362,	0363,	0364,	0365,	0366,	0367,
213 /*
214  * WARNING: as for above ISO sets, \377 may be used.  Translate it to
215  * itself.
216  */
217 /* 370 */	0370,	0371,	0372,	0373,	0374,	0375,	0376,	0377,
218 };
219 
220 /*
221  * Translation table for output with OLCUC.  All ORDINARY-class characters
222  * translate to themselves, except for lower-case letters which translate
223  * to their upper-case equivalents.  All other characters have a zero in
224  * the table, which stops the copying.
225  */
226 static unsigned char lcuctab[256] = {
227 /* 000 */	0,	0,	0,	0,	0,	0,	0,	0,
228 /* 010 */	0,	0,	0,	0,	0,	0,	0,	0,
229 /* 020 */	0,	0,	0,	0,	0,	0,	0,	0,
230 /* 030 */	0,	0,	0,	0,	0,	0,	0,	0,
231 /* 040 */	' ',	'!',	'"',	'#',	'$',	'%',	'&',	'\'',
232 /* 050 */	'(',	')',	'*',	'+',	',',	'-',	'.',	'/',
233 /* 060 */	'0',	'1',	'2',	'3',	'4',	'5',	'6',	'7',
234 /* 070 */	'8',	'9',	':',	';',	'<',	'=',	'>',	'?',
235 /* 100 */	'@',	'A',	'B',	'C',	'D',	'E',	'F',	'G',
236 /* 110 */	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
237 /* 120 */	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
238 /* 130 */	'X',	'Y',	'Z',	'[',	'\\',	']',	'^',	'_',
239 /* 140 */	'`',	'A',	'B',	'C',	'D',	'E',	'F',	'G',
240 /* 150 */	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
241 /* 160 */	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
242 /* 170 */	'X',	'Y',	'Z',	'{',	'|',	'}',	'~',	0,
243 /* 200 */	0,	0,	0,	0,	0,	0,	0,	0,
244 /* 210 */	0,	0,	0,	0,	0,	0,	0,	0,
245 /* 220 */	0,	0,	0,	0,	0,	0,	0,	0,
246 /* 230 */	0,	0,	0,	0,	0,	0,	0,	0,
247 /* 240 */	0240,	0241,	0242,	0243,	0244,	0245,	0246,	0247,
248 /* 250 */	0250,	0251,	0252,	0253,	0254,	0255,	0256,	0257,
249 /* 260 */	0260,	0261,	0262,	0263,	0264,	0265,	0266,	0267,
250 /* 270 */	0270,	0271,	0272,	0273,	0274,	0275,	0276,	0277,
251 /* 300 */	0300,	0301,	0302,	0303,	0304,	0305,	0306,	0307,
252 /* 310 */	0310,	0311,	0312,	0313,	0314,	0315,	0316,	0317,
253 /* 320 */	0320,	0321,	0322,	0323,	0324,	0325,	0326,	0327,
254 /* 330 */	0330,	0331,	0332,	0333,	0334,	0335,	0336,	0337,
255 /* 340 */	0340,	0341,	0342,	0343,	0344,	0345,	0346,	0347,
256 /* 350 */	0350,	0351,	0352,	0353,	0354,	0355,	0356,	0357,
257 /* 360 */	0360,	0361,	0362,	0363,	0364,	0365,	0366,	0367,
258 /*
259  * WARNING: as for above ISO sets, \377 may be used.  Translate it to
260  * itself.
261  */
262 /* 370 */	0370,	0371,	0372,	0373,	0374,	0375,	0376,	0377,
263 };
264 
265 /*
266  * Input mapping table -- if an entry is non-zero, and XCASE is set,
267  * when the corresponding character is typed preceded by "\" the escape
268  * sequence is replaced by the table value.  Mostly used for
269  * upper-case only terminals.
270  */
271 static char	imaptab[256] = {
272 /* 000 */	0,	0,	0,	0,	0,	0,	0,	0,
273 /* 010 */	0,	0,	0,	0,	0,	0,	0,	0,
274 /* 020 */	0,	0,	0,	0,	0,	0,	0,	0,
275 /* 030 */	0,	0,	0,	0,	0,	0,	0,	0,
276 /* 040 */	0,	'|',	0,	0,	0,	0,	0,	'`',
277 /* 050 */	'{',	'}',	0,	0,	0,	0,	0,	0,
278 /* 060 */	0,	0,	0,	0,	0,	0,	0,	0,
279 /* 070 */	0,	0,	0,	0,	0,	0,	0,	0,
280 /* 100 */	0,	0,	0,	0,	0,	0,	0,	0,
281 /* 110 */	0,	0,	0,	0,	0,	0,	0,	0,
282 /* 120 */	0,	0,	0,	0,	0,	0,	0,	0,
283 /* 130 */	0,	0,	0,	0,	'\\',	0,	'~',	0,
284 /* 140 */	0,	'A',	'B',	'C',	'D',	'E',	'F',	'G',
285 /* 150 */	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
286 /* 160 */	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
287 /* 170 */	'X',	'Y',	'Z',	0,	0,	0,	0,	0,
288 /* 200-377 aren't mapped */
289 };
290 
291 /*
292  * Output mapping table -- if an entry is non-zero, and XCASE is set,
293  * the corresponding character is printed as "\" followed by the table
294  * value.  Mostly used for upper-case only terminals.
295  */
296 static char	omaptab[256] = {
297 /* 000 */	0,	0,	0,	0,	0,	0,	0,	0,
298 /* 010 */	0,	0,	0,	0,	0,	0,	0,	0,
299 /* 020 */	0,	0,	0,	0,	0,	0,	0,	0,
300 /* 030 */	0,	0,	0,	0,	0,	0,	0,	0,
301 /* 040 */	0,	0,	0,	0,	0,	0,	0,	0,
302 /* 050 */	0,	0,	0,	0,	0,	0,	0,	0,
303 /* 060 */	0,	0,	0,	0,	0,	0,	0,	0,
304 /* 070 */	0,	0,	0,	0,	0,	0,	0,	0,
305 /* 100 */	0,	'A',	'B',	'C',	'D',	'E',	'F',	'G',
306 /* 110 */	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
307 /* 120 */	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
308 /* 130 */	'X',	'Y',	'Z',	0,	0,	0,	0,	0,
309 /* 140 */	'\'',	0,	0,	0,	0,	0,	0,	0,
310 /* 150 */	0,	0,	0,	0,	0,	0,	0,	0,
311 /* 160 */	0,	0,	0,	0,	0,	0,	0,	0,
312 /* 170 */	0,	0,	0,	'(',	'!',	')',	'^',	0,
313 /* 200-377 aren't mapped */
314 };
315 
316 /*
317  * Translation table for TS_MEUC output without OLCUC.  All printing ASCII
318  * characters translate to themselves.  All other _bytes_ have a zero in
319  * the table, which stops the copying.  This and the following table exist
320  * only so we can use the existing movtuc processing with or without OLCUC.
321  * Maybe it speeds up something...because we can copy a block of characters
322  * by only looking for zeros in the table.
323  *
324  * If we took the simple expedient of DISALLOWING "olcuc" with multi-byte
325  * processing, we could rid ourselves of both these tables and save 512 bytes;
326  * seriously, it doesn't make much sense to use olcuc with multi-byte, and
327  * it will probably never be used.  Consideration should be given to disallowing
328  * the combination TS_MEUC & OLCUC.
329  */
330 static unsigned char enotrantab[256] = {
331 /* 000 */	0,	0,	0,	0,	0,	0,	0,	0,
332 /* 010 */	0,	0,	0,	0,	0,	0,	0,	0,
333 /* 020 */	0,	0,	0,	0,	0,	0,	0,	0,
334 /* 030 */	0,	0,	0,	0,	0,	0,	0,	0,
335 /* 040 */	' ',	'!',	'"',	'#',	'$',	'%',	'&',	'\'',
336 /* 050 */	'(',	')',	'*',	'+',	',',	'-',	'.',	'/',
337 /* 060 */	'0',	'1',	'2',	'3',	'4',	'5',	'6',	'7',
338 /* 070 */	'8',	'9',	':',	';',	'<',	'=',	'>',	'?',
339 /* 100 */	'@',	'A',	'B',	'C',	'D',	'E',	'F',	'G',
340 /* 110 */	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
341 /* 120 */	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
342 /* 130 */	'X',	'Y',	'Z',	'[',	'\\',	']',	'^',	'_',
343 /* 140 */	'`',	'a',	'b',	'c',	'd',	'e',	'f',	'g',
344 /* 150 */	'h',	'i',	'j',	'k',	'l',	'm',	'n',	'o',
345 /* 160 */	'p',	'q',	'r',	's',	't',	'u',	'v',	'w',
346 /* 170 */	'x',	'y',	'z',	'{',	'|',	'}',	'~',	0,
347 /* 200 - 377 aren't mapped (they're stoppers). */
348 };
349 
350 /*
351  * Translation table for TS_MEUC output with OLCUC.  All printing ASCII
352  * translate to themselves, except for lower-case letters which translate
353  * to their upper-case equivalents.  All other bytes have a zero in
354  * the table, which stops the copying.  Useless for ISO Latin Alphabet
355  * translations, but *sigh* OLCUC is really only defined for ASCII anyway.
356  * We only have this table so we can use the existing OLCUC processing with
357  * TS_MEUC set (multi-byte mode).  Nobody would ever think of actually
358  * _using_ it...would they?
359  */
360 static unsigned char elcuctab[256] = {
361 /* 000 */	0,	0,	0,	0,	0,	0,	0,	0,
362 /* 010 */	0,	0,	0,	0,	0,	0,	0,	0,
363 /* 020 */	0,	0,	0,	0,	0,	0,	0,	0,
364 /* 030 */	0,	0,	0,	0,	0,	0,	0,	0,
365 /* 040 */	' ',	'!',	'"',	'#',	'$',	'%',	'&',	'\'',
366 /* 050 */	'(',	')',	'*',	'+',	',',	'-',	'.',	'/',
367 /* 060 */	'0',	'1',	'2',	'3',	'4',	'5',	'6',	'7',
368 /* 070 */	'8',	'9',	':',	';',	'<',	'=',	'>',	'?',
369 /* 100 */	'@',	'A',	'B',	'C',	'D',	'E',	'F',	'G',
370 /* 110 */	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
371 /* 120 */	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
372 /* 130 */	'X',	'Y',	'Z',	'[',	'\\',	']',	'^',	'_',
373 /* 140 */	'`',	'A',	'B',	'C',	'D',	'E',	'F',	'G',
374 /* 150 */	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
375 /* 160 */	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
376 /* 170 */	'X',	'Y',	'Z',	'{',	'|',	'}',	'~',	0,
377 /* 200 - 377 aren't mapped (they're stoppers). */
378 };
379 
380 static struct streamtab ldtrinfo;
381 
382 static struct fmodsw fsw = {
383 	"ldterm",
384 	&ldtrinfo,
385 	D_MTQPAIR | D_MP | _D_SINGLE_INSTANCE
386 };
387 
388 static struct modlstrmod modlstrmod = {
389 	&mod_strmodops, "terminal line discipline", &fsw
390 };
391 
392 
393 static struct modlinkage modlinkage = {
394 	MODREV_1, &modlstrmod, NULL
395 };
396 
397 
398 int
399 _init(void)
400 {
401 	return (mod_install(&modlinkage));
402 }
403 
404 int
405 _fini(void)
406 {
407 	return (mod_remove(&modlinkage));
408 }
409 
410 int
411 _info(struct modinfo *modinfop)
412 {
413 	return (mod_info(&modlinkage, modinfop));
414 }
415 
416 
417 static int	ldtermopen(queue_t *, dev_t *, int, int, cred_t *);
418 static int	ldtermclose(queue_t *, int, cred_t *);
419 static void	ldtermrput(queue_t *, mblk_t *);
420 static void	ldtermrsrv(queue_t *);
421 static int	ldtermrmsg(queue_t *, mblk_t *);
422 static void	ldtermwput(queue_t *, mblk_t *);
423 static void	ldtermwsrv(queue_t *);
424 static int	ldtermwmsg(queue_t *, mblk_t *);
425 static mblk_t	*ldterm_docanon(unsigned char, mblk_t *, size_t, queue_t *,
426 				ldtermstd_state_t *, int *);
427 static int	ldterm_unget(ldtermstd_state_t *);
428 static void	ldterm_trim(ldtermstd_state_t *);
429 static void	ldterm_rubout(unsigned char, queue_t *, size_t,
430 				ldtermstd_state_t *);
431 static int	ldterm_tabcols(ldtermstd_state_t *);
432 static void	ldterm_erase(queue_t *, size_t, ldtermstd_state_t *);
433 static void	ldterm_werase(queue_t *, size_t, ldtermstd_state_t *);
434 static void	ldterm_kill(queue_t *, size_t, ldtermstd_state_t *);
435 static void	ldterm_reprint(queue_t *, size_t, ldtermstd_state_t *);
436 static mblk_t	*ldterm_dononcanon(mblk_t *, mblk_t *, size_t, queue_t *,
437 					ldtermstd_state_t *);
438 static int	ldterm_echo(unsigned char, queue_t *, size_t,
439 				ldtermstd_state_t *);
440 static void	ldterm_outchar(unsigned char, queue_t *, size_t,
441 				ldtermstd_state_t *);
442 static void	ldterm_outstring(unsigned char *, int, queue_t *, size_t,
443 					ldtermstd_state_t *tp);
444 static mblk_t	*newmsg(ldtermstd_state_t *);
445 static void	ldterm_msg_upstream(queue_t *, ldtermstd_state_t *);
446 static void	ldterm_wenable(void *);
447 static mblk_t	*ldterm_output_msg(queue_t *, mblk_t *, mblk_t **,
448 				ldtermstd_state_t *, size_t, int);
449 static void	ldterm_flush_output(unsigned char, queue_t *,
450 					ldtermstd_state_t *);
451 static void	ldterm_dosig(queue_t *, int, unsigned char, int, int);
452 static void	ldterm_do_ioctl(queue_t *, mblk_t *);
453 static int	chgstropts(struct termios *, ldtermstd_state_t *, queue_t *);
454 static void	ldterm_ioctl_reply(queue_t *, mblk_t *);
455 static void	vmin_satisfied(queue_t *, ldtermstd_state_t *, int);
456 static void	vmin_settimer(queue_t *);
457 static void	vmin_timed_out(void *);
458 static void	ldterm_adjust_modes(ldtermstd_state_t *);
459 static void	ldterm_eucwarn(ldtermstd_state_t *);
460 static void	cp_eucwioc(eucioc_t *, eucioc_t *, int);
461 static int	ldterm_codeset(uchar_t, uchar_t);
462 
463 static void	ldterm_csi_erase(queue_t *, size_t, ldtermstd_state_t *);
464 static void	ldterm_csi_werase(queue_t *, size_t, ldtermstd_state_t *);
465 
466 static uchar_t	ldterm_utf8_width(uchar_t *, int);
467 
468 /* Codeset type specific methods for EUC, PCCS, and, UTF-8 codeset types. */
469 static int	__ldterm_dispwidth_euc(uchar_t, void *, int);
470 static int	__ldterm_memwidth_euc(uchar_t, void *);
471 
472 static int	__ldterm_dispwidth_pccs(uchar_t, void *, int);
473 static int	__ldterm_memwidth_pccs(uchar_t, void *);
474 
475 static int	__ldterm_dispwidth_utf8(uchar_t, void *, int);
476 static int	__ldterm_memwidth_utf8(uchar_t, void *);
477 
478 static const ldterm_cs_methods_t cs_methods[LDTERM_CS_TYPE_MAX + 1] = {
479 	{
480 		NULL,
481 		NULL
482 	},
483 	{
484 		__ldterm_dispwidth_euc,
485 		__ldterm_memwidth_euc
486 	},
487 	{
488 		__ldterm_dispwidth_pccs,
489 		__ldterm_memwidth_pccs
490 	},
491 	{
492 		__ldterm_dispwidth_utf8,
493 		__ldterm_memwidth_utf8
494 	}
495 };
496 
497 /*
498  * The default codeset is presumably C locale's ISO 646 in EUC but
499  * the data structure at below defined as the default codeset data also
500  * support any single byte (EUC) locales.
501  */
502 static const ldterm_cs_data_t default_cs_data = {
503 	LDTERM_DATA_VERSION,
504 	LDTERM_CS_TYPE_EUC,
505 	(uchar_t)0,
506 	(uchar_t)0,
507 	(char *)NULL,
508 	{
509 		'\0', '\0', '\0', '\0',
510 		'\0', '\0', '\0', '\0',
511 		'\0', '\0', '\0', '\0',
512 		'\0', '\0', '\0', '\0',
513 		'\0', '\0', '\0', '\0',
514 		'\0', '\0', '\0', '\0',
515 		'\0', '\0', '\0', '\0',
516 		'\0', '\0', '\0', '\0',
517 		'\0', '\0', '\0', '\0',
518 		'\0', '\0', '\0', '\0'
519 	}
520 };
521 
522 /*
523  * The following tables are from either u8_textprep.c or uconv.c at
524  * usr/src/common/unicode/. The tables are used to figure out corresponding
525  * UTF-8 character byte lengths and also the validity of given character bytes.
526  */
527 extern const int8_t u8_number_of_bytes[];
528 extern const uchar_t u8_masks_tbl[];
529 extern const uint8_t u8_valid_min_2nd_byte[];
530 extern const uint8_t u8_valid_max_2nd_byte[];
531 
532 /*
533  * Unicode character width definition tables from uwidth.c:
534  */
535 extern const ldterm_unicode_data_cell_t ldterm_ucode[][16384];
536 
537 #ifdef LDDEBUG
538 int	ldterm_debug = 0;
539 #define	DEBUG1(a)	if (ldterm_debug == 1) printf a
540 #define	DEBUG2(a)	if (ldterm_debug >= 2) printf a	/* allocations */
541 #define	DEBUG3(a)	if (ldterm_debug >= 3) printf a	/* M_CTL Stuff */
542 #define	DEBUG4(a)	if (ldterm_debug >= 4) printf a	/* M_READ Stuff */
543 #define	DEBUG5(a)	if (ldterm_debug >= 5) printf a
544 #define	DEBUG6(a)	if (ldterm_debug >= 6) printf a
545 #define	DEBUG7(a)	if (ldterm_debug >= 7) printf a
546 #else
547 #define	DEBUG1(a)
548 #define	DEBUG2(a)
549 #define	DEBUG3(a)
550 #define	DEBUG4(a)
551 #define	DEBUG5(a)
552 #define	DEBUG6(a)
553 #define	DEBUG7(a)
554 #endif		/* LDDEBUG */
555 
556 
557 /*
558  * Since most of the buffering occurs either at the stream head or in
559  * the "message currently being assembled" buffer, we have a
560  * relatively small input queue, so that blockages above us get
561  * reflected fairly quickly to the module below us.  We also have a
562  * small maximum packet size, since you can put a message of that
563  * size on an empty queue no matter how much bigger than the high
564  * water mark it is.
565  */
566 static struct module_info ldtermmiinfo = {
567 	0x0bad,
568 	"ldterm",
569 	0,
570 	_TTY_BUFSIZ,
571 	_TTY_BUFSIZ,
572 	LOWAT
573 };
574 
575 
576 static struct qinit ldtermrinit = {
577 	(int (*)())ldtermrput,
578 	(int (*)())ldtermrsrv,
579 	ldtermopen,
580 	ldtermclose,
581 	NULL,
582 	&ldtermmiinfo
583 };
584 
585 
586 static struct module_info ldtermmoinfo = {
587 	0x0bad,
588 	"ldterm",
589 	0,
590 	INFPSZ,
591 	1,
592 	0
593 };
594 
595 
596 static struct qinit ldtermwinit = {
597 	(int (*)())ldtermwput,
598 	(int (*)())ldtermwsrv,
599 	ldtermopen,
600 	ldtermclose,
601 	NULL,
602 	&ldtermmoinfo
603 };
604 
605 
606 static struct streamtab ldtrinfo = {
607 	&ldtermrinit,
608 	&ldtermwinit,
609 	NULL,
610 	NULL
611 };
612 
613 /*
614  * Dummy qbufcall callback routine used by open and close.
615  * The framework will wake up qwait_sig when we return from
616  * this routine (as part of leaving the perimeters.)
617  * (The framework enters the perimeters before calling the qbufcall() callback
618  * and leaves the perimeters after the callback routine has executed. The
619  * framework performs an implicit wakeup of any thread in qwait/qwait_sig
620  * when it leaves the perimeter. See qwait(9E).)
621  */
622 /* ARGSUSED */
623 static void
624 dummy_callback(void *arg)
625 {}
626 
627 
628 static mblk_t *
629 open_ioctl(queue_t *q, uint_t cmd)
630 {
631 	mblk_t *mp;
632 	bufcall_id_t id;
633 	int retv;
634 
635 	while ((mp = mkiocb(cmd)) == NULL) {
636 		id = qbufcall(q, sizeof (struct iocblk), BPRI_MED,
637 		    dummy_callback, NULL);
638 		retv = qwait_sig(q);
639 		qunbufcall(q, id);
640 		if (retv == 0)
641 			break;
642 	}
643 	return (mp);
644 }
645 
646 static mblk_t *
647 open_mblk(queue_t *q, size_t len)
648 {
649 	mblk_t *mp;
650 	bufcall_id_t id;
651 	int retv;
652 
653 	while ((mp = allocb(len, BPRI_MED)) == NULL) {
654 		id = qbufcall(q, len, BPRI_MED, dummy_callback, NULL);
655 		retv = qwait_sig(q);
656 		qunbufcall(q, id);
657 		if (retv == 0)
658 			break;
659 	}
660 	return (mp);
661 }
662 
663 /*
664  * Line discipline open.
665  */
666 /* ARGSUSED1 */
667 static int
668 ldtermopen(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *crp)
669 {
670 	ldtermstd_state_t *tp;
671 	mblk_t *bp, *qryp;
672 	int len;
673 	struct stroptions *strop;
674 	struct termios *termiosp;
675 	queue_t *wq;
676 
677 	if (q->q_ptr != NULL) {
678 		return (0);	/* already attached */
679 	}
680 
681 	tp = (ldtermstd_state_t *)kmem_zalloc(sizeof (ldtermstd_state_t),
682 	    KM_SLEEP);
683 
684 	/*
685 	 * Get termios defaults.  These are stored as
686 	 * a property in the "options" node.
687 	 */
688 	if (ddi_getlongprop(DDI_DEV_T_ANY, ddi_root_node(), DDI_PROP_NOTPROM,
689 	    "ttymodes", (caddr_t)&termiosp, &len) == DDI_PROP_SUCCESS &&
690 	    len == sizeof (struct termios)) {
691 		tp->t_modes = *termiosp;
692 		tp->t_amodes = *termiosp;
693 		kmem_free(termiosp, len);
694 	} else {
695 		/*
696 		 * Gack!  Whine about it.
697 		 */
698 		cmn_err(CE_WARN, "ldterm: Couldn't get ttymodes property!");
699 	}
700 	bzero(&tp->t_dmodes, sizeof (struct termios));
701 
702 	tp->t_state = 0;
703 
704 	tp->t_line = 0;
705 	tp->t_col = 0;
706 
707 	tp->t_rocount = 0;
708 	tp->t_rocol = 0;
709 
710 	tp->t_message = NULL;
711 	tp->t_endmsg = NULL;
712 	tp->t_msglen = 0;
713 	tp->t_rd_request = 0;
714 
715 	tp->t_echomp = NULL;
716 	tp->t_iocid = 0;
717 	tp->t_wbufcid = 0;
718 	tp->t_vtid = 0;
719 
720 	q->q_ptr = (caddr_t)tp;
721 	WR(q)->q_ptr = (caddr_t)tp;
722 	/*
723 	 * The following for EUC and also non-EUC codesets:
724 	 */
725 	tp->t_codeset = tp->t_eucleft = tp->t_eucign = tp->t_scratch_len = 0;
726 	bzero(&tp->eucwioc, EUCSIZE);
727 	tp->eucwioc.eucw[0] = 1;	/* ASCII mem & screen width */
728 	tp->eucwioc.scrw[0] = 1;
729 	tp->t_maxeuc = 1;	/* the max len in bytes of an EUC char */
730 	tp->t_eucp = NULL;
731 	tp->t_csmethods = cs_methods[LDTERM_CS_TYPE_EUC];
732 	tp->t_csdata = default_cs_data;
733 
734 	/*
735 	 * Try to switch to UTF-8 mode by allocating buffer for multibyte
736 	 * chars, keep EUC if allocation fails.
737 	 */
738 	if ((tp->t_eucp_mp = allocb(_TTY_BUFSIZ, BPRI_HI)) != NULL) {
739 		tp->t_eucp = tp->t_eucp_mp->b_rptr;
740 		tp->t_state = TS_MEUC;	/* Multibyte mode. */
741 		tp->t_maxeuc = 4; /* the max len in bytes of an UTF-8 char */
742 		tp->t_csdata.codeset_type = LDTERM_CS_TYPE_UTF8;
743 		tp->t_csdata.csinfo_num = 4;
744 		/* locale_name needs string length with terminating NUL */
745 		tp->t_csdata.locale_name = (char *)kmem_alloc(6, KM_SLEEP);
746 		(void) strcpy(tp->t_csdata.locale_name, "UTF-8");
747 		tp->t_csmethods = cs_methods[LDTERM_CS_TYPE_UTF8];
748 	}
749 	tp->t_eucwarn = 0;	/* no bad chars seen yet */
750 
751 	qprocson(q);
752 
753 	/*
754 	 * Find out if the module below us does canonicalization; if
755 	 * so, we won't do it ourselves.
756 	 */
757 
758 	if ((qryp = open_ioctl(q, MC_CANONQUERY)) == NULL)
759 		goto open_abort;
760 
761 	/*
762 	 * Reformulate as an M_CTL message. The actual data will
763 	 * be in the b_cont field.
764 	 */
765 	qryp->b_datap->db_type = M_CTL;
766 	wq = OTHERQ(q);
767 	putnext(wq, qryp);
768 
769 	/* allocate a TCSBRK ioctl in case we'll need it on close */
770 	if ((qryp = open_ioctl(q, TCSBRK)) == NULL)
771 		goto open_abort;
772 	tp->t_drainmsg = qryp;
773 	if ((bp = open_mblk(q, sizeof (int))) == NULL)
774 		goto open_abort;
775 	qryp->b_cont = bp;
776 
777 	/*
778 	 * Find out if the underlying driver supports proper POSIX close
779 	 * semantics.  If not, we'll have to approximate it using TCSBRK.  If
780 	 * it does, it will respond with MC_HAS_POSIX, and we'll catch that in
781 	 * the ldtermrput routine.
782 	 *
783 	 * When the ldterm_drain_limit tunable is set to zero, we behave the
784 	 * same as old ldterm: don't send this new message, and always use
785 	 * TCSBRK during close.
786 	 */
787 	if (ldterm_drain_limit != 0) {
788 		if ((qryp = open_ioctl(q, MC_POSIXQUERY)) == NULL)
789 			goto open_abort;
790 		qryp->b_datap->db_type = M_CTL;
791 		putnext(wq, qryp);
792 	}
793 
794 	/* prepare to clear the water marks on close */
795 	if ((bp = open_mblk(q, sizeof (struct stroptions))) == NULL)
796 		goto open_abort;
797 	tp->t_closeopts = bp;
798 
799 	/*
800 	 * Set the high-water and low-water marks on the stream head
801 	 * to values appropriate for a terminal.  Also set the "vmin"
802 	 * and "vtime" values to 1 and 0, turn on message-nondiscard
803 	 * mode (as we're in ICANON mode), and turn on "old-style
804 	 * NODELAY" mode.
805 	 */
806 	if ((bp = open_mblk(q, sizeof (struct stroptions))) == NULL)
807 		goto open_abort;
808 	strop = (struct stroptions *)bp->b_wptr;
809 	strop->so_flags = SO_READOPT|SO_HIWAT|SO_LOWAT|SO_NDELON|SO_ISTTY;
810 	strop->so_readopt = RMSGN;
811 	strop->so_hiwat = _TTY_BUFSIZ;
812 	strop->so_lowat = LOWAT;
813 	bp->b_wptr += sizeof (struct stroptions);
814 	bp->b_datap->db_type = M_SETOPTS;
815 	putnext(q, bp);
816 
817 	return (0);		/* this can become a controlling TTY */
818 
819 open_abort:
820 	qprocsoff(q);
821 	q->q_ptr = NULL;
822 	WR(q)->q_ptr = NULL;
823 	freemsg(tp->t_closeopts);
824 	freemsg(tp->t_drainmsg);
825 	/* Dump the state structure */
826 	kmem_free(tp, sizeof (ldtermstd_state_t));
827 	return (EINTR);
828 }
829 
830 struct close_timer {
831 	timeout_id_t id;
832 	ldtermstd_state_t *tp;
833 };
834 
835 static void
836 drain_timed_out(void *arg)
837 {
838 	struct close_timer *ctp = arg;
839 
840 	ctp->id = 0;
841 	ctp->tp->t_state &= ~TS_IOCWAIT;
842 }
843 
844 /* ARGSUSED2 */
845 static int
846 ldtermclose(queue_t *q, int cflag, cred_t *crp)
847 {
848 	ldtermstd_state_t *tp = (ldtermstd_state_t *)q->q_ptr;
849 	struct stroptions *strop;
850 	mblk_t *bp;
851 	struct close_timer cltimer;
852 
853 	/*
854 	 * If we have an outstanding vmin timeout, cancel it.
855 	 */
856 	tp->t_state |= TS_CLOSE;
857 	if (tp->t_vtid != 0)
858 		(void) quntimeout(q, tp->t_vtid);
859 	tp->t_vtid = 0;
860 
861 	/*
862 	 * Cancel outstanding qbufcall request.
863 	 */
864 	if (tp->t_wbufcid != 0)
865 		qunbufcall(q, tp->t_wbufcid);
866 
867 	/*
868 	 * Reset the high-water and low-water marks on the stream
869 	 * head (?), turn on byte-stream mode, and turn off
870 	 * "old-style NODELAY" mode.
871 	 */
872 	bp = tp->t_closeopts;
873 	strop = (struct stroptions *)bp->b_wptr;
874 	strop->so_flags = SO_READOPT|SO_NDELOFF;
875 	strop->so_readopt = RNORM;
876 	bp->b_wptr += sizeof (struct stroptions);
877 	bp->b_datap->db_type = M_SETOPTS;
878 	putnext(q, bp);
879 
880 	if (cflag & (FNDELAY|FNONBLOCK)) {
881 		freemsg(tp->t_drainmsg);
882 	} else if ((bp = tp->t_drainmsg) != NULL) {
883 		struct iocblk *iocb;
884 
885 		/*
886 		 * If the driver isn't known to have POSIX close semantics,
887 		 * then we have to emulate this the old way.  This is done by
888 		 * sending down TCSBRK,1 to drain the output and waiting for
889 		 * the reply.
890 		 */
891 		iocb = (struct iocblk *)bp->b_rptr;
892 		iocb->ioc_count = sizeof (int);
893 		*(int *)bp->b_cont->b_rptr = 1;
894 		bp->b_cont->b_wptr += sizeof (int);
895 		tp->t_state |= TS_IOCWAIT;
896 		tp->t_iocid = iocb->ioc_id;
897 		if (!putq(WR(q), bp))
898 			putnext(WR(q), bp);
899 
900 		/*
901 		 * If we're not able to receive signals at this point, then
902 		 * launch a timer.  This timer will prevent us from waiting
903 		 * forever for a signal that won't arrive.
904 		 */
905 		cltimer.id = 0;
906 		if (!ddi_can_receive_sig() && ldterm_drain_limit != 0) {
907 			cltimer.tp = tp;
908 			cltimer.id = qtimeout(q, drain_timed_out, &cltimer,
909 			    drv_usectohz(ldterm_drain_limit));
910 		}
911 
912 		/*
913 		 * Note that the read side of ldterm and the qtimeout are
914 		 * protected by D_MTQPAIR, so no additional locking is needed
915 		 * here.
916 		 */
917 		while (tp->t_state & TS_IOCWAIT) {
918 			if (qwait_sig(q) == 0)
919 				break;
920 		}
921 		if (cltimer.id != 0)
922 			(void) quntimeout(q, cltimer.id);
923 	}
924 
925 	/*
926 	 * From here to the end, the routine does not sleep and does not
927 	 * reference STREAMS, so it's guaranteed to run to completion.
928 	 */
929 
930 	qprocsoff(q);
931 
932 	freemsg(tp->t_message);
933 	freemsg(tp->t_eucp_mp);
934 
935 	/* Dump the state structure, then unlink it */
936 	if (tp->t_csdata.locale_name != NULL)
937 		kmem_free(tp->t_csdata.locale_name,
938 		    strlen(tp->t_csdata.locale_name) + 1);
939 	kmem_free(tp, sizeof (ldtermstd_state_t));
940 	q->q_ptr = NULL;
941 	return (0);
942 }
943 
944 
945 /*
946  * Put procedure for input from driver end of stream (read queue).
947  */
948 static void
949 ldtermrput(queue_t *q, mblk_t *mp)
950 {
951 	ldtermstd_state_t *tp;
952 	unsigned char c;
953 	queue_t *wrq = WR(q);		/* write queue of ldterm mod */
954 	queue_t *nextq = q->q_next;	/* queue below us */
955 	mblk_t *bp;
956 	struct iocblk *qryp;
957 	unsigned char *readp;
958 	unsigned char *writep;
959 	struct termios *emodes;		/* effective modes set by driver */
960 	int dbtype;
961 
962 	tp = (ldtermstd_state_t *)q->q_ptr;
963 	/*
964 	 * We received our ack from the driver saying there is nothing left to
965 	 * shovel out, so wake up the close routine.
966 	 */
967 	dbtype = DB_TYPE(mp);
968 	if ((dbtype == M_IOCACK || dbtype == M_IOCNAK) &&
969 	    (tp->t_state & (TS_CLOSE|TS_IOCWAIT)) == (TS_CLOSE|TS_IOCWAIT)) {
970 		struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
971 
972 		if (iocp->ioc_id == tp->t_iocid) {
973 			tp->t_state &= ~TS_IOCWAIT;
974 			freemsg(mp);
975 			return;
976 		}
977 	}
978 
979 	switch (dbtype) {
980 
981 	default:
982 		(void) putq(q, mp);
983 		return;
984 
985 		/*
986 		 * Send these up unmolested
987 		 *
988 		 */
989 	case M_PCSIG:
990 	case M_SIG:
991 	case M_IOCNAK:
992 
993 		putnext(q, mp);
994 		return;
995 
996 	case M_IOCACK:
997 
998 		ldterm_ioctl_reply(q, mp);
999 		return;
1000 
1001 	case M_BREAK:
1002 
1003 		/*
1004 		 * Parity errors are sent up as M_BREAKS with single
1005 		 * character data (formerly handled in the driver)
1006 		 */
1007 		if (mp->b_wptr - mp->b_rptr == 1) {
1008 			/*
1009 			 * IGNPAR	PARMRK		RESULT
1010 			 * off		off		0
1011 			 * off		on		3 byte sequence
1012 			 * on		either		ignored
1013 			 */
1014 			if (!(tp->t_amodes.c_iflag & IGNPAR)) {
1015 				mp->b_wptr = mp->b_rptr;
1016 				if (tp->t_amodes.c_iflag & PARMRK) {
1017 					unsigned char c;
1018 
1019 					c = *mp->b_rptr;
1020 					freemsg(mp);
1021 					if ((mp = allocb(3, BPRI_HI)) == NULL) {
1022 						cmn_err(CE_WARN,
1023 						    "ldtermrput: no blocks");
1024 						return;
1025 					}
1026 					mp->b_datap->db_type = M_DATA;
1027 					*mp->b_wptr++ = (uchar_t)'\377';
1028 					*mp->b_wptr++ = '\0';
1029 					*mp->b_wptr++ = c;
1030 					putnext(q, mp);
1031 				} else {
1032 					mp->b_datap->db_type = M_DATA;
1033 					*mp->b_wptr++ = '\0';
1034 					putnext(q, mp);
1035 				}
1036 			} else {
1037 				freemsg(mp);
1038 			}
1039 			return;
1040 		}
1041 		/*
1042 		 * We look at the apparent modes here instead of the
1043 		 * effective modes. Effective modes cannot be used if
1044 		 * IGNBRK, BRINT and PARMRK have been negotiated to
1045 		 * be handled by the driver. Since M_BREAK should be
1046 		 * sent upstream only if break processing was not
1047 		 * already done, it should be ok to use the apparent
1048 		 * modes.
1049 		 */
1050 
1051 		if (!(tp->t_amodes.c_iflag & IGNBRK)) {
1052 			if (tp->t_amodes.c_iflag & BRKINT) {
1053 				ldterm_dosig(q, SIGINT, '\0', M_PCSIG, FLUSHRW);
1054 				freemsg(mp);
1055 			} else if (tp->t_amodes.c_iflag & PARMRK) {
1056 				/*
1057 				 * Send '\377','\0', '\0'.
1058 				 */
1059 				freemsg(mp);
1060 				if ((mp = allocb(3, BPRI_HI)) == NULL) {
1061 					cmn_err(CE_WARN,
1062 					    "ldtermrput: no blocks");
1063 					return;
1064 				}
1065 				mp->b_datap->db_type = M_DATA;
1066 				*mp->b_wptr++ = (uchar_t)'\377';
1067 				*mp->b_wptr++ = '\0';
1068 				*mp->b_wptr++ = '\0';
1069 				putnext(q, mp);
1070 			} else {
1071 				/*
1072 				 * Act as if a '\0' came in.
1073 				 */
1074 				freemsg(mp);
1075 				if ((mp = allocb(1, BPRI_HI)) == NULL) {
1076 					cmn_err(CE_WARN,
1077 					    "ldtermrput: no blocks");
1078 					return;
1079 				}
1080 				mp->b_datap->db_type = M_DATA;
1081 				*mp->b_wptr++ = '\0';
1082 				putnext(q, mp);
1083 			}
1084 		} else {
1085 			freemsg(mp);
1086 		}
1087 		return;
1088 
1089 	case M_CTL:
1090 		DEBUG3(("ldtermrput: M_CTL received\n"));
1091 		/*
1092 		 * The M_CTL has been standardized to look like an
1093 		 * M_IOCTL message.
1094 		 */
1095 
1096 		if ((mp->b_wptr - mp->b_rptr) != sizeof (struct iocblk)) {
1097 			DEBUG3((
1098 			    "Non standard M_CTL received by ldterm module\n"));
1099 			/* May be for someone else; pass it on */
1100 			putnext(q, mp);
1101 			return;
1102 		}
1103 		qryp = (struct iocblk *)mp->b_rptr;
1104 
1105 		switch (qryp->ioc_cmd) {
1106 
1107 		case MC_PART_CANON:
1108 
1109 			DEBUG3(("ldtermrput: M_CTL Query Reply\n"));
1110 			if (!mp->b_cont) {
1111 				DEBUG3(("No information in Query Message\n"));
1112 				break;
1113 			}
1114 			if ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) ==
1115 			    sizeof (struct termios)) {
1116 				DEBUG3(("ldtermrput: M_CTL GrandScheme\n"));
1117 				/* elaborate turning off scheme */
1118 				emodes = (struct termios *)mp->b_cont->b_rptr;
1119 				bcopy(emodes, &tp->t_dmodes,
1120 					sizeof (struct termios));
1121 				ldterm_adjust_modes(tp);
1122 				break;
1123 			} else {
1124 				DEBUG3(("Incorrect query replysize\n"));
1125 				break;
1126 			}
1127 
1128 		case MC_NO_CANON:
1129 			tp->t_state |= TS_NOCANON;
1130 			/*
1131 			 * Note: this is very nasty.  It's not clear
1132 			 * what the right thing to do with a partial
1133 			 * message is; We throw it out
1134 			 */
1135 			if (tp->t_message != NULL) {
1136 				freemsg(tp->t_message);
1137 				tp->t_message = NULL;
1138 				tp->t_endmsg = NULL;
1139 				tp->t_msglen = 0;
1140 				tp->t_rocount = 0;
1141 				tp->t_rocol = 0;
1142 				if (tp->t_state & TS_MEUC) {
1143 					ASSERT(tp->t_eucp_mp);
1144 					tp->t_eucp = tp->t_eucp_mp->b_rptr;
1145 					tp->t_codeset = 0;
1146 					tp->t_eucleft = 0;
1147 				}
1148 			}
1149 			break;
1150 
1151 		case MC_DO_CANON:
1152 			tp->t_state &= ~TS_NOCANON;
1153 			break;
1154 
1155 		case MC_HAS_POSIX:
1156 			/* no longer any reason to drain from ldterm */
1157 			if (ldterm_drain_limit != 0) {
1158 				freemsg(tp->t_drainmsg);
1159 				tp->t_drainmsg = NULL;
1160 			}
1161 			break;
1162 
1163 		default:
1164 			DEBUG3(("Unknown M_CTL Message\n"));
1165 			break;
1166 		}
1167 		putnext(q, mp);	/* In case anyone else has to see it */
1168 		return;
1169 
1170 	case M_FLUSH:
1171 		/*
1172 		 * Flush everything we haven't looked at yet.
1173 		 */
1174 
1175 		if ((tp->t_state & TS_ISPTSTTY) && (*mp->b_rptr & FLUSHBAND))
1176 			flushband(q, *(mp->b_rptr + 1), FLUSHDATA);
1177 		else
1178 			flushq(q, FLUSHDATA);
1179 
1180 		/*
1181 		 * Flush everything we have looked at.
1182 		 */
1183 		freemsg(tp->t_message);
1184 		tp->t_message = NULL;
1185 		tp->t_endmsg = NULL;
1186 		tp->t_msglen = 0;
1187 		tp->t_rocount = 0;
1188 		tp->t_rocol = 0;
1189 		if (tp->t_state & TS_MEUC) {	/* EUC multi-byte */
1190 			ASSERT(tp->t_eucp_mp);
1191 			tp->t_eucp = tp->t_eucp_mp->b_rptr;
1192 		}
1193 		putnext(q, mp);	/* pass it on */
1194 
1195 		/*
1196 		 * Relieve input flow control
1197 		 */
1198 		if ((tp->t_modes.c_iflag & IXOFF) &&
1199 		    (tp->t_state & TS_TBLOCK) &&
1200 		    !(tp->t_state & TS_IFBLOCK) && q->q_count <= TTXOLO) {
1201 			tp->t_state &= ~TS_TBLOCK;
1202 			(void) putnextctl(wrq, M_STARTI);
1203 			DEBUG1(("M_STARTI down\n"));
1204 		}
1205 		return;
1206 
1207 	case M_DATA:
1208 		break;
1209 	}
1210 	(void) drv_setparm(SYSRAWC, msgdsize(mp));
1211 
1212 	/*
1213 	 * Flow control: send "start input" message if blocked and
1214 	 * our queue is below its low water mark.
1215 	 */
1216 	if ((tp->t_modes.c_iflag & IXOFF) && (tp->t_state & TS_TBLOCK) &&
1217 	    !(tp->t_state & TS_IFBLOCK) && q->q_count <= TTXOLO) {
1218 		tp->t_state &= ~TS_TBLOCK;
1219 		(void) putnextctl(wrq, M_STARTI);
1220 		DEBUG1(("M_STARTI down\n"));
1221 	}
1222 	/*
1223 	 * If somebody below us ("intelligent" communications
1224 	 * board, pseudo-tty controlled by an editor) is doing
1225 	 * canonicalization, don't scan it for special characters.
1226 	 */
1227 	if (tp->t_state & TS_NOCANON) {
1228 		(void) putq(q, mp);
1229 		return;
1230 	}
1231 	bp = mp;
1232 
1233 	do {
1234 		readp = bp->b_rptr;
1235 		writep = readp;
1236 		if (tp->t_modes.c_iflag & (INLCR|IGNCR|ICRNL|IUCLC|IXON) ||
1237 		    tp->t_modes.c_lflag & (ISIG|ICANON)) {
1238 			/*
1239 			 * We're doing some sort of non-trivial
1240 			 * processing of input; look at every
1241 			 * character.
1242 			 */
1243 			while (readp < bp->b_wptr) {
1244 				c = *readp++;
1245 
1246 				if (tp->t_modes.c_iflag & ISTRIP)
1247 					c &= 0177;
1248 
1249 				/*
1250 				 * First, check that this hasn't been
1251 				 * escaped with the "literal next"
1252 				 * character.
1253 				 */
1254 				if (tp->t_state & TS_PLNCH) {
1255 					tp->t_state &= ~TS_PLNCH;
1256 					tp->t_modes.c_lflag &= ~FLUSHO;
1257 					*writep++ = c;
1258 					continue;
1259 				}
1260 				/*
1261 				 * Setting a special character to NUL
1262 				 * disables it, so if this character
1263 				 * is NUL, it should not be compared
1264 				 * with any of the special characters.
1265 				 * It should, however, restart frozen
1266 				 * output if IXON and IXANY are set.
1267 				 */
1268 				if (c == _POSIX_VDISABLE) {
1269 					if (tp->t_modes.c_iflag & IXON &&
1270 					    tp->t_state & TS_TTSTOP &&
1271 					    tp->t_modes.c_lflag & IEXTEN &&
1272 					    tp->t_modes.c_iflag & IXANY) {
1273 						tp->t_state &=
1274 						    ~(TS_TTSTOP|TS_OFBLOCK);
1275 						(void) putnextctl(wrq, M_START);
1276 					}
1277 					tp->t_modes.c_lflag &= ~FLUSHO;
1278 					*writep++ = c;
1279 					continue;
1280 				}
1281 				/*
1282 				 * If stopped, start if you can; if
1283 				 * running, stop if you must.
1284 				 */
1285 				if (tp->t_modes.c_iflag & IXON) {
1286 					if (tp->t_state & TS_TTSTOP) {
1287 						if (c ==
1288 						    tp->t_modes.c_cc[VSTART] ||
1289 						    (tp->t_modes.c_lflag &
1290 						    IEXTEN &&
1291 						    tp->t_modes.c_iflag &
1292 						    IXANY)) {
1293 							tp->t_state &=
1294 							    ~(TS_TTSTOP |
1295 							    TS_OFBLOCK);
1296 							(void) putnextctl(wrq,
1297 							    M_START);
1298 						}
1299 					} else {
1300 						if (c ==
1301 						    tp->t_modes.c_cc[VSTOP]) {
1302 							tp->t_state |=
1303 							    TS_TTSTOP;
1304 							(void) putnextctl(wrq,
1305 							    M_STOP);
1306 						}
1307 					}
1308 					if (c == tp->t_modes.c_cc[VSTOP] ||
1309 					    c == tp->t_modes.c_cc[VSTART])
1310 						continue;
1311 				}
1312 				/*
1313 				 * Check for "literal next" character
1314 				 * and "flush output" character.
1315 				 * Note that we omit checks for ISIG
1316 				 * and ICANON, since the IEXTEN
1317 				 * setting subsumes them.
1318 				 */
1319 				if (tp->t_modes.c_lflag & IEXTEN) {
1320 					if (c == tp->t_modes.c_cc[VLNEXT]) {
1321 						/*
1322 						 * Remember that we saw a
1323 						 * "literal next" while
1324 						 * scanning input, but leave
1325 						 * leave it in the message so
1326 						 * that the service routine
1327 						 * can see it too.
1328 						 */
1329 						tp->t_state |= TS_PLNCH;
1330 						tp->t_modes.c_lflag &= ~FLUSHO;
1331 						*writep++ = c;
1332 						continue;
1333 					}
1334 					if (c == tp->t_modes.c_cc[VDISCARD]) {
1335 						ldterm_flush_output(c, wrq, tp);
1336 						continue;
1337 					}
1338 				}
1339 				tp->t_modes.c_lflag &= ~FLUSHO;
1340 
1341 				/*
1342 				 * Check for signal-generating
1343 				 * characters.
1344 				 */
1345 				if (tp->t_modes.c_lflag & ISIG) {
1346 					if (c == tp->t_modes.c_cc[VINTR]) {
1347 						ldterm_dosig(q, SIGINT, c,
1348 						    M_PCSIG, FLUSHRW);
1349 						continue;
1350 					}
1351 					if (c == tp->t_modes.c_cc[VQUIT]) {
1352 						ldterm_dosig(q, SIGQUIT, c,
1353 						    M_PCSIG, FLUSHRW);
1354 						continue;
1355 					}
1356 					if (c == tp->t_modes.c_cc[VSWTCH]) {
1357 						/*
1358 						 * Ancient SXT support; discard
1359 						 * character without action.
1360 						 */
1361 						continue;
1362 					}
1363 					if (c == tp->t_modes.c_cc[VSUSP]) {
1364 						ldterm_dosig(q, SIGTSTP, c,
1365 						    M_PCSIG, FLUSHRW);
1366 						continue;
1367 					}
1368 					if ((tp->t_modes.c_lflag & IEXTEN) &&
1369 					    (c == tp->t_modes.c_cc[VDSUSP])) {
1370 						ldterm_dosig(q, SIGTSTP, c,
1371 						    M_SIG, 0);
1372 						continue;
1373 					}
1374 
1375 					/*
1376 					 * Consumers do not expect the ^T to be
1377 					 * echoed out when we generate a
1378 					 * VSTATUS.
1379 					 */
1380 					if (c == tp->t_modes.c_cc[VSTATUS]) {
1381 						ldterm_dosig(q, SIGINFO, '\0',
1382 						    M_PCSIG, FLUSHRW);
1383 						continue;
1384 					}
1385 				}
1386 				/*
1387 				 * Throw away CR if IGNCR set, or
1388 				 * turn it into NL if ICRNL set.
1389 				 */
1390 				if (c == '\r') {
1391 					if (tp->t_modes.c_iflag & IGNCR)
1392 						continue;
1393 					if (tp->t_modes.c_iflag & ICRNL)
1394 						c = '\n';
1395 				} else {
1396 					/*
1397 					 * Turn NL into CR if INLCR
1398 					 * set.
1399 					 */
1400 					if (c == '\n' &&
1401 					    tp->t_modes.c_iflag & INLCR)
1402 						c = '\r';
1403 				}
1404 
1405 				/*
1406 				 * Map upper case input to lower case
1407 				 * if IUCLC flag set.
1408 				 */
1409 				if (tp->t_modes.c_iflag & IUCLC &&
1410 				    c >= 'A' && c <= 'Z')
1411 					c += 'a' - 'A';
1412 
1413 				/*
1414 				 * Put the possibly-transformed
1415 				 * character back in the message.
1416 				 */
1417 				*writep++ = c;
1418 			}
1419 
1420 			/*
1421 			 * If we didn't copy some characters because
1422 			 * we were ignoring them, fix the size of the
1423 			 * data block by adjusting the write pointer.
1424 			 * XXX This may result in a zero-length
1425 			 * block; will this cause anybody gastric
1426 			 * distress?
1427 			 */
1428 			bp->b_wptr -= (readp - writep);
1429 		} else {
1430 			/*
1431 			 * We won't be doing anything other than
1432 			 * possibly stripping the input.
1433 			 */
1434 			if (tp->t_modes.c_iflag & ISTRIP) {
1435 				while (readp < bp->b_wptr)
1436 					*writep++ = *readp++ & 0177;
1437 			}
1438 			tp->t_modes.c_lflag &= ~FLUSHO;
1439 		}
1440 
1441 	} while ((bp = bp->b_cont) != NULL);	/* next block, if any */
1442 
1443 	/*
1444 	 * Queue the message for service procedure if the
1445 	 * queue is not empty or canputnext() fails or
1446 	 * tp->t_state & TS_RESCAN is true.
1447 	 */
1448 
1449 	if (q->q_first != NULL || !bcanputnext(q, mp->b_band) ||
1450 	    (tp->t_state & TS_RESCAN))
1451 		(void) putq(q, mp);
1452 	else
1453 		(void) ldtermrmsg(q, mp);
1454 
1455 	/*
1456 	 * Flow control: send "stop input" message if our queue is
1457 	 * approaching its high-water mark. The message will be
1458 	 * dropped on the floor in the service procedure, if we
1459 	 * cannot ship it up and we have had it upto our neck!
1460 	 *
1461 	 * Set QWANTW to ensure that the read queue service procedure
1462 	 * gets run when nextq empties up again, so that it can
1463 	 * unstop the input.
1464 	 */
1465 	if ((tp->t_modes.c_iflag & IXOFF) && !(tp->t_state & TS_TBLOCK) &&
1466 	    q->q_count >= TTXOHI) {
1467 		mutex_enter(QLOCK(nextq));
1468 		nextq->q_flag |= QWANTW;
1469 		mutex_exit(QLOCK(nextq));
1470 		tp->t_state |= TS_TBLOCK;
1471 		(void) putnextctl(wrq, M_STOPI);
1472 		DEBUG1(("M_STOPI down\n"));
1473 	}
1474 }
1475 
1476 
1477 /*
1478  * Line discipline input server processing.  Erase/kill and escape
1479  * ('\') processing, gathering into messages, upper/lower case input
1480  * mapping.
1481  */
1482 static void
1483 ldtermrsrv(queue_t *q)
1484 {
1485 	ldtermstd_state_t *tp;
1486 	mblk_t *mp;
1487 
1488 	tp = (ldtermstd_state_t *)q->q_ptr;
1489 
1490 	if (tp->t_state & TS_RESCAN) {
1491 		/*
1492 		 * Canonicalization was turned on or off. Put the
1493 		 * message being assembled back in the input queue,
1494 		 * so that we rescan it.
1495 		 */
1496 		if (tp->t_message != NULL) {
1497 			DEBUG5(("RESCAN WAS SET; put back in q\n"));
1498 			if (tp->t_msglen != 0)
1499 				(void) putbq(q, tp->t_message);
1500 			else
1501 				freemsg(tp->t_message);
1502 			tp->t_message = NULL;
1503 			tp->t_endmsg = NULL;
1504 			tp->t_msglen = 0;
1505 		}
1506 		if (tp->t_state & TS_MEUC) {
1507 			ASSERT(tp->t_eucp_mp);
1508 			tp->t_eucp = tp->t_eucp_mp->b_rptr;
1509 			tp->t_codeset = 0;
1510 			tp->t_eucleft = 0;
1511 		}
1512 		tp->t_state &= ~TS_RESCAN;
1513 	}
1514 
1515 	while ((mp = getq(q)) != NULL) {
1516 		if (!ldtermrmsg(q, mp))
1517 			break;
1518 	}
1519 
1520 	/*
1521 	 * Flow control: send start message if blocked and our queue
1522 	 * is below its low water mark.
1523 	 */
1524 	if ((tp->t_modes.c_iflag & IXOFF) && (tp->t_state & TS_TBLOCK) &&
1525 	    !(tp->t_state & TS_IFBLOCK) && q->q_count <= TTXOLO) {
1526 		tp->t_state &= ~TS_TBLOCK;
1527 		(void) putctl(WR(q), M_STARTI);
1528 	}
1529 }
1530 
1531 /*
1532  * This routine is called from both ldtermrput and ldtermrsrv to
1533  * do the actual work of dealing with mp. Return 1 on sucesss and
1534  * 0 on failure.
1535  */
1536 static int
1537 ldtermrmsg(queue_t *q, mblk_t *mp)
1538 {
1539 	unsigned char c;
1540 	int dofree;
1541 	int status = 1;
1542 	size_t   ebsize;
1543 	mblk_t *bp;
1544 	mblk_t *bpt;
1545 	ldtermstd_state_t *tp;
1546 
1547 	bpt = NULL;
1548 
1549 	tp = (ldtermstd_state_t *)q->q_ptr;
1550 
1551 	if (mp->b_datap->db_type <= QPCTL && !bcanputnext(q, mp->b_band)) {
1552 		/*
1553 		 * Stream head is flow controlled. If echo is
1554 		 * turned on, flush the read side or send a
1555 		 * bell down the line to stop input and
1556 		 * process the current message.
1557 		 * Otherwise(putbq) the user will not see any
1558 		 * response to to the typed input. Typically
1559 		 * happens if there is no reader process.
1560 		 * Note that you will loose the data in this
1561 		 * case if the data is coming too fast. There
1562 		 * is an assumption here that if ECHO is
1563 		 * turned on its some user typing the data on
1564 		 * a terminal and its not network.
1565 		 */
1566 		if (tp->t_modes.c_lflag & ECHO) {
1567 			if ((tp->t_modes.c_iflag & IMAXBEL) &&
1568 			    (tp->t_modes.c_lflag & ICANON)) {
1569 				freemsg(mp);
1570 				if (canputnext(WR(q)))
1571 					ldterm_outchar(CTRL('g'), WR(q), 4, tp);
1572 				status = 0;
1573 				goto echo;
1574 			} else {
1575 				(void) putctl1(q, M_FLUSH, FLUSHR);
1576 			}
1577 		} else {
1578 			(void) putbq(q, mp);
1579 			status = 0;
1580 			goto out;	/* read side is blocked */
1581 		}
1582 	}
1583 	switch (mp->b_datap->db_type) {
1584 
1585 	default:
1586 		putnext(q, mp);	/* pass it on */
1587 		goto out;
1588 
1589 	case M_HANGUP:
1590 		/*
1591 		 * Flush everything we haven't looked at yet.
1592 		 */
1593 		flushq(q, FLUSHDATA);
1594 
1595 		/*
1596 		 * Flush everything we have looked at.
1597 		 */
1598 		freemsg(tp->t_message);
1599 		tp->t_message = NULL;
1600 		tp->t_endmsg = NULL;
1601 		tp->t_msglen = 0;
1602 		/*
1603 		 * XXX  should we set read request
1604 		 * tp->t_rd_request to NULL?
1605 		 */
1606 		tp->t_rocount = 0;	/* if it hasn't been typed */
1607 		tp->t_rocol = 0;	/* it hasn't been echoed :-) */
1608 		if (tp->t_state & TS_MEUC) {
1609 			ASSERT(tp->t_eucp_mp);
1610 			tp->t_eucp = tp->t_eucp_mp->b_rptr;
1611 		}
1612 		/*
1613 		 * Restart output, since it's probably got
1614 		 * nowhere to go anyway, and we're probably
1615 		 * not going to see another ^Q for a while.
1616 		 */
1617 		if (tp->t_state & TS_TTSTOP) {
1618 			tp->t_state &= ~(TS_TTSTOP|TS_OFBLOCK);
1619 			(void) putnextctl(WR(q), M_START);
1620 		}
1621 		/*
1622 		 * This message will travel up the read
1623 		 * queue, flushing as it goes, get turned
1624 		 * around at the stream head, and travel back
1625 		 * down the write queue, flushing as it goes.
1626 		 */
1627 		(void) putnextctl1(q, M_FLUSH, FLUSHW);
1628 
1629 		/*
1630 		 * This message will travel down the write
1631 		 * queue, flushing as it goes, get turned
1632 		 * around at the driver, and travel back up
1633 		 * the read queue, flushing as it goes.
1634 		 */
1635 		(void) putctl1(WR(q), M_FLUSH, FLUSHR);
1636 
1637 		/*
1638 		 * Now that that's done, we send a SIGCONT
1639 		 * upstream, followed by the M_HANGUP.
1640 		 */
1641 		/* (void) putnextctl1(q, M_PCSIG, SIGCONT); */
1642 		putnext(q, mp);
1643 		goto out;
1644 
1645 	case M_IOCACK:
1646 
1647 		/*
1648 		 * Augment whatever information the driver is
1649 		 * returning  with the information we supply.
1650 		 */
1651 		ldterm_ioctl_reply(q, mp);
1652 		goto out;
1653 
1654 	case M_DATA:
1655 		break;
1656 	}
1657 
1658 	/*
1659 	 * This is an M_DATA message.
1660 	 */
1661 
1662 	/*
1663 	 * If somebody below us ("intelligent" communications
1664 	 * board, pseudo-tty controlled by an editor) is
1665 	 * doing canonicalization, don't scan it for special
1666 	 * characters.
1667 	 */
1668 	if (tp->t_state & TS_NOCANON) {
1669 		putnext(q, mp);
1670 		goto out;
1671 	}
1672 	bp = mp;
1673 
1674 	if ((bpt = newmsg(tp)) != NULL) {
1675 		mblk_t *bcont;
1676 
1677 		do {
1678 			ASSERT(bp->b_wptr >= bp->b_rptr);
1679 			ebsize = bp->b_wptr - bp->b_rptr;
1680 			if (ebsize > EBSIZE)
1681 				ebsize = EBSIZE;
1682 			bcont = bp->b_cont;
1683 			if (CANON_MODE) {
1684 				/*
1685 				 * By default, free the message once processed
1686 				 */
1687 				dofree = 1;
1688 
1689 				/*
1690 				 * update sysinfo canch
1691 				 * character. The value of
1692 				 * canch may vary as compared
1693 				 * to character tty
1694 				 * implementation.
1695 				 */
1696 				while (bp->b_rptr < bp->b_wptr) {
1697 					c = *bp->b_rptr++;
1698 					if ((bpt = ldterm_docanon(c,
1699 					    bpt, ebsize, q, tp, &dofree)) ==
1700 					    NULL)
1701 						break;
1702 				}
1703 				/*
1704 				 * Release this block or put back on queue.
1705 				 */
1706 				if (dofree)
1707 					freeb(bp);
1708 				else {
1709 					(void) putbq(q, bp);
1710 					break;
1711 				}
1712 			} else
1713 				bpt = ldterm_dononcanon(bp, bpt, ebsize, q, tp);
1714 			if (bpt == NULL) {
1715 				cmn_err(CE_WARN,
1716 				    "ldtermrsrv: out of blocks");
1717 				freemsg(bcont);
1718 				break;
1719 			}
1720 		} while ((bp = bcont) != NULL);
1721 	}
1722 echo:
1723 	/*
1724 	 * Send whatever we echoed downstream.
1725 	 */
1726 	if (tp->t_echomp != NULL) {
1727 		if (canputnext(WR(q)))
1728 			putnext(WR(q), tp->t_echomp);
1729 		else
1730 			freemsg(tp->t_echomp);
1731 		tp->t_echomp = NULL;
1732 	}
1733 
1734 out:
1735 	return (status);
1736 }
1737 
1738 
1739 /*
1740  * Do canonical mode input; check whether this character is to be
1741  * treated as a special character - if so, check whether it's equal
1742  * to any of the special characters and handle it accordingly.
1743  * Otherwise, just add it to the current line.
1744  */
1745 static mblk_t *
1746 ldterm_docanon(uchar_t c, mblk_t *bpt, size_t ebsize, queue_t *q,
1747     ldtermstd_state_t *tp, int *dofreep)
1748 {
1749 	queue_t *wrq = WR(q);
1750 	int i;
1751 
1752 	/*
1753 	 * If the previous character was the "literal next"
1754 	 * character, treat this character as regular input.
1755 	 */
1756 	if (tp->t_state & TS_SLNCH)
1757 		goto escaped;
1758 
1759 	/*
1760 	 * Setting a special character to NUL disables it, so if this
1761 	 * character is NUL, it should not be compared with any of
1762 	 * the special characters.
1763 	 */
1764 	if (c == _POSIX_VDISABLE) {
1765 		tp->t_state &= ~TS_QUOT;
1766 		goto escaped;
1767 	}
1768 	/*
1769 	 * If this character is the literal next character, echo it
1770 	 * as '^', backspace over it, and record that fact.
1771 	 */
1772 	if ((tp->t_modes.c_lflag & IEXTEN) && c == tp->t_modes.c_cc[VLNEXT]) {
1773 		if (tp->t_modes.c_lflag & ECHO)
1774 			ldterm_outstring((unsigned char *)"^\b", 2, wrq,
1775 			    ebsize, tp);
1776 		tp->t_state |= TS_SLNCH;
1777 		goto out;
1778 	}
1779 	/*
1780 	 * Check for the editing character. If the display width of
1781 	 * the last byte at the canonical buffer is not one and also
1782 	 * smaller than or equal to UNKNOWN_WIDTH, the character at
1783 	 * the end of the buffer is a multi-byte and/or multi-column
1784 	 * character.
1785 	 */
1786 	if (c == tp->t_modes.c_cc[VERASE] || c == tp->t_modes.c_cc[VERASE2]) {
1787 		if (tp->t_state & TS_QUOT) {
1788 			/*
1789 			 * Get rid of the backslash, and put the
1790 			 * erase character in its place.
1791 			 */
1792 			ldterm_erase(wrq, ebsize, tp);
1793 			bpt = tp->t_endmsg;
1794 			goto escaped;
1795 		} else {
1796 			if ((tp->t_state & TS_MEUC) && tp->t_msglen &&
1797 			    (*(tp->t_eucp - 1) != 1 &&
1798 			    *(tp->t_eucp - 1) <= UNKNOWN_WIDTH))
1799 				ldterm_csi_erase(wrq, ebsize, tp);
1800 			else
1801 				ldterm_erase(wrq, ebsize, tp);
1802 			bpt = tp->t_endmsg;
1803 			goto out;
1804 		}
1805 	}
1806 	if ((tp->t_modes.c_lflag & IEXTEN) && c == tp->t_modes.c_cc[VWERASE]) {
1807 		/*
1808 		 * Do "ASCII word" or "multibyte character token/chunk" erase.
1809 		 */
1810 		if (tp->t_state & TS_MEUC)
1811 			ldterm_csi_werase(wrq, ebsize, tp);
1812 		else
1813 			ldterm_werase(wrq, ebsize, tp);
1814 		bpt = tp->t_endmsg;
1815 		goto out;
1816 	}
1817 	if (c == tp->t_modes.c_cc[VKILL]) {
1818 		if (tp->t_state & TS_QUOT) {
1819 			/*
1820 			 * Get rid of the backslash, and put the kill
1821 			 * character in its place.
1822 			 */
1823 			ldterm_erase(wrq, ebsize, tp);
1824 			bpt = tp->t_endmsg;
1825 			goto escaped;
1826 		} else {
1827 			ldterm_kill(wrq, ebsize, tp);
1828 			bpt = tp->t_endmsg;
1829 			goto out;
1830 		}
1831 	}
1832 	if ((tp->t_modes.c_lflag & IEXTEN) && c == tp->t_modes.c_cc[VREPRINT]) {
1833 		ldterm_reprint(wrq, ebsize, tp);
1834 		goto out;
1835 	}
1836 	/*
1837 	 * If the preceding character was a backslash: if the current
1838 	 * character is an EOF, get rid of the backslash and treat
1839 	 * the EOF as data; if we're in XCASE mode and the current
1840 	 * character is part of a backslash-X escape sequence,
1841 	 * process it; otherwise, just treat the current character
1842 	 * normally.
1843 	 */
1844 	if (tp->t_state & TS_QUOT) {
1845 		tp->t_state &= ~TS_QUOT;
1846 		if (c == tp->t_modes.c_cc[VEOF]) {
1847 			/*
1848 			 * EOF character. Since it's escaped, get rid
1849 			 * of the backslash and put the EOF character
1850 			 * in its place.
1851 			 */
1852 			ldterm_erase(wrq, ebsize, tp);
1853 			bpt = tp->t_endmsg;
1854 		} else {
1855 			/*
1856 			 * If we're in XCASE mode, and the current
1857 			 * character is part of a backslash-X
1858 			 * sequence, get rid of the backslash and
1859 			 * replace the current character with what
1860 			 * that sequence maps to.
1861 			 */
1862 			if ((tp->t_modes.c_lflag & XCASE) &&
1863 			    imaptab[c] != '\0') {
1864 				ldterm_erase(wrq, ebsize, tp);
1865 				bpt = tp->t_endmsg;
1866 				c = imaptab[c];
1867 			}
1868 		}
1869 	} else {
1870 		/*
1871 		 * Previous character wasn't backslash; check whether
1872 		 * this was the EOF character.
1873 		 */
1874 		if (c == tp->t_modes.c_cc[VEOF]) {
1875 			/*
1876 			 * EOF character. Don't echo it unless
1877 			 * ECHOCTL is set, don't stuff it in the
1878 			 * current line, but send the line up the
1879 			 * stream.
1880 			 */
1881 			if ((tp->t_modes.c_lflag & ECHOCTL) &&
1882 			    (tp->t_modes.c_lflag & IEXTEN) &&
1883 			    (tp->t_modes.c_lflag & ECHO)) {
1884 				i = ldterm_echo(c, wrq, ebsize, tp);
1885 				while (i > 0) {
1886 					ldterm_outchar('\b', wrq, ebsize, tp);
1887 					i--;
1888 				}
1889 			}
1890 			bpt->b_datap->db_type = M_DATA;
1891 			ldterm_msg_upstream(q, tp);
1892 			if (!canputnext(q)) {
1893 				bpt = NULL;
1894 				*dofreep = 0;
1895 			} else {
1896 				bpt = newmsg(tp);
1897 				*dofreep = 1;
1898 			}
1899 			goto out;
1900 		}
1901 	}
1902 
1903 escaped:
1904 	/*
1905 	 * First, make sure we can fit one WHOLE multi-byte char in the
1906 	 * buffer.  This is one place where we have overhead even if
1907 	 * not in multi-byte mode; the overhead is subtracting
1908 	 * tp->t_maxeuc from MAX_CANON before checking.
1909 	 *
1910 	 * Allows MAX_CANON bytes in the buffer before throwing awaying
1911 	 * the the overflow of characters.
1912 	 */
1913 	if ((tp->t_msglen > ((_TTY_BUFSIZ + 1) - (int)tp->t_maxeuc)) &&
1914 	    !((tp->t_state & TS_MEUC) && tp->t_eucleft)) {
1915 
1916 		/*
1917 		 * Byte will cause line to overflow, or the next EUC
1918 		 * won't fit: Ring the bell or discard all input, and
1919 		 * don't save the byte away.
1920 		 */
1921 		if (tp->t_modes.c_iflag & IMAXBEL) {
1922 			if (canputnext(wrq))
1923 				ldterm_outchar(CTRL('g'), wrq, ebsize, tp);
1924 			goto out;
1925 		} else {
1926 			/*
1927 			 * MAX_CANON processing. free everything in
1928 			 * the current line and start with the
1929 			 * current character as the first character.
1930 			 */
1931 			DEBUG7(("ldterm_docanon: MAX_CANON processing\n"));
1932 			freemsg(tp->t_message);
1933 			tp->t_message = NULL;
1934 			tp->t_endmsg = NULL;
1935 			tp->t_msglen = 0;
1936 			tp->t_rocount = 0;	/* if it hasn't been type */
1937 			tp->t_rocol = 0;	/* it hasn't been echoed :-) */
1938 			if (tp->t_state & TS_MEUC) {
1939 				ASSERT(tp->t_eucp_mp);
1940 				tp->t_eucp = tp->t_eucp_mp->b_rptr;
1941 			}
1942 			tp->t_state &= ~TS_SLNCH;
1943 			bpt = newmsg(tp);
1944 		}
1945 	}
1946 	/*
1947 	 * Add the character to the current line.
1948 	 */
1949 	if (bpt->b_wptr >= bpt->b_datap->db_lim) {
1950 		/*
1951 		 * No more room in this mblk; save this one away, and
1952 		 * allocate a new one.
1953 		 */
1954 		bpt->b_datap->db_type = M_DATA;
1955 		if ((bpt = allocb(IBSIZE, BPRI_MED)) == NULL)
1956 			goto out;
1957 
1958 		/*
1959 		 * Chain the new one to the end of the old one, and
1960 		 * mark it as the last block in the current line.
1961 		 */
1962 		tp->t_endmsg->b_cont = bpt;
1963 		tp->t_endmsg = bpt;
1964 	}
1965 	*bpt->b_wptr++ = c;
1966 	tp->t_msglen++;		/* message length in BYTES */
1967 
1968 	/*
1969 	 * In multi-byte mode, we have to keep track of where we are.
1970 	 * The first bytes of multi-byte chars get the full count for the
1971 	 * whole character.  We don't do any column calculations
1972 	 * here, but we need the information for when we do. We could
1973 	 * come across cases where we are getting garbage on the
1974 	 * line, but we're in multi-byte mode.  In that case, we may
1975 	 * see ASCII controls come in the middle of what should have been a
1976 	 * multi-byte character.  Call ldterm_eucwarn...eventually, a
1977 	 * warning message will be printed about it.
1978 	 */
1979 	if (tp->t_state & TS_MEUC) {
1980 		if (tp->t_eucleft) {	/* if in a multi-byte char already */
1981 			--tp->t_eucleft;
1982 			*tp->t_eucp++ = 0;	/* is a subsequent byte */
1983 			if (c < (uchar_t)0x20)
1984 				ldterm_eucwarn(tp);
1985 		} else { /* is the first byte of a multi-byte, or is ASCII */
1986 			if (ISASCII(c)) {
1987 				*tp->t_eucp++ =
1988 				    tp->t_csmethods.ldterm_dispwidth(c,
1989 				    (void *)tp, tp->t_modes.c_lflag & ECHOCTL);
1990 				tp->t_codeset = 0;
1991 			} else {
1992 				*tp->t_eucp++ =
1993 				    tp->t_csmethods.ldterm_dispwidth(c,
1994 				    (void *)tp, tp->t_modes.c_lflag & ECHOCTL);
1995 				tp->t_eucleft =
1996 				    tp->t_csmethods.ldterm_memwidth(c,
1997 				    (void *)tp) - 1;
1998 				tp->t_codeset = ldterm_codeset(
1999 				    tp->t_csdata.codeset_type, c);
2000 			}
2001 		}
2002 	}
2003 	/*
2004 	 * AT&T is concerned about the following but we aren't since
2005 	 * we have already shipped code that works.
2006 	 *
2007 	 * EOL2/XCASE should be conditioned with IEXTEN to be truly
2008 	 * POSIX conformant. This is going to cause problems for
2009 	 * pre-SVR4.0 programs that don't know about IEXTEN. Hence
2010 	 * EOL2/IEXTEN is not conditioned with IEXTEN.
2011 	 */
2012 	if (!(tp->t_state & TS_SLNCH) &&
2013 	    (c == '\n' || (c != '\0' && (c == tp->t_modes.c_cc[VEOL] ||
2014 	    (c == tp->t_modes.c_cc[VEOL2]))))) {
2015 		/*
2016 		 * || ((tp->t_modes.c_lflag & IEXTEN) && c ==
2017 		 * tp->t_modes.c_cc[VEOL2]))))) {
2018 		 */
2019 		/*
2020 		 * It's a line-termination character; send the line
2021 		 * up the stream.
2022 		 */
2023 		bpt->b_datap->db_type = M_DATA;
2024 		ldterm_msg_upstream(q, tp);
2025 		if (tp->t_state & TS_MEUC) {
2026 			ASSERT(tp->t_eucp_mp);
2027 			tp->t_eucp = tp->t_eucp_mp->b_rptr;
2028 		}
2029 		if ((bpt = newmsg(tp)) == NULL)
2030 			goto out;
2031 	} else {
2032 		/*
2033 		 * Character was escaped with LNEXT.
2034 		 */
2035 		if (tp->t_rocount++ == 0)
2036 			tp->t_rocol = tp->t_col;
2037 		tp->t_state &= ~(TS_SLNCH|TS_QUOT);
2038 		/*
2039 		 * If the current character is a single byte and single
2040 		 * column character and it is the backslash character and
2041 		 * IEXTEN, then the state will have TS_QUOT.
2042 		 */
2043 		if ((c == '\\') && (tp->t_modes.c_lflag & IEXTEN) &&
2044 		    (!(tp->t_state & TS_MEUC) ||
2045 		    ((tp->t_state & TS_MEUC) && (!tp->t_eucleft))))
2046 			tp->t_state |= TS_QUOT;
2047 	}
2048 
2049 	/*
2050 	 * Echo it.
2051 	 */
2052 	if (tp->t_state & TS_ERASE) {
2053 		tp->t_state &= ~TS_ERASE;
2054 		if (tp->t_modes.c_lflag & ECHO)
2055 			ldterm_outchar('/', wrq, ebsize, tp);
2056 	}
2057 	if (tp->t_modes.c_lflag & ECHO)
2058 		(void) ldterm_echo(c, wrq, ebsize, tp);
2059 	else {
2060 		/*
2061 		 * Echo NL when ECHO turned off, if ECHONL flag is
2062 		 * set.
2063 		 */
2064 		if (c == '\n' && (tp->t_modes.c_lflag & ECHONL))
2065 			ldterm_outchar(c, wrq, ebsize, tp);
2066 	}
2067 
2068 out:
2069 
2070 	return (bpt);
2071 }
2072 
2073 
2074 static int
2075 ldterm_unget(ldtermstd_state_t *tp)
2076 {
2077 	mblk_t *bpt;
2078 
2079 	if ((bpt = tp->t_endmsg) == NULL)
2080 		return (-1);	/* no buffers */
2081 	if (bpt->b_rptr == bpt->b_wptr)
2082 		return (-1);	/* zero-length record */
2083 	tp->t_msglen--;		/* one fewer character */
2084 	return (*--bpt->b_wptr);
2085 }
2086 
2087 
2088 static void
2089 ldterm_trim(ldtermstd_state_t *tp)
2090 {
2091 	mblk_t *bpt;
2092 	mblk_t *bp;
2093 
2094 	ASSERT(tp->t_endmsg);
2095 	bpt = tp->t_endmsg;
2096 
2097 	if (bpt->b_rptr == bpt->b_wptr) {
2098 		/*
2099 		 * This mblk is now empty. Find the previous mblk;
2100 		 * throw this one away, unless it's the first one.
2101 		 */
2102 		bp = tp->t_message;
2103 		if (bp != bpt) {
2104 			while (bp->b_cont != bpt) {
2105 				ASSERT(bp->b_cont);
2106 				bp = bp->b_cont;
2107 			}
2108 			bp->b_cont = NULL;
2109 			freeb(bpt);
2110 			tp->t_endmsg = bp;	/* point to that mblk */
2111 		}
2112 	}
2113 }
2114 
2115 
2116 /*
2117  * Rubout one character from the current line being built for tp as
2118  * cleanly as possible.  q is the write queue for tp. Most of this
2119  * can't be applied to multi-byte processing.  We do our own thing
2120  * for that... See the "ldterm_eucerase" routine.  We never call
2121  * ldterm_rubout on a multi-byte or multi-column character.
2122  */
2123 static void
2124 ldterm_rubout(uchar_t c, queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
2125 {
2126 	int tabcols;
2127 	static unsigned char crtrubout[] = "\b \b\b \b";
2128 #define	RUBOUT1	&crtrubout[3]	/* rub out one position */
2129 #define	RUBOUT2	&crtrubout[0]	/* rub out two positions */
2130 
2131 	if (!(tp->t_modes.c_lflag & ECHO))
2132 		return;
2133 	if (tp->t_modes.c_lflag & ECHOE) {
2134 		/*
2135 		 * "CRT rubout"; try erasing it from the screen.
2136 		 */
2137 		if (tp->t_rocount == 0) {
2138 			/*
2139 			 * After the character being erased was
2140 			 * echoed, some data was written to the
2141 			 * terminal; we can't erase it cleanly, so we
2142 			 * just reprint the whole line as if the user
2143 			 * had typed the reprint character.
2144 			 */
2145 			ldterm_reprint(q, ebsize, tp);
2146 			return;
2147 		} else {
2148 			/*
2149 			 * XXX what about escaped characters?
2150 			 */
2151 			switch (typetab[c]) {
2152 
2153 			case ORDINARY:
2154 				if ((tp->t_modes.c_lflag & XCASE) &&
2155 				    omaptab[c])
2156 					ldterm_outstring(RUBOUT1, 3, q, ebsize,
2157 					    tp);
2158 				ldterm_outstring(RUBOUT1, 3, q, ebsize, tp);
2159 				break;
2160 
2161 			case VTAB:
2162 			case BACKSPACE:
2163 			case CONTROL:
2164 			case RETURN:
2165 			case NEWLINE:
2166 				if ((tp->t_modes.c_lflag & ECHOCTL) &&
2167 				    (tp->t_modes.c_lflag & IEXTEN))
2168 					ldterm_outstring(RUBOUT2, 6, q, ebsize,
2169 					    tp);
2170 				break;
2171 
2172 			case TAB:
2173 				if (tp->t_rocount < tp->t_msglen) {
2174 					/*
2175 					 * While the tab being erased was
2176 					 * expanded, some data was written
2177 					 * to the terminal; we can't erase
2178 					 * it cleanly, so we just reprint
2179 					 * the whole line as if the user
2180 					 * had typed the reprint character.
2181 					 */
2182 					ldterm_reprint(q, ebsize, tp);
2183 					return;
2184 				}
2185 				tabcols = ldterm_tabcols(tp);
2186 				while (--tabcols >= 0)
2187 					ldterm_outchar('\b', q, ebsize, tp);
2188 				break;
2189 			}
2190 		}
2191 	} else if ((tp->t_modes.c_lflag & ECHOPRT) &&
2192 	    (tp->t_modes.c_lflag & IEXTEN)) {
2193 		/*
2194 		 * "Printing rubout"; echo it between \ and /.
2195 		 */
2196 		if (!(tp->t_state & TS_ERASE)) {
2197 			ldterm_outchar('\\', q, ebsize, tp);
2198 			tp->t_state |= TS_ERASE;
2199 		}
2200 		(void) ldterm_echo(c, q, ebsize, tp);
2201 	} else
2202 		(void) ldterm_echo(tp->t_modes.c_cc[VERASE], q, ebsize, tp);
2203 	tp->t_rocount--;	/* we "unechoed" this character */
2204 }
2205 
2206 
2207 /*
2208  * Find the number of characters the tab we just deleted took up by
2209  * zipping through the current line and recomputing the column
2210  * number.
2211  */
2212 static int
2213 ldterm_tabcols(ldtermstd_state_t *tp)
2214 {
2215 	int col;
2216 	int i;
2217 	mblk_t *bp;
2218 	unsigned char *readp, *endp;
2219 	unsigned char c;
2220 	uchar_t *startp;
2221 	char errflg;
2222 	uchar_t u8[LDTERM_CS_MAX_BYTE_LENGTH];
2223 
2224 	col = tp->t_rocol;
2225 	/*
2226 	 * If we're doing multi-byte stuff, zip through the list of
2227 	 * widths to figure out where we are (we've kept track in most
2228 	 * cases).
2229 	 */
2230 	if (tp->t_state & TS_MEUC) {
2231 		ASSERT(tp->t_eucp_mp);
2232 		bp = tp->t_message;
2233 		startp = bp->b_datap->db_base;
2234 		readp = tp->t_eucp_mp->b_rptr;
2235 		endp = tp->t_eucp;
2236 		errflg = (char)0;
2237 		while (readp < endp) {
2238 			switch (*readp) {
2239 			case EUC_TWIDTH:	/* it's a tab */
2240 				col |= 07;	/* bump up */
2241 				col++;
2242 				break;
2243 			case EUC_BSWIDTH:	/* backspace */
2244 				if (col)
2245 					col--;
2246 				break;
2247 			case EUC_NLWIDTH:	/* newline */
2248 				if (tp->t_modes.c_oflag & ONLRET)
2249 					col = 0;
2250 				break;
2251 			case EUC_CRWIDTH:	/* return */
2252 				col = 0;
2253 				break;
2254 			case UNKNOWN_WIDTH:	/* UTF-8 unknown width */
2255 				if (tp->t_csdata.codeset_type !=
2256 				    LDTERM_CS_TYPE_UTF8 || errflg) {
2257 					*readp = 1;
2258 					col++;
2259 					break;
2260 				}
2261 				/*
2262 				 * Collect the current UTF-8 character bytes
2263 				 * from (possibly multiple) data buffers so
2264 				 * that we can figure out the display width.
2265 				 */
2266 				u8[0] = *startp;
2267 				for (i = 1; (i < LDTERM_CS_MAX_BYTE_LENGTH) &&
2268 				    (*(readp + i) == 0); i++) {
2269 					startp++;
2270 					if (startp >= bp->b_datap->db_lim) {
2271 						if (bp->b_cont) {
2272 							bp = bp->b_cont;
2273 							startp =
2274 							    bp->b_datap->
2275 							    db_base;
2276 						} else {
2277 							*readp = 1;
2278 							col++;
2279 							break;
2280 						}
2281 					}
2282 					u8[i] = *startp;
2283 				}
2284 
2285 				/* tp->t_eucp_mp contains wrong info?? */
2286 				if (*readp == 1)
2287 					break;
2288 
2289 				*readp = ldterm_utf8_width(u8, i);
2290 
2291 				col += *readp;
2292 				readp += (i - 1);
2293 				break;
2294 			default:
2295 				col += *readp;
2296 				break;
2297 			}
2298 			++readp;
2299 			++startp;
2300 			if (startp >= bp->b_datap->db_lim) {
2301 				if (bp->b_cont) {
2302 					bp = bp->b_cont;
2303 					startp = bp->b_datap->db_base;
2304 				} else {
2305 					/*
2306 					 * This will happen only if
2307 					 * tp->t_eucp_mp contains wrong
2308 					 * display width info.
2309 					 */
2310 					errflg = (char)1;
2311 					startp--;
2312 				}
2313 			}
2314 		}
2315 		goto eucout;	/* finished! */
2316 	}
2317 	bp = tp->t_message;
2318 	do {
2319 		readp = bp->b_rptr;
2320 		while (readp < bp->b_wptr) {
2321 			c = *readp++;
2322 			if ((tp->t_modes.c_lflag & ECHOCTL) &&
2323 			    (tp->t_modes.c_lflag & IEXTEN)) {
2324 				if (c <= 037 && c != '\t' && c != '\n' ||
2325 				    c == 0177) {
2326 					col += 2;
2327 					continue;
2328 				}
2329 			}
2330 			/*
2331 			 * Column position calculated here.
2332 			 */
2333 			switch (typetab[c]) {
2334 
2335 				/*
2336 				 * Ordinary characters; advance by
2337 				 * one.
2338 				 */
2339 			case ORDINARY:
2340 				col++;
2341 				break;
2342 
2343 				/*
2344 				 * Non-printing characters; nothing
2345 				 * happens.
2346 				 */
2347 			case CONTROL:
2348 				break;
2349 
2350 				/* Backspace */
2351 			case BACKSPACE:
2352 				if (col != 0)
2353 					col--;
2354 				break;
2355 
2356 				/* Newline; column depends on flags. */
2357 			case NEWLINE:
2358 				if (tp->t_modes.c_oflag & ONLRET)
2359 					col = 0;
2360 				break;
2361 
2362 				/* tab */
2363 			case TAB:
2364 				col |= 07;
2365 				col++;
2366 				break;
2367 
2368 				/* vertical motion */
2369 			case VTAB:
2370 				break;
2371 
2372 				/* carriage return */
2373 			case RETURN:
2374 				col = 0;
2375 				break;
2376 			}
2377 		}
2378 	} while ((bp = bp->b_cont) != NULL);	/* next block, if any */
2379 
2380 	/*
2381 	 * "col" is now the column number before the tab. "tp->t_col"
2382 	 * is still the column number after the tab, since we haven't
2383 	 * erased the tab yet. Thus "tp->t_col - col" is the number
2384 	 * of positions the tab moved.
2385 	 */
2386 eucout:
2387 	col = tp->t_col - col;
2388 	if (col > 8)
2389 		col = 8;	/* overflow screw */
2390 	return (col);
2391 }
2392 
2393 
2394 /*
2395  * Erase a single character; We ONLY ONLY deal with ASCII or
2396  * single-column single-byte codeset character.  For multi-byte characters,
2397  * see "ldterm_csi_erase".
2398  */
2399 static void
2400 ldterm_erase(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
2401 {
2402 	int c;
2403 
2404 	if ((c = ldterm_unget(tp)) != -1) {
2405 		ldterm_rubout((unsigned char) c, q, ebsize, tp);
2406 		ldterm_trim(tp);
2407 		if (tp->t_state & TS_MEUC)
2408 			--tp->t_eucp;
2409 	}
2410 }
2411 
2412 
2413 /*
2414  * Erase an entire word, single-byte EUC only please.
2415  */
2416 static void
2417 ldterm_werase(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
2418 {
2419 	int c;
2420 
2421 	/*
2422 	 * Erase trailing white space, if any.
2423 	 */
2424 	while ((c = ldterm_unget(tp)) == ' ' || c == '\t') {
2425 		ldterm_rubout((unsigned char) c, q, ebsize, tp);
2426 		ldterm_trim(tp);
2427 	}
2428 
2429 	/*
2430 	 * Erase non-white-space characters, if any.
2431 	 */
2432 	while (c != -1 && c != ' ' && c != '\t') {
2433 		ldterm_rubout((unsigned char) c, q, ebsize, tp);
2434 		ldterm_trim(tp);
2435 		c = ldterm_unget(tp);
2436 	}
2437 	if (c != -1) {
2438 		/*
2439 		 * We removed one too many characters; put the last
2440 		 * one back.
2441 		 */
2442 		tp->t_endmsg->b_wptr++;	/* put 'c' back */
2443 		tp->t_msglen++;
2444 	}
2445 }
2446 
2447 
2448 /*
2449  * ldterm_csi_werase - This is multi-byte equivalent of "word erase".
2450  * "Word erase" only makes sense in languages which space between words,
2451  * and it's presumptuous for us to attempt "word erase" when we don't
2452  * know anything about what's really going on.  It makes no sense for
2453  * many languages, as the criteria for defining words and tokens may
2454  * be completely different.
2455  *
2456  * In the TS_MEUC case (which is how we got here), we define a token to
2457  * be space- or tab-delimited, and erase one of them.  It helps to
2458  * have this for command lines, but it's otherwise useless for text
2459  * editing applications; you need more sophistication than we can
2460  * provide here.
2461  */
2462 static void
2463 ldterm_csi_werase(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
2464 {
2465 	int c, i;
2466 	int len;
2467 	uchar_t *ip;
2468 	uchar_t	u8[LDTERM_CS_MAX_BYTE_LENGTH];
2469 	uchar_t	u8_2[LDTERM_CS_MAX_BYTE_LENGTH];
2470 
2471 	/*
2472 	 * ip points to the width of the actual bytes.  t_eucp points
2473 	 * one byte beyond, where the next thing will be inserted.
2474 	 */
2475 	ip = tp->t_eucp - 1;
2476 	/*
2477 	 * Erase trailing white space, if any.
2478 	 */
2479 	while ((c = ldterm_unget(tp)) == ' ' || c == '\t') {
2480 		tp->t_eucp--;
2481 		ldterm_rubout((unsigned char) c, q, ebsize, tp);
2482 		ldterm_trim(tp);
2483 		--ip;
2484 	}
2485 
2486 	/*
2487 	 * Erase non-white-space characters, if any.  The outer loop
2488 	 * bops through each byte in the buffer. Multi-byte is removed, as
2489 	 * is ASCII, one byte at a time. The inner loop (for) is only
2490 	 * executed for first bytes of multi-byte.  The inner loop erases
2491 	 * the number of columns required for the multi-byte char.  We check
2492 	 * for ASCII first, and ldterm_rubout knows about ASCII.
2493 	 */
2494 	len = 0;
2495 	while (c != -1 && c != ' ' && c != '\t') {
2496 		tp->t_eucp--;
2497 		if (len < LDTERM_CS_MAX_BYTE_LENGTH) {
2498 			u8[len++] = (uchar_t)c;
2499 		}
2500 		/*
2501 		 * Unlike EUC, except the leading byte, some bytes of
2502 		 * a non-EUC multi-byte characters are in the ASCII code
2503 		 * range, esp., 0x41 ~ 0x7a. Thus, we cannot simply check
2504 		 * ISASCII().
2505 		 * Checking the (*ip == 1 || *ip == 2 || *ip > UNKNOWN_WIDTH)
2506 		 * will ensure that it is a single byte character (even though
2507 		 * it is on display width not byte length) and can be further
2508 		 * checked whether it is an ASCII character or not.
2509 		 *
2510 		 * When ECHOCTL is on and 'c' is an ASCII control character,
2511 		 * *ip == 2 happens.
2512 		 */
2513 		if ((*ip == 1 || *ip == 2 || *ip > UNKNOWN_WIDTH) &&
2514 		    ISASCII(c)) {
2515 			ldterm_rubout((unsigned char) c, q, ebsize, tp);
2516 			len = 0;
2517 		} else if (*ip) {
2518 			if (*ip == UNKNOWN_WIDTH) {
2519 				if (tp->t_csdata.codeset_type ==
2520 				    LDTERM_CS_TYPE_UTF8) {
2521 					for (i = 0; i < len; i++)
2522 						u8_2[i] = u8[len - i - 1];
2523 					*ip = ldterm_utf8_width(u8_2, len);
2524 				} else {
2525 					*ip = 1;
2526 				}
2527 			}
2528 			/*
2529 			 * erase for number of columns required for
2530 			 * this multi-byte character. Hopefully, matches
2531 			 * ldterm_dispwidth!
2532 			 */
2533 			for (i = 0; i < (int)*ip; i++)
2534 				ldterm_rubout(' ', q, ebsize, tp);
2535 			len = 0;
2536 		}
2537 		ldterm_trim(tp);
2538 		--ip;
2539 		c = ldterm_unget(tp);
2540 	}
2541 	if (c != -1) {
2542 		/*
2543 		 * We removed one too many characters; put the last
2544 		 * one back.
2545 		 */
2546 		tp->t_endmsg->b_wptr++;	/* put 'c' back */
2547 		tp->t_msglen++;
2548 	}
2549 }
2550 
2551 
2552 /*
2553  * Kill an entire line, erasing each character one-by-one (if ECHOKE
2554  * is set) or just echoing the kill character, followed by a newline
2555  * (if ECHOK is set).  Multi-byte processing is included here.
2556  */
2557 
2558 static void
2559 ldterm_kill(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
2560 {
2561 	int c, i;
2562 	int len;
2563 	uchar_t *ip;
2564 	uchar_t u8[LDTERM_CS_MAX_BYTE_LENGTH];
2565 	uchar_t u8_2[LDTERM_CS_MAX_BYTE_LENGTH];
2566 
2567 	if ((tp->t_modes.c_lflag & ECHOKE) &&
2568 	    (tp->t_modes.c_lflag & IEXTEN) &&
2569 	    (tp->t_msglen == tp->t_rocount)) {
2570 		if (tp->t_state & TS_MEUC) {
2571 			ip = tp->t_eucp - 1;
2572 			/*
2573 			 * This loop similar to "ldterm_csi_werase" above.
2574 			 */
2575 			len = 0;
2576 			while ((c = ldterm_unget(tp)) != (-1)) {
2577 				tp->t_eucp--;
2578 				if (len < LDTERM_CS_MAX_BYTE_LENGTH) {
2579 					u8[len++] = (uchar_t)c;
2580 				}
2581 				if ((*ip == 1 || *ip == 2 ||
2582 				    *ip > UNKNOWN_WIDTH) && ISASCII(c)) {
2583 					ldterm_rubout((unsigned char) c, q,
2584 					    ebsize, tp);
2585 					len = 0;
2586 				} else if (*ip) {
2587 					if (*ip == UNKNOWN_WIDTH) {
2588 						if (tp->t_csdata.codeset_type
2589 						    == LDTERM_CS_TYPE_UTF8) {
2590 							for (i = 0; i < len;
2591 							    i++)
2592 								u8_2[i] =
2593 								    u8[len-i-1];
2594 							*ip = ldterm_utf8_width(
2595 							    u8_2, len);
2596 						} else {
2597 							*ip = 1;
2598 						}
2599 					}
2600 					for (i = 0; i < (int)*ip; i++)
2601 						ldterm_rubout(' ', q, ebsize,
2602 						    tp);
2603 					len = 0;
2604 				}
2605 				ldterm_trim(tp);
2606 				--ip;
2607 			}
2608 		} else {
2609 			while ((c = ldterm_unget(tp)) != -1) {
2610 				ldterm_rubout((unsigned char) c, q, ebsize, tp);
2611 				ldterm_trim(tp);
2612 			}
2613 		}
2614 	} else {
2615 		(void) ldterm_echo(tp->t_modes.c_cc[VKILL], q, ebsize, tp);
2616 		if (tp->t_modes.c_lflag & ECHOK)
2617 			(void) ldterm_echo('\n', q, ebsize, tp);
2618 		while (ldterm_unget(tp) != -1) {
2619 			if (tp->t_state & TS_MEUC)
2620 				--tp->t_eucp;
2621 			ldterm_trim(tp);
2622 		}
2623 		tp->t_rocount = 0;
2624 		if (tp->t_state & TS_MEUC)
2625 			tp->t_eucp = tp->t_eucp_mp->b_rptr;
2626 	}
2627 	tp->t_state &= ~(TS_QUOT|TS_ERASE|TS_SLNCH);
2628 }
2629 
2630 
2631 /*
2632  * Reprint the current input line. We assume c_cc has already been
2633  * checked. XXX just the current line, not the whole queue? What
2634  * about DEFECHO mode?
2635  */
2636 static void
2637 ldterm_reprint(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
2638 {
2639 	mblk_t *bp;
2640 	unsigned char *readp;
2641 
2642 	if (tp->t_modes.c_cc[VREPRINT] != (unsigned char) 0)
2643 		(void) ldterm_echo(tp->t_modes.c_cc[VREPRINT], q, ebsize, tp);
2644 	ldterm_outchar('\n', q, ebsize, tp);
2645 
2646 	bp = tp->t_message;
2647 	do {
2648 		readp = bp->b_rptr;
2649 		while (readp < bp->b_wptr)
2650 			(void) ldterm_echo(*readp++, q, ebsize, tp);
2651 	} while ((bp = bp->b_cont) != NULL);	/* next block, if any */
2652 
2653 	tp->t_state &= ~TS_ERASE;
2654 	tp->t_rocount = tp->t_msglen;	/* we reechoed the entire line */
2655 	tp->t_rocol = 0;
2656 }
2657 
2658 
2659 /*
2660  * Non canonical processing. Called with q locked from  ldtermrsrv.
2661  *
2662  */
2663 static mblk_t *
2664 ldterm_dononcanon(mblk_t *bp, mblk_t *bpt, size_t ebsize, queue_t *q,
2665     ldtermstd_state_t *tp)
2666 {
2667 	queue_t *wrq = WR(q);
2668 	unsigned char *rptr;
2669 	size_t bytes_in_bp;
2670 	size_t roomleft;
2671 	size_t bytes_to_move;
2672 	int free_flag = 0;
2673 
2674 	if (tp->t_modes.c_lflag & (ECHO|ECHONL|IEXTEN)) {
2675 		unsigned char *wptr;
2676 		unsigned char c;
2677 
2678 		/*
2679 		 * Either we must echo the characters, or we must
2680 		 * echo NL, or we must check for VLNEXT. Process
2681 		 * characters one at a time.
2682 		 */
2683 		rptr = bp->b_rptr;
2684 		wptr = bp->b_rptr;
2685 		while (rptr < bp->b_wptr) {
2686 			c = *rptr++;
2687 			/*
2688 			 * If this character is the literal next
2689 			 * character, echo it as '^' and backspace
2690 			 * over it if echoing is enabled, indicate
2691 			 * that the next character is to be treated
2692 			 * literally, and remove the LNEXT from the
2693 			 * input stream.
2694 			 *
2695 			 * If the *previous* character was the literal
2696 			 * next character, don't check whether this
2697 			 * is a literal next or not.
2698 			 */
2699 			if ((tp->t_modes.c_lflag & IEXTEN) &&
2700 			    !(tp->t_state & TS_SLNCH) &&
2701 			    c != _POSIX_VDISABLE &&
2702 			    c == tp->t_modes.c_cc[VLNEXT]) {
2703 				if (tp->t_modes.c_lflag & ECHO)
2704 					ldterm_outstring(
2705 					    (unsigned char *)"^\b",
2706 					    2, wrq, ebsize, tp);
2707 				tp->t_state |= TS_SLNCH;
2708 				continue;	/* and ignore it */
2709 			}
2710 			/*
2711 			 * Not a "literal next" character, so it
2712 			 * should show up as input. If it was
2713 			 * literal-nexted, turn off the literal-next
2714 			 * flag.
2715 			 */
2716 			tp->t_state &= ~TS_SLNCH;
2717 			*wptr++ = c;
2718 			if (tp->t_modes.c_lflag & ECHO) {
2719 				/*
2720 				 * Echo the character.
2721 				 */
2722 				(void) ldterm_echo(c, wrq, ebsize, tp);
2723 			} else if (tp->t_modes.c_lflag & ECHONL) {
2724 				/*
2725 				 * Echo NL, even though ECHO is not
2726 				 * set.
2727 				 */
2728 				if (c == '\n')
2729 					ldterm_outchar('\n', wrq, 1, tp);
2730 			}
2731 		}
2732 		bp->b_wptr = wptr;
2733 	} else {
2734 		/*
2735 		 * If there are any characters in this buffer, and
2736 		 * the first of them was literal-nexted, turn off the
2737 		 * literal-next flag.
2738 		 */
2739 		if (bp->b_rptr != bp->b_wptr)
2740 			tp->t_state &= ~TS_SLNCH;
2741 	}
2742 
2743 	ASSERT(bp->b_wptr >= bp->b_rptr);
2744 	bytes_in_bp = bp->b_wptr - bp->b_rptr;
2745 	rptr = bp->b_rptr;
2746 	while (bytes_in_bp != 0) {
2747 		roomleft = bpt->b_datap->db_lim - bpt->b_wptr;
2748 		if (roomleft == 0) {
2749 			/*
2750 			 * No more room in this mblk; save this one
2751 			 * away, and allocate a new one.
2752 			 */
2753 			if ((bpt = allocb(IBSIZE, BPRI_MED)) == NULL) {
2754 				freeb(bp);
2755 				DEBUG4(("ldterm_do_noncanon: allcob failed\n"));
2756 				return (bpt);
2757 			}
2758 			/*
2759 			 * Chain the new one to the end of the old
2760 			 * one, and mark it as the last block in the
2761 			 * current lump.
2762 			 */
2763 			tp->t_endmsg->b_cont = bpt;
2764 			tp->t_endmsg = bpt;
2765 			roomleft = IBSIZE;
2766 		}
2767 		DEBUG5(("roomleft=%d, bytes_in_bp=%d, tp->t_rd_request=%d\n",
2768 		    roomleft, bytes_in_bp, tp->t_rd_request));
2769 		/*
2770 		 * if there is a read pending before this data got
2771 		 * here move bytes according to the minimum of room
2772 		 * left in this buffer, bytes in the message and byte
2773 		 * count requested in the read. If there is no read
2774 		 * pending, move the minimum of the first two
2775 		 */
2776 		if (tp->t_rd_request == 0)
2777 			bytes_to_move = MIN(roomleft, bytes_in_bp);
2778 		else
2779 			bytes_to_move =
2780 			    MIN(MIN(roomleft, bytes_in_bp), tp->t_rd_request);
2781 		DEBUG5(("Bytes to move = %lu\n", bytes_to_move));
2782 		if (bytes_to_move == 0)
2783 			break;
2784 		bcopy(rptr, bpt->b_wptr, bytes_to_move);
2785 		bpt->b_wptr += bytes_to_move;
2786 		rptr += bytes_to_move;
2787 		tp->t_msglen += bytes_to_move;
2788 		bytes_in_bp -= bytes_to_move;
2789 	}
2790 	if (bytes_in_bp == 0) {
2791 		DEBUG4(("bytes_in_bp is zero\n"));
2792 		freeb(bp);
2793 	} else
2794 		free_flag = 1;	/* for debugging olny */
2795 
2796 	DEBUG4(("ldterm_do_noncanon: VMIN = %d, VTIME = %d, msglen = %d, \
2797 		tid = %d\n", V_MIN, V_TIME, tp->t_msglen, tp->t_vtid));
2798 	/*
2799 	 * If there is a pending read request at the stream head we
2800 	 * need to do VMIN/VTIME processing. The four possible cases
2801 	 * are:
2802 	 *	MIN = 0, TIME > 0
2803 	 *	MIN = >, TIME = 0
2804 	 *	MIN > 0, TIME > 0
2805 	 *	MIN = 0, TIME = 0
2806 	 * If we can satisfy VMIN, send it up, and start a new
2807 	 * timer if necessary.  These four cases of VMIN/VTIME
2808 	 * are also dealt with in the write side put routine
2809 	 * when the M_READ is first seen.
2810 	 */
2811 
2812 	DEBUG4(("Incoming data while M_READ'ing\n"));
2813 	/*
2814 	 * Case 1:  Any data will satisfy the read, so send
2815 	 * it upstream.
2816 	 */
2817 	if (V_MIN == 0 && V_TIME > 0) {
2818 		if (tp->t_msglen)
2819 			vmin_satisfied(q, tp, 1);
2820 		else {
2821 			/* EMPTY */
2822 			DEBUG4(("ldterm_do_noncanon called, but no data!\n"));
2823 		}
2824 		/*
2825 		 * Case 2:  This should never time out, so
2826 		 * until there's enough data, do nothing.
2827 		 */
2828 	} else if (V_MIN > 0 && V_TIME == 0) {
2829 		if (tp->t_msglen >= (int)V_MIN)
2830 			vmin_satisfied(q, tp, 1);
2831 
2832 		/*
2833 		 * Case 3:  If MIN is satisfied, send it up.
2834 		 * Also, remember to start a new timer *every*
2835 		 * time we see something if MIN isn't
2836 		 * safisfied
2837 		 */
2838 	} else if (V_MIN > 0 && V_TIME > 0) {
2839 		if (tp->t_msglen >= (int)V_MIN)
2840 			vmin_satisfied(q, tp, 1);
2841 		else
2842 			vmin_settimer(q);
2843 		/*
2844 		 * Case 4:  Not possible.  This request
2845 		 * should always be satisfied from the write
2846 		 * side, left here for debugging.
2847 		 */
2848 	} else {	/* V_MIN == 0 && V_TIME == 0 */
2849 			vmin_satisfied(q, tp, 1);
2850 	}
2851 
2852 	if (free_flag) {
2853 		/* EMPTY */
2854 		DEBUG4(("CAUTION message block not freed\n"));
2855 	}
2856 	return (newmsg(tp));
2857 }
2858 
2859 
2860 /*
2861  * Echo a typed byte to the terminal.  Returns the number of bytes
2862  * printed. Bytes of EUC characters drop through the ECHOCTL stuff
2863  * and are just output as themselves.
2864  */
2865 static int
2866 ldterm_echo(uchar_t c, queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
2867 {
2868 	int i;
2869 
2870 	if (!(tp->t_modes.c_lflag & ECHO))
2871 		return (0);
2872 	i = 0;
2873 
2874 	/*
2875 	 * Echo control characters (c <= 37) only if the ECHOCTRL
2876 	 * flag is set as ^X.
2877 	 */
2878 
2879 	if ((tp->t_modes.c_lflag & ECHOCTL) &&
2880 	    (tp->t_modes.c_lflag & IEXTEN)) {
2881 		if (c <= 037 && c != '\t' && c != '\n') {
2882 			ldterm_outchar('^', q, ebsize, tp);
2883 			i++;
2884 			if (tp->t_modes.c_oflag & OLCUC)
2885 				c += 'a' - 1;
2886 			else
2887 				c += 'A' - 1;
2888 		} else if (c == 0177) {
2889 			ldterm_outchar('^', q, ebsize, tp);
2890 			i++;
2891 			c = '?';
2892 		}
2893 		ldterm_outchar(c, q, ebsize, tp);
2894 		return (i + 1);
2895 		/* echo only special control character and the Bell */
2896 	} else if ((c > 037 && c != 0177) || c == '\t' || c == '\n' ||
2897 	    c == '\r' || c == '\b' || c == 007 ||
2898 	    c == tp->t_modes.c_cc[VKILL]) {
2899 		ldterm_outchar(c, q, ebsize, tp);
2900 		return (i + 1);
2901 	}
2902 	return (i);
2903 }
2904 
2905 
2906 /*
2907  * Put a character on the output queue.
2908  */
2909 static void
2910 ldterm_outchar(uchar_t c, queue_t *q, size_t bsize, ldtermstd_state_t *tp)
2911 {
2912 	mblk_t *curbp;
2913 
2914 	/*
2915 	 * Don't even look at the characters unless we have something
2916 	 * useful to do with them.
2917 	 */
2918 	if ((tp->t_modes.c_oflag & OPOST) ||
2919 	    ((tp->t_modes.c_lflag & XCASE) &&
2920 	    (tp->t_modes.c_lflag & ICANON))) {
2921 		mblk_t *mp;
2922 
2923 		if ((mp = allocb(4, BPRI_HI)) == NULL) {
2924 			cmn_err(CE_WARN,
2925 			    "ldterm: (ldterm_outchar) out of blocks");
2926 			return;
2927 		}
2928 		*mp->b_wptr++ = c;
2929 		mp = ldterm_output_msg(q, mp, &tp->t_echomp, tp, bsize, 1);
2930 		if (mp != NULL)
2931 			freemsg(mp);
2932 
2933 	} else {
2934 		if ((curbp = tp->t_echomp) != NULL) {
2935 			while (curbp->b_cont != NULL)
2936 				curbp = curbp->b_cont;
2937 			if (curbp->b_datap->db_lim == curbp->b_wptr) {
2938 				mblk_t *newbp;
2939 
2940 				if ((newbp = allocb(bsize, BPRI_HI)) == NULL) {
2941 					cmn_err(CE_WARN,
2942 					    "ldterm_outchar: out of blocks");
2943 					return;
2944 				}
2945 				curbp->b_cont = newbp;
2946 				curbp = newbp;
2947 			}
2948 		} else {
2949 			if ((curbp = allocb(bsize, BPRI_HI)) == NULL) {
2950 				cmn_err(CE_WARN,
2951 				    "ldterm_outchar: out of blocks");
2952 				return;
2953 			}
2954 			tp->t_echomp = curbp;
2955 		}
2956 		*curbp->b_wptr++ = c;
2957 	}
2958 }
2959 
2960 
2961 /*
2962  * Copy a string, of length len, to the output queue.
2963  */
2964 static void
2965 ldterm_outstring(uchar_t *cp, int len, queue_t *q, size_t bsize,
2966     ldtermstd_state_t *tp)
2967 {
2968 	while (len > 0) {
2969 		ldterm_outchar(*cp++, q, bsize, tp);
2970 		len--;
2971 	}
2972 }
2973 
2974 
2975 static mblk_t *
2976 newmsg(ldtermstd_state_t *tp)
2977 {
2978 	mblk_t *bp;
2979 
2980 	/*
2981 	 * If no current message, allocate a block for it.
2982 	 */
2983 	if ((bp = tp->t_endmsg) == NULL) {
2984 		if ((bp = allocb(IBSIZE, BPRI_MED)) == NULL) {
2985 			cmn_err(CE_WARN,
2986 			    "ldterm: (ldtermrsrv/newmsg) out of blocks");
2987 			return (bp);
2988 		}
2989 		tp->t_message = bp;
2990 		tp->t_endmsg = bp;
2991 	}
2992 	return (bp);
2993 }
2994 
2995 
2996 static void
2997 ldterm_msg_upstream(queue_t *q, ldtermstd_state_t *tp)
2998 {
2999 	ssize_t s;
3000 	mblk_t *bp;
3001 
3002 	bp = tp->t_message;
3003 	s = msgdsize(bp);
3004 	if (bp)
3005 		putnext(q, tp->t_message);
3006 
3007 	/*
3008 	 * update sysinfo canch character.
3009 	 */
3010 	if (CANON_MODE)
3011 		(void) drv_setparm(SYSCANC, s);
3012 	tp->t_message = NULL;
3013 	tp->t_endmsg = NULL;
3014 	tp->t_msglen = 0;
3015 	tp->t_rocount = 0;
3016 	tp->t_rd_request = 0;
3017 	if (tp->t_state & TS_MEUC) {
3018 		ASSERT(tp->t_eucp_mp);
3019 		tp->t_eucp = tp->t_eucp_mp->b_rptr;
3020 		/* can't reset everything, as we may have other input */
3021 	}
3022 }
3023 
3024 
3025 /*
3026  * Re-enable the write-side service procedure.  When an allocation
3027  * failure causes write-side processing to stall, we disable the
3028  * write side and arrange to call this function when allocation once
3029  * again becomes possible.
3030  */
3031 static void
3032 ldterm_wenable(void *addr)
3033 {
3034 	queue_t *q = addr;
3035 	ldtermstd_state_t *tp;
3036 
3037 	tp = (ldtermstd_state_t *)q->q_ptr;
3038 	/*
3039 	 * The bufcall is no longer pending.
3040 	 */
3041 	tp->t_wbufcid = 0;
3042 	enableok(q);
3043 	qenable(q);
3044 }
3045 
3046 
3047 /*
3048  * Line discipline output queue put procedure.  Attempts to process
3049  * the message directly and send it on downstream, queueing it only
3050  * if there's already something pending or if its downstream neighbor
3051  * is clogged.
3052  */
3053 static void
3054 ldtermwput(queue_t *q, mblk_t *mp)
3055 {
3056 	ldtermstd_state_t *tp;
3057 	unsigned char type = mp->b_datap->db_type;
3058 
3059 	tp = (ldtermstd_state_t *)q->q_ptr;
3060 
3061 	/*
3062 	 * Always process priority messages, regardless of whether or
3063 	 * not our queue is nonempty.
3064 	 */
3065 	if (type >= QPCTL) {
3066 		switch (type) {
3067 
3068 		case M_FLUSH:
3069 			/*
3070 			 * Get rid of it, see comment in
3071 			 * ldterm_dosig().
3072 			 */
3073 			if ((tp->t_state & TS_FLUSHWAIT) &&
3074 			    (*mp->b_rptr == FLUSHW)) {
3075 				tp->t_state &= ~TS_FLUSHWAIT;
3076 				freemsg(mp);
3077 				return;
3078 			}
3079 			/*
3080 			 * This is coming from above, so we only
3081 			 * handle the write queue here.  If FLUSHR is
3082 			 * set, it will get turned around at the
3083 			 * driver, and the read procedure will see it
3084 			 * eventually.
3085 			 */
3086 			if (*mp->b_rptr & FLUSHW) {
3087 				if ((tp->t_state & TS_ISPTSTTY) &&
3088 				    (*mp->b_rptr & FLUSHBAND))
3089 					flushband(q, *(mp->b_rptr + 1),
3090 					    FLUSHDATA);
3091 				else
3092 					flushq(q, FLUSHDATA);
3093 			}
3094 
3095 			putnext(q, mp);
3096 			/*
3097 			 * If a timed read is interrupted, there is
3098 			 * no way to cancel an existing M_READ
3099 			 * request.  We kludge by allowing a flush to
3100 			 * do so.
3101 			 */
3102 			if (tp->t_state & TS_MREAD)
3103 				vmin_satisfied(RD(q), tp, 0);
3104 			break;
3105 
3106 		case M_READ:
3107 			DEBUG1(("ldtermwmsg:M_READ RECEIVED\n"));
3108 			/*
3109 			 * Stream head needs data to satisfy timed
3110 			 * read. Has meaning only if ICANON flag is
3111 			 * off indicating raw mode
3112 			 */
3113 
3114 			DEBUG4((
3115 			    "M_READ: RAW_MODE=%d, CNT=%d, VMIN=%d, VTIME=%d\n",
3116 			    RAW_MODE, *(unsigned int *)mp->b_rptr, V_MIN,
3117 			    V_TIME));
3118 
3119 			tp->t_rd_request = *(unsigned int *)mp->b_rptr;
3120 
3121 			if (RAW_MODE) {
3122 				if (newmsg(tp) != NULL) {
3123 					/*
3124 					 * VMIN/VTIME processing...
3125 					 * The four possible cases are:
3126 					 *	MIN = 0, TIME > 0
3127 					 *	MIN = >, TIME = 0
3128 					 *	MIN > 0, TIME > 0
3129 					 *	MIN = 0, TIME = 0
3130 					 * These four conditions must be dealt
3131 					 * with on the read side as well in
3132 					 * ldterm_do_noncanon(). Set TS_MREAD
3133 					 * so that the read side will know
3134 					 * there is a pending read request
3135 					 * waiting at the stream head.  If we
3136 					 * can satisfy MIN do it here, rather
3137 					 * than on the read side.  If we can't,
3138 					 * start timers if necessary and let
3139 					 * the other side deal with it.
3140 					 *
3141 					 * We got another M_READ before the
3142 					 * pending one completed, cancel any
3143 					 * existing timeout.
3144 					 */
3145 					if (tp->t_state & TS_MREAD) {
3146 						vmin_satisfied(RD(q),
3147 						    tp, 0);
3148 					}
3149 					tp->t_state |= TS_MREAD;
3150 					/*
3151 					 * Case 1:  Any data will
3152 					 * satisfy read, otherwise
3153 					 * start timer
3154 					 */
3155 					if (V_MIN == 0 && V_TIME > 0) {
3156 						if (tp->t_msglen)
3157 							vmin_satisfied(RD(q),
3158 							    tp, 1);
3159 						else
3160 							vmin_settimer(RD(q));
3161 
3162 						/*
3163 						 * Case 2:  If we have enough
3164 						 * data, send up now.
3165 						 * Otherwise, the read side
3166 						 * should wait forever until MIN
3167 						 * is satisified.
3168 						 */
3169 					} else if (V_MIN > 0 && V_TIME == 0) {
3170 						if (tp->t_msglen >= (int)V_MIN)
3171 							vmin_satisfied(RD(q),
3172 							    tp, 1);
3173 
3174 						/*
3175 						 * Case 3:  If we can satisfy
3176 						 * the read, send it up. If we
3177 						 * don't have enough data, but
3178 						 * there is at least one char,
3179 						 * start a timer.  Otherwise,
3180 						 * let the read side start
3181 						 * the timer.
3182 						 */
3183 					} else if (V_MIN > 0 && V_TIME > 0) {
3184 						if (tp->t_msglen >= (int)V_MIN)
3185 							vmin_satisfied(RD(q),
3186 							    tp, 1);
3187 						else if (tp->t_msglen)
3188 							vmin_settimer(RD(q));
3189 						/*
3190 						 * Case 4:  Read returns
3191 						 * whatever data is available
3192 						 * or zero if none.
3193 						 */
3194 					} else { /* V_MIN == 0 && V_TIME == 0 */
3195 						vmin_satisfied(RD(q), tp, 1);
3196 					}
3197 
3198 				} else	/* should do bufcall, really! */
3199 					cmn_err(CE_WARN,
3200 					    "ldtermwmsg: out of blocks");
3201 			}
3202 			/*
3203 			 * pass M_READ down
3204 			 */
3205 			putnext(q, mp);
3206 			break;
3207 
3208 		default:
3209 			/* Pass it through unmolested. */
3210 			putnext(q, mp);
3211 			break;
3212 		}
3213 		return;
3214 	}
3215 	/*
3216 	 * If our queue is nonempty or there's a traffic jam
3217 	 * downstream, this message must get in line.
3218 	 */
3219 	if (q->q_first != NULL || !bcanputnext(q, mp->b_band)) {
3220 		/*
3221 		 * Exception: ioctls, except for those defined to
3222 		 * take effect after output has drained, should be
3223 		 * processed immediately.
3224 		 */
3225 		if (type == M_IOCTL) {
3226 			struct iocblk *iocp;
3227 
3228 			iocp = (struct iocblk *)mp->b_rptr;
3229 			switch (iocp->ioc_cmd) {
3230 
3231 				/*
3232 				 * Queue these.
3233 				 */
3234 			case TCSETSW:
3235 			case TCSETSF:
3236 			case TCSETAW:
3237 			case TCSETAF:
3238 			case TCSBRK:
3239 				break;
3240 
3241 				/*
3242 				 * Handle all others immediately.
3243 				 */
3244 			default:
3245 				(void) ldtermwmsg(q, mp);
3246 				return;
3247 			}
3248 		}
3249 		(void) putq(q, mp);
3250 		return;
3251 	}
3252 	/*
3253 	 * We can take the fast path through, by simply calling
3254 	 * ldtermwmsg to dispose of mp.
3255 	 */
3256 	(void) ldtermwmsg(q, mp);
3257 }
3258 
3259 
3260 /*
3261  * Line discipline output queue service procedure.
3262  */
3263 static void
3264 ldtermwsrv(queue_t *q)
3265 {
3266 	mblk_t *mp;
3267 
3268 	/*
3269 	 * We expect this loop to iterate at most once, but must be
3270 	 * prepared for more in case our upstream neighbor isn't
3271 	 * paying strict attention to what canput tells it.
3272 	 */
3273 	while ((mp = getq(q)) != NULL) {
3274 		/*
3275 		 * N.B.: ldtermwput has already handled high-priority
3276 		 * messages, so we don't have to worry about them
3277 		 * here. Hence, the putbq call is safe.
3278 		 */
3279 		if (!bcanputnext(q, mp->b_band)) {
3280 			(void) putbq(q, mp);
3281 			break;
3282 		}
3283 		if (!ldtermwmsg(q, mp)) {
3284 			/*
3285 			 * Couldn't handle the whole thing; give up
3286 			 * for now and wait to be rescheduled.
3287 			 */
3288 			break;
3289 		}
3290 	}
3291 }
3292 
3293 
3294 /*
3295  * Process the write-side message denoted by mp.  If mp can't be
3296  * processed completely (due to allocation failures), put the
3297  * residual unprocessed part on the front of the write queue, disable
3298  * the queue, and schedule a qbufcall to arrange to complete its
3299  * processing later.
3300  *
3301  * Return 1 if the message was processed completely and 0 if not.
3302  *
3303  * This routine is called from both ldtermwput and ldtermwsrv to do the
3304  * actual work of dealing with mp.  ldtermwput will have already
3305  * dealt with high priority messages.
3306  */
3307 static int
3308 ldtermwmsg(queue_t *q, mblk_t *mp)
3309 {
3310 	ldtermstd_state_t *tp;
3311 	mblk_t *residmp = NULL;
3312 	size_t size;
3313 
3314 	tp = (ldtermstd_state_t *)q->q_ptr;
3315 
3316 	switch (mp->b_datap->db_type) {
3317 
3318 	case M_IOCTL:
3319 		ldterm_do_ioctl(q, mp);
3320 		break;
3321 
3322 	case M_DATA:
3323 		{
3324 			mblk_t *omp = NULL;
3325 
3326 			if ((tp->t_modes.c_lflag & FLUSHO) &&
3327 			    (tp->t_modes.c_lflag & IEXTEN)) {
3328 				freemsg(mp);	/* drop on floor */
3329 				break;
3330 			}
3331 			tp->t_rocount = 0;
3332 			/*
3333 			 * Don't even look at the characters unless
3334 			 * we have something useful to do with them.
3335 			 */
3336 			if (((tp->t_modes.c_oflag & OPOST) ||
3337 			    ((tp->t_modes.c_lflag & XCASE) &&
3338 			    (tp->t_modes.c_lflag & ICANON))) &&
3339 			    (msgdsize(mp) || !(tp->t_state & TS_ISPTSTTY))) {
3340 				unsigned char band = mp->b_band;
3341 				short flag = mp->b_flag;
3342 
3343 				residmp = ldterm_output_msg(q, mp, &omp,
3344 				    tp, OBSIZE, 0);
3345 				if ((mp = omp) == NULL)
3346 					break;
3347 				mp->b_band |= band;
3348 				mp->b_flag |= flag;
3349 			}
3350 			/* Update sysinfo outch */
3351 			(void) drv_setparm(SYSOUTC, msgdsize(mp));
3352 			putnext(q, mp);
3353 			break;
3354 		}
3355 
3356 	default:
3357 		putnext(q, mp);	/* pass it through unmolested */
3358 		break;
3359 	}
3360 
3361 	if (residmp == NULL)
3362 		return (1);
3363 
3364 	/*
3365 	 * An allocation failure occurred that prevented the message
3366 	 * from being completely processed.  First, disable our
3367 	 * queue, since it's pointless to attempt further processing
3368 	 * until the allocation situation is resolved.  (This must
3369 	 * precede the putbq call below, which would otherwise mark
3370 	 * the queue to be serviced.)
3371 	 */
3372 	noenable(q);
3373 	/*
3374 	 * Stuff the remnant on our write queue so that we can
3375 	 * complete it later when times become less lean.  Note that
3376 	 * this sets QFULL, so that our upstream neighbor will be
3377 	 * blocked by flow control.
3378 	 */
3379 	(void) putbq(q, residmp);
3380 	/*
3381 	 * Schedule a qbufcall to re-enable the queue.  The failure
3382 	 * won't have been for an allocation of more than OBSIZE
3383 	 * bytes, so don't ask for more than that from bufcall.
3384 	 */
3385 	size = msgdsize(residmp);
3386 	if (size > OBSIZE)
3387 		size = OBSIZE;
3388 	if (tp->t_wbufcid)
3389 		qunbufcall(q, tp->t_wbufcid);
3390 	tp->t_wbufcid = qbufcall(q, size, BPRI_MED, ldterm_wenable, q);
3391 
3392 	return (0);
3393 }
3394 
3395 
3396 /*
3397  * Perform output processing on a message, accumulating the output
3398  * characters in a new message.
3399  */
3400 static mblk_t *
3401 ldterm_output_msg(queue_t *q, mblk_t *imp, mblk_t **omp,
3402     ldtermstd_state_t *tp, size_t bsize, int echoing)
3403 {
3404 	mblk_t *ibp;		/* block we're examining from input message */
3405 	mblk_t *obp;		/* block we're filling in output message */
3406 	mblk_t *cbp;		/* continuation block */
3407 	mblk_t *oobp;		/* old value of obp; valid if NEW_BLOCK fails */
3408 	mblk_t **contpp;	/* where to stuff ptr to newly-allocated blk */
3409 	unsigned char c, n;
3410 	int count, ctype;
3411 	ssize_t bytes_left;
3412 
3413 	mblk_t *bp;		/* block to stuff an M_DELAY message in */
3414 
3415 
3416 	/*
3417 	 * Allocate a new block into which to put bytes. If we can't,
3418 	 * we just drop the rest of the message on the floor. If x is
3419 	 * non-zero, just fall thru; failure requires cleanup before
3420 	 * going out
3421 	 */
3422 
3423 #define	NEW_BLOCK(x) \
3424 	{ \
3425 		oobp = obp; \
3426 		if ((obp = allocb(bsize, BPRI_MED)) == NULL) { \
3427 			if (x == 0) \
3428 				goto outofbufs; \
3429 		} else { \
3430 			*contpp = obp; \
3431 			contpp = &obp->b_cont; \
3432 			bytes_left = obp->b_datap->db_lim - obp->b_wptr; \
3433 		} \
3434 	}
3435 
3436 	ibp = imp;
3437 
3438 	/*
3439 	 * When we allocate the first block of a message, we should
3440 	 * stuff the pointer to it in "*omp".  All subsequent blocks
3441 	 * should have the pointer to them stuffed into the "b_cont"
3442 	 * field of the previous block.  "contpp" points to the place
3443 	 * where we should stuff the pointer.
3444 	 *
3445 	 * If we already have a message we're filling in, continue doing
3446 	 * so.
3447 	 */
3448 	if ((obp = *omp) != NULL) {
3449 		while (obp->b_cont != NULL)
3450 			obp = obp->b_cont;
3451 		contpp = &obp->b_cont;
3452 		bytes_left = obp->b_datap->db_lim - obp->b_wptr;
3453 	} else {
3454 		contpp = omp;
3455 		bytes_left = 0;
3456 	}
3457 
3458 	do {
3459 		while (ibp->b_rptr < ibp->b_wptr) {
3460 			/*
3461 			 * Make sure there's room for one more
3462 			 * character.  At most, we'll need "t_maxeuc"
3463 			 * bytes.
3464 			 */
3465 			if ((bytes_left < (int)tp->t_maxeuc)) {
3466 				/* LINTED */
3467 				NEW_BLOCK(0);
3468 			}
3469 			/*
3470 			 * If doing XCASE processing (not very
3471 			 * likely, in this day and age), look at each
3472 			 * character individually.
3473 			 */
3474 			if ((tp->t_modes.c_lflag & XCASE) &&
3475 			    (tp->t_modes.c_lflag & ICANON)) {
3476 				c = *ibp->b_rptr++;
3477 
3478 				/*
3479 				 * We need to make sure that this is not
3480 				 * a following byte of a multibyte character
3481 				 * before applying an XCASE processing.
3482 				 *
3483 				 * tp->t_eucign will be 0 if and only
3484 				 * if the current 'c' is an ASCII character
3485 				 * and also a byte. Otherwise, it will have
3486 				 * the byte length of a multibyte character.
3487 				 */
3488 				if ((tp->t_state & TS_MEUC) &&
3489 				    tp->t_eucign == 0 && NOTASCII(c)) {
3490 					tp->t_eucign =
3491 					    tp->t_csmethods.ldterm_memwidth(
3492 					    c, (void *)tp);
3493 					tp->t_scratch_len = tp->t_eucign;
3494 
3495 					if (tp->t_csdata.codeset_type !=
3496 					    LDTERM_CS_TYPE_UTF8) {
3497 						tp->t_col +=
3498 						    tp->
3499 						    t_csmethods.
3500 						    ldterm_dispwidth(c,
3501 						    (void *)tp,
3502 						    tp->t_modes.c_lflag &
3503 						    ECHOCTL);
3504 					}
3505 				}
3506 
3507 				/*
3508 				 * If character is mapped on output,
3509 				 * put out a backslash followed by
3510 				 * what it is mapped to.
3511 				 */
3512 				if (tp->t_eucign == 0 && omaptab[c] != 0 &&
3513 				    (!echoing || c != '\\')) {
3514 					/* backslash is an ordinary character */
3515 					tp->t_col++;
3516 					*obp->b_wptr++ = '\\';
3517 					bytes_left--;
3518 					if (bytes_left == 0) {
3519 						/* LINTED */
3520 						NEW_BLOCK(1);
3521 					}
3522 					/*
3523 					 * Allocation failed, make
3524 					 * state consistent before
3525 					 * returning
3526 					 */
3527 					if (obp == NULL) {
3528 						ibp->b_rptr--;
3529 						tp->t_col--;
3530 						oobp->b_wptr--;
3531 						goto outofbufs;
3532 					}
3533 					c = omaptab[c];
3534 				}
3535 				/*
3536 				 * If no other output processing is
3537 				 * required, push the character into
3538 				 * the block and get another.
3539 				 */
3540 				if (!(tp->t_modes.c_oflag & OPOST)) {
3541 					if (tp->t_eucign > 0) {
3542 						--tp->t_eucign;
3543 					} else {
3544 						tp->t_col++;
3545 					}
3546 					*obp->b_wptr++ = c;
3547 					bytes_left--;
3548 					continue;
3549 				}
3550 				/*
3551 				 * OPOST output flag is set. Map
3552 				 * lower case to upper case if OLCUC
3553 				 * flag is set and the 'c' is a lowercase
3554 				 * ASCII character.
3555 				 */
3556 				if (tp->t_eucign == 0 &&
3557 				    (tp->t_modes.c_oflag & OLCUC) &&
3558 				    c >= 'a' && c <= 'z')
3559 					c -= 'a' - 'A';
3560 			} else {
3561 				/*
3562 				 * Copy all the ORDINARY characters,
3563 				 * possibly mapping upper case to
3564 				 * lower case.  We use "movtuc",
3565 				 * STOPPING when we can't move some
3566 				 * character. For multi-byte or
3567 				 * multi-column EUC, we can't depend
3568 				 * on the regular tables. Rather than
3569 				 * just drop through to the "big
3570 				 * switch" for all characters, it
3571 				 * _might_ be faster to let "movtuc"
3572 				 * move a bunch of characters.
3573 				 * Chances are, even in multi-byte
3574 				 * mode we'll have lots of ASCII
3575 				 * going through. We check the flag
3576 				 * once, and call movtuc with the
3577 				 * appropriate table as an argument.
3578 				 *
3579 				 * "movtuc will work for all codeset
3580 				 * types since it stops at the beginning
3581 				 * byte of a multibyte character.
3582 				 */
3583 				size_t bytes_to_move;
3584 				size_t bytes_moved;
3585 
3586 				ASSERT(ibp->b_wptr >= ibp->b_rptr);
3587 				bytes_to_move = ibp->b_wptr - ibp->b_rptr;
3588 				if (bytes_to_move > bytes_left)
3589 					bytes_to_move = bytes_left;
3590 				if (tp->t_state & TS_MEUC) {
3591 					bytes_moved = movtuc(bytes_to_move,
3592 					    ibp->b_rptr, obp->b_wptr,
3593 					    (tp->t_modes.c_oflag & OLCUC ?
3594 					    elcuctab : enotrantab));
3595 				} else {
3596 					bytes_moved = movtuc(bytes_to_move,
3597 					    ibp->b_rptr, obp->b_wptr,
3598 					    (tp->t_modes.c_oflag & OLCUC ?
3599 					    lcuctab : notrantab));
3600 				}
3601 				/*
3602 				 * We're save to just do this column
3603 				 * calculation, because if TS_MEUC is
3604 				 * set, we used the proper EUC
3605 				 * tables, and won't have copied any
3606 				 * EUC bytes.
3607 				 */
3608 				tp->t_col += bytes_moved;
3609 				ibp->b_rptr += bytes_moved;
3610 				obp->b_wptr += bytes_moved;
3611 				bytes_left -= bytes_moved;
3612 				if (ibp->b_rptr >= ibp->b_wptr)
3613 					continue;	/* moved all of block */
3614 				if (bytes_left == 0) {
3615 					/* LINTED */
3616 					NEW_BLOCK(0);
3617 				}
3618 				c = *ibp->b_rptr++;	/* stopper */
3619 			}
3620 
3621 			/*
3622 			 * Again, we need to make sure that this is not
3623 			 * a following byte of a multibyte character at
3624 			 * here.
3625 			 *
3626 			 * 'tp->t_eucign' will be 0 iff the current 'c' is
3627 			 * an ASCII character. Otherwise, it will have
3628 			 * the byte length of a multibyte character.
3629 			 * We also add the display width to 'tp->t_col' if
3630 			 * the current codeset is not UTF-8 since this is
3631 			 * a leading byte of a multibyte character.
3632 			 * For UTF-8 codeset type, we add the display width
3633 			 * when we get the last byte of a character.
3634 			 */
3635 			if ((tp->t_state & TS_MEUC) && tp->t_eucign == 0 &&
3636 			    NOTASCII(c)) {
3637 				tp->t_eucign = tp->t_csmethods.ldterm_memwidth(
3638 				    c, (void *)tp);
3639 				tp->t_scratch_len = tp->t_eucign;
3640 
3641 				if (tp->t_csdata.codeset_type !=
3642 				    LDTERM_CS_TYPE_UTF8) {
3643 					tp->t_col +=
3644 					    tp->t_csmethods.ldterm_dispwidth(c,
3645 					    (void *)tp,
3646 					    tp->t_modes.c_lflag & ECHOCTL);
3647 				}
3648 			}
3649 
3650 			/*
3651 			 * If the driver has requested, don't process
3652 			 * output flags.  However, if we're in
3653 			 * multi-byte mode, we HAVE to look at
3654 			 * EVERYTHING going out to maintain column
3655 			 * position properly. Therefore IF the driver
3656 			 * says don't AND we're not doing multi-byte,
3657 			 * then don't do it.  Otherwise, do it.
3658 			 *
3659 			 * NOTE:  Hardware USUALLY doesn't expand tabs
3660 			 * properly for multi-byte situations anyway;
3661 			 * that's a known problem with the 3B2
3662 			 * "PORTS" board firmware, and any other
3663 			 * hardware that doesn't ACTUALLY know about
3664 			 * the current EUC mapping that WE are using
3665 			 * at this very moment.  The problem is that
3666 			 * memory width is INDEPENDENT of screen
3667 			 * width - no relation - so WE know how wide
3668 			 * the characters are, but an off-the-host
3669 			 * board probably doesn't.  So, until we're
3670 			 * SURE that the hardware below us can
3671 			 * correctly expand tabs in a
3672 			 * multi-byte/multi-column EUC situation, we
3673 			 * do it ourselves.
3674 			 */
3675 			/*
3676 			 * Map <CR>to<NL> on output if OCRNL flag
3677 			 * set. ONLCR processing is not done if OCRNL
3678 			 * is set.
3679 			 */
3680 			if (c == '\r' && (tp->t_modes.c_oflag & OCRNL)) {
3681 				c = '\n';
3682 				ctype = typetab[c];
3683 				goto jocrnl;
3684 			}
3685 
3686 			if (tp->t_csdata.codeset_type == LDTERM_CS_TYPE_EUC) {
3687 				ctype = typetab[c];
3688 			} else {
3689 				/*
3690 				 * In other codeset types, we safely assume
3691 				 * any byte of a multibyte character will have
3692 				 * 'ORDINARY' type. For ASCII characters, we
3693 				 * still use the typetab[].
3694 				 */
3695 				if (tp->t_eucign == 0)
3696 					ctype = typetab[c];
3697 				else
3698 					ctype = ORDINARY;
3699 			}
3700 
3701 			/*
3702 			 * Map <NL> to <CR><NL> on output if ONLCR
3703 			 * flag is set.
3704 			 */
3705 			if (c == '\n' && (tp->t_modes.c_oflag & ONLCR)) {
3706 				if (!(tp->t_state & TS_TTCR)) {
3707 					tp->t_state |= TS_TTCR;
3708 					c = '\r';
3709 					ctype = typetab['\r'];
3710 					--ibp->b_rptr;
3711 				} else
3712 					tp->t_state &= ~TS_TTCR;
3713 			}
3714 			/*
3715 			 * Delay values and column position
3716 			 * calculated here.  For EUC chars in
3717 			 * multi-byte mode, we use "t_eucign" to help
3718 			 * calculate columns.  When we see the first
3719 			 * byte of an EUC, we set t_eucign to the
3720 			 * number of bytes that will FOLLOW it, and
3721 			 * we add the screen width of the WHOLE EUC
3722 			 * character to the column position.  In
3723 			 * particular, we can't count SS2 or SS3 as
3724 			 * printing characters.  Remember, folks, the
3725 			 * screen width and memory width are
3726 			 * independent - no relation. We could have
3727 			 * dropped through for ASCII, but we want to
3728 			 * catch any bad characters (i.e., t_eucign
3729 			 * set and an ASCII char received) and
3730 			 * possibly report the garbage situation.
3731 			 */
3732 	jocrnl:
3733 
3734 			count = 0;
3735 			switch (ctype) {
3736 
3737 			case T_SS2:
3738 			case T_SS3:
3739 			case ORDINARY:
3740 				if (tp->t_state & TS_MEUC) {
3741 					if (tp->t_eucign) {
3742 						*obp->b_wptr++ = c;
3743 						bytes_left--;
3744 
3745 						tp->t_scratch[tp->t_scratch_len
3746 						    - tp->t_eucign] = c;
3747 
3748 						--tp->t_eucign;
3749 
3750 						if (tp->t_csdata.codeset_type
3751 						    == LDTERM_CS_TYPE_UTF8 &&
3752 						    tp->t_eucign <= 0) {
3753 							tp->t_col +=
3754 							    ldterm_utf8_width(
3755 							    tp->t_scratch,
3756 							    tp->t_scratch_len);
3757 						}
3758 					} else {
3759 						if (tp->t_modes.c_oflag & OLCUC)
3760 							n = elcuctab[c];
3761 						else
3762 							n = enotrantab[c];
3763 						if (n)
3764 							c = n;
3765 						tp->t_col++;
3766 						*obp->b_wptr++ = c;
3767 						bytes_left--;
3768 					}
3769 				} else {	/* ho hum, ASCII mode... */
3770 					if (tp->t_modes.c_oflag & OLCUC)
3771 						n = lcuctab[c];
3772 					else
3773 						n = notrantab[c];
3774 					if (n)
3775 						c = n;
3776 					tp->t_col++;
3777 					*obp->b_wptr++ = c;
3778 					bytes_left--;
3779 				}
3780 				break;
3781 
3782 				/*
3783 				 * If we're doing ECHOCTL, we've
3784 				 * already mapped the thing during
3785 				 * the process of canonising.  Don't
3786 				 * bother here, as it's not one that
3787 				 * we did.
3788 				 */
3789 			case CONTROL:
3790 				*obp->b_wptr++ = c;
3791 				bytes_left--;
3792 				break;
3793 
3794 				/*
3795 				 * This is probably a backspace
3796 				 * received, not one that we're
3797 				 * echoing.  Let it go as a
3798 				 * single-column backspace.
3799 				 */
3800 			case BACKSPACE:
3801 				if (tp->t_col)
3802 					tp->t_col--;
3803 				if (tp->t_modes.c_oflag & BSDLY) {
3804 					if (tp->t_modes.c_oflag & OFILL)
3805 						count = 1;
3806 				}
3807 				*obp->b_wptr++ = c;
3808 				bytes_left--;
3809 				break;
3810 
3811 			case NEWLINE:
3812 				if (tp->t_modes.c_oflag & ONLRET)
3813 					goto cr;
3814 				if ((tp->t_modes.c_oflag & NLDLY) == NL1)
3815 					count = 2;
3816 				*obp->b_wptr++ = c;
3817 				bytes_left--;
3818 				break;
3819 
3820 			case TAB:
3821 				/*
3822 				 * Map '\t' to spaces if XTABS flag
3823 				 * is set.  The calculation of
3824 				 * "t_eucign" has probably insured
3825 				 * that column will be correct, as we
3826 				 * bumped t_col by the DISP width,
3827 				 * not the memory width.
3828 				 */
3829 				if ((tp->t_modes.c_oflag & TABDLY) == XTABS) {
3830 					for (;;) {
3831 						*obp->b_wptr++ = ' ';
3832 						bytes_left--;
3833 						tp->t_col++;
3834 						if ((tp->t_col & 07) == 0)
3835 							break;	/* every 8th */
3836 						/*
3837 						 * If we don't have
3838 						 * room to fully
3839 						 * expand this tab in
3840 						 * this block, back
3841 						 * up to continue
3842 						 * expanding it into
3843 						 * the next block.
3844 						 */
3845 						if (obp->b_wptr >=
3846 						    obp->b_datap->db_lim) {
3847 							ibp->b_rptr--;
3848 							break;
3849 						}
3850 					}
3851 				} else {
3852 					tp->t_col |= 07;
3853 					tp->t_col++;
3854 					if (tp->t_modes.c_oflag & OFILL) {
3855 						if (tp->t_modes.c_oflag &
3856 						    TABDLY)
3857 							count = 2;
3858 					} else {
3859 						switch (tp->t_modes.c_oflag &
3860 						    TABDLY) {
3861 						case TAB2:
3862 							count = 6;
3863 							break;
3864 
3865 						case TAB1:
3866 							count = 1 + (tp->t_col |
3867 							    ~07);
3868 							if (count < 5)
3869 								count = 0;
3870 							break;
3871 						}
3872 					}
3873 					*obp->b_wptr++ = c;
3874 					bytes_left--;
3875 				}
3876 				break;
3877 
3878 			case VTAB:
3879 				if ((tp->t_modes.c_oflag & VTDLY) &&
3880 				    !(tp->t_modes.c_oflag & OFILL))
3881 					count = 127;
3882 				*obp->b_wptr++ = c;
3883 				bytes_left--;
3884 				break;
3885 
3886 			case RETURN:
3887 				/*
3888 				 * Ignore <CR> in column 0 if ONOCR
3889 				 * flag set.
3890 				 */
3891 				if (tp->t_col == 0 &&
3892 				    (tp->t_modes.c_oflag & ONOCR))
3893 					break;
3894 
3895 		cr:
3896 				switch (tp->t_modes.c_oflag & CRDLY) {
3897 
3898 				case CR1:
3899 					if (tp->t_modes.c_oflag & OFILL)
3900 						count = 2;
3901 					else
3902 						count = tp->t_col % 2;
3903 					break;
3904 
3905 				case CR2:
3906 					if (tp->t_modes.c_oflag & OFILL)
3907 						count = 4;
3908 					else
3909 						count = 6;
3910 					break;
3911 
3912 				case CR3:
3913 					if (tp->t_modes.c_oflag & OFILL)
3914 						count = 0;
3915 					else
3916 						count = 9;
3917 					break;
3918 				}
3919 				tp->t_col = 0;
3920 				*obp->b_wptr++ = c;
3921 				bytes_left--;
3922 				break;
3923 			}
3924 
3925 			if (count != 0) {
3926 				if (tp->t_modes.c_oflag & OFILL) {
3927 					do {
3928 						if (bytes_left == 0) {
3929 							/* LINTED */
3930 							NEW_BLOCK(0);
3931 						}
3932 						if (tp->t_modes.c_oflag & OFDEL)
3933 							*obp->b_wptr++ = CDEL;
3934 						else
3935 							*obp->b_wptr++ = CNUL;
3936 						bytes_left--;
3937 					} while (--count != 0);
3938 				} else {
3939 					if ((tp->t_modes.c_lflag & FLUSHO) &&
3940 					    (tp->t_modes.c_lflag & IEXTEN)) {
3941 						/* drop on floor */
3942 						freemsg(*omp);
3943 					} else {
3944 						/*
3945 						 * Update sysinfo
3946 						 * outch
3947 						 */
3948 						(void) drv_setparm(SYSOUTC,
3949 						    msgdsize(*omp));
3950 						putnext(q, *omp);
3951 						/*
3952 						 * Send M_DELAY
3953 						 * downstream
3954 						 */
3955 						if ((bp =
3956 						    allocb(1, BPRI_MED)) !=
3957 						    NULL) {
3958 							bp->b_datap->db_type =
3959 							    M_DELAY;
3960 							*bp->b_wptr++ =
3961 							    (uchar_t)count;
3962 							putnext(q, bp);
3963 						}
3964 					}
3965 					bytes_left = 0;
3966 					/*
3967 					 * We have to start a new
3968 					 * message; the delay
3969 					 * introduces a break between
3970 					 * messages.
3971 					 */
3972 					*omp = NULL;
3973 					contpp = omp;
3974 				}
3975 			}
3976 		}
3977 		cbp = ibp->b_cont;
3978 		freeb(ibp);
3979 	} while ((ibp = cbp) != NULL);	/* next block, if any */
3980 
3981 outofbufs:
3982 	return (ibp);
3983 #undef NEW_BLOCK
3984 }
3985 
3986 
3987 #if !defined(__sparc)
3988 int
3989 movtuc(size_t size, unsigned char *from, unsigned char *origto,
3990     unsigned char *table)
3991 {
3992 	unsigned char *to = origto;
3993 	unsigned char c;
3994 
3995 	while (size != 0 && (c = table[*from++]) != 0) {
3996 		*to++ = c;
3997 		size--;
3998 	}
3999 	return (to - origto);
4000 }
4001 #endif
4002 
4003 static void
4004 ldterm_flush_output(uchar_t c, queue_t *q, ldtermstd_state_t *tp)
4005 {
4006 	/* Already conditioned with IEXTEN during VDISCARD processing */
4007 	if (tp->t_modes.c_lflag & FLUSHO)
4008 		tp->t_modes.c_lflag &= ~FLUSHO;
4009 	else {
4010 		flushq(q, FLUSHDATA);	/* flush our write queue */
4011 		/* flush ones below us */
4012 		(void) putnextctl1(q, M_FLUSH, FLUSHW);
4013 		if ((tp->t_echomp = allocb(EBSIZE, BPRI_HI)) != NULL) {
4014 			(void) ldterm_echo(c, q, 1, tp);
4015 			if (tp->t_msglen != 0)
4016 				ldterm_reprint(q, EBSIZE, tp);
4017 			if (tp->t_echomp != NULL) {
4018 				putnext(q, tp->t_echomp);
4019 				tp->t_echomp = NULL;
4020 			}
4021 		}
4022 		tp->t_modes.c_lflag |= FLUSHO;
4023 	}
4024 }
4025 
4026 
4027 /*
4028  * Signal generated by the reader: M_PCSIG and M_FLUSH messages sent.
4029  */
4030 static void
4031 ldterm_dosig(queue_t *q, int sig, uchar_t c, int mtype, int mode)
4032 {
4033 	ldtermstd_state_t *tp = (ldtermstd_state_t *)q->q_ptr;
4034 	int sndsig = 0;
4035 
4036 	/*
4037 	 * c == \0 is brk case; need to flush on BRKINT even if
4038 	 * noflsh is set.
4039 	 */
4040 	if ((!(tp->t_modes.c_lflag & NOFLSH)) || (c == '\0')) {
4041 		if (mode) {
4042 			if (tp->t_state & TS_TTSTOP) {
4043 				sndsig = 1;
4044 				(void) putnextctl1(q, mtype, sig);
4045 			}
4046 			/*
4047 			 * Flush read or write side.
4048 			 * Restart the input or output.
4049 			 */
4050 			if (mode & FLUSHR) {
4051 				flushq(q, FLUSHDATA);
4052 				(void) putnextctl1(WR(q), M_FLUSH, mode);
4053 				if (tp->t_state & (TS_TBLOCK|TS_IFBLOCK)) {
4054 					(void) putnextctl(WR(q), M_STARTI);
4055 					tp->t_state &= ~(TS_TBLOCK|TS_IFBLOCK);
4056 				}
4057 			}
4058 			if (mode & FLUSHW) {
4059 				flushq(WR(q), FLUSHDATA);
4060 				/*
4061 				 * XXX This is extremely gross.
4062 				 * Since we can't be sure our M_FLUSH
4063 				 * will have run its course by the
4064 				 * time we do the echo below, we set
4065 				 * state and toss it in the write put
4066 				 * routine to prevent flushing our
4067 				 * own data.  Note that downstream
4068 				 * modules on the write side will be
4069 				 * flushed by the M_FLUSH sent above.
4070 				 */
4071 				tp->t_state |= TS_FLUSHWAIT;
4072 				(void) putnextctl1(q, M_FLUSH, FLUSHW);
4073 				if (tp->t_state & TS_TTSTOP) {
4074 					(void) putnextctl(WR(q), M_START);
4075 					tp->t_state &= ~(TS_TTSTOP|TS_OFBLOCK);
4076 				}
4077 			}
4078 		}
4079 	}
4080 	tp->t_state &= ~TS_QUOT;
4081 	if (sndsig == 0)
4082 		(void) putnextctl1(q, mtype, sig);
4083 
4084 	if (c != '\0') {
4085 		if ((tp->t_echomp = allocb(4, BPRI_HI)) != NULL) {
4086 			if (ldterm_echo(c, WR(q), 4, tp) > 0)
4087 				putnext(WR(q), tp->t_echomp);
4088 			else
4089 				freemsg(tp->t_echomp);
4090 			tp->t_echomp = NULL;
4091 		}
4092 	}
4093 }
4094 
4095 
4096 /*
4097  * Called when an M_IOCTL message is seen on the write queue; does
4098  * whatever we're supposed to do with it, and either replies
4099  * immediately or passes it to the next module down.
4100  */
4101 static void
4102 ldterm_do_ioctl(queue_t *q, mblk_t *mp)
4103 {
4104 	ldtermstd_state_t *tp;
4105 	struct iocblk *iocp;
4106 	struct eucioc *euciocp;	/* needed for EUC ioctls */
4107 	ldterm_cs_data_user_t *csdp;
4108 	int i;
4109 	int locale_name_sz;
4110 	uchar_t maxbytelen;
4111 	uchar_t maxscreenlen;
4112 	int error;
4113 
4114 	iocp = (struct iocblk *)mp->b_rptr;
4115 	tp = (ldtermstd_state_t *)q->q_ptr;
4116 
4117 	switch (iocp->ioc_cmd) {
4118 
4119 	case TCSETS:
4120 	case TCSETSW:
4121 	case TCSETSF:
4122 		{
4123 			/*
4124 			 * Set current parameters and special
4125 			 * characters.
4126 			 */
4127 			struct termios *cb;
4128 			struct termios oldmodes;
4129 
4130 			error = miocpullup(mp, sizeof (struct termios));
4131 			if (error != 0) {
4132 				miocnak(q, mp, 0, error);
4133 				return;
4134 			}
4135 
4136 			cb = (struct termios *)mp->b_cont->b_rptr;
4137 
4138 			oldmodes = tp->t_amodes;
4139 			tp->t_amodes = *cb;
4140 			if ((tp->t_amodes.c_lflag & PENDIN) &&
4141 			    (tp->t_modes.c_lflag & IEXTEN)) {
4142 				/*
4143 				 * Yuk.  The C shell file completion
4144 				 * code actually uses this "feature",
4145 				 * so we have to support it.
4146 				 */
4147 				if (tp->t_message != NULL) {
4148 					tp->t_state |= TS_RESCAN;
4149 					qenable(RD(q));
4150 				}
4151 				tp->t_amodes.c_lflag &= ~PENDIN;
4152 			}
4153 			bcopy(tp->t_amodes.c_cc, tp->t_modes.c_cc, NCCS);
4154 
4155 			/*
4156 			 * ldterm_adjust_modes does not deal with
4157 			 * cflags
4158 			 */
4159 			tp->t_modes.c_cflag = tp->t_amodes.c_cflag;
4160 
4161 			ldterm_adjust_modes(tp);
4162 			if (chgstropts(&oldmodes, tp, RD(q)) == (-1)) {
4163 				miocnak(q, mp, 0, EAGAIN);
4164 				return;
4165 			}
4166 			/*
4167 			 * The driver may want to know about the
4168 			 * following iflags: IGNBRK, BRKINT, IGNPAR,
4169 			 * PARMRK, INPCK, IXON, IXANY.
4170 			 */
4171 			break;
4172 		}
4173 
4174 	case TCSETA:
4175 	case TCSETAW:
4176 	case TCSETAF:
4177 		{
4178 			/*
4179 			 * Old-style "ioctl" to set current
4180 			 * parameters and special characters. Don't
4181 			 * clear out the unset portions, leave them
4182 			 * as they are.
4183 			 */
4184 			struct termio *cb;
4185 			struct termios oldmodes;
4186 
4187 			error = miocpullup(mp, sizeof (struct termio));
4188 			if (error != 0) {
4189 				miocnak(q, mp, 0, error);
4190 				return;
4191 			}
4192 
4193 			cb = (struct termio *)mp->b_cont->b_rptr;
4194 
4195 			oldmodes = tp->t_amodes;
4196 			tp->t_amodes.c_iflag =
4197 			    (tp->t_amodes.c_iflag & 0xffff0000 | cb->c_iflag);
4198 			tp->t_amodes.c_oflag =
4199 			    (tp->t_amodes.c_oflag & 0xffff0000 | cb->c_oflag);
4200 			tp->t_amodes.c_cflag =
4201 			    (tp->t_amodes.c_cflag & 0xffff0000 | cb->c_cflag);
4202 			tp->t_amodes.c_lflag =
4203 			    (tp->t_amodes.c_lflag & 0xffff0000 | cb->c_lflag);
4204 
4205 			bcopy(cb->c_cc, tp->t_modes.c_cc, NCC);
4206 			/* TCGETS returns amodes, so update that too */
4207 			bcopy(cb->c_cc, tp->t_amodes.c_cc, NCC);
4208 
4209 			/* ldterm_adjust_modes does not deal with cflags */
4210 
4211 			tp->t_modes.c_cflag = tp->t_amodes.c_cflag;
4212 
4213 			ldterm_adjust_modes(tp);
4214 			if (chgstropts(&oldmodes, tp, RD(q)) == (-1)) {
4215 				miocnak(q, mp, 0, EAGAIN);
4216 				return;
4217 			}
4218 			/*
4219 			 * The driver may want to know about the
4220 			 * following iflags: IGNBRK, BRKINT, IGNPAR,
4221 			 * PARMRK, INPCK, IXON, IXANY.
4222 			 */
4223 			break;
4224 		}
4225 
4226 	case TCFLSH:
4227 		/*
4228 		 * Do the flush on the write queue immediately, and
4229 		 * queue up any flush on the read queue for the
4230 		 * service procedure to see.  Then turn it into the
4231 		 * appropriate M_FLUSH message, so that the module
4232 		 * below us doesn't have to know about TCFLSH.
4233 		 */
4234 		error = miocpullup(mp, sizeof (int));
4235 		if (error != 0) {
4236 			miocnak(q, mp, 0, error);
4237 			return;
4238 		}
4239 
4240 		ASSERT(mp->b_datap != NULL);
4241 		if (*(int *)mp->b_cont->b_rptr == 0) {
4242 			ASSERT(mp->b_datap != NULL);
4243 			(void) putnextctl1(q, M_FLUSH, FLUSHR);
4244 			(void) putctl1(RD(q), M_FLUSH, FLUSHR);
4245 		} else if (*(int *)mp->b_cont->b_rptr == 1) {
4246 			flushq(q, FLUSHDATA);
4247 			ASSERT(mp->b_datap != NULL);
4248 			tp->t_state |= TS_FLUSHWAIT;
4249 			(void) putnextctl1(RD(q), M_FLUSH, FLUSHW);
4250 			(void) putnextctl1(q, M_FLUSH, FLUSHW);
4251 		} else if (*(int *)mp->b_cont->b_rptr == 2) {
4252 			flushq(q, FLUSHDATA);
4253 			ASSERT(mp->b_datap != NULL);
4254 			(void) putnextctl1(q, M_FLUSH, FLUSHRW);
4255 			tp->t_state |= TS_FLUSHWAIT;
4256 			(void) putnextctl1(RD(q), M_FLUSH, FLUSHRW);
4257 		} else {
4258 			miocnak(q, mp, 0, EINVAL);
4259 			return;
4260 		}
4261 		ASSERT(mp->b_datap != NULL);
4262 		iocp->ioc_rval = 0;
4263 		miocack(q, mp, 0, 0);
4264 		return;
4265 
4266 	case TCXONC:
4267 		error = miocpullup(mp, sizeof (int));
4268 		if (error != 0) {
4269 			miocnak(q, mp, 0, error);
4270 			return;
4271 		}
4272 
4273 		switch (*(int *)mp->b_cont->b_rptr) {
4274 		case 0:
4275 			if (!(tp->t_state & TS_TTSTOP)) {
4276 				(void) putnextctl(q, M_STOP);
4277 				tp->t_state |= (TS_TTSTOP|TS_OFBLOCK);
4278 			}
4279 			break;
4280 
4281 		case 1:
4282 			if (tp->t_state & TS_TTSTOP) {
4283 				(void) putnextctl(q, M_START);
4284 				tp->t_state &= ~(TS_TTSTOP|TS_OFBLOCK);
4285 			}
4286 			break;
4287 
4288 		case 2:
4289 			(void) putnextctl(q, M_STOPI);
4290 			tp->t_state |= (TS_TBLOCK|TS_IFBLOCK);
4291 			break;
4292 
4293 		case 3:
4294 			(void) putnextctl(q, M_STARTI);
4295 			tp->t_state &= ~(TS_TBLOCK|TS_IFBLOCK);
4296 			break;
4297 
4298 		default:
4299 			miocnak(q, mp, 0, EINVAL);
4300 			return;
4301 		}
4302 		ASSERT(mp->b_datap != NULL);
4303 		iocp->ioc_rval = 0;
4304 		miocack(q, mp, 0, 0);
4305 		return;
4306 		/*
4307 		 * TCSBRK is expected to be handled by the driver.
4308 		 * The reason its left for the driver is that when
4309 		 * the argument to TCSBRK is zero driver has to drain
4310 		 * the data and sending a M_IOCACK from LDTERM before
4311 		 * the driver drains the data is going to cause
4312 		 * problems.
4313 		 */
4314 
4315 		/*
4316 		 * The following are EUC related ioctls.  For
4317 		 * EUC_WSET, we have to pass the information on, even
4318 		 * though we ACK the call.  It's vital in the EUC
4319 		 * environment that everybody downstream knows about
4320 		 * the EUC codeset widths currently in use; we
4321 		 * therefore pass down the information in an M_CTL
4322 		 * message.  It will bottom out in the driver.
4323 		 */
4324 	case EUC_WSET:
4325 		{
4326 
4327 			/* only needed for EUC_WSET */
4328 			struct iocblk *riocp;
4329 
4330 			mblk_t *dmp, *dmp_cont;
4331 
4332 			/*
4333 			 * If the user didn't supply any information,
4334 			 * NAK it.
4335 			 */
4336 			error = miocpullup(mp, sizeof (struct eucioc));
4337 			if (error != 0) {
4338 				miocnak(q, mp, 0, error);
4339 				return;
4340 			}
4341 
4342 			euciocp = (struct eucioc *)mp->b_cont->b_rptr;
4343 			/*
4344 			 * Check here for something reasonable.  If
4345 			 * anything will take more than EUC_MAXW
4346 			 * columns or more than EUC_MAXW bytes
4347 			 * following SS2 or SS3, then just reject it
4348 			 * out of hand. It's not impossible for us to
4349 			 * do it, it just isn't reasonable.  So far,
4350 			 * in the world, we've seen the absolute max
4351 			 * columns to be 2 and the max number of
4352 			 * bytes to be 3.  This allows room for some
4353 			 * expansion of that, but it probably won't
4354 			 * even be necessary. At the moment, we
4355 			 * return a "range" error.  If you really
4356 			 * need to, you can push EUC_MAXW up to over
4357 			 * 200; it doesn't make sense, though, with
4358 			 * only a CANBSIZ sized input limit (usually
4359 			 * 256)!
4360 			 */
4361 			for (i = 0; i < 4; i++) {
4362 				if ((euciocp->eucw[i] > EUC_MAXW) ||
4363 				    (euciocp->scrw[i] > EUC_MAXW)) {
4364 					miocnak(q, mp, 0, ERANGE);
4365 					return;
4366 				}
4367 			}
4368 			/*
4369 			 * Otherwise, save the information in tp,
4370 			 * force codeset 0 (ASCII) to be one byte,
4371 			 * one column.
4372 			 */
4373 			cp_eucwioc(euciocp, &tp->eucwioc, EUCIN);
4374 			tp->eucwioc.eucw[0] = tp->eucwioc.scrw[0] = 1;
4375 			/*
4376 			 * Now, check out whether we're doing
4377 			 * multibyte processing. if we are, we need
4378 			 * to allocate a block to hold the parallel
4379 			 * array. By convention, we've been passed
4380 			 * what amounts to a CSWIDTH definition.  We
4381 			 * actually NEED the number of bytes for
4382 			 * Codesets 2 & 3.
4383 			 */
4384 			tp->t_maxeuc = 0;	/* reset to say we're NOT */
4385 
4386 			tp->t_state &= ~TS_MEUC;
4387 			/*
4388 			 * We'll set TS_MEUC if we're doing
4389 			 * multi-column OR multi- byte OR both.  It
4390 			 * makes things easier...  NOTE:  If we fail
4391 			 * to get the buffer we need to hold display
4392 			 * widths, then DON'T let the TS_MEUC bit get
4393 			 * set!
4394 			 */
4395 			for (i = 0; i < 4; i++) {
4396 				if (tp->eucwioc.eucw[i] > tp->t_maxeuc)
4397 					tp->t_maxeuc = tp->eucwioc.eucw[i];
4398 				if (tp->eucwioc.scrw[i] > 1)
4399 					tp->t_state |= TS_MEUC;
4400 			}
4401 			if ((tp->t_maxeuc > 1) || (tp->t_state & TS_MEUC)) {
4402 				if (!tp->t_eucp_mp) {
4403 					if ((tp->t_eucp_mp = allocb(_TTY_BUFSIZ,
4404 					    BPRI_HI)) == NULL) {
4405 						tp->t_maxeuc = 1;
4406 						tp->t_state &= ~TS_MEUC;
4407 						cmn_err(CE_WARN,
4408 						    "Can't allocate eucp_mp");
4409 						miocnak(q, mp, 0, ENOSR);
4410 						return;
4411 					}
4412 					/*
4413 					 * here, if there's junk in
4414 					 * the canonical buffer, then
4415 					 * move the eucp pointer past
4416 					 * it, so we don't run off
4417 					 * the beginning.  This is a
4418 					 * total botch, but will
4419 					 * hopefully keep stuff from
4420 					 * getting too messed up
4421 					 * until the user flushes
4422 					 * this line!
4423 					 */
4424 					if (tp->t_msglen) {
4425 						tp->t_eucp =
4426 						    tp->t_eucp_mp->b_rptr;
4427 						for (i = tp->t_msglen; i; i--)
4428 							*tp->t_eucp++ = 1;
4429 					} else {
4430 						tp->t_eucp =
4431 						    tp->t_eucp_mp->b_rptr;
4432 					}
4433 				}
4434 				/* doing multi-byte handling */
4435 				tp->t_state |= TS_MEUC;
4436 
4437 			} else if (tp->t_eucp_mp) {
4438 				freemsg(tp->t_eucp_mp);
4439 				tp->t_eucp_mp = NULL;
4440 				tp->t_eucp = NULL;
4441 			}
4442 
4443 			/*
4444 			 * Save the EUC width data we have at
4445 			 * the t_csdata, set t_csdata.codeset_type to
4446 			 * EUC one, and, switch the codeset methods at
4447 			 * t_csmethods.
4448 			 */
4449 			bzero(&tp->t_csdata.eucpc_data,
4450 			    (sizeof (ldterm_eucpc_data_t) *
4451 			    LDTERM_CS_MAX_CODESETS));
4452 			tp->t_csdata.eucpc_data[0].byte_length =
4453 			    tp->eucwioc.eucw[1];
4454 			tp->t_csdata.eucpc_data[0].screen_width =
4455 			    tp->eucwioc.scrw[1];
4456 			tp->t_csdata.eucpc_data[1].byte_length =
4457 			    tp->eucwioc.eucw[2];
4458 			tp->t_csdata.eucpc_data[1].screen_width =
4459 			    tp->eucwioc.scrw[2];
4460 			tp->t_csdata.eucpc_data[2].byte_length =
4461 			    tp->eucwioc.eucw[3];
4462 			tp->t_csdata.eucpc_data[2].screen_width =
4463 			    tp->eucwioc.scrw[3];
4464 			tp->t_csdata.version = LDTERM_DATA_VERSION;
4465 			tp->t_csdata.codeset_type = LDTERM_CS_TYPE_EUC;
4466 			/*
4467 			 * We are not using the 'csinfo_num' anyway if the
4468 			 * current codeset type is EUC. So, set it to
4469 			 * the maximum possible.
4470 			 */
4471 			tp->t_csdata.csinfo_num =
4472 			    LDTERM_CS_TYPE_EUC_MAX_SUBCS;
4473 			if (tp->t_csdata.locale_name != (char *)NULL) {
4474 				kmem_free(tp->t_csdata.locale_name,
4475 				    strlen(tp->t_csdata.locale_name) + 1);
4476 				tp->t_csdata.locale_name = (char *)NULL;
4477 			}
4478 			tp->t_csmethods = cs_methods[LDTERM_CS_TYPE_EUC];
4479 
4480 			/*
4481 			 * If we are able to allocate two blocks (the
4482 			 * iocblk and the associated data), then pass
4483 			 * it downstream, otherwise we'll need to NAK
4484 			 * it, and drop whatever we WERE able to
4485 			 * allocate.
4486 			 */
4487 			if ((dmp = mkiocb(EUC_WSET)) == NULL) {
4488 				miocnak(q, mp, 0, ENOSR);
4489 				return;
4490 			}
4491 			if ((dmp_cont = allocb(EUCSIZE, BPRI_HI)) == NULL) {
4492 				freemsg(dmp);
4493 				miocnak(q, mp, 0, ENOSR);
4494 				return;
4495 			}
4496 
4497 			/*
4498 			 * We got both buffers.  Copy out the EUC
4499 			 * information (as we received it, not what
4500 			 * we're using!) & pass it on.
4501 			 */
4502 			bcopy(mp->b_cont->b_rptr, dmp_cont->b_rptr, EUCSIZE);
4503 			dmp_cont->b_wptr += EUCSIZE;
4504 			dmp->b_cont = dmp_cont;
4505 			dmp->b_datap->db_type = M_CTL;
4506 			dmp_cont->b_datap->db_type = M_DATA;
4507 			riocp = (struct iocblk *)dmp->b_rptr;
4508 			riocp->ioc_count = EUCSIZE;
4509 			putnext(q, dmp);
4510 
4511 			/*
4512 			 * Now ACK the ioctl.
4513 			 */
4514 			iocp->ioc_rval = 0;
4515 			miocack(q, mp, 0, 0);
4516 			return;
4517 		}
4518 
4519 	case EUC_WGET:
4520 		error = miocpullup(mp, sizeof (struct eucioc));
4521 		if (error != 0) {
4522 			miocnak(q, mp, 0, error);
4523 			return;
4524 		}
4525 		euciocp = (struct eucioc *)mp->b_cont->b_rptr;
4526 		cp_eucwioc(&tp->eucwioc, euciocp, EUCOUT);
4527 		iocp->ioc_rval = 0;
4528 		miocack(q, mp, EUCSIZE, 0);
4529 		return;
4530 
4531 	case CSDATA_SET:
4532 		error = miocpullup(mp, sizeof (ldterm_cs_data_user_t));
4533 		if (error != 0) {
4534 			miocnak(q, mp, 0, error);
4535 			return;
4536 		}
4537 
4538 		csdp = (ldterm_cs_data_user_t *)mp->b_cont->b_rptr;
4539 
4540 		/* Validate the codeset data provided. */
4541 		if (csdp->version > LDTERM_DATA_VERSION ||
4542 		    csdp->codeset_type < LDTERM_CS_TYPE_MIN ||
4543 		    csdp->codeset_type > LDTERM_CS_TYPE_MAX) {
4544 			miocnak(q, mp, 0, ERANGE);
4545 			return;
4546 		}
4547 
4548 		if ((csdp->codeset_type == LDTERM_CS_TYPE_EUC &&
4549 		    csdp->csinfo_num > LDTERM_CS_TYPE_EUC_MAX_SUBCS) ||
4550 		    (csdp->codeset_type == LDTERM_CS_TYPE_PCCS &&
4551 		    (csdp->csinfo_num < LDTERM_CS_TYPE_PCCS_MIN_SUBCS ||
4552 		    csdp->csinfo_num > LDTERM_CS_TYPE_PCCS_MAX_SUBCS))) {
4553 			miocnak(q, mp, 0, ERANGE);
4554 			return;
4555 		}
4556 
4557 		maxbytelen = maxscreenlen = 0;
4558 		if (csdp->codeset_type == LDTERM_CS_TYPE_EUC) {
4559 			for (i = 0; i < LDTERM_CS_TYPE_EUC_MAX_SUBCS; i++) {
4560 				if (csdp->eucpc_data[i].byte_length >
4561 				    EUC_MAXW ||
4562 				    csdp->eucpc_data[i].screen_width >
4563 				    EUC_MAXW) {
4564 					miocnak(q, mp, 0, ERANGE);
4565 					return;
4566 				}
4567 
4568 				if (csdp->eucpc_data[i].byte_length >
4569 				    maxbytelen)
4570 					maxbytelen =
4571 					    csdp->eucpc_data[i].byte_length;
4572 				if (csdp->eucpc_data[i].screen_width >
4573 				    maxscreenlen)
4574 					maxscreenlen =
4575 					    csdp->eucpc_data[i].screen_width;
4576 			}
4577 			/* POSIX/C locale? */
4578 			if (maxbytelen == 0 && maxscreenlen == 0)
4579 				maxbytelen = maxscreenlen = 1;
4580 		} else if (csdp->codeset_type == LDTERM_CS_TYPE_PCCS) {
4581 			for (i = 0; i < LDTERM_CS_MAX_CODESETS; i++) {
4582 				if (csdp->eucpc_data[i].byte_length >
4583 				    LDTERM_CS_MAX_BYTE_LENGTH) {
4584 					miocnak(q, mp, 0, ERANGE);
4585 					return;
4586 				}
4587 				if (csdp->eucpc_data[i].byte_length >
4588 				    maxbytelen)
4589 					maxbytelen =
4590 					    csdp->eucpc_data[i].byte_length;
4591 				if (csdp->eucpc_data[i].screen_width >
4592 				    maxscreenlen)
4593 					maxscreenlen =
4594 					    csdp->eucpc_data[i].screen_width;
4595 			}
4596 		} else if (csdp->codeset_type == LDTERM_CS_TYPE_UTF8) {
4597 			maxbytelen = 4;
4598 			maxscreenlen = 2;
4599 		}
4600 
4601 		locale_name_sz = 0;
4602 
4603 		for (i = 0; i < MAXNAMELEN; i++)
4604 			if (csdp->locale_name[i] == '\0')
4605 				break;
4606 		/*
4607 		 * We cannot have any string that is not NULL byte
4608 		 * terminated.
4609 		 */
4610 		if (i >= MAXNAMELEN) {
4611 			miocnak(q, mp, 0, ERANGE);
4612 			return;
4613 		}
4614 
4615 		locale_name_sz = i + 1;
4616 
4617 		/*
4618 		 * As the final check, if there was invalid codeset_type
4619 		 * given, or invalid byte_length was specified, it's an error.
4620 		 */
4621 		if (maxbytelen <= 0 || maxscreenlen <= 0) {
4622 			miocnak(q, mp, 0, ERANGE);
4623 			return;
4624 		}
4625 
4626 		/* Do the switching. */
4627 		tp->t_maxeuc = maxbytelen;
4628 		tp->t_state &= ~TS_MEUC;
4629 		if (maxbytelen > 1 || maxscreenlen > 1) {
4630 			if (!tp->t_eucp_mp) {
4631 				if (!(tp->t_eucp_mp = allocb(_TTY_BUFSIZ,
4632 				    BPRI_HI))) {
4633 					cmn_err(CE_WARN,
4634 					    "Can't allocate eucp_mp");
4635 					miocnak(q, mp, 0, ENOSR);
4636 					return;
4637 				}
4638 				/*
4639 				 * If there's junk in the canonical buffer,
4640 				 * then move the eucp pointer past it,
4641 				 * so we don't run off the beginning. This is
4642 				 * a total botch, but will hopefully keep
4643 				 * stuff from getting too messed up until
4644 				 * the user flushes this line!
4645 				 */
4646 				if (tp->t_msglen) {
4647 					tp->t_eucp = tp->t_eucp_mp->b_rptr;
4648 					for (i = tp->t_msglen; i; i--)
4649 						*tp->t_eucp++ = 1;
4650 				} else {
4651 					tp->t_eucp = tp->t_eucp_mp->b_rptr;
4652 				}
4653 			}
4654 
4655 			/*
4656 			 * We only set TS_MEUC for a multibyte/multi-column
4657 			 * codeset.
4658 			 */
4659 			tp->t_state |= TS_MEUC;
4660 
4661 			tp->t_csdata.version = csdp->version;
4662 			tp->t_csdata.codeset_type = csdp->codeset_type;
4663 			tp->t_csdata.csinfo_num = csdp->csinfo_num;
4664 			bcopy(csdp->eucpc_data, tp->t_csdata.eucpc_data,
4665 			    sizeof (ldterm_eucpc_data_t) *
4666 			    LDTERM_CS_MAX_CODESETS);
4667 			tp->t_csmethods = cs_methods[csdp->codeset_type];
4668 
4669 			if (csdp->codeset_type == LDTERM_CS_TYPE_EUC) {
4670 				tp->eucwioc.eucw[0] = 1;
4671 				tp->eucwioc.scrw[0] = 1;
4672 
4673 				tp->eucwioc.eucw[1] =
4674 				    csdp->eucpc_data[0].byte_length;
4675 				tp->eucwioc.scrw[1] =
4676 				    csdp->eucpc_data[0].screen_width;
4677 
4678 				tp->eucwioc.eucw[2] =
4679 				    csdp->eucpc_data[1].byte_length + 1;
4680 				tp->eucwioc.scrw[2] =
4681 				    csdp->eucpc_data[1].screen_width;
4682 
4683 				tp->eucwioc.eucw[3] =
4684 				    csdp->eucpc_data[2].byte_length + 1;
4685 				tp->eucwioc.scrw[3] =
4686 				    csdp->eucpc_data[2].screen_width;
4687 			} else {
4688 				/*
4689 				 * We are not going to use this data
4690 				 * structure. So, clear it. Also, stty(1) will
4691 				 * make use of the cleared tp->eucwioc when
4692 				 * it prints out codeset width setting.
4693 				 */
4694 				bzero(&tp->eucwioc, EUCSIZE);
4695 			}
4696 		} else {
4697 			/*
4698 			 * If this codeset is a single byte codeset that
4699 			 * requires only single display column for all
4700 			 * characters, we switch to default EUC codeset
4701 			 * methods and data setting.
4702 			 */
4703 
4704 			if (tp->t_eucp_mp) {
4705 				freemsg(tp->t_eucp_mp);
4706 				tp->t_eucp_mp = NULL;
4707 				tp->t_eucp = NULL;
4708 			}
4709 
4710 			bzero(&tp->eucwioc, EUCSIZE);
4711 			tp->eucwioc.eucw[0] = 1;
4712 			tp->eucwioc.scrw[0] = 1;
4713 			if (tp->t_csdata.locale_name != (char *)NULL) {
4714 				kmem_free(tp->t_csdata.locale_name,
4715 				    strlen(tp->t_csdata.locale_name) + 1);
4716 			}
4717 			tp->t_csdata = default_cs_data;
4718 			tp->t_csmethods = cs_methods[LDTERM_CS_TYPE_EUC];
4719 		}
4720 
4721 		/* Copy over locale_name. */
4722 		if (tp->t_csdata.locale_name != (char *)NULL) {
4723 			kmem_free(tp->t_csdata.locale_name,
4724 			    strlen(tp->t_csdata.locale_name) + 1);
4725 		}
4726 		if (locale_name_sz > 1) {
4727 			tp->t_csdata.locale_name = (char *)kmem_alloc(
4728 			    locale_name_sz, KM_SLEEP);
4729 			(void) strcpy(tp->t_csdata.locale_name,
4730 			    csdp->locale_name);
4731 		} else {
4732 			tp->t_csdata.locale_name = (char *)NULL;
4733 		}
4734 
4735 		/*
4736 		 * Now ACK the ioctl.
4737 		 */
4738 		iocp->ioc_rval = 0;
4739 		miocack(q, mp, 0, 0);
4740 		return;
4741 
4742 	case CSDATA_GET:
4743 		error = miocpullup(mp, sizeof (ldterm_cs_data_user_t));
4744 		if (error != 0) {
4745 			miocnak(q, mp, 0, error);
4746 			return;
4747 		}
4748 
4749 		csdp = (ldterm_cs_data_user_t *)mp->b_cont->b_rptr;
4750 
4751 		csdp->version = tp->t_csdata.version;
4752 		csdp->codeset_type = tp->t_csdata.codeset_type;
4753 		csdp->csinfo_num = tp->t_csdata.csinfo_num;
4754 		csdp->pad = tp->t_csdata.pad;
4755 		if (tp->t_csdata.locale_name) {
4756 			(void) strcpy(csdp->locale_name,
4757 			    tp->t_csdata.locale_name);
4758 		} else {
4759 			csdp->locale_name[0] = '\0';
4760 		}
4761 		bcopy(tp->t_csdata.eucpc_data, csdp->eucpc_data,
4762 		    sizeof (ldterm_eucpc_data_t) * LDTERM_CS_MAX_CODESETS);
4763 		/*
4764 		 * If the codeset is an EUC codeset and if it has 2nd and/or
4765 		 * 3rd supplementary codesets, we subtract one from each
4766 		 * byte length of the supplementary codesets. This is
4767 		 * because single shift characters, SS2 and SS3, are not
4768 		 * included in the byte lengths in the user space.
4769 		 */
4770 		if (csdp->codeset_type == LDTERM_CS_TYPE_EUC) {
4771 			if (csdp->eucpc_data[1].byte_length)
4772 				csdp->eucpc_data[1].byte_length -= 1;
4773 			if (csdp->eucpc_data[2].byte_length)
4774 				csdp->eucpc_data[2].byte_length -= 1;
4775 		}
4776 		iocp->ioc_rval = 0;
4777 		miocack(q, mp, sizeof (ldterm_cs_data_user_t), 0);
4778 		return;
4779 
4780 	case PTSSTTY:
4781 		tp->t_state |= TS_ISPTSTTY;
4782 		break;
4783 
4784 	}
4785 
4786 	putnext(q, mp);
4787 }
4788 
4789 
4790 /*
4791  * Send an M_SETOPTS message upstream if any mode changes are being
4792  * made that affect the stream head options. returns -1 if allocb
4793  * fails, else returns 0.
4794  */
4795 static int
4796 chgstropts(struct termios *oldmodep, ldtermstd_state_t *tp, queue_t *q)
4797 {
4798 	struct stroptions optbuf;
4799 	mblk_t *bp;
4800 
4801 	optbuf.so_flags = 0;
4802 	if ((oldmodep->c_lflag ^ tp->t_modes.c_lflag) & ICANON) {
4803 		/*
4804 		 * Canonical mode is changing state; switch the
4805 		 * stream head to message-nondiscard or byte-stream
4806 		 * mode.  Also, rerun the service procedure so it can
4807 		 * change its mind about whether to send data
4808 		 * upstream or not.
4809 		 */
4810 		if (tp->t_modes.c_lflag & ICANON) {
4811 			DEBUG4(("CHANGING TO CANON MODE\n"));
4812 			optbuf.so_flags = SO_READOPT|SO_MREADOFF;
4813 			optbuf.so_readopt = RMSGN;
4814 
4815 			/*
4816 			 * if there is a pending raw mode timeout,
4817 			 * clear it
4818 			 */
4819 
4820 			/*
4821 			 * Clear VMIN/VTIME state, cancel timers
4822 			 */
4823 			vmin_satisfied(q, tp, 0);
4824 		} else {
4825 			DEBUG4(("CHANGING TO RAW MODE\n"));
4826 			optbuf.so_flags = SO_READOPT|SO_MREADON;
4827 			optbuf.so_readopt = RNORM;
4828 		}
4829 	}
4830 	if ((oldmodep->c_lflag ^ tp->t_modes.c_lflag) & TOSTOP) {
4831 		/*
4832 		 * The "stop on background write" bit is changing.
4833 		 */
4834 		if (tp->t_modes.c_lflag & TOSTOP)
4835 			optbuf.so_flags |= SO_TOSTOP;
4836 		else
4837 			optbuf.so_flags |= SO_TONSTOP;
4838 	}
4839 	if (optbuf.so_flags != 0) {
4840 		if ((bp = allocb(sizeof (struct stroptions), BPRI_HI)) ==
4841 		    NULL) {
4842 			return (-1);
4843 		}
4844 		*(struct stroptions *)bp->b_wptr = optbuf;
4845 		bp->b_wptr += sizeof (struct stroptions);
4846 		bp->b_datap->db_type = M_SETOPTS;
4847 		DEBUG4(("M_SETOPTS to stream head\n"));
4848 		putnext(q, bp);
4849 	}
4850 	return (0);
4851 }
4852 
4853 
4854 /*
4855  * Called when an M_IOCACK message is seen on the read queue;
4856  * modifies the data being returned, if necessary, and passes the
4857  * reply up.
4858  */
4859 static void
4860 ldterm_ioctl_reply(queue_t *q, mblk_t *mp)
4861 {
4862 	ldtermstd_state_t *tp;
4863 	struct iocblk *iocp;
4864 
4865 	iocp = (struct iocblk *)mp->b_rptr;
4866 	tp = (ldtermstd_state_t *)q->q_ptr;
4867 
4868 	switch (iocp->ioc_cmd) {
4869 
4870 	case TCGETS:
4871 		{
4872 			/*
4873 			 * Get current parameters and return them to
4874 			 * stream head eventually.
4875 			 */
4876 			struct termios *cb =
4877 			    (struct termios *)mp->b_cont->b_rptr;
4878 
4879 			/*
4880 			 * cflag has cflags sent upstream by the
4881 			 * driver
4882 			 */
4883 			tcflag_t cflag = cb->c_cflag;
4884 
4885 			*cb = tp->t_amodes;
4886 			if (cflag != 0)
4887 				cb->c_cflag = cflag;	/* set by driver */
4888 			break;
4889 		}
4890 
4891 	case TCGETA:
4892 		{
4893 			/*
4894 			 * Old-style "ioctl" to get current
4895 			 * parameters and return them to stream head
4896 			 * eventually.
4897 			 */
4898 			struct termio *cb =
4899 			    (struct termio *)mp->b_cont->b_rptr;
4900 
4901 			cb->c_iflag = tp->t_amodes.c_iflag; /* all except the */
4902 			cb->c_oflag = tp->t_amodes.c_oflag; /* cb->c_cflag */
4903 			cb->c_lflag = tp->t_amodes.c_lflag;
4904 
4905 			if (cb->c_cflag == 0)	/* not set by driver */
4906 				cb->c_cflag = tp->t_amodes.c_cflag;
4907 
4908 			cb->c_line = 0;
4909 			bcopy(tp->t_amodes.c_cc, cb->c_cc, NCC);
4910 			break;
4911 		}
4912 	}
4913 	putnext(q, mp);
4914 }
4915 
4916 
4917 /*
4918  * A VMIN/VTIME request has been satisfied. Cancel outstanding timers
4919  * if they exist, clear TS_MREAD state, and send upstream. If a NULL
4920  * queue ptr is passed, just reset VMIN/VTIME state.
4921  */
4922 static void
4923 vmin_satisfied(queue_t *q, ldtermstd_state_t *tp, int sendup)
4924 {
4925 	ASSERT(q);
4926 	if (tp->t_vtid != 0)  {
4927 		DEBUG4(("vmin_satisfied: cancelled timer id %d\n", tp->t_vtid));
4928 		(void) quntimeout(q, tp->t_vtid);
4929 		tp->t_vtid = 0;
4930 	}
4931 	if (sendup) {
4932 		if (tp->t_msglen == 0 && V_MIN) {
4933 			/* EMPTY */
4934 			DEBUG4(("vmin_satisfied: data swiped, msglen = 0\n"));
4935 		} else {
4936 			if ((!q->q_first) ||
4937 			    (q->q_first->b_datap->db_type != M_DATA) ||
4938 			    (tp->t_msglen >= LDCHUNK)) {
4939 				ldterm_msg_upstream(q, tp);
4940 				DEBUG4(("vmin_satisfied: delivering data\n"));
4941 			}
4942 		}
4943 	} else {
4944 		/* EMPTY */
4945 		DEBUG4(("vmin_satisfied: VMIN/TIME state reset\n"));
4946 	}
4947 	tp->t_state &= ~TS_MREAD;
4948 }
4949 
4950 static void
4951 vmin_settimer(queue_t *q)
4952 {
4953 	ldtermstd_state_t *tp;
4954 
4955 	tp = (ldtermstd_state_t *)q->q_ptr;
4956 
4957 	/*
4958 	 * Don't start any time bombs.
4959 	 */
4960 	if (tp->t_state & TS_CLOSE)
4961 		return;
4962 
4963 	/*
4964 	 * tp->t_vtid should NOT be set here unless VMIN > 0 and
4965 	 * VTIME > 0.
4966 	 */
4967 	if (tp->t_vtid) {
4968 		if (V_MIN && V_TIME) {
4969 			/* EMPTY */
4970 			DEBUG4(("vmin_settimer: timer restarted, old tid=%d\n",
4971 			    tp->t_vtid));
4972 		} else {
4973 			/* EMPTY */
4974 			DEBUG4(("vmin_settimer: tid = %d was still active!\n",
4975 			    tp->t_vtid));
4976 		}
4977 		(void) quntimeout(q, tp->t_vtid);
4978 		tp->t_vtid = 0;
4979 	}
4980 	tp->t_vtid = qtimeout(q, vmin_timed_out, q,
4981 	    (clock_t)(V_TIME * (hz / 10)));
4982 	DEBUG4(("vmin_settimer: timer started, tid = %d\n", tp->t_vtid));
4983 }
4984 
4985 
4986 /*
4987  * BRRrrringgg!! VTIME was satisfied instead of VMIN
4988  */
4989 static void
4990 vmin_timed_out(void *arg)
4991 {
4992 	queue_t *q = arg;
4993 	ldtermstd_state_t *tp;
4994 
4995 	tp = (ldtermstd_state_t *)q->q_ptr;
4996 
4997 	DEBUG4(("vmin_timed_out: tid = %d\n", tp->t_vtid));
4998 	/* don't call untimeout now that we are in the timeout */
4999 	tp->t_vtid = 0;
5000 	vmin_satisfied(q, tp, 1);
5001 }
5002 
5003 
5004 /*
5005  * Routine to adjust termios flags to be processed by the line
5006  * discipline. Driver below sends a termios structure, with the flags
5007  * the driver intends to process. XOR'ing the driver sent termios
5008  * structure with current termios structure with the default values
5009  * (or set by ioctls from userland), we come up with a new termios
5010  * structrue, the flags of which will be used by the line discipline
5011  * in processing input and output. On return from this routine, we
5012  * will have the following fields set in tp structure -->
5013  * tp->t_modes:	modes the line discipline will process tp->t_amodes:
5014  * modes the user process thinks the line discipline is processing
5015  */
5016 
5017 static void
5018 ldterm_adjust_modes(ldtermstd_state_t *tp)
5019 {
5020 
5021 	DEBUG6(("original iflag = %o\n", tp->t_modes.c_iflag));
5022 	tp->t_modes.c_iflag = tp->t_amodes.c_iflag & ~(tp->t_dmodes.c_iflag);
5023 	tp->t_modes.c_oflag = tp->t_amodes.c_oflag & ~(tp->t_dmodes.c_oflag);
5024 	tp->t_modes.c_lflag = tp->t_amodes.c_lflag & ~(tp->t_dmodes.c_lflag);
5025 	DEBUG6(("driver iflag = %o\n", tp->t_dmodes.c_iflag));
5026 	DEBUG6(("apparent iflag = %o\n", tp->t_amodes.c_iflag));
5027 	DEBUG6(("effective iflag = %o\n", tp->t_modes.c_iflag));
5028 
5029 	/* No negotiation of clfags  c_cc array special characters */
5030 	/*
5031 	 * Copy from amodes to modes already done by TCSETA/TCSETS
5032 	 * code
5033 	 */
5034 }
5035 
5036 
5037 /*
5038  * Erase one multi-byte character.  If TS_MEUC is set AND this
5039  * is a multi-byte character, then this should be called instead of
5040  * ldterm_erase.  "ldterm_erase" will handle ASCII nicely, thank you.
5041  *
5042  * We'd better be pointing to the last byte.  If we aren't, it will get
5043  * screwed up.
5044  */
5045 static void
5046 ldterm_csi_erase(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
5047 {
5048 	int i, ung;
5049 	uchar_t *p, *bottom;
5050 	uchar_t u8[LDTERM_CS_MAX_BYTE_LENGTH];
5051 	int c;
5052 	int j;
5053 	int len;
5054 
5055 	if (tp->t_eucleft) {
5056 		/* XXX Ick.  We're in the middle of an EUC! */
5057 		/* What to do now? */
5058 		ldterm_eucwarn(tp);
5059 		return;		/* ignore it??? */
5060 	}
5061 	bottom = tp->t_eucp_mp->b_rptr;
5062 	p = tp->t_eucp - 1;	/* previous byte */
5063 	if (p < bottom)
5064 		return;
5065 	ung = 1;		/* number of bytes to un-get from buffer */
5066 	/*
5067 	 * go through the buffer until we find the beginning of the
5068 	 * multi-byte char.
5069 	 */
5070 	while ((*p == 0) && (p > bottom)) {
5071 		p--;
5072 		++ung;
5073 	}
5074 
5075 	/*
5076 	 * Now, "ung" is the number of bytes to unget from the buffer
5077 	 * and "*p" is the disp width of it. Fool "ldterm_rubout"
5078 	 * into thinking we're rubbing out ASCII characters.  Do that
5079 	 * for the display width of the character.
5080 	 *
5081 	 * Also we accumulate bytes of the character so that if the character
5082 	 * is a UTF-8 character, we will get the display width of the UTF-8
5083 	 * character.
5084 	 */
5085 	if (ung >= LDTERM_CS_MAX_BYTE_LENGTH) {
5086 		j = len = LDTERM_CS_MAX_BYTE_LENGTH;
5087 	} else {
5088 		j = len = ung;
5089 	}
5090 	for (i = 0; i < ung; i++) {	/* remove from buf */
5091 		if ((c = ldterm_unget(tp)) != (-1)) {
5092 			ldterm_trim(tp);
5093 			if (j > 0)
5094 				u8[--j] = (uchar_t)c;
5095 		}
5096 	}
5097 	if (*p == UNKNOWN_WIDTH) {
5098 		if (tp->t_csdata.codeset_type == LDTERM_CS_TYPE_UTF8) {
5099 			*p = ldterm_utf8_width(u8, len);
5100 		} else {
5101 			*p = 1;
5102 		}
5103 	}
5104 	for (i = 0; i < (int)*p; i++)	/* remove from screen */
5105 		ldterm_rubout(' ', q, ebsize, tp);
5106 	/*
5107 	 * Adjust the parallel array pointer.  Zero out the contents
5108 	 * of parallel array for this position, just to make sure...
5109 	 */
5110 	tp->t_eucp = p;
5111 	*p = 0;
5112 }
5113 
5114 
5115 /*
5116  * This is kind of a safety valve.  Whenever we see a bad sequence
5117  * come up, we call eucwarn.  It just tallies the junk until a
5118  * threshold is reached.  Then it prints ONE message on the console
5119  * and not any more. Hopefully, we can catch garbage; maybe it will
5120  * be useful to somebody.
5121  */
5122 static void
5123 ldterm_eucwarn(ldtermstd_state_t *tp)
5124 {
5125 	++tp->t_eucwarn;
5126 #ifdef DEBUG
5127 	if ((tp->t_eucwarn > EUC_WARNCNT) && !(tp->t_state & TS_WARNED)) {
5128 		cmn_err(CE_WARN,
5129 		    "ldterm: tty at addr %p in multi-byte mode --",
5130 		    (void *)tp);
5131 		cmn_err(CE_WARN,
5132 		    "Over %d bad EUC characters this session", EUC_WARNCNT);
5133 		tp->t_state |= TS_WARNED;
5134 	}
5135 #endif
5136 }
5137 
5138 
5139 /*
5140  * Copy an "eucioc_t" structure.  We use the structure with
5141  * incremented values for Codesets 2 & 3.  The specification in
5142  * eucioctl is that the sames values as the CSWIDTH definition at
5143  * user level are passed to us. When we copy it "in" to ourselves, we
5144  * do the increment.  That allows us to avoid treating each character
5145  * set separately for "t_eucleft" purposes. When we copy it "out" to
5146  * return it to the user, we decrement the values so the user gets
5147  * what it expects, and it matches CSWIDTH in the environment (if
5148  * things are consistent!).
5149  */
5150 static void
5151 cp_eucwioc(eucioc_t *from, eucioc_t *to, int dir)
5152 {
5153 	bcopy(from, to, EUCSIZE);
5154 	if (dir == EUCOUT) {	/* copying out to user */
5155 		if (to->eucw[2])
5156 			--to->eucw[2];
5157 		if (to->eucw[3])
5158 			--to->eucw[3];
5159 	} else {		/* copying in */
5160 		if (to->eucw[2])
5161 			++to->eucw[2];
5162 		if (to->eucw[3])
5163 			++to->eucw[3];
5164 	}
5165 }
5166 
5167 
5168 /*
5169  * Take the first byte of a multi-byte, or an ASCII char.  Return its
5170  * codeset. If it's NOT the first byte of an EUC, then the return
5171  * value may be garbage, as it's probably not SS2 or SS3, and
5172  * therefore must be in codeset 1.  Another bizarre catch here is the
5173  * fact that we don't do anything about the "C1" control codes.  In
5174  * real life, we should; but nobody's come up with a good way of
5175  * treating them.
5176  */
5177 
5178 static int
5179 ldterm_codeset(uchar_t codeset_type, uchar_t c)
5180 {
5181 
5182 	if (ISASCII(c))
5183 		return (0);
5184 
5185 	if (codeset_type != LDTERM_CS_TYPE_EUC)
5186 		return (1);
5187 
5188 	switch (c) {
5189 	case SS2:
5190 		return (2);
5191 	case SS3:
5192 		return (3);
5193 	default:
5194 		return (1);
5195 	}
5196 }
5197 
5198 /* The following two functions are additional EUC codeset specific methods. */
5199 /*
5200  * ldterm_dispwidth - Take the first byte of an EUC (or ASCII) and
5201  * return the display width.  Since this is intended mostly for
5202  * multi-byte handling, it returns EUC_TWIDTH for tabs so they can be
5203  * differentiated from EUC characters (assumption: EUC require fewer
5204  * than 255 columns).  Also, if it's a backspace and !flag, it
5205  * returns EUC_BSWIDTH.  Newline & CR also depend on flag.  This
5206  * routine SHOULD be cleaner than this, but we have the situation
5207  * where we may or may not be counting control characters as having a
5208  * column width. Therefore, the computation of ASCII is pretty messy.
5209  * The caller will be storing the value, and then switching on it
5210  * when it's used.  We really should define the EUC_TWIDTH and other
5211  * constants in a header so that the routine could be used in other
5212  * modules in the kernel.
5213  */
5214 static int
5215 __ldterm_dispwidth_euc(uchar_t c, void *p, int mode)
5216 {
5217 	ldtermstd_state_t *tp = (ldtermstd_state_t *)p;
5218 
5219 	if (ISASCII(c)) {
5220 		if (c <= '\037') {
5221 			switch (c) {
5222 			case '\t':
5223 				return (EUC_TWIDTH);
5224 			case '\b':
5225 				return (mode ? 2 : EUC_BSWIDTH);
5226 			case '\n':
5227 				return (EUC_NLWIDTH);
5228 			case '\r':
5229 				return (mode ? 2 : EUC_CRWIDTH);
5230 			default:
5231 				return (mode ? 2 : 0);
5232 			}
5233 		}
5234 		return (1);
5235 	}
5236 	switch (c) {
5237 	case SS2:
5238 		return (tp->eucwioc.scrw[2]);
5239 	case SS3:
5240 		return (tp->eucwioc.scrw[3]);
5241 	default:
5242 		return (tp->eucwioc.scrw[1]);
5243 	}
5244 }
5245 
5246 /*
5247  * ldterm_memwidth_euc - Take the first byte of an EUC (or an ASCII char)
5248  * and return its memory width.  The routine could have been
5249  * implemented to use only the codeset number, but that would require
5250  * the caller to have that value available.  Perhaps the user doesn't
5251  * want to make the extra call or keep the value of codeset around.
5252  * Therefore, we use the actual character with which they're
5253  * concerned.  This should never be called with anything but the
5254  * first byte of an EUC, otherwise it will return a garbage value.
5255  */
5256 static int
5257 __ldterm_memwidth_euc(uchar_t c, void *p)
5258 {
5259 	ldtermstd_state_t *tp = (ldtermstd_state_t *)p;
5260 
5261 	if (ISASCII(c))
5262 		return (1);
5263 	switch (c) {
5264 	case SS2:
5265 		return (tp->eucwioc.eucw[2]);
5266 	case SS3:
5267 		return (tp->eucwioc.eucw[3]);
5268 	default:
5269 		return (tp->eucwioc.eucw[1]);
5270 	}
5271 }
5272 
5273 
5274 /* The following two functions are PCCS codeset specific methods. */
5275 static int
5276 __ldterm_dispwidth_pccs(uchar_t c, void *p, int mode)
5277 {
5278 	ldtermstd_state_t *tp = (ldtermstd_state_t *)p;
5279 	int i;
5280 
5281 	if (ISASCII(c)) {
5282 		if (c <= '\037') {
5283 			switch (c) {
5284 			case '\t':
5285 				return (EUC_TWIDTH);
5286 			case '\b':
5287 				return (mode ? 2 : EUC_BSWIDTH);
5288 			case '\n':
5289 				return (EUC_NLWIDTH);
5290 			case '\r':
5291 				return (mode ? 2 : EUC_CRWIDTH);
5292 			default:
5293 				return (mode ? 2 : 0);
5294 			}
5295 		}
5296 		return (1);
5297 	}
5298 
5299 	for (i = 0; i < tp->t_csdata.csinfo_num; i++) {
5300 		if (c >= tp->t_csdata.eucpc_data[i].msb_start &&
5301 		    c <= tp->t_csdata.eucpc_data[i].msb_end)
5302 			return (tp->t_csdata.eucpc_data[i].screen_width);
5303 	}
5304 
5305 	/*
5306 	 * If this leading byte is not in the range list, either provided
5307 	 * locale data is not sufficient or we encountered an invalid
5308 	 * character. We return 1 in this case as a fallback value.
5309 	 */
5310 	return (1);
5311 }
5312 
5313 static int
5314 __ldterm_memwidth_pccs(uchar_t c, void *p)
5315 {
5316 	ldtermstd_state_t *tp = (ldtermstd_state_t *)p;
5317 	int i;
5318 
5319 	for (i = 0; i < tp->t_csdata.csinfo_num; i++) {
5320 		if (c >= tp->t_csdata.eucpc_data[i].msb_start &&
5321 		    c <= tp->t_csdata.eucpc_data[i].msb_end)
5322 			return (tp->t_csdata.eucpc_data[i].byte_length);
5323 	}
5324 
5325 	/*
5326 	 * If this leading byte is not in the range list, either provided
5327 	 * locale data is not sufficient or we encountered an invalid
5328 	 * character. We return 1 in this case as a fallback value.
5329 	 */
5330 	return (1);
5331 }
5332 
5333 
5334 /* The following two functions are UTF-8 codeset specific methods. */
5335 static int
5336 __ldterm_dispwidth_utf8(uchar_t c, void *p, int mode)
5337 {
5338 	ldtermstd_state_t *tp = (ldtermstd_state_t *)p;
5339 
5340 	if (ISASCII(c)) {
5341 		if (c <= '\037') {
5342 			switch (c) {
5343 			case '\t':
5344 				return (EUC_TWIDTH);
5345 			case '\b':
5346 				return (mode ? 2 : EUC_BSWIDTH);
5347 			case '\n':
5348 				return (EUC_NLWIDTH);
5349 			case '\r':
5350 				return (mode ? 2 : EUC_CRWIDTH);
5351 			default:
5352 				return (mode ? 2 : 0);
5353 			}
5354 		}
5355 		return (1);
5356 	}
5357 
5358 	/* This is to silence the lint. */
5359 	if (tp->t_csdata.codeset_type != LDTERM_CS_TYPE_UTF8)
5360 		return (1);
5361 
5362 	/*
5363 	 * If it is a valid leading byte of a UTF-8 character, we set
5364 	 * the width as 'UNKNOWN_WIDTH' for now. We need to have all
5365 	 * the bytes to figure out the display width.
5366 	 */
5367 	if (c >= (uchar_t)0xc0 && c <= (uchar_t)0xfd)
5368 		return (UNKNOWN_WIDTH);
5369 
5370 	/*
5371 	 * If it is an invalid leading byte, we just do our best by
5372 	 * giving the display width of 1.
5373 	 */
5374 	return (1);
5375 }
5376 
5377 
5378 static int
5379 __ldterm_memwidth_utf8(uchar_t c, void *p)
5380 {
5381 	ldtermstd_state_t *tp = (ldtermstd_state_t *)p;
5382 	int len;
5383 
5384 	/*
5385 	 * If the codeset type doesn't match, we treat them as
5386 	 * an illegal character and return 1.
5387 	 */
5388 	if (tp->t_csdata.codeset_type != LDTERM_CS_TYPE_UTF8)
5389 		return (1);
5390 
5391 	len = u8_number_of_bytes[c];
5392 
5393 	/*
5394 	 * If this is a start of an illegal character, we treat
5395 	 * such as an 1 byte character and screen out.
5396 	 */
5397 	return ((len <= 0) ? 1 : len);
5398 }
5399 
5400 static uchar_t
5401 ldterm_utf8_width(uchar_t *u8, int length)
5402 {
5403 	int i;
5404 	int j;
5405 	uint_t intcode = 0;
5406 
5407 	if (length == 0)
5408 		return ('\0');
5409 
5410 	j = u8_number_of_bytes[u8[0]] - 1;
5411 
5412 	/*
5413 	 * If the UTF-8 character is out of UTF-16 code range, or,
5414 	 * if it is either an ASCII character or an invalid leading byte for
5415 	 * a UTF-8 character, return 1.
5416 	 */
5417 	if (length > 4 || j <= 0)
5418 		return ('\1');
5419 
5420 	intcode = u8[0] & u8_masks_tbl[j];
5421 	for (i = 1; j > 0; j--, i++) {
5422 		/*
5423 		 * The following additional checking is needed to conform to
5424 		 * the "UTF-8 Corrigendum" introduced at the Unicode 3.1 and
5425 		 * then updated one more time at the Unicode 3.2.
5426 		 */
5427 		if (i == 1) {
5428 			if (u8[i] < u8_valid_min_2nd_byte[u8[0]] ||
5429 			    u8[i] > u8_valid_max_2nd_byte[u8[0]])
5430 				return ('\1');
5431 		} else if (u8[i] < (uchar_t)LDTERM_CS_TYPE_UTF8_MIN_BYTE ||
5432 		    u8[i] > (uchar_t)LDTERM_CS_TYPE_UTF8_MAX_BYTE)
5433 			return ('\1');
5434 
5435 		/*
5436 		 * All subsequent bytes of UTF-8 character has the following
5437 		 * binary encoding:
5438 		 *
5439 		 * 10xx xxxx
5440 		 *
5441 		 * hence left shift six bits to make space and then get
5442 		 * six bits from the new byte.
5443 		 */
5444 		intcode = (intcode << LDTERM_CS_TYPE_UTF8_SHIFT_BITS) |
5445 		    (u8[i] & LDTERM_CS_TYPE_UTF8_BIT_MASK);
5446 	}
5447 
5448 	i = 0;
5449 	if (intcode <= LDTERM_CS_TYPE_UTF8_MAX_P00) {
5450 		/* Basic Multilingual Plane. */
5451 		i = intcode / 4;
5452 		j = intcode % 4;
5453 		switch (j) {
5454 		case 0:
5455 			i = ldterm_ucode[0][i].u0;
5456 			break;
5457 		case 1:
5458 			i = ldterm_ucode[0][i].u1;
5459 			break;
5460 		case 2:
5461 			i = ldterm_ucode[0][i].u2;
5462 			break;
5463 		case 3:
5464 			i = ldterm_ucode[0][i].u3;
5465 			break;
5466 		}
5467 	} else if (intcode <= LDTERM_CS_TYPE_UTF8_MAX_P01) {
5468 		/* Secondary Multilingual Plane. */
5469 		intcode = intcode & (uint_t)0xffff;
5470 		i = intcode / 4;
5471 		j = intcode % 4;
5472 		switch (j) {
5473 		case 0:
5474 			i = ldterm_ucode[1][i].u0;
5475 			break;
5476 		case 1:
5477 			i = ldterm_ucode[1][i].u1;
5478 			break;
5479 		case 2:
5480 			i = ldterm_ucode[1][i].u2;
5481 			break;
5482 		case 3:
5483 			i = ldterm_ucode[1][i].u3;
5484 			break;
5485 		}
5486 	} else if ((intcode >= LDTERM_CS_TYPE_UTF8_MIN_CJKEXTB &&
5487 	    intcode <= LDTERM_CS_TYPE_UTF8_MAX_CJKEXTB) ||
5488 	    (intcode >= LDTERM_CS_TYPE_UTF8_MIN_CJKCOMP &&
5489 	    intcode <= LDTERM_CS_TYPE_UTF8_MAX_CJKCOMP) ||
5490 	    (intcode >= LDTERM_CS_TYPE_UTF8_MIN_P15 &&
5491 	    intcode <= LDTERM_CS_TYPE_UTF8_MAX_P15) ||
5492 	    (intcode >= LDTERM_CS_TYPE_UTF8_MIN_P16 &&
5493 	    intcode <= LDTERM_CS_TYPE_UTF8_MAX_P16)) {
5494 		/*
5495 		 * Supplementary Plane for CJK Ideographs and
5496 		 * Private Use Planes.
5497 		 */
5498 		return ('\2');
5499 	} else if ((intcode >= LDTERM_CS_TYPE_UTF8_MIN_P14 &&
5500 	    intcode <= LDTERM_CS_TYPE_UTF8_MAX_P14) ||
5501 	    (intcode >= LDTERM_CS_TYPE_UTF8_MIN_VARSEL &&
5502 	    intcode <= LDTERM_CS_TYPE_UTF8_MAX_VARSEL)) {
5503 		/*
5504 		 * Some Special Purpose Plane characters:
5505 		 * These are like control characters and not printable.
5506 		 */
5507 		return ('\0');
5508 	}
5509 
5510 	/*
5511 	 * We return the display width of 1 for all character code points
5512 	 * that we didn't catch from the above logic and also for combining
5513 	 * and conjoining characters with width value of zero.
5514 	 *
5515 	 * In particular, the reason why we are returning 1 for combining
5516 	 * and conjoining characters is because the GUI-based terminal
5517 	 * emulators are not yet capable of properly handling such characters
5518 	 * and in most of the cases, they just treat such characters as if
5519 	 * they occupy a display cell. If the terminal emulators are capable of
5520 	 * handling the characters correctly, then, this logic of returning
5521 	 * 1 should be revisited and changed. See CR 6660526 for more
5522 	 * details on this.
5523 	 */
5524 	return ((i == 0) ? '\1' : (uchar_t)i);
5525 }
5526