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