blob: ff36dab9488dfad59b2d3a0631aaa3c02132d489 [file] [log] [blame]
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
is85bb5f12008-07-02 17:06:30 -07005 * Common Development and Distribution License (the "License").
6 * You may not use this file except in compliance with the License.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07007 *
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/*
is85bb5f12008-07-02 17:06:30 -070022 * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070023 * Use is subject to license terms.
Robert Mustacchi19d32b92013-12-05 01:26:55 +000024 * Copyright (c) 2014, Joyent, Inc. All rights reserved.
Andy Fiddaman6cfa0a72018-05-30 00:15:35 +000025 * Copyright 2018 OmniOS Community Edition (OmniOSce) Association.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070026 */
27
28/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
29/* All Rights Reserved */
30
31/*
32 * University Copyright- Copyright (c) 1982, 1986, 1988
33 * The Regents of the University of California
34 * All Rights Reserved
35 *
36 * University Acknowledgment- Portions of this document are derived from
37 * software developed by the University of California, Berkeley, and its
38 * contributors.
39 */
40
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -070041/*
42 * Standard Streams Terminal Line Discipline module.
43 */
44
45#include <sys/param.h>
46#include <sys/types.h>
47#include <sys/termio.h>
48#include <sys/stream.h>
49#include <sys/conf.h>
50#include <sys/stropts.h>
51#include <sys/strsubr.h>
52#include <sys/strsun.h>
53#include <sys/strtty.h>
54#include <sys/signal.h>
55#include <sys/file.h>
56#include <sys/errno.h>
57#include <sys/debug.h>
58#include <sys/cmn_err.h>
59#include <sys/euc.h>
60#include <sys/eucioctl.h>
61#include <sys/csiioctl.h>
62#include <sys/ptms.h>
63#include <sys/ldterm.h>
64#include <sys/cred.h>
65#include <sys/ddi.h>
66#include <sys/sunddi.h>
67#include <sys/kmem.h>
68#include <sys/modctl.h>
69
70/* Time limit when draining during a close(9E) invoked by exit(2) */
71/* Can be set to zero to emulate the old, broken behavior */
72int ldterm_drain_limit = 15000000;
73
74/*
75 * Character types.
76 */
77#define ORDINARY 0
78#define CONTROL 1
79#define BACKSPACE 2
80#define NEWLINE 3
81#define TAB 4
82#define VTAB 5
83#define RETURN 6
84
85/*
86 * The following for EUC handling:
87 */
88#define T_SS2 7
89#define T_SS3 8
90
91/*
92 * Table indicating character classes to tty driver. In particular,
93 * if the class is ORDINARY, then the character needs no special
94 * processing on output.
95 *
96 * Characters in the C1 set are all considered CONTROL; this will
97 * work with terminals that properly use the ANSI/ISO extensions,
98 * but might cause distress with terminals that put graphics in
99 * the range 0200-0237. On the other hand, characters in that
100 * range cause even greater distress to other UNIX terminal drivers....
101 */
102
103static char typetab[256] = {
104/* 000 */ CONTROL, CONTROL, CONTROL, CONTROL,
105/* 004 */ CONTROL, CONTROL, CONTROL, CONTROL,
106/* 010 */ BACKSPACE, TAB, NEWLINE, CONTROL,
107/* 014 */ VTAB, RETURN, CONTROL, CONTROL,
108/* 020 */ CONTROL, CONTROL, CONTROL, CONTROL,
109/* 024 */ CONTROL, CONTROL, CONTROL, CONTROL,
110/* 030 */ CONTROL, CONTROL, CONTROL, CONTROL,
111/* 034 */ CONTROL, CONTROL, CONTROL, CONTROL,
112/* 040 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
113/* 044 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
114/* 050 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
115/* 054 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
116/* 060 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
117/* 064 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
118/* 070 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
119/* 074 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
120/* 100 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
121/* 104 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
122/* 110 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
123/* 114 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
124/* 120 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
125/* 124 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
126/* 130 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
127/* 134 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
128/* 140 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
129/* 144 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
130/* 150 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
131/* 154 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
132/* 160 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
133/* 164 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
134/* 170 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
135/* 174 */ ORDINARY, ORDINARY, ORDINARY, CONTROL,
136/* 200 */ CONTROL, CONTROL, CONTROL, CONTROL,
137/* 204 */ CONTROL, CONTROL, T_SS2, T_SS3,
138/* 210 */ CONTROL, CONTROL, CONTROL, CONTROL,
139/* 214 */ CONTROL, CONTROL, CONTROL, CONTROL,
140/* 220 */ CONTROL, CONTROL, CONTROL, CONTROL,
141/* 224 */ CONTROL, CONTROL, CONTROL, CONTROL,
142/* 230 */ CONTROL, CONTROL, CONTROL, CONTROL,
143/* 234 */ CONTROL, CONTROL, CONTROL, CONTROL,
144/* 240 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
145/* 244 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
146/* 250 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
147/* 254 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
148/* 260 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
149/* 264 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
150/* 270 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
151/* 274 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
152/* 300 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
153/* 304 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
154/* 310 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
155/* 314 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
156/* 320 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
157/* 324 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
158/* 330 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
159/* 334 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
160/* 340 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
161/* 344 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
162/* 350 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
163/* 354 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
164/* 360 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
165/* 364 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
166/* 370 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
167/*
168 * WARNING: For EUC, 0xFF must be an ordinary character. It is used with
169 * single-byte EUC in some of the "ISO Latin Alphabet" codesets, and occupies
170 * a screen position; in those ISO sets where that position isn't used, it
171 * shouldn't make any difference.
172 */
173/* 374 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
174};
175
176/*
177 * Translation table for output without OLCUC. All ORDINARY-class characters
178 * translate to themselves. All other characters have a zero in the table,
179 * which stops the copying.
180 */
181static unsigned char notrantab[256] = {
182/* 000 */ 0, 0, 0, 0, 0, 0, 0, 0,
183/* 010 */ 0, 0, 0, 0, 0, 0, 0, 0,
184/* 020 */ 0, 0, 0, 0, 0, 0, 0, 0,
185/* 030 */ 0, 0, 0, 0, 0, 0, 0, 0,
186/* 040 */ ' ', '!', '"', '#', '$', '%', '&', '\'',
187/* 050 */ '(', ')', '*', '+', ',', '-', '.', '/',
188/* 060 */ '0', '1', '2', '3', '4', '5', '6', '7',
189/* 070 */ '8', '9', ':', ';', '<', '=', '>', '?',
190/* 100 */ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
191/* 110 */ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
192/* 120 */ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
193/* 130 */ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
194/* 140 */ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
195/* 150 */ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
196/* 160 */ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
197/* 170 */ 'x', 'y', 'z', '{', '|', '}', '~', 0,
198/* 200 */ 0, 0, 0, 0, 0, 0, 0, 0,
199/* 210 */ 0, 0, 0, 0, 0, 0, 0, 0,
200/* 220 */ 0, 0, 0, 0, 0, 0, 0, 0,
201/* 230 */ 0, 0, 0, 0, 0, 0, 0, 0,
202/* 240 */ 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
203/* 250 */ 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
204/* 260 */ 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
205/* 270 */ 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
206/* 300 */ 0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
207/* 310 */ 0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
208/* 320 */ 0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
209/* 330 */ 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
210/* 340 */ 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
211/* 350 */ 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
212/* 360 */ 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
213/*
214 * WARNING: as for above ISO sets, \377 may be used. Translate it to
215 * itself.
216 */
217/* 370 */ 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377,
218};
219
220/*
221 * Translation table for output with OLCUC. All ORDINARY-class characters
222 * translate to themselves, except for lower-case letters which translate
223 * to their upper-case equivalents. All other characters have a zero in
224 * the table, which stops the copying.
225 */
226static unsigned char lcuctab[256] = {
227/* 000 */ 0, 0, 0, 0, 0, 0, 0, 0,
228/* 010 */ 0, 0, 0, 0, 0, 0, 0, 0,
229/* 020 */ 0, 0, 0, 0, 0, 0, 0, 0,
230/* 030 */ 0, 0, 0, 0, 0, 0, 0, 0,
231/* 040 */ ' ', '!', '"', '#', '$', '%', '&', '\'',
232/* 050 */ '(', ')', '*', '+', ',', '-', '.', '/',
233/* 060 */ '0', '1', '2', '3', '4', '5', '6', '7',
234/* 070 */ '8', '9', ':', ';', '<', '=', '>', '?',
235/* 100 */ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
236/* 110 */ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
237/* 120 */ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
238/* 130 */ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
239/* 140 */ '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
240/* 150 */ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
241/* 160 */ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
242/* 170 */ 'X', 'Y', 'Z', '{', '|', '}', '~', 0,
243/* 200 */ 0, 0, 0, 0, 0, 0, 0, 0,
244/* 210 */ 0, 0, 0, 0, 0, 0, 0, 0,
245/* 220 */ 0, 0, 0, 0, 0, 0, 0, 0,
246/* 230 */ 0, 0, 0, 0, 0, 0, 0, 0,
247/* 240 */ 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
248/* 250 */ 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
249/* 260 */ 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
250/* 270 */ 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
251/* 300 */ 0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
252/* 310 */ 0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
253/* 320 */ 0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
254/* 330 */ 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
255/* 340 */ 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
256/* 350 */ 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
257/* 360 */ 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
258/*
259 * WARNING: as for above ISO sets, \377 may be used. Translate it to
260 * itself.
261 */
262/* 370 */ 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377,
263};
264
265/*
266 * Input mapping table -- if an entry is non-zero, and XCASE is set,
267 * when the corresponding character is typed preceded by "\" the escape
268 * sequence is replaced by the table value. Mostly used for
269 * upper-case only terminals.
270 */
271static char imaptab[256] = {
272/* 000 */ 0, 0, 0, 0, 0, 0, 0, 0,
273/* 010 */ 0, 0, 0, 0, 0, 0, 0, 0,
274/* 020 */ 0, 0, 0, 0, 0, 0, 0, 0,
275/* 030 */ 0, 0, 0, 0, 0, 0, 0, 0,
276/* 040 */ 0, '|', 0, 0, 0, 0, 0, '`',
277/* 050 */ '{', '}', 0, 0, 0, 0, 0, 0,
278/* 060 */ 0, 0, 0, 0, 0, 0, 0, 0,
279/* 070 */ 0, 0, 0, 0, 0, 0, 0, 0,
280/* 100 */ 0, 0, 0, 0, 0, 0, 0, 0,
281/* 110 */ 0, 0, 0, 0, 0, 0, 0, 0,
282/* 120 */ 0, 0, 0, 0, 0, 0, 0, 0,
283/* 130 */ 0, 0, 0, 0, '\\', 0, '~', 0,
284/* 140 */ 0, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
285/* 150 */ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
286/* 160 */ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
287/* 170 */ 'X', 'Y', 'Z', 0, 0, 0, 0, 0,
288/* 200-377 aren't mapped */
289};
290
291/*
292 * Output mapping table -- if an entry is non-zero, and XCASE is set,
293 * the corresponding character is printed as "\" followed by the table
294 * value. Mostly used for upper-case only terminals.
295 */
296static char omaptab[256] = {
297/* 000 */ 0, 0, 0, 0, 0, 0, 0, 0,
298/* 010 */ 0, 0, 0, 0, 0, 0, 0, 0,
299/* 020 */ 0, 0, 0, 0, 0, 0, 0, 0,
300/* 030 */ 0, 0, 0, 0, 0, 0, 0, 0,
301/* 040 */ 0, 0, 0, 0, 0, 0, 0, 0,
302/* 050 */ 0, 0, 0, 0, 0, 0, 0, 0,
303/* 060 */ 0, 0, 0, 0, 0, 0, 0, 0,
304/* 070 */ 0, 0, 0, 0, 0, 0, 0, 0,
305/* 100 */ 0, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
306/* 110 */ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
307/* 120 */ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
308/* 130 */ 'X', 'Y', 'Z', 0, 0, 0, 0, 0,
309/* 140 */ '\'', 0, 0, 0, 0, 0, 0, 0,
310/* 150 */ 0, 0, 0, 0, 0, 0, 0, 0,
311/* 160 */ 0, 0, 0, 0, 0, 0, 0, 0,
312/* 170 */ 0, 0, 0, '(', '!', ')', '^', 0,
313/* 200-377 aren't mapped */
314};
315
316/*
317 * Translation table for TS_MEUC output without OLCUC. All printing ASCII
318 * characters translate to themselves. All other _bytes_ have a zero in
319 * the table, which stops the copying. This and the following table exist
320 * only so we can use the existing movtuc processing with or without OLCUC.
321 * Maybe it speeds up something...because we can copy a block of characters
322 * by only looking for zeros in the table.
323 *
324 * If we took the simple expedient of DISALLOWING "olcuc" with multi-byte
325 * processing, we could rid ourselves of both these tables and save 512 bytes;
326 * seriously, it doesn't make much sense to use olcuc with multi-byte, and
327 * it will probably never be used. Consideration should be given to disallowing
328 * the combination TS_MEUC & OLCUC.
329 */
330static unsigned char enotrantab[256] = {
331/* 000 */ 0, 0, 0, 0, 0, 0, 0, 0,
332/* 010 */ 0, 0, 0, 0, 0, 0, 0, 0,
333/* 020 */ 0, 0, 0, 0, 0, 0, 0, 0,
334/* 030 */ 0, 0, 0, 0, 0, 0, 0, 0,
335/* 040 */ ' ', '!', '"', '#', '$', '%', '&', '\'',
336/* 050 */ '(', ')', '*', '+', ',', '-', '.', '/',
337/* 060 */ '0', '1', '2', '3', '4', '5', '6', '7',
338/* 070 */ '8', '9', ':', ';', '<', '=', '>', '?',
339/* 100 */ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
340/* 110 */ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
341/* 120 */ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
342/* 130 */ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
343/* 140 */ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
344/* 150 */ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
345/* 160 */ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
346/* 170 */ 'x', 'y', 'z', '{', '|', '}', '~', 0,
347/* 200 - 377 aren't mapped (they're stoppers). */
348};
349
350/*
351 * Translation table for TS_MEUC output with OLCUC. All printing ASCII
352 * translate to themselves, except for lower-case letters which translate
353 * to their upper-case equivalents. All other bytes have a zero in
354 * the table, which stops the copying. Useless for ISO Latin Alphabet
355 * translations, but *sigh* OLCUC is really only defined for ASCII anyway.
356 * We only have this table so we can use the existing OLCUC processing with
357 * TS_MEUC set (multi-byte mode). Nobody would ever think of actually
358 * _using_ it...would they?
359 */
360static unsigned char elcuctab[256] = {
361/* 000 */ 0, 0, 0, 0, 0, 0, 0, 0,
362/* 010 */ 0, 0, 0, 0, 0, 0, 0, 0,
363/* 020 */ 0, 0, 0, 0, 0, 0, 0, 0,
364/* 030 */ 0, 0, 0, 0, 0, 0, 0, 0,
365/* 040 */ ' ', '!', '"', '#', '$', '%', '&', '\'',
366/* 050 */ '(', ')', '*', '+', ',', '-', '.', '/',
367/* 060 */ '0', '1', '2', '3', '4', '5', '6', '7',
368/* 070 */ '8', '9', ':', ';', '<', '=', '>', '?',
369/* 100 */ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
370/* 110 */ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
371/* 120 */ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
372/* 130 */ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
373/* 140 */ '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
374/* 150 */ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
375/* 160 */ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
376/* 170 */ 'X', 'Y', 'Z', '{', '|', '}', '~', 0,
377/* 200 - 377 aren't mapped (they're stoppers). */
378};
379
380static struct streamtab ldtrinfo;
381
382static struct fmodsw fsw = {
383 "ldterm",
384 &ldtrinfo,
Andy Fiddaman6cfa0a72018-05-30 00:15:35 +0000385 D_MTQPAIR | D_MP | _D_SINGLE_INSTANCE
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700386};
387
388static struct modlstrmod modlstrmod = {
389 &mod_strmodops, "terminal line discipline", &fsw
390};
391
392
393static struct modlinkage modlinkage = {
394 MODREV_1, &modlstrmod, NULL
395};
396
397
398int
399_init(void)
400{
401 return (mod_install(&modlinkage));
402}
403
404int
405_fini(void)
406{
407 return (mod_remove(&modlinkage));
408}
409
410int
411_info(struct modinfo *modinfop)
412{
413 return (mod_info(&modlinkage, modinfop));
414}
415
416
417static int ldtermopen(queue_t *, dev_t *, int, int, cred_t *);
418static int ldtermclose(queue_t *, int, cred_t *);
419static void ldtermrput(queue_t *, mblk_t *);
420static void ldtermrsrv(queue_t *);
421static int ldtermrmsg(queue_t *, mblk_t *);
422static void ldtermwput(queue_t *, mblk_t *);
423static void ldtermwsrv(queue_t *);
424static int ldtermwmsg(queue_t *, mblk_t *);
425static mblk_t *ldterm_docanon(unsigned char, mblk_t *, size_t, queue_t *,
426 ldtermstd_state_t *, int *);
427static int ldterm_unget(ldtermstd_state_t *);
428static void ldterm_trim(ldtermstd_state_t *);
429static void ldterm_rubout(unsigned char, queue_t *, size_t,
430 ldtermstd_state_t *);
431static int ldterm_tabcols(ldtermstd_state_t *);
432static void ldterm_erase(queue_t *, size_t, ldtermstd_state_t *);
433static void ldterm_werase(queue_t *, size_t, ldtermstd_state_t *);
434static void ldterm_kill(queue_t *, size_t, ldtermstd_state_t *);
435static void ldterm_reprint(queue_t *, size_t, ldtermstd_state_t *);
436static mblk_t *ldterm_dononcanon(mblk_t *, mblk_t *, size_t, queue_t *,
437 ldtermstd_state_t *);
438static int ldterm_echo(unsigned char, queue_t *, size_t,
439 ldtermstd_state_t *);
440static void ldterm_outchar(unsigned char, queue_t *, size_t,
441 ldtermstd_state_t *);
442static void ldterm_outstring(unsigned char *, int, queue_t *, size_t,
443 ldtermstd_state_t *tp);
444static mblk_t *newmsg(ldtermstd_state_t *);
445static void ldterm_msg_upstream(queue_t *, ldtermstd_state_t *);
446static void ldterm_wenable(void *);
447static mblk_t *ldterm_output_msg(queue_t *, mblk_t *, mblk_t **,
448 ldtermstd_state_t *, size_t, int);
449static void ldterm_flush_output(unsigned char, queue_t *,
450 ldtermstd_state_t *);
451static void ldterm_dosig(queue_t *, int, unsigned char, int, int);
452static void ldterm_do_ioctl(queue_t *, mblk_t *);
453static int chgstropts(struct termios *, ldtermstd_state_t *, queue_t *);
454static void ldterm_ioctl_reply(queue_t *, mblk_t *);
455static void vmin_satisfied(queue_t *, ldtermstd_state_t *, int);
456static void vmin_settimer(queue_t *);
457static void vmin_timed_out(void *);
458static void ldterm_adjust_modes(ldtermstd_state_t *);
459static void ldterm_eucwarn(ldtermstd_state_t *);
460static void cp_eucwioc(eucioc_t *, eucioc_t *, int);
461static int ldterm_codeset(uchar_t, uchar_t);
462
463static void ldterm_csi_erase(queue_t *, size_t, ldtermstd_state_t *);
464static void ldterm_csi_werase(queue_t *, size_t, ldtermstd_state_t *);
465
466static uchar_t ldterm_utf8_width(uchar_t *, int);
467
468/* Codeset type specific methods for EUC, PCCS, and, UTF-8 codeset types. */
469static int __ldterm_dispwidth_euc(uchar_t, void *, int);
470static int __ldterm_memwidth_euc(uchar_t, void *);
471
472static int __ldterm_dispwidth_pccs(uchar_t, void *, int);
473static int __ldterm_memwidth_pccs(uchar_t, void *);
474
475static int __ldterm_dispwidth_utf8(uchar_t, void *, int);
476static int __ldterm_memwidth_utf8(uchar_t, void *);
477
478static const ldterm_cs_methods_t cs_methods[LDTERM_CS_TYPE_MAX + 1] = {
479 {
480 NULL,
481 NULL
482 },
483 {
484 __ldterm_dispwidth_euc,
485 __ldterm_memwidth_euc
486 },
487 {
488 __ldterm_dispwidth_pccs,
489 __ldterm_memwidth_pccs
490 },
491 {
492 __ldterm_dispwidth_utf8,
493 __ldterm_memwidth_utf8
494 }
495};
496
497/*
498 * The default codeset is presumably C locale's ISO 646 in EUC but
499 * the data structure at below defined as the default codeset data also
500 * support any single byte (EUC) locales.
501 */
502static const ldterm_cs_data_t default_cs_data = {
503 LDTERM_DATA_VERSION,
504 LDTERM_CS_TYPE_EUC,
505 (uchar_t)0,
506 (uchar_t)0,
507 (char *)NULL,
508 {
509 '\0', '\0', '\0', '\0',
510 '\0', '\0', '\0', '\0',
511 '\0', '\0', '\0', '\0',
512 '\0', '\0', '\0', '\0',
513 '\0', '\0', '\0', '\0',
514 '\0', '\0', '\0', '\0',
515 '\0', '\0', '\0', '\0',
516 '\0', '\0', '\0', '\0',
517 '\0', '\0', '\0', '\0',
518 '\0', '\0', '\0', '\0'
519 }
520};
521
522/*
is85bb5f12008-07-02 17:06:30 -0700523 * 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.
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700526 */
is85bb5f12008-07-02 17:06:30 -0700527extern const int8_t u8_number_of_bytes[];
528extern const uchar_t u8_masks_tbl[];
529extern const uint8_t u8_valid_min_2nd_byte[];
530extern const uint8_t u8_valid_max_2nd_byte[];
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700531
532/*
533 * Unicode character width definition tables from uwidth.c:
534 */
535extern const ldterm_unicode_data_cell_t ldterm_ucode[][16384];
536
537#ifdef LDDEBUG
538int ldterm_debug = 0;
539#define DEBUG1(a) if (ldterm_debug == 1) printf a
540#define DEBUG2(a) if (ldterm_debug >= 2) printf a /* allocations */
541#define DEBUG3(a) if (ldterm_debug >= 3) printf a /* M_CTL Stuff */
542#define DEBUG4(a) if (ldterm_debug >= 4) printf a /* M_READ Stuff */
543#define DEBUG5(a) if (ldterm_debug >= 5) printf a
544#define DEBUG6(a) if (ldterm_debug >= 6) printf a
545#define DEBUG7(a) if (ldterm_debug >= 7) printf a
546#else
547#define DEBUG1(a)
548#define DEBUG2(a)
549#define DEBUG3(a)
550#define DEBUG4(a)
551#define DEBUG5(a)
552#define DEBUG6(a)
553#define DEBUG7(a)
554#endif /* LDDEBUG */
555
556
557/*
558 * Since most of the buffering occurs either at the stream head or in
559 * the "message currently being assembled" buffer, we have a
560 * relatively small input queue, so that blockages above us get
561 * reflected fairly quickly to the module below us. We also have a
562 * small maximum packet size, since you can put a message of that
563 * size on an empty queue no matter how much bigger than the high
564 * water mark it is.
565 */
566static struct module_info ldtermmiinfo = {
567 0x0bad,
568 "ldterm",
569 0,
Richard Lowe2463e922017-06-15 13:29:55 -0400570 _TTY_BUFSIZ,
571 _TTY_BUFSIZ,
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700572 LOWAT
573};
574
575
576static struct qinit ldtermrinit = {
577 (int (*)())ldtermrput,
578 (int (*)())ldtermrsrv,
579 ldtermopen,
580 ldtermclose,
581 NULL,
582 &ldtermmiinfo
583};
584
585
586static struct module_info ldtermmoinfo = {
587 0x0bad,
588 "ldterm",
589 0,
590 INFPSZ,
591 1,
592 0
593};
594
595
596static struct qinit ldtermwinit = {
597 (int (*)())ldtermwput,
598 (int (*)())ldtermwsrv,
599 ldtermopen,
600 ldtermclose,
601 NULL,
602 &ldtermmoinfo
603};
604
605
606static struct streamtab ldtrinfo = {
607 &ldtermrinit,
608 &ldtermwinit,
609 NULL,
610 NULL
611};
612
613/*
614 * Dummy qbufcall callback routine used by open and close.
615 * The framework will wake up qwait_sig when we return from
616 * this routine (as part of leaving the perimeters.)
617 * (The framework enters the perimeters before calling the qbufcall() callback
618 * and leaves the perimeters after the callback routine has executed. The
619 * framework performs an implicit wakeup of any thread in qwait/qwait_sig
620 * when it leaves the perimeter. See qwait(9E).)
621 */
622/* ARGSUSED */
623static void
624dummy_callback(void *arg)
625{}
626
627
628static mblk_t *
629open_ioctl(queue_t *q, uint_t cmd)
630{
631 mblk_t *mp;
632 bufcall_id_t id;
633 int retv;
634
635 while ((mp = mkiocb(cmd)) == NULL) {
636 id = qbufcall(q, sizeof (struct iocblk), BPRI_MED,
637 dummy_callback, NULL);
638 retv = qwait_sig(q);
639 qunbufcall(q, id);
640 if (retv == 0)
641 break;
642 }
643 return (mp);
644}
645
646static mblk_t *
647open_mblk(queue_t *q, size_t len)
648{
649 mblk_t *mp;
650 bufcall_id_t id;
651 int retv;
652
653 while ((mp = allocb(len, BPRI_MED)) == NULL) {
654 id = qbufcall(q, len, BPRI_MED, dummy_callback, NULL);
655 retv = qwait_sig(q);
656 qunbufcall(q, id);
657 if (retv == 0)
658 break;
659 }
660 return (mp);
661}
662
663/*
664 * Line discipline open.
665 */
666/* ARGSUSED1 */
667static int
668ldtermopen(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *crp)
669{
670 ldtermstd_state_t *tp;
671 mblk_t *bp, *qryp;
672 int len;
673 struct stroptions *strop;
674 struct termios *termiosp;
675 queue_t *wq;
676
677 if (q->q_ptr != NULL) {
678 return (0); /* already attached */
679 }
680
681 tp = (ldtermstd_state_t *)kmem_zalloc(sizeof (ldtermstd_state_t),
is85bb5f12008-07-02 17:06:30 -0700682 KM_SLEEP);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700683
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;
Richard Lowe2463e922017-06-15 13:29:55 -0400797 strop->so_hiwat = _TTY_BUFSIZ;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -0700798 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
805open_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
816struct close_timer {
817 timeout_id_t id;
818 ldtermstd_state_t *tp;
819};
820
821static void
822drain_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 */
831static int
832ldtermclose(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 */
934static void
935ldtermrput(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,
is85bb5f12008-07-02 17:06:30 -07001048 "ldtermrput: no blocks");
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001049 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,
is85bb5f12008-07-02 17:06:30 -07001063 "ldtermrput: no blocks");
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001064 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 &=
is85bb5f12008-07-02 17:06:30 -07001280 ~(TS_TTSTOP |
1281 TS_OFBLOCK);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001282 (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 }
Robert Mustacchi19d32b92013-12-05 01:26:55 +00001360
1361 /*
1362 * Consumers do not expect the ^T to be
1363 * echoed out when we generate a
1364 * VSTATUS.
1365 */
1366 if (c == tp->t_modes.c_cc[VSTATUS]) {
1367 ldterm_dosig(q, SIGINFO, '\0',
1368 M_PCSIG, FLUSHRW);
1369 continue;
1370 }
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001371 }
1372 /*
1373 * Throw away CR if IGNCR set, or
1374 * turn it into NL if ICRNL set.
1375 */
1376 if (c == '\r') {
1377 if (tp->t_modes.c_iflag & IGNCR)
1378 continue;
1379 if (tp->t_modes.c_iflag & ICRNL)
1380 c = '\n';
1381 } else {
1382 /*
1383 * Turn NL into CR if INLCR
1384 * set.
1385 */
1386 if (c == '\n' &&
1387 tp->t_modes.c_iflag & INLCR)
1388 c = '\r';
1389 }
1390
1391 /*
1392 * Map upper case input to lower case
1393 * if IUCLC flag set.
1394 */
1395 if (tp->t_modes.c_iflag & IUCLC &&
1396 c >= 'A' && c <= 'Z')
1397 c += 'a' - 'A';
1398
1399 /*
1400 * Put the possibly-transformed
1401 * character back in the message.
1402 */
1403 *writep++ = c;
1404 }
1405
1406 /*
1407 * If we didn't copy some characters because
1408 * we were ignoring them, fix the size of the
1409 * data block by adjusting the write pointer.
1410 * XXX This may result in a zero-length
1411 * block; will this cause anybody gastric
1412 * distress?
1413 */
1414 bp->b_wptr -= (readp - writep);
1415 } else {
1416 /*
1417 * We won't be doing anything other than
1418 * possibly stripping the input.
1419 */
1420 if (tp->t_modes.c_iflag & ISTRIP) {
1421 while (readp < bp->b_wptr)
1422 *writep++ = *readp++ & 0177;
1423 }
1424 tp->t_modes.c_lflag &= ~FLUSHO;
1425 }
1426
1427 } while ((bp = bp->b_cont) != NULL); /* next block, if any */
1428
1429 /*
1430 * Queue the message for service procedure if the
1431 * queue is not empty or canputnext() fails or
1432 * tp->t_state & TS_RESCAN is true.
1433 */
1434
1435 if (q->q_first != NULL || !bcanputnext(q, mp->b_band) ||
is85bb5f12008-07-02 17:06:30 -07001436 (tp->t_state & TS_RESCAN))
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001437 (void) putq(q, mp);
1438 else
1439 (void) ldtermrmsg(q, mp);
1440
1441 /*
1442 * Flow control: send "stop input" message if our queue is
1443 * approaching its high-water mark. The message will be
1444 * dropped on the floor in the service procedure, if we
1445 * cannot ship it up and we have had it upto our neck!
1446 *
1447 * Set QWANTW to ensure that the read queue service procedure
1448 * gets run when nextq empties up again, so that it can
1449 * unstop the input.
1450 */
1451 if ((tp->t_modes.c_iflag & IXOFF) && !(tp->t_state & TS_TBLOCK) &&
1452 q->q_count >= TTXOHI) {
1453 mutex_enter(QLOCK(nextq));
1454 nextq->q_flag |= QWANTW;
1455 mutex_exit(QLOCK(nextq));
1456 tp->t_state |= TS_TBLOCK;
1457 (void) putnextctl(wrq, M_STOPI);
1458 DEBUG1(("M_STOPI down\n"));
1459 }
1460}
1461
1462
1463/*
1464 * Line discipline input server processing. Erase/kill and escape
1465 * ('\') processing, gathering into messages, upper/lower case input
1466 * mapping.
1467 */
1468static void
1469ldtermrsrv(queue_t *q)
1470{
1471 ldtermstd_state_t *tp;
1472 mblk_t *mp;
1473
1474 tp = (ldtermstd_state_t *)q->q_ptr;
1475
1476 if (tp->t_state & TS_RESCAN) {
1477 /*
1478 * Canonicalization was turned on or off. Put the
1479 * message being assembled back in the input queue,
1480 * so that we rescan it.
1481 */
1482 if (tp->t_message != NULL) {
1483 DEBUG5(("RESCAN WAS SET; put back in q\n"));
1484 if (tp->t_msglen != 0)
1485 (void) putbq(q, tp->t_message);
1486 else
1487 freemsg(tp->t_message);
1488 tp->t_message = NULL;
1489 tp->t_endmsg = NULL;
1490 tp->t_msglen = 0;
1491 }
1492 if (tp->t_state & TS_MEUC) {
1493 ASSERT(tp->t_eucp_mp);
1494 tp->t_eucp = tp->t_eucp_mp->b_rptr;
1495 tp->t_codeset = 0;
1496 tp->t_eucleft = 0;
1497 }
1498 tp->t_state &= ~TS_RESCAN;
1499 }
1500
1501 while ((mp = getq(q)) != NULL) {
1502 if (!ldtermrmsg(q, mp))
1503 break;
1504 }
1505
1506 /*
1507 * Flow control: send start message if blocked and our queue
1508 * is below its low water mark.
1509 */
1510 if ((tp->t_modes.c_iflag & IXOFF) && (tp->t_state & TS_TBLOCK) &&
1511 !(tp->t_state & TS_IFBLOCK) && q->q_count <= TTXOLO) {
1512 tp->t_state &= ~TS_TBLOCK;
1513 (void) putctl(WR(q), M_STARTI);
1514 }
1515}
1516
1517/*
1518 * This routine is called from both ldtermrput and ldtermrsrv to
1519 * do the actual work of dealing with mp. Return 1 on sucesss and
1520 * 0 on failure.
1521 */
1522static int
1523ldtermrmsg(queue_t *q, mblk_t *mp)
1524{
1525 unsigned char c;
1526 int dofree;
1527 int status = 1;
1528 size_t ebsize;
1529 mblk_t *bp;
1530 mblk_t *bpt;
1531 ldtermstd_state_t *tp;
1532
1533 bpt = NULL;
1534
1535 tp = (ldtermstd_state_t *)q->q_ptr;
1536
1537 if (mp->b_datap->db_type <= QPCTL && !bcanputnext(q, mp->b_band)) {
1538 /*
1539 * Stream head is flow controlled. If echo is
1540 * turned on, flush the read side or send a
1541 * bell down the line to stop input and
1542 * process the current message.
1543 * Otherwise(putbq) the user will not see any
1544 * response to to the typed input. Typically
1545 * happens if there is no reader process.
1546 * Note that you will loose the data in this
1547 * case if the data is coming too fast. There
1548 * is an assumption here that if ECHO is
1549 * turned on its some user typing the data on
1550 * a terminal and its not network.
1551 */
1552 if (tp->t_modes.c_lflag & ECHO) {
1553 if ((tp->t_modes.c_iflag & IMAXBEL) &&
1554 (tp->t_modes.c_lflag & ICANON)) {
1555 freemsg(mp);
1556 if (canputnext(WR(q)))
1557 ldterm_outchar(CTRL('g'), WR(q), 4, tp);
1558 status = 0;
1559 goto echo;
1560 } else {
1561 (void) putctl1(q, M_FLUSH, FLUSHR);
1562 }
1563 } else {
1564 (void) putbq(q, mp);
1565 status = 0;
1566 goto out; /* read side is blocked */
1567 }
1568 }
1569 switch (mp->b_datap->db_type) {
1570
1571 default:
1572 putnext(q, mp); /* pass it on */
1573 goto out;
1574
1575 case M_HANGUP:
1576 /*
1577 * Flush everything we haven't looked at yet.
1578 */
1579 flushq(q, FLUSHDATA);
1580
1581 /*
1582 * Flush everything we have looked at.
1583 */
1584 freemsg(tp->t_message);
1585 tp->t_message = NULL;
1586 tp->t_endmsg = NULL;
1587 tp->t_msglen = 0;
1588 /*
1589 * XXX should we set read request
1590 * tp->t_rd_request to NULL?
1591 */
1592 tp->t_rocount = 0; /* if it hasn't been typed */
1593 tp->t_rocol = 0; /* it hasn't been echoed :-) */
1594 if (tp->t_state & TS_MEUC) {
1595 ASSERT(tp->t_eucp_mp);
1596 tp->t_eucp = tp->t_eucp_mp->b_rptr;
1597 }
1598 /*
1599 * Restart output, since it's probably got
1600 * nowhere to go anyway, and we're probably
1601 * not going to see another ^Q for a while.
1602 */
1603 if (tp->t_state & TS_TTSTOP) {
1604 tp->t_state &= ~(TS_TTSTOP|TS_OFBLOCK);
1605 (void) putnextctl(WR(q), M_START);
1606 }
1607 /*
1608 * This message will travel up the read
1609 * queue, flushing as it goes, get turned
1610 * around at the stream head, and travel back
1611 * down the write queue, flushing as it goes.
1612 */
1613 (void) putnextctl1(q, M_FLUSH, FLUSHW);
1614
1615 /*
1616 * This message will travel down the write
1617 * queue, flushing as it goes, get turned
1618 * around at the driver, and travel back up
1619 * the read queue, flushing as it goes.
1620 */
1621 (void) putctl1(WR(q), M_FLUSH, FLUSHR);
1622
1623 /*
1624 * Now that that's done, we send a SIGCONT
1625 * upstream, followed by the M_HANGUP.
1626 */
1627 /* (void) putnextctl1(q, M_PCSIG, SIGCONT); */
1628 putnext(q, mp);
1629 goto out;
1630
1631 case M_IOCACK:
1632
1633 /*
1634 * Augment whatever information the driver is
1635 * returning with the information we supply.
1636 */
1637 ldterm_ioctl_reply(q, mp);
1638 goto out;
1639
1640 case M_DATA:
1641 break;
1642 }
1643
1644 /*
1645 * This is an M_DATA message.
1646 */
1647
1648 /*
1649 * If somebody below us ("intelligent" communications
1650 * board, pseudo-tty controlled by an editor) is
1651 * doing canonicalization, don't scan it for special
1652 * characters.
1653 */
1654 if (tp->t_state & TS_NOCANON) {
1655 putnext(q, mp);
1656 goto out;
1657 }
1658 bp = mp;
1659
1660 if ((bpt = newmsg(tp)) != NULL) {
1661 mblk_t *bcont;
1662
1663 do {
1664 ASSERT(bp->b_wptr >= bp->b_rptr);
1665 ebsize = bp->b_wptr - bp->b_rptr;
1666 if (ebsize > EBSIZE)
1667 ebsize = EBSIZE;
1668 bcont = bp->b_cont;
1669 if (CANON_MODE) {
1670 /*
1671 * By default, free the message once processed
1672 */
1673 dofree = 1;
1674
1675 /*
1676 * update sysinfo canch
1677 * character. The value of
1678 * canch may vary as compared
1679 * to character tty
1680 * implementation.
1681 */
1682 while (bp->b_rptr < bp->b_wptr) {
1683 c = *bp->b_rptr++;
1684 if ((bpt = ldterm_docanon(c,
1685 bpt, ebsize, q, tp, &dofree)) ==
1686 NULL)
1687 break;
1688 }
1689 /*
1690 * Release this block or put back on queue.
1691 */
1692 if (dofree)
1693 freeb(bp);
1694 else {
1695 (void) putbq(q, bp);
1696 break;
1697 }
1698 } else
is85bb5f12008-07-02 17:06:30 -07001699 bpt = ldterm_dononcanon(bp, bpt, ebsize, q, tp);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001700 if (bpt == NULL) {
1701 cmn_err(CE_WARN,
1702 "ldtermrsrv: out of blocks");
1703 freemsg(bcont);
1704 break;
1705 }
1706 } while ((bp = bcont) != NULL);
1707 }
1708echo:
1709 /*
1710 * Send whatever we echoed downstream.
1711 */
1712 if (tp->t_echomp != NULL) {
1713 if (canputnext(WR(q)))
1714 putnext(WR(q), tp->t_echomp);
1715 else
1716 freemsg(tp->t_echomp);
1717 tp->t_echomp = NULL;
1718 }
1719
1720out:
1721 return (status);
1722}
1723
1724
1725/*
1726 * Do canonical mode input; check whether this character is to be
1727 * treated as a special character - if so, check whether it's equal
1728 * to any of the special characters and handle it accordingly.
1729 * Otherwise, just add it to the current line.
1730 */
1731static mblk_t *
1732ldterm_docanon(uchar_t c, mblk_t *bpt, size_t ebsize, queue_t *q,
1733 ldtermstd_state_t *tp, int *dofreep)
1734{
1735 queue_t *wrq = WR(q);
1736 int i;
1737
1738 /*
1739 * If the previous character was the "literal next"
1740 * character, treat this character as regular input.
1741 */
1742 if (tp->t_state & TS_SLNCH)
1743 goto escaped;
1744
1745 /*
1746 * Setting a special character to NUL disables it, so if this
1747 * character is NUL, it should not be compared with any of
1748 * the special characters.
1749 */
1750 if (c == _POSIX_VDISABLE) {
1751 tp->t_state &= ~TS_QUOT;
1752 goto escaped;
1753 }
1754 /*
1755 * If this character is the literal next character, echo it
1756 * as '^', backspace over it, and record that fact.
1757 */
1758 if ((tp->t_modes.c_lflag & IEXTEN) && c == tp->t_modes.c_cc[VLNEXT]) {
1759 if (tp->t_modes.c_lflag & ECHO)
1760 ldterm_outstring((unsigned char *)"^\b", 2, wrq,
is85bb5f12008-07-02 17:06:30 -07001761 ebsize, tp);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001762 tp->t_state |= TS_SLNCH;
1763 goto out;
1764 }
1765 /*
1766 * Check for the editing character. If the display width of
1767 * the last byte at the canonical buffer is not one and also
1768 * smaller than or equal to UNKNOWN_WIDTH, the character at
1769 * the end of the buffer is a multi-byte and/or multi-column
1770 * character.
1771 */
Toomas Soome9a2c4682016-10-09 12:16:15 +03001772 if (c == tp->t_modes.c_cc[VERASE] || c == tp->t_modes.c_cc[VERASE2]) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001773 if (tp->t_state & TS_QUOT) {
1774 /*
1775 * Get rid of the backslash, and put the
1776 * erase character in its place.
1777 */
1778 ldterm_erase(wrq, ebsize, tp);
1779 bpt = tp->t_endmsg;
1780 goto escaped;
1781 } else {
1782 if ((tp->t_state & TS_MEUC) && tp->t_msglen &&
1783 (*(tp->t_eucp - 1) != 1 &&
1784 *(tp->t_eucp - 1) <= UNKNOWN_WIDTH))
1785 ldterm_csi_erase(wrq, ebsize, tp);
1786 else
1787 ldterm_erase(wrq, ebsize, tp);
1788 bpt = tp->t_endmsg;
1789 goto out;
1790 }
1791 }
1792 if ((tp->t_modes.c_lflag & IEXTEN) && c == tp->t_modes.c_cc[VWERASE]) {
1793 /*
1794 * Do "ASCII word" or "multibyte character token/chunk" erase.
1795 */
1796 if (tp->t_state & TS_MEUC)
1797 ldterm_csi_werase(wrq, ebsize, tp);
1798 else
1799 ldterm_werase(wrq, ebsize, tp);
1800 bpt = tp->t_endmsg;
1801 goto out;
1802 }
1803 if (c == tp->t_modes.c_cc[VKILL]) {
1804 if (tp->t_state & TS_QUOT) {
1805 /*
1806 * Get rid of the backslash, and put the kill
1807 * character in its place.
1808 */
1809 ldterm_erase(wrq, ebsize, tp);
1810 bpt = tp->t_endmsg;
1811 goto escaped;
1812 } else {
1813 ldterm_kill(wrq, ebsize, tp);
1814 bpt = tp->t_endmsg;
1815 goto out;
1816 }
1817 }
1818 if ((tp->t_modes.c_lflag & IEXTEN) && c == tp->t_modes.c_cc[VREPRINT]) {
1819 ldterm_reprint(wrq, ebsize, tp);
1820 goto out;
1821 }
1822 /*
1823 * If the preceding character was a backslash: if the current
1824 * character is an EOF, get rid of the backslash and treat
1825 * the EOF as data; if we're in XCASE mode and the current
1826 * character is part of a backslash-X escape sequence,
1827 * process it; otherwise, just treat the current character
1828 * normally.
1829 */
1830 if (tp->t_state & TS_QUOT) {
1831 tp->t_state &= ~TS_QUOT;
1832 if (c == tp->t_modes.c_cc[VEOF]) {
1833 /*
1834 * EOF character. Since it's escaped, get rid
1835 * of the backslash and put the EOF character
1836 * in its place.
1837 */
1838 ldterm_erase(wrq, ebsize, tp);
1839 bpt = tp->t_endmsg;
1840 } else {
1841 /*
1842 * If we're in XCASE mode, and the current
1843 * character is part of a backslash-X
1844 * sequence, get rid of the backslash and
1845 * replace the current character with what
1846 * that sequence maps to.
1847 */
1848 if ((tp->t_modes.c_lflag & XCASE) &&
1849 imaptab[c] != '\0') {
1850 ldterm_erase(wrq, ebsize, tp);
1851 bpt = tp->t_endmsg;
1852 c = imaptab[c];
1853 }
1854 }
1855 } else {
1856 /*
1857 * Previous character wasn't backslash; check whether
1858 * this was the EOF character.
1859 */
1860 if (c == tp->t_modes.c_cc[VEOF]) {
1861 /*
1862 * EOF character. Don't echo it unless
1863 * ECHOCTL is set, don't stuff it in the
1864 * current line, but send the line up the
1865 * stream.
1866 */
1867 if ((tp->t_modes.c_lflag & ECHOCTL) &&
1868 (tp->t_modes.c_lflag & IEXTEN) &&
1869 (tp->t_modes.c_lflag & ECHO)) {
1870 i = ldterm_echo(c, wrq, ebsize, tp);
1871 while (i > 0) {
1872 ldterm_outchar('\b', wrq, ebsize, tp);
1873 i--;
1874 }
1875 }
1876 bpt->b_datap->db_type = M_DATA;
1877 ldterm_msg_upstream(q, tp);
1878 if (!canputnext(q)) {
1879 bpt = NULL;
1880 *dofreep = 0;
1881 } else {
1882 bpt = newmsg(tp);
1883 *dofreep = 1;
1884 }
1885 goto out;
1886 }
1887 }
1888
1889escaped:
1890 /*
1891 * First, make sure we can fit one WHOLE multi-byte char in the
1892 * buffer. This is one place where we have overhead even if
1893 * not in multi-byte mode; the overhead is subtracting
1894 * tp->t_maxeuc from MAX_CANON before checking.
1895 *
1896 * Allows MAX_CANON bytes in the buffer before throwing awaying
1897 * the the overflow of characters.
1898 */
Richard Lowe2463e922017-06-15 13:29:55 -04001899 if ((tp->t_msglen > ((_TTY_BUFSIZ + 1) - (int)tp->t_maxeuc)) &&
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001900 !((tp->t_state & TS_MEUC) && tp->t_eucleft)) {
1901
1902 /*
1903 * Byte will cause line to overflow, or the next EUC
1904 * won't fit: Ring the bell or discard all input, and
1905 * don't save the byte away.
1906 */
1907 if (tp->t_modes.c_iflag & IMAXBEL) {
1908 if (canputnext(wrq))
1909 ldterm_outchar(CTRL('g'), wrq, ebsize, tp);
1910 goto out;
1911 } else {
1912 /*
1913 * MAX_CANON processing. free everything in
1914 * the current line and start with the
1915 * current character as the first character.
1916 */
1917 DEBUG7(("ldterm_docanon: MAX_CANON processing\n"));
1918 freemsg(tp->t_message);
1919 tp->t_message = NULL;
1920 tp->t_endmsg = NULL;
1921 tp->t_msglen = 0;
1922 tp->t_rocount = 0; /* if it hasn't been type */
1923 tp->t_rocol = 0; /* it hasn't been echoed :-) */
1924 if (tp->t_state & TS_MEUC) {
1925 ASSERT(tp->t_eucp_mp);
1926 tp->t_eucp = tp->t_eucp_mp->b_rptr;
1927 }
1928 tp->t_state &= ~TS_SLNCH;
1929 bpt = newmsg(tp);
1930 }
1931 }
1932 /*
1933 * Add the character to the current line.
1934 */
1935 if (bpt->b_wptr >= bpt->b_datap->db_lim) {
1936 /*
1937 * No more room in this mblk; save this one away, and
1938 * allocate a new one.
1939 */
1940 bpt->b_datap->db_type = M_DATA;
1941 if ((bpt = allocb(IBSIZE, BPRI_MED)) == NULL)
1942 goto out;
1943
1944 /*
1945 * Chain the new one to the end of the old one, and
1946 * mark it as the last block in the current line.
1947 */
1948 tp->t_endmsg->b_cont = bpt;
1949 tp->t_endmsg = bpt;
1950 }
1951 *bpt->b_wptr++ = c;
1952 tp->t_msglen++; /* message length in BYTES */
1953
1954 /*
1955 * In multi-byte mode, we have to keep track of where we are.
1956 * The first bytes of multi-byte chars get the full count for the
1957 * whole character. We don't do any column calculations
1958 * here, but we need the information for when we do. We could
1959 * come across cases where we are getting garbage on the
1960 * line, but we're in multi-byte mode. In that case, we may
1961 * see ASCII controls come in the middle of what should have been a
1962 * multi-byte character. Call ldterm_eucwarn...eventually, a
1963 * warning message will be printed about it.
1964 */
1965 if (tp->t_state & TS_MEUC) {
1966 if (tp->t_eucleft) { /* if in a multi-byte char already */
1967 --tp->t_eucleft;
1968 *tp->t_eucp++ = 0; /* is a subsequent byte */
1969 if (c < (uchar_t)0x20)
1970 ldterm_eucwarn(tp);
1971 } else { /* is the first byte of a multi-byte, or is ASCII */
1972 if (ISASCII(c)) {
1973 *tp->t_eucp++ =
is85bb5f12008-07-02 17:06:30 -07001974 tp->t_csmethods.ldterm_dispwidth(c,
1975 (void *)tp, tp->t_modes.c_lflag & ECHOCTL);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001976 tp->t_codeset = 0;
1977 } else {
1978 *tp->t_eucp++ =
is85bb5f12008-07-02 17:06:30 -07001979 tp->t_csmethods.ldterm_dispwidth(c,
1980 (void *)tp, tp->t_modes.c_lflag & ECHOCTL);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001981 tp->t_eucleft =
is85bb5f12008-07-02 17:06:30 -07001982 tp->t_csmethods.ldterm_memwidth(c,
1983 (void *)tp) - 1;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001984 tp->t_codeset = ldterm_codeset(
is85bb5f12008-07-02 17:06:30 -07001985 tp->t_csdata.codeset_type, c);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07001986 }
1987 }
1988 }
1989 /*
1990 * AT&T is concerned about the following but we aren't since
1991 * we have already shipped code that works.
1992 *
1993 * EOL2/XCASE should be conditioned with IEXTEN to be truly
1994 * POSIX conformant. This is going to cause problems for
1995 * pre-SVR4.0 programs that don't know about IEXTEN. Hence
1996 * EOL2/IEXTEN is not conditioned with IEXTEN.
1997 */
1998 if (!(tp->t_state & TS_SLNCH) &&
1999 (c == '\n' || (c != '\0' && (c == tp->t_modes.c_cc[VEOL] ||
2000 (c == tp->t_modes.c_cc[VEOL2]))))) {
2001 /*
2002 * || ((tp->t_modes.c_lflag & IEXTEN) && c ==
2003 * tp->t_modes.c_cc[VEOL2]))))) {
2004 */
2005 /*
2006 * It's a line-termination character; send the line
2007 * up the stream.
2008 */
2009 bpt->b_datap->db_type = M_DATA;
2010 ldterm_msg_upstream(q, tp);
2011 if (tp->t_state & TS_MEUC) {
2012 ASSERT(tp->t_eucp_mp);
2013 tp->t_eucp = tp->t_eucp_mp->b_rptr;
2014 }
2015 if ((bpt = newmsg(tp)) == NULL)
2016 goto out;
2017 } else {
2018 /*
2019 * Character was escaped with LNEXT.
2020 */
2021 if (tp->t_rocount++ == 0)
2022 tp->t_rocol = tp->t_col;
2023 tp->t_state &= ~(TS_SLNCH|TS_QUOT);
2024 /*
2025 * If the current character is a single byte and single
2026 * column character and it is the backslash character and
2027 * IEXTEN, then the state will have TS_QUOT.
2028 */
2029 if ((c == '\\') && (tp->t_modes.c_lflag & IEXTEN) &&
2030 (!(tp->t_state & TS_MEUC) ||
2031 ((tp->t_state & TS_MEUC) && (!tp->t_eucleft))))
2032 tp->t_state |= TS_QUOT;
2033 }
2034
2035 /*
2036 * Echo it.
2037 */
2038 if (tp->t_state & TS_ERASE) {
2039 tp->t_state &= ~TS_ERASE;
2040 if (tp->t_modes.c_lflag & ECHO)
2041 ldterm_outchar('/', wrq, ebsize, tp);
2042 }
2043 if (tp->t_modes.c_lflag & ECHO)
2044 (void) ldterm_echo(c, wrq, ebsize, tp);
2045 else {
2046 /*
2047 * Echo NL when ECHO turned off, if ECHONL flag is
2048 * set.
2049 */
2050 if (c == '\n' && (tp->t_modes.c_lflag & ECHONL))
2051 ldterm_outchar(c, wrq, ebsize, tp);
2052 }
2053
2054out:
2055
2056 return (bpt);
2057}
2058
2059
2060static int
2061ldterm_unget(ldtermstd_state_t *tp)
2062{
2063 mblk_t *bpt;
2064
2065 if ((bpt = tp->t_endmsg) == NULL)
2066 return (-1); /* no buffers */
2067 if (bpt->b_rptr == bpt->b_wptr)
2068 return (-1); /* zero-length record */
2069 tp->t_msglen--; /* one fewer character */
2070 return (*--bpt->b_wptr);
2071}
2072
2073
2074static void
2075ldterm_trim(ldtermstd_state_t *tp)
2076{
2077 mblk_t *bpt;
2078 mblk_t *bp;
2079
2080 ASSERT(tp->t_endmsg);
2081 bpt = tp->t_endmsg;
2082
2083 if (bpt->b_rptr == bpt->b_wptr) {
2084 /*
2085 * This mblk is now empty. Find the previous mblk;
2086 * throw this one away, unless it's the first one.
2087 */
2088 bp = tp->t_message;
2089 if (bp != bpt) {
2090 while (bp->b_cont != bpt) {
2091 ASSERT(bp->b_cont);
2092 bp = bp->b_cont;
2093 }
2094 bp->b_cont = NULL;
2095 freeb(bpt);
2096 tp->t_endmsg = bp; /* point to that mblk */
2097 }
2098 }
2099}
2100
2101
2102/*
2103 * Rubout one character from the current line being built for tp as
2104 * cleanly as possible. q is the write queue for tp. Most of this
2105 * can't be applied to multi-byte processing. We do our own thing
2106 * for that... See the "ldterm_eucerase" routine. We never call
2107 * ldterm_rubout on a multi-byte or multi-column character.
2108 */
2109static void
2110ldterm_rubout(uchar_t c, queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
2111{
2112 int tabcols;
2113 static unsigned char crtrubout[] = "\b \b\b \b";
2114#define RUBOUT1 &crtrubout[3] /* rub out one position */
2115#define RUBOUT2 &crtrubout[0] /* rub out two positions */
2116
2117 if (!(tp->t_modes.c_lflag & ECHO))
2118 return;
2119 if (tp->t_modes.c_lflag & ECHOE) {
2120 /*
2121 * "CRT rubout"; try erasing it from the screen.
2122 */
2123 if (tp->t_rocount == 0) {
2124 /*
2125 * After the character being erased was
2126 * echoed, some data was written to the
2127 * terminal; we can't erase it cleanly, so we
2128 * just reprint the whole line as if the user
2129 * had typed the reprint character.
2130 */
2131 ldterm_reprint(q, ebsize, tp);
2132 return;
2133 } else {
2134 /*
2135 * XXX what about escaped characters?
2136 */
2137 switch (typetab[c]) {
2138
2139 case ORDINARY:
2140 if ((tp->t_modes.c_lflag & XCASE) &&
2141 omaptab[c])
2142 ldterm_outstring(RUBOUT1, 3, q, ebsize,
is85bb5f12008-07-02 17:06:30 -07002143 tp);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002144 ldterm_outstring(RUBOUT1, 3, q, ebsize, tp);
2145 break;
2146
2147 case VTAB:
2148 case BACKSPACE:
2149 case CONTROL:
2150 case RETURN:
2151 case NEWLINE:
2152 if ((tp->t_modes.c_lflag & ECHOCTL) &&
2153 (tp->t_modes.c_lflag & IEXTEN))
2154 ldterm_outstring(RUBOUT2, 6, q, ebsize,
is85bb5f12008-07-02 17:06:30 -07002155 tp);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002156 break;
2157
2158 case TAB:
2159 if (tp->t_rocount < tp->t_msglen) {
2160 /*
2161 * While the tab being erased was
2162 * expanded, some data was written
2163 * to the terminal; we can't erase
2164 * it cleanly, so we just reprint
2165 * the whole line as if the user
2166 * had typed the reprint character.
2167 */
2168 ldterm_reprint(q, ebsize, tp);
2169 return;
2170 }
2171 tabcols = ldterm_tabcols(tp);
2172 while (--tabcols >= 0)
2173 ldterm_outchar('\b', q, ebsize, tp);
2174 break;
2175 }
2176 }
2177 } else if ((tp->t_modes.c_lflag & ECHOPRT) &&
is85bb5f12008-07-02 17:06:30 -07002178 (tp->t_modes.c_lflag & IEXTEN)) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002179 /*
2180 * "Printing rubout"; echo it between \ and /.
2181 */
2182 if (!(tp->t_state & TS_ERASE)) {
2183 ldterm_outchar('\\', q, ebsize, tp);
2184 tp->t_state |= TS_ERASE;
2185 }
2186 (void) ldterm_echo(c, q, ebsize, tp);
2187 } else
2188 (void) ldterm_echo(tp->t_modes.c_cc[VERASE], q, ebsize, tp);
2189 tp->t_rocount--; /* we "unechoed" this character */
2190}
2191
2192
2193/*
2194 * Find the number of characters the tab we just deleted took up by
2195 * zipping through the current line and recomputing the column
2196 * number.
2197 */
2198static int
2199ldterm_tabcols(ldtermstd_state_t *tp)
2200{
2201 int col;
2202 int i;
2203 mblk_t *bp;
2204 unsigned char *readp, *endp;
2205 unsigned char c;
2206 uchar_t *startp;
2207 char errflg;
2208 uchar_t u8[LDTERM_CS_MAX_BYTE_LENGTH];
2209
2210 col = tp->t_rocol;
2211 /*
2212 * If we're doing multi-byte stuff, zip through the list of
2213 * widths to figure out where we are (we've kept track in most
2214 * cases).
2215 */
2216 if (tp->t_state & TS_MEUC) {
2217 ASSERT(tp->t_eucp_mp);
2218 bp = tp->t_message;
2219 startp = bp->b_datap->db_base;
2220 readp = tp->t_eucp_mp->b_rptr;
2221 endp = tp->t_eucp;
2222 errflg = (char)0;
2223 while (readp < endp) {
2224 switch (*readp) {
2225 case EUC_TWIDTH: /* it's a tab */
2226 col |= 07; /* bump up */
2227 col++;
2228 break;
2229 case EUC_BSWIDTH: /* backspace */
2230 if (col)
2231 col--;
2232 break;
2233 case EUC_NLWIDTH: /* newline */
2234 if (tp->t_modes.c_oflag & ONLRET)
2235 col = 0;
2236 break;
2237 case EUC_CRWIDTH: /* return */
2238 col = 0;
2239 break;
2240 case UNKNOWN_WIDTH: /* UTF-8 unknown width */
2241 if (tp->t_csdata.codeset_type !=
2242 LDTERM_CS_TYPE_UTF8 || errflg) {
2243 *readp = 1;
2244 col++;
2245 break;
2246 }
2247 /*
2248 * Collect the current UTF-8 character bytes
2249 * from (possibly multiple) data buffers so
2250 * that we can figure out the display width.
2251 */
2252 u8[0] = *startp;
2253 for (i = 1; (i < LDTERM_CS_MAX_BYTE_LENGTH) &&
is85bb5f12008-07-02 17:06:30 -07002254 (*(readp + i) == 0); i++) {
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002255 startp++;
2256 if (startp >= bp->b_datap->db_lim) {
2257 if (bp->b_cont) {
2258 bp = bp->b_cont;
2259 startp =
is85bb5f12008-07-02 17:06:30 -07002260 bp->b_datap->
2261 db_base;
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002262 } else {
2263 *readp = 1;
2264 col++;
2265 break;
2266 }
2267 }
2268 u8[i] = *startp;
2269 }
2270
2271 /* tp->t_eucp_mp contains wrong info?? */
2272 if (*readp == 1)
2273 break;
2274
2275 *readp = ldterm_utf8_width(u8, i);
2276
2277 col += *readp;
2278 readp += (i - 1);
2279 break;
2280 default:
2281 col += *readp;
2282 break;
2283 }
2284 ++readp;
2285 ++startp;
2286 if (startp >= bp->b_datap->db_lim) {
2287 if (bp->b_cont) {
2288 bp = bp->b_cont;
2289 startp = bp->b_datap->db_base;
2290 } else {
2291 /*
2292 * This will happen only if
2293 * tp->t_eucp_mp contains wrong
2294 * display width info.
2295 */
2296 errflg = (char)1;
2297 startp--;
2298 }
2299 }
2300 }
2301 goto eucout; /* finished! */
2302 }
2303 bp = tp->t_message;
2304 do {
2305 readp = bp->b_rptr;
2306 while (readp < bp->b_wptr) {
2307 c = *readp++;
2308 if ((tp->t_modes.c_lflag & ECHOCTL) &&
2309 (tp->t_modes.c_lflag & IEXTEN)) {
2310 if (c <= 037 && c != '\t' && c != '\n' ||
2311 c == 0177) {
2312 col += 2;
2313 continue;
2314 }
2315 }
2316 /*
2317 * Column position calculated here.
2318 */
2319 switch (typetab[c]) {
2320
2321 /*
2322 * Ordinary characters; advance by
2323 * one.
2324 */
2325 case ORDINARY:
2326 col++;
2327 break;
2328
2329 /*
2330 * Non-printing characters; nothing
2331 * happens.
2332 */
2333 case CONTROL:
2334 break;
2335
2336 /* Backspace */
2337 case BACKSPACE:
2338 if (col != 0)
2339 col--;
2340 break;
2341
2342 /* Newline; column depends on flags. */
2343 case NEWLINE:
2344 if (tp->t_modes.c_oflag & ONLRET)
2345 col = 0;
2346 break;
2347
2348 /* tab */
2349 case TAB:
2350 col |= 07;
2351 col++;
2352 break;
2353
2354 /* vertical motion */
2355 case VTAB:
2356 break;
2357
2358 /* carriage return */
2359 case RETURN:
2360 col = 0;
2361 break;
2362 }
2363 }
2364 } while ((bp = bp->b_cont) != NULL); /* next block, if any */
2365
2366 /*
2367 * "col" is now the column number before the tab. "tp->t_col"
2368 * is still the column number after the tab, since we haven't
2369 * erased the tab yet. Thus "tp->t_col - col" is the number
2370 * of positions the tab moved.
2371 */
2372eucout:
2373 col = tp->t_col - col;
2374 if (col > 8)
2375 col = 8; /* overflow screw */
2376 return (col);
2377}
2378
2379
2380/*
2381 * Erase a single character; We ONLY ONLY deal with ASCII or
2382 * single-column single-byte codeset character. For multi-byte characters,
2383 * see "ldterm_csi_erase".
2384 */
2385static void
2386ldterm_erase(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
2387{
2388 int c;
2389
2390 if ((c = ldterm_unget(tp)) != -1) {
2391 ldterm_rubout((unsigned char) c, q, ebsize, tp);
2392 ldterm_trim(tp);
2393 if (tp->t_state & TS_MEUC)
2394 --tp->t_eucp;
2395 }
2396}
2397
2398
2399/*
2400 * Erase an entire word, single-byte EUC only please.
2401 */
2402static void
2403ldterm_werase(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
2404{
2405 int c;
2406
2407 /*
2408 * Erase trailing white space, if any.
2409 */
2410 while ((c = ldterm_unget(tp)) == ' ' || c == '\t') {
2411 ldterm_rubout((unsigned char) c, q, ebsize, tp);
2412 ldterm_trim(tp);
2413 }
2414
2415 /*
2416 * Erase non-white-space characters, if any.
2417 */
2418 while (c != -1 && c != ' ' && c != '\t') {
2419 ldterm_rubout((unsigned char) c, q, ebsize, tp);
2420 ldterm_trim(tp);
2421 c = ldterm_unget(tp);
2422 }
2423 if (c != -1) {
2424 /*
2425 * We removed one too many characters; put the last
2426 * one back.
2427 */
2428 tp->t_endmsg->b_wptr++; /* put 'c' back */
2429 tp->t_msglen++;
2430 }
2431}
2432
2433
2434/*
2435 * ldterm_csi_werase - This is multi-byte equivalent of "word erase".
2436 * "Word erase" only makes sense in languages which space between words,
2437 * and it's presumptuous for us to attempt "word erase" when we don't
2438 * know anything about what's really going on. It makes no sense for
2439 * many languages, as the criteria for defining words and tokens may
2440 * be completely different.
2441 *
2442 * In the TS_MEUC case (which is how we got here), we define a token to
2443 * be space- or tab-delimited, and erase one of them. It helps to
2444 * have this for command lines, but it's otherwise useless for text
2445 * editing applications; you need more sophistication than we can
2446 * provide here.
2447 */
2448static void
2449ldterm_csi_werase(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
2450{
2451 int c, i;
2452 int len;
2453 uchar_t *ip;
2454 uchar_t u8[LDTERM_CS_MAX_BYTE_LENGTH];
2455 uchar_t u8_2[LDTERM_CS_MAX_BYTE_LENGTH];
2456
2457 /*
2458 * ip points to the width of the actual bytes. t_eucp points
2459 * one byte beyond, where the next thing will be inserted.
2460 */
2461 ip = tp->t_eucp - 1;
2462 /*
2463 * Erase trailing white space, if any.
2464 */
2465 while ((c = ldterm_unget(tp)) == ' ' || c == '\t') {
2466 tp->t_eucp--;
2467 ldterm_rubout((unsigned char) c, q, ebsize, tp);
2468 ldterm_trim(tp);
2469 --ip;
2470 }
2471
2472 /*
2473 * Erase non-white-space characters, if any. The outer loop
2474 * bops through each byte in the buffer. Multi-byte is removed, as
2475 * is ASCII, one byte at a time. The inner loop (for) is only
2476 * executed for first bytes of multi-byte. The inner loop erases
2477 * the number of columns required for the multi-byte char. We check
2478 * for ASCII first, and ldterm_rubout knows about ASCII.
2479 */
2480 len = 0;
2481 while (c != -1 && c != ' ' && c != '\t') {
2482 tp->t_eucp--;
2483 if (len < LDTERM_CS_MAX_BYTE_LENGTH) {
2484 u8[len++] = (uchar_t)c;
2485 }
2486 /*
2487 * Unlike EUC, except the leading byte, some bytes of
2488 * a non-EUC multi-byte characters are in the ASCII code
2489 * range, esp., 0x41 ~ 0x7a. Thus, we cannot simply check
2490 * ISASCII().
2491 * Checking the (*ip == 1 || *ip == 2 || *ip > UNKNOWN_WIDTH)
2492 * will ensure that it is a single byte character (even though
2493 * it is on display width not byte length) and can be further
2494 * checked whether it is an ASCII character or not.
2495 *
2496 * When ECHOCTL is on and 'c' is an ASCII control character,
2497 * *ip == 2 happens.
2498 */
2499 if ((*ip == 1 || *ip == 2 || *ip > UNKNOWN_WIDTH) &&
2500 ISASCII(c)) {
2501 ldterm_rubout((unsigned char) c, q, ebsize, tp);
2502 len = 0;
2503 } else if (*ip) {
2504 if (*ip == UNKNOWN_WIDTH) {
2505 if (tp->t_csdata.codeset_type ==
2506 LDTERM_CS_TYPE_UTF8) {
2507 for (i = 0; i < len; i++)
2508 u8_2[i] = u8[len - i - 1];
2509 *ip = ldterm_utf8_width(u8_2, len);
2510 } else {
2511 *ip = 1;
2512 }
2513 }
2514 /*
2515 * erase for number of columns required for
2516 * this multi-byte character. Hopefully, matches
2517 * ldterm_dispwidth!
2518 */
2519 for (i = 0; i < (int)*ip; i++)
2520 ldterm_rubout(' ', q, ebsize, tp);
2521 len = 0;
2522 }
2523 ldterm_trim(tp);
2524 --ip;
2525 c = ldterm_unget(tp);
2526 }
2527 if (c != -1) {
2528 /*
2529 * We removed one too many characters; put the last
2530 * one back.
2531 */
2532 tp->t_endmsg->b_wptr++; /* put 'c' back */
2533 tp->t_msglen++;
2534 }
2535}
2536
2537
2538/*
2539 * Kill an entire line, erasing each character one-by-one (if ECHOKE
2540 * is set) or just echoing the kill character, followed by a newline
2541 * (if ECHOK is set). Multi-byte processing is included here.
2542 */
2543
2544static void
2545ldterm_kill(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
2546{
2547 int c, i;
2548 int len;
2549 uchar_t *ip;
2550 uchar_t u8[LDTERM_CS_MAX_BYTE_LENGTH];
2551 uchar_t u8_2[LDTERM_CS_MAX_BYTE_LENGTH];
2552
2553 if ((tp->t_modes.c_lflag & ECHOKE) &&
2554 (tp->t_modes.c_lflag & IEXTEN) &&
2555 (tp->t_msglen == tp->t_rocount)) {
2556 if (tp->t_state & TS_MEUC) {
2557 ip = tp->t_eucp - 1;
2558 /*
2559 * This loop similar to "ldterm_csi_werase" above.
2560 */
2561 len = 0;
2562 while ((c = ldterm_unget(tp)) != (-1)) {
2563 tp->t_eucp--;
2564 if (len < LDTERM_CS_MAX_BYTE_LENGTH) {
2565 u8[len++] = (uchar_t)c;
2566 }
2567 if ((*ip == 1 || *ip == 2 ||
2568 *ip > UNKNOWN_WIDTH) && ISASCII(c)) {
2569 ldterm_rubout((unsigned char) c, q,
is85bb5f12008-07-02 17:06:30 -07002570 ebsize, tp);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002571 len = 0;
2572 } else if (*ip) {
2573 if (*ip == UNKNOWN_WIDTH) {
2574 if (tp->t_csdata.codeset_type
2575 == LDTERM_CS_TYPE_UTF8) {
2576 for (i = 0; i < len;
2577 i++)
2578 u8_2[i] =
2579 u8[len-i-1];
2580 *ip = ldterm_utf8_width(
is85bb5f12008-07-02 17:06:30 -07002581 u8_2, len);
stevel@tonic-gate7c478bd2005-06-14 00:00:00 -07002582 } else {
2583 *ip = 1;
2584 }
2585 }
2586 for (i = 0; i < (int)*ip; i++)
2587 ldterm_rubout(' ', q, ebsize,
2588 tp);
2589 len = 0;
2590 }
2591 ldterm_trim(tp);
2592 --ip;
2593 }
2594 } else {
2595 while ((c = ldterm_unget(tp)) != -1) {
2596 ldterm_rubout((unsigned char) c, q, ebsize, tp);
2597 ldterm_trim(tp);
2598 }
2599 }
2600 } else {
2601 (void)