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