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