xref: /illumos-gate/usr/src/uts/common/io/ldterm.c (revision 4b9db4f6425b1a08fca4390f446072c4a6aae8d5)
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 */
72  int ldterm_drain_limit = 15000000;
73  
74  /*
75   * Character types.
76   */
77  #define	ORDINARY	0
78  #define	CONTROL		1
79  #define	BACKSPACE	2
80  #define	NEWLINE		3
81  #define	TAB		4
82  #define	VTAB		5
83  #define	RETURN		6
84  
85  /*
86   * The following for EUC handling:
87   */
88  #define	T_SS2		7
89  #define	T_SS3		8
90  
91  /*
92   * Table indicating character classes to tty driver.  In particular,
93   * if the class is ORDINARY, then the character needs no special
94   * processing on output.
95   *
96   * Characters in the C1 set are all considered CONTROL; this will
97   * work with terminals that properly use the ANSI/ISO extensions,
98   * but might cause distress with terminals that put graphics in
99   * the range 0200-0237.  On the other hand, characters in that
100   * range cause even greater distress to other UNIX terminal drivers....
101   */
102  
103  static char typetab[256] = {
104  /* 000 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
105  /* 004 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
106  /* 010 */	BACKSPACE,	TAB,		NEWLINE,	CONTROL,
107  /* 014 */	VTAB,		RETURN,		CONTROL,	CONTROL,
108  /* 020 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
109  /* 024 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
110  /* 030 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
111  /* 034 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
112  /* 040 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
113  /* 044 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
114  /* 050 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
115  /* 054 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
116  /* 060 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
117  /* 064 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
118  /* 070 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
119  /* 074 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
120  /* 100 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
121  /* 104 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
122  /* 110 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
123  /* 114 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
124  /* 120 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
125  /* 124 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
126  /* 130 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
127  /* 134 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
128  /* 140 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
129  /* 144 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
130  /* 150 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
131  /* 154 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
132  /* 160 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
133  /* 164 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
134  /* 170 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
135  /* 174 */	ORDINARY,	ORDINARY,	ORDINARY,	CONTROL,
136  /* 200 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
137  /* 204 */	CONTROL,	CONTROL,	T_SS2,		T_SS3,
138  /* 210 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
139  /* 214 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
140  /* 220 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
141  /* 224 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
142  /* 230 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
143  /* 234 */	CONTROL,	CONTROL,	CONTROL,	CONTROL,
144  /* 240 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
145  /* 244 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
146  /* 250 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
147  /* 254 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
148  /* 260 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
149  /* 264 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
150  /* 270 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
151  /* 274 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
152  /* 300 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
153  /* 304 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
154  /* 310 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
155  /* 314 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
156  /* 320 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
157  /* 324 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
158  /* 330 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
159  /* 334 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
160  /* 340 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
161  /* 344 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
162  /* 350 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
163  /* 354 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
164  /* 360 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
165  /* 364 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
166  /* 370 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
167  /*
168   * WARNING:  For EUC, 0xFF must be an ordinary character.  It is used with
169   * single-byte EUC in some of the "ISO Latin Alphabet" codesets, and occupies
170   * a screen position; in those ISO sets where that position isn't used, it
171   * shouldn't make any difference.
172   */
173  /* 374 */	ORDINARY,	ORDINARY,	ORDINARY,	ORDINARY,
174  };
175  
176  /*
177   * Translation table for output without OLCUC.  All ORDINARY-class characters
178   * translate to themselves.  All other characters have a zero in the table,
179   * which stops the copying.
180   */
181  static unsigned char notrantab[256] = {
182  /* 000 */	0,	0,	0,	0,	0,	0,	0,	0,
183  /* 010 */	0,	0,	0,	0,	0,	0,	0,	0,
184  /* 020 */	0,	0,	0,	0,	0,	0,	0,	0,
185  /* 030 */	0,	0,	0,	0,	0,	0,	0,	0,
186  /* 040 */	' ',	'!',	'"',	'#',	'$',	'%',	'&',	'\'',
187  /* 050 */	'(',	')',	'*',	'+',	',',	'-',	'.',	'/',
188  /* 060 */	'0',	'1',	'2',	'3',	'4',	'5',	'6',	'7',
189  /* 070 */	'8',	'9',	':',	';',	'<',	'=',	'>',	'?',
190  /* 100 */	'@',	'A',	'B',	'C',	'D',	'E',	'F',	'G',
191  /* 110 */	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
192  /* 120 */	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
193  /* 130 */	'X',	'Y',	'Z',	'[',	'\\',	']',	'^',	'_',
194  /* 140 */	'`',	'a',	'b',	'c',	'd',	'e',	'f',	'g',
195  /* 150 */	'h',	'i',	'j',	'k',	'l',	'm',	'n',	'o',
196  /* 160 */	'p',	'q',	'r',	's',	't',	'u',	'v',	'w',
197  /* 170 */	'x',	'y',	'z',	'{',	'|',	'}',	'~',	0,
198  /* 200 */	0,	0,	0,	0,	0,	0,	0,	0,
199  /* 210 */	0,	0,	0,	0,	0,	0,	0,	0,
200  /* 220 */	0,	0,	0,	0,	0,	0,	0,	0,
201  /* 230 */	0,	0,	0,	0,	0,	0,	0,	0,
202  /* 240 */	0240,	0241,	0242,	0243,	0244,	0245,	0246,	0247,
203  /* 250 */	0250,	0251,	0252,	0253,	0254,	0255,	0256,	0257,
204  /* 260 */	0260,	0261,	0262,	0263,	0264,	0265,	0266,	0267,
205  /* 270 */	0270,	0271,	0272,	0273,	0274,	0275,	0276,	0277,
206  /* 300 */	0300,	0301,	0302,	0303,	0304,	0305,	0306,	0307,
207  /* 310 */	0310,	0311,	0312,	0313,	0314,	0315,	0316,	0317,
208  /* 320 */	0320,	0321,	0322,	0323,	0324,	0325,	0326,	0327,
209  /* 330 */	0330,	0331,	0332,	0333,	0334,	0335,	0336,	0337,
210  /* 340 */	0340,	0341,	0342,	0343,	0344,	0345,	0346,	0347,
211  /* 350 */	0350,	0351,	0352,	0353,	0354,	0355,	0356,	0357,
212  /* 360 */	0360,	0361,	0362,	0363,	0364,	0365,	0366,	0367,
213  /*
214   * WARNING: as for above ISO sets, \377 may be used.  Translate it to
215   * itself.
216   */
217  /* 370 */	0370,	0371,	0372,	0373,	0374,	0375,	0376,	0377,
218  };
219  
220  /*
221   * Translation table for output with OLCUC.  All ORDINARY-class characters
222   * translate to themselves, except for lower-case letters which translate
223   * to their upper-case equivalents.  All other characters have a zero in
224   * the table, which stops the copying.
225   */
226  static unsigned char lcuctab[256] = {
227  /* 000 */	0,	0,	0,	0,	0,	0,	0,	0,
228  /* 010 */	0,	0,	0,	0,	0,	0,	0,	0,
229  /* 020 */	0,	0,	0,	0,	0,	0,	0,	0,
230  /* 030 */	0,	0,	0,	0,	0,	0,	0,	0,
231  /* 040 */	' ',	'!',	'"',	'#',	'$',	'%',	'&',	'\'',
232  /* 050 */	'(',	')',	'*',	'+',	',',	'-',	'.',	'/',
233  /* 060 */	'0',	'1',	'2',	'3',	'4',	'5',	'6',	'7',
234  /* 070 */	'8',	'9',	':',	';',	'<',	'=',	'>',	'?',
235  /* 100 */	'@',	'A',	'B',	'C',	'D',	'E',	'F',	'G',
236  /* 110 */	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
237  /* 120 */	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
238  /* 130 */	'X',	'Y',	'Z',	'[',	'\\',	']',	'^',	'_',
239  /* 140 */	'`',	'A',	'B',	'C',	'D',	'E',	'F',	'G',
240  /* 150 */	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
241  /* 160 */	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
242  /* 170 */	'X',	'Y',	'Z',	'{',	'|',	'}',	'~',	0,
243  /* 200 */	0,	0,	0,	0,	0,	0,	0,	0,
244  /* 210 */	0,	0,	0,	0,	0,	0,	0,	0,
245  /* 220 */	0,	0,	0,	0,	0,	0,	0,	0,
246  /* 230 */	0,	0,	0,	0,	0,	0,	0,	0,
247  /* 240 */	0240,	0241,	0242,	0243,	0244,	0245,	0246,	0247,
248  /* 250 */	0250,	0251,	0252,	0253,	0254,	0255,	0256,	0257,
249  /* 260 */	0260,	0261,	0262,	0263,	0264,	0265,	0266,	0267,
250  /* 270 */	0270,	0271,	0272,	0273,	0274,	0275,	0276,	0277,
251  /* 300 */	0300,	0301,	0302,	0303,	0304,	0305,	0306,	0307,
252  /* 310 */	0310,	0311,	0312,	0313,	0314,	0315,	0316,	0317,
253  /* 320 */	0320,	0321,	0322,	0323,	0324,	0325,	0326,	0327,
254  /* 330 */	0330,	0331,	0332,	0333,	0334,	0335,	0336,	0337,
255  /* 340 */	0340,	0341,	0342,	0343,	0344,	0345,	0346,	0347,
256  /* 350 */	0350,	0351,	0352,	0353,	0354,	0355,	0356,	0357,
257  /* 360 */	0360,	0361,	0362,	0363,	0364,	0365,	0366,	0367,
258  /*
259   * WARNING: as for above ISO sets, \377 may be used.  Translate it to
260   * itself.
261   */
262  /* 370 */	0370,	0371,	0372,	0373,	0374,	0375,	0376,	0377,
263  };
264  
265  /*
266   * Input mapping table -- if an entry is non-zero, and XCASE is set,
267   * when the corresponding character is typed preceded by "\" the escape
268   * sequence is replaced by the table value.  Mostly used for
269   * upper-case only terminals.
270   */
271  static char	imaptab[256] = {
272  /* 000 */	0,	0,	0,	0,	0,	0,	0,	0,
273  /* 010 */	0,	0,	0,	0,	0,	0,	0,	0,
274  /* 020 */	0,	0,	0,	0,	0,	0,	0,	0,
275  /* 030 */	0,	0,	0,	0,	0,	0,	0,	0,
276  /* 040 */	0,	'|',	0,	0,	0,	0,	0,	'`',
277  /* 050 */	'{',	'}',	0,	0,	0,	0,	0,	0,
278  /* 060 */	0,	0,	0,	0,	0,	0,	0,	0,
279  /* 070 */	0,	0,	0,	0,	0,	0,	0,	0,
280  /* 100 */	0,	0,	0,	0,	0,	0,	0,	0,
281  /* 110 */	0,	0,	0,	0,	0,	0,	0,	0,
282  /* 120 */	0,	0,	0,	0,	0,	0,	0,	0,
283  /* 130 */	0,	0,	0,	0,	'\\',	0,	'~',	0,
284  /* 140 */	0,	'A',	'B',	'C',	'D',	'E',	'F',	'G',
285  /* 150 */	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
286  /* 160 */	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
287  /* 170 */	'X',	'Y',	'Z',	0,	0,	0,	0,	0,
288  /* 200-377 aren't mapped */
289  };
290  
291  /*
292   * Output mapping table -- if an entry is non-zero, and XCASE is set,
293   * the corresponding character is printed as "\" followed by the table
294   * value.  Mostly used for upper-case only terminals.
295   */
296  static char	omaptab[256] = {
297  /* 000 */	0,	0,	0,	0,	0,	0,	0,	0,
298  /* 010 */	0,	0,	0,	0,	0,	0,	0,	0,
299  /* 020 */	0,	0,	0,	0,	0,	0,	0,	0,
300  /* 030 */	0,	0,	0,	0,	0,	0,	0,	0,
301  /* 040 */	0,	0,	0,	0,	0,	0,	0,	0,
302  /* 050 */	0,	0,	0,	0,	0,	0,	0,	0,
303  /* 060 */	0,	0,	0,	0,	0,	0,	0,	0,
304  /* 070 */	0,	0,	0,	0,	0,	0,	0,	0,
305  /* 100 */	0,	'A',	'B',	'C',	'D',	'E',	'F',	'G',
306  /* 110 */	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
307  /* 120 */	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
308  /* 130 */	'X',	'Y',	'Z',	0,	0,	0,	0,	0,
309  /* 140 */	'\'',	0,	0,	0,	0,	0,	0,	0,
310  /* 150 */	0,	0,	0,	0,	0,	0,	0,	0,
311  /* 160 */	0,	0,	0,	0,	0,	0,	0,	0,
312  /* 170 */	0,	0,	0,	'(',	'!',	')',	'^',	0,
313  /* 200-377 aren't mapped */
314  };
315  
316  /*
317   * Translation table for TS_MEUC output without OLCUC.  All printing ASCII
318   * characters translate to themselves.  All other _bytes_ have a zero in
319   * the table, which stops the copying.  This and the following table exist
320   * only so we can use the existing movtuc processing with or without OLCUC.
321   * Maybe it speeds up something...because we can copy a block of characters
322   * by only looking for zeros in the table.
323   *
324   * If we took the simple expedient of DISALLOWING "olcuc" with multi-byte
325   * processing, we could rid ourselves of both these tables and save 512 bytes;
326   * seriously, it doesn't make much sense to use olcuc with multi-byte, and
327   * it will probably never be used.  Consideration should be given to disallowing
328   * the combination TS_MEUC & OLCUC.
329   */
330  static unsigned char enotrantab[256] = {
331  /* 000 */	0,	0,	0,	0,	0,	0,	0,	0,
332  /* 010 */	0,	0,	0,	0,	0,	0,	0,	0,
333  /* 020 */	0,	0,	0,	0,	0,	0,	0,	0,
334  /* 030 */	0,	0,	0,	0,	0,	0,	0,	0,
335  /* 040 */	' ',	'!',	'"',	'#',	'$',	'%',	'&',	'\'',
336  /* 050 */	'(',	')',	'*',	'+',	',',	'-',	'.',	'/',
337  /* 060 */	'0',	'1',	'2',	'3',	'4',	'5',	'6',	'7',
338  /* 070 */	'8',	'9',	':',	';',	'<',	'=',	'>',	'?',
339  /* 100 */	'@',	'A',	'B',	'C',	'D',	'E',	'F',	'G',
340  /* 110 */	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
341  /* 120 */	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
342  /* 130 */	'X',	'Y',	'Z',	'[',	'\\',	']',	'^',	'_',
343  /* 140 */	'`',	'a',	'b',	'c',	'd',	'e',	'f',	'g',
344  /* 150 */	'h',	'i',	'j',	'k',	'l',	'm',	'n',	'o',
345  /* 160 */	'p',	'q',	'r',	's',	't',	'u',	'v',	'w',
346  /* 170 */	'x',	'y',	'z',	'{',	'|',	'}',	'~',	0,
347  /* 200 - 377 aren't mapped (they're stoppers). */
348  };
349  
350  /*
351   * Translation table for TS_MEUC output with OLCUC.  All printing ASCII
352   * translate to themselves, except for lower-case letters which translate
353   * to their upper-case equivalents.  All other bytes have a zero in
354   * the table, which stops the copying.  Useless for ISO Latin Alphabet
355   * translations, but *sigh* OLCUC is really only defined for ASCII anyway.
356   * We only have this table so we can use the existing OLCUC processing with
357   * TS_MEUC set (multi-byte mode).  Nobody would ever think of actually
358   * _using_ it...would they?
359   */
360  static unsigned char elcuctab[256] = {
361  /* 000 */	0,	0,	0,	0,	0,	0,	0,	0,
362  /* 010 */	0,	0,	0,	0,	0,	0,	0,	0,
363  /* 020 */	0,	0,	0,	0,	0,	0,	0,	0,
364  /* 030 */	0,	0,	0,	0,	0,	0,	0,	0,
365  /* 040 */	' ',	'!',	'"',	'#',	'$',	'%',	'&',	'\'',
366  /* 050 */	'(',	')',	'*',	'+',	',',	'-',	'.',	'/',
367  /* 060 */	'0',	'1',	'2',	'3',	'4',	'5',	'6',	'7',
368  /* 070 */	'8',	'9',	':',	';',	'<',	'=',	'>',	'?',
369  /* 100 */	'@',	'A',	'B',	'C',	'D',	'E',	'F',	'G',
370  /* 110 */	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
371  /* 120 */	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
372  /* 130 */	'X',	'Y',	'Z',	'[',	'\\',	']',	'^',	'_',
373  /* 140 */	'`',	'A',	'B',	'C',	'D',	'E',	'F',	'G',
374  /* 150 */	'H',	'I',	'J',	'K',	'L',	'M',	'N',	'O',
375  /* 160 */	'P',	'Q',	'R',	'S',	'T',	'U',	'V',	'W',
376  /* 170 */	'X',	'Y',	'Z',	'{',	'|',	'}',	'~',	0,
377  /* 200 - 377 aren't mapped (they're stoppers). */
378  };
379  
380  static struct streamtab ldtrinfo;
381  
382  static struct fmodsw fsw = {
383  	"ldterm",
384  	&ldtrinfo,
385  	D_MTQPAIR | D_MP | _D_SINGLE_INSTANCE
386  };
387  
388  static struct modlstrmod modlstrmod = {
389  	&mod_strmodops, "terminal line discipline", &fsw
390  };
391  
392  
393  static struct modlinkage modlinkage = {
394  	MODREV_1, &modlstrmod, NULL
395  };
396  
397  
398  int
_init(void)399  _init(void)
400  {
401  	return (mod_install(&modlinkage));
402  }
403  
404  int
_fini(void)405  _fini(void)
406  {
407  	return (mod_remove(&modlinkage));
408  }
409  
410  int
_info(struct modinfo * modinfop)411  _info(struct modinfo *modinfop)
412  {
413  	return (mod_info(&modlinkage, modinfop));
414  }
415  
416  
417  static int	ldtermopen(queue_t *, dev_t *, int, int, cred_t *);
418  static int	ldtermclose(queue_t *, int, cred_t *);
419  static int	ldtermrput(queue_t *, mblk_t *);
420  static int	ldtermrsrv(queue_t *);
421  static int	ldtermrmsg(queue_t *, mblk_t *);
422  static int	ldtermwput(queue_t *, mblk_t *);
423  static int	ldtermwsrv(queue_t *);
424  static int	ldtermwmsg(queue_t *, mblk_t *);
425  static mblk_t	*ldterm_docanon(unsigned char, mblk_t *, size_t, queue_t *,
426  				ldtermstd_state_t *, int *);
427  static int	ldterm_unget(ldtermstd_state_t *);
428  static void	ldterm_trim(ldtermstd_state_t *);
429  static void	ldterm_rubout(unsigned char, queue_t *, size_t,
430  				ldtermstd_state_t *);
431  static int	ldterm_tabcols(ldtermstd_state_t *);
432  static void	ldterm_erase(queue_t *, size_t, ldtermstd_state_t *);
433  static void	ldterm_werase(queue_t *, size_t, ldtermstd_state_t *);
434  static void	ldterm_kill(queue_t *, size_t, ldtermstd_state_t *);
435  static void	ldterm_reprint(queue_t *, size_t, ldtermstd_state_t *);
436  static mblk_t	*ldterm_dononcanon(mblk_t *, mblk_t *, size_t, queue_t *,
437  					ldtermstd_state_t *);
438  static int	ldterm_echo(unsigned char, queue_t *, size_t,
439  				ldtermstd_state_t *);
440  static void	ldterm_outchar(unsigned char, queue_t *, size_t,
441  				ldtermstd_state_t *);
442  static void	ldterm_outstring(unsigned char *, int, queue_t *, size_t,
443  					ldtermstd_state_t *tp);
444  static mblk_t	*newmsg(ldtermstd_state_t *);
445  static void	ldterm_msg_upstream(queue_t *, ldtermstd_state_t *);
446  static void	ldterm_wenable(void *);
447  static mblk_t	*ldterm_output_msg(queue_t *, mblk_t *, mblk_t **,
448  				ldtermstd_state_t *, size_t, int);
449  static void	ldterm_flush_output(unsigned char, queue_t *,
450  					ldtermstd_state_t *);
451  static void	ldterm_dosig(queue_t *, int, unsigned char, int, int);
452  static void	ldterm_do_ioctl(queue_t *, mblk_t *);
453  static int	chgstropts(struct termios *, ldtermstd_state_t *, queue_t *);
454  static void	ldterm_ioctl_reply(queue_t *, mblk_t *);
455  static void	vmin_satisfied(queue_t *, ldtermstd_state_t *, int);
456  static void	vmin_settimer(queue_t *);
457  static void	vmin_timed_out(void *);
458  static void	ldterm_adjust_modes(ldtermstd_state_t *);
459  static void	ldterm_eucwarn(ldtermstd_state_t *);
460  static void	cp_eucwioc(eucioc_t *, eucioc_t *, int);
461  static int	ldterm_codeset(uchar_t, uchar_t);
462  
463  static void	ldterm_csi_erase(queue_t *, size_t, ldtermstd_state_t *);
464  static void	ldterm_csi_werase(queue_t *, size_t, ldtermstd_state_t *);
465  
466  static uchar_t	ldterm_utf8_width(uchar_t *, int);
467  
468  /* Codeset type specific methods for EUC, PCCS, and, UTF-8 codeset types. */
469  static int	__ldterm_dispwidth_euc(uchar_t, void *, int);
470  static int	__ldterm_memwidth_euc(uchar_t, void *);
471  
472  static int	__ldterm_dispwidth_pccs(uchar_t, void *, int);
473  static int	__ldterm_memwidth_pccs(uchar_t, void *);
474  
475  static int	__ldterm_dispwidth_utf8(uchar_t, void *, int);
476  static int	__ldterm_memwidth_utf8(uchar_t, void *);
477  
478  static const ldterm_cs_methods_t cs_methods[LDTERM_CS_TYPE_MAX + 1] = {
479  	{
480  		NULL,
481  		NULL
482  	},
483  	{
484  		__ldterm_dispwidth_euc,
485  		__ldterm_memwidth_euc
486  	},
487  	{
488  		__ldterm_dispwidth_pccs,
489  		__ldterm_memwidth_pccs
490  	},
491  	{
492  		__ldterm_dispwidth_utf8,
493  		__ldterm_memwidth_utf8
494  	}
495  };
496  
497  /*
498   * The default codeset is presumably C locale's ISO 646 in EUC but
499   * the data structure at below defined as the default codeset data also
500   * support any single byte (EUC) locales.
501   */
502  static const ldterm_cs_data_t default_cs_data = {
503  	LDTERM_DATA_VERSION,
504  	LDTERM_CS_TYPE_EUC,
505  	(uchar_t)0,
506  	(uchar_t)0,
507  	(char *)NULL,
508  	{
509  		'\0', '\0', '\0', '\0',
510  		'\0', '\0', '\0', '\0',
511  		'\0', '\0', '\0', '\0',
512  		'\0', '\0', '\0', '\0',
513  		'\0', '\0', '\0', '\0',
514  		'\0', '\0', '\0', '\0',
515  		'\0', '\0', '\0', '\0',
516  		'\0', '\0', '\0', '\0',
517  		'\0', '\0', '\0', '\0',
518  		'\0', '\0', '\0', '\0'
519  	}
520  };
521  
522  /*
523   * The following tables are from either u8_textprep.c or uconv.c at
524   * usr/src/common/unicode/. The tables are used to figure out corresponding
525   * UTF-8 character byte lengths and also the validity of given character bytes.
526   */
527  extern const int8_t u8_number_of_bytes[];
528  extern const uchar_t u8_masks_tbl[];
529  extern const uint8_t u8_valid_min_2nd_byte[];
530  extern const uint8_t u8_valid_max_2nd_byte[];
531  
532  /*
533   * Unicode character width definition tables from uwidth.c:
534   */
535  extern const ldterm_unicode_data_cell_t ldterm_ucode[][16384];
536  
537  #ifdef LDDEBUG
538  int	ldterm_debug = 0;
539  #define	DEBUG1(a)	if (ldterm_debug == 1) printf a
540  #define	DEBUG2(a)	if (ldterm_debug >= 2) printf a	/* allocations */
541  #define	DEBUG3(a)	if (ldterm_debug >= 3) printf a	/* M_CTL Stuff */
542  #define	DEBUG4(a)	if (ldterm_debug >= 4) printf a	/* M_READ Stuff */
543  #define	DEBUG5(a)	if (ldterm_debug >= 5) printf a
544  #define	DEBUG6(a)	if (ldterm_debug >= 6) printf a
545  #define	DEBUG7(a)	if (ldterm_debug >= 7) printf a
546  #else
547  #define	DEBUG1(a)
548  #define	DEBUG2(a)
549  #define	DEBUG3(a)
550  #define	DEBUG4(a)
551  #define	DEBUG5(a)
552  #define	DEBUG6(a)
553  #define	DEBUG7(a)
554  #endif		/* LDDEBUG */
555  
556  
557  /*
558   * Since most of the buffering occurs either at the stream head or in
559   * the "message currently being assembled" buffer, we have a
560   * relatively small input queue, so that blockages above us get
561   * reflected fairly quickly to the module below us.  We also have a
562   * small maximum packet size, since you can put a message of that
563   * size on an empty queue no matter how much bigger than the high
564   * water mark it is.
565   */
566  static struct module_info ldtermmiinfo = {
567  	0x0bad,
568  	"ldterm",
569  	0,
570  	_TTY_BUFSIZ,
571  	_TTY_BUFSIZ,
572  	LOWAT
573  };
574  
575  
576  static struct qinit ldtermrinit = {
577  	ldtermrput,
578  	ldtermrsrv,
579  	ldtermopen,
580  	ldtermclose,
581  	NULL,
582  	&ldtermmiinfo
583  };
584  
585  
586  static struct module_info ldtermmoinfo = {
587  	0x0bad,
588  	"ldterm",
589  	0,
590  	INFPSZ,
591  	1,
592  	0
593  };
594  
595  
596  static struct qinit ldtermwinit = {
597  	ldtermwput,
598  	ldtermwsrv,
599  	ldtermopen,
600  	ldtermclose,
601  	NULL,
602  	&ldtermmoinfo
603  };
604  
605  
606  static struct streamtab ldtrinfo = {
607  	&ldtermrinit,
608  	&ldtermwinit,
609  	NULL,
610  	NULL
611  };
612  
613  /*
614   * Dummy qbufcall callback routine used by open and close.
615   * The framework will wake up qwait_sig when we return from
616   * this routine (as part of leaving the perimeters.)
617   * (The framework enters the perimeters before calling the qbufcall() callback
618   * and leaves the perimeters after the callback routine has executed. The
619   * framework performs an implicit wakeup of any thread in qwait/qwait_sig
620   * when it leaves the perimeter. See qwait(9F).)
621   */
622  /* ARGSUSED */
623  static void
dummy_callback(void * arg)624  dummy_callback(void *arg)
625  {}
626  
627  
628  static mblk_t *
open_ioctl(queue_t * q,uint_t cmd)629  open_ioctl(queue_t *q, uint_t cmd)
630  {
631  	mblk_t *mp;
632  	bufcall_id_t id;
633  	int retv;
634  
635  	while ((mp = mkiocb(cmd)) == NULL) {
636  		id = qbufcall(q, sizeof (struct iocblk), BPRI_MED,
637  		    dummy_callback, NULL);
638  		retv = qwait_sig(q);
639  		qunbufcall(q, id);
640  		if (retv == 0)
641  			break;
642  	}
643  	return (mp);
644  }
645  
646  static mblk_t *
open_mblk(queue_t * q,size_t len)647  open_mblk(queue_t *q, size_t len)
648  {
649  	mblk_t *mp;
650  	bufcall_id_t id;
651  	int retv;
652  
653  	while ((mp = allocb(len, BPRI_MED)) == NULL) {
654  		id = qbufcall(q, len, BPRI_MED, dummy_callback, NULL);
655  		retv = qwait_sig(q);
656  		qunbufcall(q, id);
657  		if (retv == 0)
658  			break;
659  	}
660  	return (mp);
661  }
662  
663  /*
664   * Line discipline open.
665   */
666  /* ARGSUSED1 */
667  static int
ldtermopen(queue_t * q,dev_t * devp,int oflag,int sflag,cred_t * crp)668  ldtermopen(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *crp)
669  {
670  	ldtermstd_state_t *tp;
671  	mblk_t *bp, *qryp;
672  	int len;
673  	struct stroptions *strop;
674  	struct termios *termiosp;
675  	queue_t *wq;
676  
677  	if (q->q_ptr != NULL) {
678  		return (0);	/* already attached */
679  	}
680  
681  	tp = (ldtermstd_state_t *)kmem_zalloc(sizeof (ldtermstd_state_t),
682  	    KM_SLEEP);
683  
684  	/*
685  	 * Get termios defaults.  These are stored as
686  	 * a property in the "options" node.
687  	 */
688  	if (ddi_getlongprop(DDI_DEV_T_ANY, ddi_root_node(), DDI_PROP_NOTPROM,
689  	    "ttymodes", (caddr_t)&termiosp, &len) == DDI_PROP_SUCCESS &&
690  	    len == sizeof (struct termios)) {
691  		tp->t_modes = *termiosp;
692  		tp->t_amodes = *termiosp;
693  		kmem_free(termiosp, len);
694  	} else {
695  		/*
696  		 * Gack!  Whine about it.
697  		 */
698  		cmn_err(CE_WARN, "ldterm: Couldn't get ttymodes property!");
699  	}
700  	bzero(&tp->t_dmodes, sizeof (struct termios));
701  
702  	tp->t_state = 0;
703  
704  	tp->t_line = 0;
705  	tp->t_col = 0;
706  
707  	tp->t_rocount = 0;
708  	tp->t_rocol = 0;
709  
710  	tp->t_message = NULL;
711  	tp->t_endmsg = NULL;
712  	tp->t_msglen = 0;
713  	tp->t_rd_request = 0;
714  
715  	tp->t_echomp = NULL;
716  	tp->t_iocid = 0;
717  	tp->t_wbufcid = 0;
718  	tp->t_vtid = 0;
719  
720  	q->q_ptr = (caddr_t)tp;
721  	WR(q)->q_ptr = (caddr_t)tp;
722  	/*
723  	 * The following for EUC and also non-EUC codesets:
724  	 */
725  	tp->t_codeset = tp->t_eucleft = tp->t_eucign = tp->t_scratch_len = 0;
726  	bzero(&tp->eucwioc, EUCSIZE);
727  	tp->eucwioc.eucw[0] = 1;	/* ASCII mem & screen width */
728  	tp->eucwioc.scrw[0] = 1;
729  	tp->t_maxeuc = 1;	/* the max len in bytes of an EUC char */
730  	tp->t_eucp = NULL;
731  	tp->t_csmethods = cs_methods[LDTERM_CS_TYPE_EUC];
732  	tp->t_csdata = default_cs_data;
733  
734  	/*
735  	 * Try to switch to UTF-8 mode by allocating buffer for multibyte
736  	 * chars, keep EUC if allocation fails.
737  	 */
738  	if ((tp->t_eucp_mp = allocb(_TTY_BUFSIZ, BPRI_HI)) != NULL) {
739  		tp->t_eucp = tp->t_eucp_mp->b_rptr;
740  		tp->t_state = TS_MEUC;	/* Multibyte mode. */
741  		tp->t_maxeuc = 4; /* the max len in bytes of an UTF-8 char */
742  		tp->t_csdata.codeset_type = LDTERM_CS_TYPE_UTF8;
743  		tp->t_csdata.csinfo_num = 4;
744  		/* locale_name needs string length with terminating NUL */
745  		tp->t_csdata.locale_name = (char *)kmem_alloc(6, KM_SLEEP);
746  		(void) strcpy(tp->t_csdata.locale_name, "UTF-8");
747  		tp->t_csmethods = cs_methods[LDTERM_CS_TYPE_UTF8];
748  	}
749  	tp->t_eucwarn = 0;	/* no bad chars seen yet */
750  
751  	qprocson(q);
752  
753  	/*
754  	 * Find out if the module below us does canonicalization; if
755  	 * so, we won't do it ourselves.
756  	 */
757  
758  	if ((qryp = open_ioctl(q, MC_CANONQUERY)) == NULL)
759  		goto open_abort;
760  
761  	/*
762  	 * Reformulate as an M_CTL message. The actual data will
763  	 * be in the b_cont field.
764  	 */
765  	qryp->b_datap->db_type = M_CTL;
766  	wq = OTHERQ(q);
767  	putnext(wq, qryp);
768  
769  	/* allocate a TCSBRK ioctl in case we'll need it on close */
770  	if ((qryp = open_ioctl(q, TCSBRK)) == NULL)
771  		goto open_abort;
772  	tp->t_drainmsg = qryp;
773  	if ((bp = open_mblk(q, sizeof (int))) == NULL)
774  		goto open_abort;
775  	qryp->b_cont = bp;
776  
777  	/*
778  	 * Find out if the underlying driver supports proper POSIX close
779  	 * semantics.  If not, we'll have to approximate it using TCSBRK.  If
780  	 * it does, it will respond with MC_HAS_POSIX, and we'll catch that in
781  	 * the ldtermrput routine.
782  	 *
783  	 * When the ldterm_drain_limit tunable is set to zero, we behave the
784  	 * same as old ldterm: don't send this new message, and always use
785  	 * TCSBRK during close.
786  	 */
787  	if (ldterm_drain_limit != 0) {
788  		if ((qryp = open_ioctl(q, MC_POSIXQUERY)) == NULL)
789  			goto open_abort;
790  		qryp->b_datap->db_type = M_CTL;
791  		putnext(wq, qryp);
792  	}
793  
794  	/* prepare to clear the water marks on close */
795  	if ((bp = open_mblk(q, sizeof (struct stroptions))) == NULL)
796  		goto open_abort;
797  	tp->t_closeopts = bp;
798  
799  	/*
800  	 * Set the high-water and low-water marks on the stream head
801  	 * to values appropriate for a terminal.  Also set the "vmin"
802  	 * and "vtime" values to 1 and 0, turn on message-nondiscard
803  	 * mode (as we're in ICANON mode), and turn on "old-style
804  	 * NODELAY" mode.
805  	 */
806  	if ((bp = open_mblk(q, sizeof (struct stroptions))) == NULL)
807  		goto open_abort;
808  	strop = (struct stroptions *)bp->b_wptr;
809  	strop->so_flags = SO_READOPT|SO_HIWAT|SO_LOWAT|SO_NDELON|SO_ISTTY;
810  	strop->so_readopt = RMSGN;
811  	strop->so_hiwat = _TTY_BUFSIZ;
812  	strop->so_lowat = LOWAT;
813  	bp->b_wptr += sizeof (struct stroptions);
814  	bp->b_datap->db_type = M_SETOPTS;
815  	putnext(q, bp);
816  
817  	return (0);		/* this can become a controlling TTY */
818  
819  open_abort:
820  	qprocsoff(q);
821  	q->q_ptr = NULL;
822  	WR(q)->q_ptr = NULL;
823  	freemsg(tp->t_closeopts);
824  	freemsg(tp->t_drainmsg);
825  	/* Dump the state structure */
826  	kmem_free(tp, sizeof (ldtermstd_state_t));
827  	return (EINTR);
828  }
829  
830  struct close_timer {
831  	timeout_id_t id;
832  	ldtermstd_state_t *tp;
833  };
834  
835  static void
drain_timed_out(void * arg)836  drain_timed_out(void *arg)
837  {
838  	struct close_timer *ctp = arg;
839  
840  	ctp->id = 0;
841  	ctp->tp->t_state &= ~TS_IOCWAIT;
842  }
843  
844  /* ARGSUSED2 */
845  static int
ldtermclose(queue_t * q,int cflag,cred_t * crp)846  ldtermclose(queue_t *q, int cflag, cred_t *crp)
847  {
848  	ldtermstd_state_t *tp = (ldtermstd_state_t *)q->q_ptr;
849  	struct stroptions *strop;
850  	mblk_t *bp;
851  	struct close_timer cltimer;
852  
853  	/*
854  	 * If we have an outstanding vmin timeout, cancel it.
855  	 */
856  	tp->t_state |= TS_CLOSE;
857  	if (tp->t_vtid != 0)
858  		(void) quntimeout(q, tp->t_vtid);
859  	tp->t_vtid = 0;
860  
861  	/*
862  	 * Cancel outstanding qbufcall request.
863  	 */
864  	if (tp->t_wbufcid != 0)
865  		qunbufcall(q, tp->t_wbufcid);
866  
867  	/*
868  	 * Reset the high-water and low-water marks on the stream
869  	 * head (?), turn on byte-stream mode, and turn off
870  	 * "old-style NODELAY" mode.
871  	 */
872  	bp = tp->t_closeopts;
873  	strop = (struct stroptions *)bp->b_wptr;
874  	strop->so_flags = SO_READOPT|SO_NDELOFF;
875  	strop->so_readopt = RNORM;
876  	bp->b_wptr += sizeof (struct stroptions);
877  	bp->b_datap->db_type = M_SETOPTS;
878  	putnext(q, bp);
879  
880  	if (cflag & (FNDELAY|FNONBLOCK)) {
881  		freemsg(tp->t_drainmsg);
882  	} else if ((bp = tp->t_drainmsg) != NULL) {
883  		struct iocblk *iocb;
884  
885  		/*
886  		 * If the driver isn't known to have POSIX close semantics,
887  		 * then we have to emulate this the old way.  This is done by
888  		 * sending down TCSBRK,1 to drain the output and waiting for
889  		 * the reply.
890  		 */
891  		iocb = (struct iocblk *)bp->b_rptr;
892  		iocb->ioc_count = sizeof (int);
893  		*(int *)bp->b_cont->b_rptr = 1;
894  		bp->b_cont->b_wptr += sizeof (int);
895  		tp->t_state |= TS_IOCWAIT;
896  		tp->t_iocid = iocb->ioc_id;
897  		if (!putq(WR(q), bp))
898  			putnext(WR(q), bp);
899  
900  		/*
901  		 * If we're not able to receive signals at this point, then
902  		 * launch a timer.  This timer will prevent us from waiting
903  		 * forever for a signal that won't arrive.
904  		 */
905  		cltimer.id = 0;
906  		if (!ddi_can_receive_sig() && ldterm_drain_limit != 0) {
907  			cltimer.tp = tp;
908  			cltimer.id = qtimeout(q, drain_timed_out, &cltimer,
909  			    drv_usectohz(ldterm_drain_limit));
910  		}
911  
912  		/*
913  		 * Note that the read side of ldterm and the qtimeout are
914  		 * protected by D_MTQPAIR, so no additional locking is needed
915  		 * here.
916  		 */
917  		while (tp->t_state & TS_IOCWAIT) {
918  			if (qwait_sig(q) == 0)
919  				break;
920  		}
921  		if (cltimer.id != 0)
922  			(void) quntimeout(q, cltimer.id);
923  	}
924  
925  	/*
926  	 * From here to the end, the routine does not sleep and does not
927  	 * reference STREAMS, so it's guaranteed to run to completion.
928  	 */
929  
930  	qprocsoff(q);
931  
932  	freemsg(tp->t_message);
933  	freemsg(tp->t_eucp_mp);
934  
935  	/* Dump the state structure, then unlink it */
936  	if (tp->t_csdata.locale_name != NULL)
937  		kmem_free(tp->t_csdata.locale_name,
938  		    strlen(tp->t_csdata.locale_name) + 1);
939  	kmem_free(tp, sizeof (ldtermstd_state_t));
940  	q->q_ptr = NULL;
941  	return (0);
942  }
943  
944  
945  /*
946   * Put procedure for input from driver end of stream (read queue).
947   */
948  static int
ldtermrput(queue_t * q,mblk_t * mp)949  ldtermrput(queue_t *q, mblk_t *mp)
950  {
951  	ldtermstd_state_t *tp;
952  	unsigned char c;
953  	queue_t *wrq = WR(q);		/* write queue of ldterm mod */
954  	queue_t *nextq = q->q_next;	/* queue below us */
955  	mblk_t *bp;
956  	struct iocblk *qryp;
957  	unsigned char *readp;
958  	unsigned char *writep;
959  	struct termios *emodes;		/* effective modes set by driver */
960  	int dbtype;
961  
962  	tp = (ldtermstd_state_t *)q->q_ptr;
963  	/*
964  	 * We received our ack from the driver saying there is nothing left to
965  	 * shovel out, so wake up the close routine.
966  	 */
967  	dbtype = DB_TYPE(mp);
968  	if ((dbtype == M_IOCACK || dbtype == M_IOCNAK) &&
969  	    (tp->t_state & (TS_CLOSE|TS_IOCWAIT)) == (TS_CLOSE|TS_IOCWAIT)) {
970  		struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
971  
972  		if (iocp->ioc_id == tp->t_iocid) {
973  			tp->t_state &= ~TS_IOCWAIT;
974  			freemsg(mp);
975  			return (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   */
1483  static int
ldtermrsrv(queue_t * q)1484  ldtermrsrv(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   */
1538  static int
ldtermrmsg(queue_t * q,mblk_t * mp)1539  ldtermrmsg(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  	}
1724  echo:
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  
1736  out:
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   */
1747  static mblk_t *
ldterm_docanon(uchar_t c,mblk_t * bpt,size_t ebsize,queue_t * q,ldtermstd_state_t * tp,int * dofreep)1748  ldterm_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  
1905  escaped:
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  
2070  out:
2071  
2072  	return (bpt);
2073  }
2074  
2075  
2076  static int
ldterm_unget(ldtermstd_state_t * tp)2077  ldterm_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  
2090  static void
ldterm_trim(ldtermstd_state_t * tp)2091  ldterm_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   */
2125  static void
ldterm_rubout(uchar_t c,queue_t * q,size_t ebsize,ldtermstd_state_t * tp)2126  ldterm_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   */
2214  static int
ldterm_tabcols(ldtermstd_state_t * tp)2215  ldterm_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  	 */
2388  eucout:
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   */
2401  static void
ldterm_erase(queue_t * q,size_t ebsize,ldtermstd_state_t * tp)2402  ldterm_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   */
2418  static void
ldterm_werase(queue_t * q,size_t ebsize,ldtermstd_state_t * tp)2419  ldterm_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   */
2464  static void
ldterm_csi_werase(queue_t * q,size_t ebsize,ldtermstd_state_t * tp)2465  ldterm_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  
2560  static void
ldterm_kill(queue_t * q,size_t ebsize,ldtermstd_state_t * tp)2561  ldterm_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   */
2638  static void
ldterm_reprint(queue_t * q,size_t ebsize,ldtermstd_state_t * tp)2639  ldterm_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   */
2665  static mblk_t *
ldterm_dononcanon(mblk_t * bp,mblk_t * bpt,size_t ebsize,queue_t * q,ldtermstd_state_t * tp)2666  ldterm_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   */
2867  static int
ldterm_echo(uchar_t c,queue_t * q,size_t ebsize,ldtermstd_state_t * tp)2868  ldterm_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   */
2911  static void
ldterm_outchar(uchar_t c,queue_t * q,size_t bsize,ldtermstd_state_t * tp)2912  ldterm_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   */
2966  static void
ldterm_outstring(uchar_t * cp,int len,queue_t * q,size_t bsize,ldtermstd_state_t * tp)2967  ldterm_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  
2977  static mblk_t *
newmsg(ldtermstd_state_t * tp)2978  newmsg(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  
2998  static void
ldterm_msg_upstream(queue_t * q,ldtermstd_state_t * tp)2999  ldterm_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   */
3033  static void
ldterm_wenable(void * addr)3034  ldterm_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   */
3055  static int
ldtermwput(queue_t * q,mblk_t * mp)3056  ldtermwput(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   */
3266  static int
ldtermwsrv(queue_t * q)3267  ldtermwsrv(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   */
3311  static int
ldtermwmsg(queue_t * q,mblk_t * mp)3312  ldtermwmsg(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   */
3404  static mblk_t *
ldterm_output_msg(queue_t * q,mblk_t * imp,mblk_t ** omp,ldtermstd_state_t * tp,size_t bsize,int echoing)3405  ldterm_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  
3985  outofbufs:
3986  	return (ibp);
3987  #undef NEW_BLOCK
3988  }
3989  
3990  
3991  #if !defined(__sparc)
3992  int
movtuc(size_t size,unsigned char * from,unsigned char * origto,unsigned char * table)3993  movtuc(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  
4007  static void
ldterm_flush_output(uchar_t c,queue_t * q,ldtermstd_state_t * tp)4008  ldterm_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   */
4034  static void
ldterm_dosig(queue_t * q,int sig,uchar_t c,int mtype,int mode)4035  ldterm_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   */
4106  static void
ldterm_do_ioctl(queue_t * q,mblk_t * mp)4107  ldterm_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   */
4800  static int
chgstropts(struct termios * oldmodep,ldtermstd_state_t * tp,queue_t * q)4801  chgstropts(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   */
4864  static void
ldterm_ioctl_reply(queue_t * q,mblk_t * mp)4865  ldterm_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   */
4927  static void
vmin_satisfied(queue_t * q,ldtermstd_state_t * tp,int sendup)4928  vmin_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  
4955  static void
vmin_settimer(queue_t * q)4956  vmin_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   */
4994  static void
vmin_timed_out(void * arg)4995  vmin_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  
5022  static void
ldterm_adjust_modes(ldtermstd_state_t * tp)5023  ldterm_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   */
5050  static void
ldterm_csi_erase(queue_t * q,size_t ebsize,ldtermstd_state_t * tp)5051  ldterm_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   */
5127  static void
ldterm_eucwarn(ldtermstd_state_t * tp)5128  ldterm_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   */
5155  static void
cp_eucwioc(eucioc_t * from,eucioc_t * to,int dir)5156  cp_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  
5183  static int
ldterm_codeset(uchar_t codeset_type,uchar_t c)5184  ldterm_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   */
5219  static int
__ldterm_dispwidth_euc(uchar_t c,void * p,int mode)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   */
5261  static int
__ldterm_memwidth_euc(uchar_t c,void * p)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. */
5280  static int
__ldterm_dispwidth_pccs(uchar_t c,void * p,int mode)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  
5318  static int
__ldterm_memwidth_pccs(uchar_t c,void * p)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. */
5340  static int
__ldterm_dispwidth_utf8(uchar_t c,void * p,int mode)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  
5383  static int
__ldterm_memwidth_utf8(uchar_t c,void * p)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  
5405  static uchar_t
ldterm_utf8_width(uchar_t * u8,int length)5406  ldterm_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