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