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