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