10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
5*7012Sis * Common Development and Distribution License (the "License").
6*7012Sis * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*7012Sis * Copyright 2008 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate /* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
270Sstevel@tonic-gate /* All Rights Reserved */
280Sstevel@tonic-gate
290Sstevel@tonic-gate /*
300Sstevel@tonic-gate * University Copyright- Copyright (c) 1982, 1986, 1988
310Sstevel@tonic-gate * The Regents of the University of California
320Sstevel@tonic-gate * All Rights Reserved
330Sstevel@tonic-gate *
340Sstevel@tonic-gate * University Acknowledgment- Portions of this document are derived from
350Sstevel@tonic-gate * software developed by the University of California, Berkeley, and its
360Sstevel@tonic-gate * contributors.
370Sstevel@tonic-gate */
380Sstevel@tonic-gate
390Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI"
400Sstevel@tonic-gate
410Sstevel@tonic-gate /*
420Sstevel@tonic-gate * Standard Streams Terminal Line Discipline module.
430Sstevel@tonic-gate */
440Sstevel@tonic-gate
450Sstevel@tonic-gate #include <sys/param.h>
460Sstevel@tonic-gate #include <sys/types.h>
470Sstevel@tonic-gate #include <sys/termio.h>
480Sstevel@tonic-gate #include <sys/stream.h>
490Sstevel@tonic-gate #include <sys/conf.h>
500Sstevel@tonic-gate #include <sys/stropts.h>
510Sstevel@tonic-gate #include <sys/strsubr.h>
520Sstevel@tonic-gate #include <sys/strsun.h>
530Sstevel@tonic-gate #include <sys/strtty.h>
540Sstevel@tonic-gate #include <sys/signal.h>
550Sstevel@tonic-gate #include <sys/file.h>
560Sstevel@tonic-gate #include <sys/errno.h>
570Sstevel@tonic-gate #include <sys/debug.h>
580Sstevel@tonic-gate #include <sys/cmn_err.h>
590Sstevel@tonic-gate #include <sys/euc.h>
600Sstevel@tonic-gate #include <sys/eucioctl.h>
610Sstevel@tonic-gate #include <sys/csiioctl.h>
620Sstevel@tonic-gate #include <sys/ptms.h>
630Sstevel@tonic-gate #include <sys/ldterm.h>
640Sstevel@tonic-gate #include <sys/cred.h>
650Sstevel@tonic-gate #include <sys/ddi.h>
660Sstevel@tonic-gate #include <sys/sunddi.h>
670Sstevel@tonic-gate #include <sys/kmem.h>
680Sstevel@tonic-gate #include <sys/modctl.h>
690Sstevel@tonic-gate
700Sstevel@tonic-gate /* Time limit when draining during a close(9E) invoked by exit(2) */
710Sstevel@tonic-gate /* Can be set to zero to emulate the old, broken behavior */
720Sstevel@tonic-gate int ldterm_drain_limit = 15000000;
730Sstevel@tonic-gate
740Sstevel@tonic-gate /*
750Sstevel@tonic-gate * Character types.
760Sstevel@tonic-gate */
770Sstevel@tonic-gate #define ORDINARY 0
780Sstevel@tonic-gate #define CONTROL 1
790Sstevel@tonic-gate #define BACKSPACE 2
800Sstevel@tonic-gate #define NEWLINE 3
810Sstevel@tonic-gate #define TAB 4
820Sstevel@tonic-gate #define VTAB 5
830Sstevel@tonic-gate #define RETURN 6
840Sstevel@tonic-gate
850Sstevel@tonic-gate /*
860Sstevel@tonic-gate * The following for EUC handling:
870Sstevel@tonic-gate */
880Sstevel@tonic-gate #define T_SS2 7
890Sstevel@tonic-gate #define T_SS3 8
900Sstevel@tonic-gate
910Sstevel@tonic-gate /*
920Sstevel@tonic-gate * Table indicating character classes to tty driver. In particular,
930Sstevel@tonic-gate * if the class is ORDINARY, then the character needs no special
940Sstevel@tonic-gate * processing on output.
950Sstevel@tonic-gate *
960Sstevel@tonic-gate * Characters in the C1 set are all considered CONTROL; this will
970Sstevel@tonic-gate * work with terminals that properly use the ANSI/ISO extensions,
980Sstevel@tonic-gate * but might cause distress with terminals that put graphics in
990Sstevel@tonic-gate * the range 0200-0237. On the other hand, characters in that
1000Sstevel@tonic-gate * range cause even greater distress to other UNIX terminal drivers....
1010Sstevel@tonic-gate */
1020Sstevel@tonic-gate
1030Sstevel@tonic-gate static char typetab[256] = {
1040Sstevel@tonic-gate /* 000 */ CONTROL, CONTROL, CONTROL, CONTROL,
1050Sstevel@tonic-gate /* 004 */ CONTROL, CONTROL, CONTROL, CONTROL,
1060Sstevel@tonic-gate /* 010 */ BACKSPACE, TAB, NEWLINE, CONTROL,
1070Sstevel@tonic-gate /* 014 */ VTAB, RETURN, CONTROL, CONTROL,
1080Sstevel@tonic-gate /* 020 */ CONTROL, CONTROL, CONTROL, CONTROL,
1090Sstevel@tonic-gate /* 024 */ CONTROL, CONTROL, CONTROL, CONTROL,
1100Sstevel@tonic-gate /* 030 */ CONTROL, CONTROL, CONTROL, CONTROL,
1110Sstevel@tonic-gate /* 034 */ CONTROL, CONTROL, CONTROL, CONTROL,
1120Sstevel@tonic-gate /* 040 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1130Sstevel@tonic-gate /* 044 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1140Sstevel@tonic-gate /* 050 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1150Sstevel@tonic-gate /* 054 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1160Sstevel@tonic-gate /* 060 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1170Sstevel@tonic-gate /* 064 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1180Sstevel@tonic-gate /* 070 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1190Sstevel@tonic-gate /* 074 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1200Sstevel@tonic-gate /* 100 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1210Sstevel@tonic-gate /* 104 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1220Sstevel@tonic-gate /* 110 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1230Sstevel@tonic-gate /* 114 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1240Sstevel@tonic-gate /* 120 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1250Sstevel@tonic-gate /* 124 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1260Sstevel@tonic-gate /* 130 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1270Sstevel@tonic-gate /* 134 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1280Sstevel@tonic-gate /* 140 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1290Sstevel@tonic-gate /* 144 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1300Sstevel@tonic-gate /* 150 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1310Sstevel@tonic-gate /* 154 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1320Sstevel@tonic-gate /* 160 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1330Sstevel@tonic-gate /* 164 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1340Sstevel@tonic-gate /* 170 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1350Sstevel@tonic-gate /* 174 */ ORDINARY, ORDINARY, ORDINARY, CONTROL,
1360Sstevel@tonic-gate /* 200 */ CONTROL, CONTROL, CONTROL, CONTROL,
1370Sstevel@tonic-gate /* 204 */ CONTROL, CONTROL, T_SS2, T_SS3,
1380Sstevel@tonic-gate /* 210 */ CONTROL, CONTROL, CONTROL, CONTROL,
1390Sstevel@tonic-gate /* 214 */ CONTROL, CONTROL, CONTROL, CONTROL,
1400Sstevel@tonic-gate /* 220 */ CONTROL, CONTROL, CONTROL, CONTROL,
1410Sstevel@tonic-gate /* 224 */ CONTROL, CONTROL, CONTROL, CONTROL,
1420Sstevel@tonic-gate /* 230 */ CONTROL, CONTROL, CONTROL, CONTROL,
1430Sstevel@tonic-gate /* 234 */ CONTROL, CONTROL, CONTROL, CONTROL,
1440Sstevel@tonic-gate /* 240 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1450Sstevel@tonic-gate /* 244 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1460Sstevel@tonic-gate /* 250 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1470Sstevel@tonic-gate /* 254 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1480Sstevel@tonic-gate /* 260 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1490Sstevel@tonic-gate /* 264 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1500Sstevel@tonic-gate /* 270 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1510Sstevel@tonic-gate /* 274 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1520Sstevel@tonic-gate /* 300 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1530Sstevel@tonic-gate /* 304 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1540Sstevel@tonic-gate /* 310 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1550Sstevel@tonic-gate /* 314 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1560Sstevel@tonic-gate /* 320 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1570Sstevel@tonic-gate /* 324 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1580Sstevel@tonic-gate /* 330 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1590Sstevel@tonic-gate /* 334 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1600Sstevel@tonic-gate /* 340 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1610Sstevel@tonic-gate /* 344 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1620Sstevel@tonic-gate /* 350 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1630Sstevel@tonic-gate /* 354 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1640Sstevel@tonic-gate /* 360 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1650Sstevel@tonic-gate /* 364 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1660Sstevel@tonic-gate /* 370 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1670Sstevel@tonic-gate /*
1680Sstevel@tonic-gate * WARNING: For EUC, 0xFF must be an ordinary character. It is used with
1690Sstevel@tonic-gate * single-byte EUC in some of the "ISO Latin Alphabet" codesets, and occupies
1700Sstevel@tonic-gate * a screen position; in those ISO sets where that position isn't used, it
1710Sstevel@tonic-gate * shouldn't make any difference.
1720Sstevel@tonic-gate */
1730Sstevel@tonic-gate /* 374 */ ORDINARY, ORDINARY, ORDINARY, ORDINARY,
1740Sstevel@tonic-gate };
1750Sstevel@tonic-gate
1760Sstevel@tonic-gate /*
1770Sstevel@tonic-gate * Translation table for output without OLCUC. All ORDINARY-class characters
1780Sstevel@tonic-gate * translate to themselves. All other characters have a zero in the table,
1790Sstevel@tonic-gate * which stops the copying.
1800Sstevel@tonic-gate */
1810Sstevel@tonic-gate static unsigned char notrantab[256] = {
1820Sstevel@tonic-gate /* 000 */ 0, 0, 0, 0, 0, 0, 0, 0,
1830Sstevel@tonic-gate /* 010 */ 0, 0, 0, 0, 0, 0, 0, 0,
1840Sstevel@tonic-gate /* 020 */ 0, 0, 0, 0, 0, 0, 0, 0,
1850Sstevel@tonic-gate /* 030 */ 0, 0, 0, 0, 0, 0, 0, 0,
1860Sstevel@tonic-gate /* 040 */ ' ', '!', '"', '#', '$', '%', '&', '\'',
1870Sstevel@tonic-gate /* 050 */ '(', ')', '*', '+', ',', '-', '.', '/',
1880Sstevel@tonic-gate /* 060 */ '0', '1', '2', '3', '4', '5', '6', '7',
1890Sstevel@tonic-gate /* 070 */ '8', '9', ':', ';', '<', '=', '>', '?',
1900Sstevel@tonic-gate /* 100 */ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
1910Sstevel@tonic-gate /* 110 */ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
1920Sstevel@tonic-gate /* 120 */ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
1930Sstevel@tonic-gate /* 130 */ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
1940Sstevel@tonic-gate /* 140 */ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
1950Sstevel@tonic-gate /* 150 */ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
1960Sstevel@tonic-gate /* 160 */ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
1970Sstevel@tonic-gate /* 170 */ 'x', 'y', 'z', '{', '|', '}', '~', 0,
1980Sstevel@tonic-gate /* 200 */ 0, 0, 0, 0, 0, 0, 0, 0,
1990Sstevel@tonic-gate /* 210 */ 0, 0, 0, 0, 0, 0, 0, 0,
2000Sstevel@tonic-gate /* 220 */ 0, 0, 0, 0, 0, 0, 0, 0,
2010Sstevel@tonic-gate /* 230 */ 0, 0, 0, 0, 0, 0, 0, 0,
2020Sstevel@tonic-gate /* 240 */ 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
2030Sstevel@tonic-gate /* 250 */ 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
2040Sstevel@tonic-gate /* 260 */ 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
2050Sstevel@tonic-gate /* 270 */ 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
2060Sstevel@tonic-gate /* 300 */ 0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
2070Sstevel@tonic-gate /* 310 */ 0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
2080Sstevel@tonic-gate /* 320 */ 0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
2090Sstevel@tonic-gate /* 330 */ 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
2100Sstevel@tonic-gate /* 340 */ 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
2110Sstevel@tonic-gate /* 350 */ 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
2120Sstevel@tonic-gate /* 360 */ 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
2130Sstevel@tonic-gate /*
2140Sstevel@tonic-gate * WARNING: as for above ISO sets, \377 may be used. Translate it to
2150Sstevel@tonic-gate * itself.
2160Sstevel@tonic-gate */
2170Sstevel@tonic-gate /* 370 */ 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377,
2180Sstevel@tonic-gate };
2190Sstevel@tonic-gate
2200Sstevel@tonic-gate /*
2210Sstevel@tonic-gate * Translation table for output with OLCUC. All ORDINARY-class characters
2220Sstevel@tonic-gate * translate to themselves, except for lower-case letters which translate
2230Sstevel@tonic-gate * to their upper-case equivalents. All other characters have a zero in
2240Sstevel@tonic-gate * the table, which stops the copying.
2250Sstevel@tonic-gate */
2260Sstevel@tonic-gate static unsigned char lcuctab[256] = {
2270Sstevel@tonic-gate /* 000 */ 0, 0, 0, 0, 0, 0, 0, 0,
2280Sstevel@tonic-gate /* 010 */ 0, 0, 0, 0, 0, 0, 0, 0,
2290Sstevel@tonic-gate /* 020 */ 0, 0, 0, 0, 0, 0, 0, 0,
2300Sstevel@tonic-gate /* 030 */ 0, 0, 0, 0, 0, 0, 0, 0,
2310Sstevel@tonic-gate /* 040 */ ' ', '!', '"', '#', '$', '%', '&', '\'',
2320Sstevel@tonic-gate /* 050 */ '(', ')', '*', '+', ',', '-', '.', '/',
2330Sstevel@tonic-gate /* 060 */ '0', '1', '2', '3', '4', '5', '6', '7',
2340Sstevel@tonic-gate /* 070 */ '8', '9', ':', ';', '<', '=', '>', '?',
2350Sstevel@tonic-gate /* 100 */ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
2360Sstevel@tonic-gate /* 110 */ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
2370Sstevel@tonic-gate /* 120 */ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
2380Sstevel@tonic-gate /* 130 */ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
2390Sstevel@tonic-gate /* 140 */ '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
2400Sstevel@tonic-gate /* 150 */ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
2410Sstevel@tonic-gate /* 160 */ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
2420Sstevel@tonic-gate /* 170 */ 'X', 'Y', 'Z', '{', '|', '}', '~', 0,
2430Sstevel@tonic-gate /* 200 */ 0, 0, 0, 0, 0, 0, 0, 0,
2440Sstevel@tonic-gate /* 210 */ 0, 0, 0, 0, 0, 0, 0, 0,
2450Sstevel@tonic-gate /* 220 */ 0, 0, 0, 0, 0, 0, 0, 0,
2460Sstevel@tonic-gate /* 230 */ 0, 0, 0, 0, 0, 0, 0, 0,
2470Sstevel@tonic-gate /* 240 */ 0240, 0241, 0242, 0243, 0244, 0245, 0246, 0247,
2480Sstevel@tonic-gate /* 250 */ 0250, 0251, 0252, 0253, 0254, 0255, 0256, 0257,
2490Sstevel@tonic-gate /* 260 */ 0260, 0261, 0262, 0263, 0264, 0265, 0266, 0267,
2500Sstevel@tonic-gate /* 270 */ 0270, 0271, 0272, 0273, 0274, 0275, 0276, 0277,
2510Sstevel@tonic-gate /* 300 */ 0300, 0301, 0302, 0303, 0304, 0305, 0306, 0307,
2520Sstevel@tonic-gate /* 310 */ 0310, 0311, 0312, 0313, 0314, 0315, 0316, 0317,
2530Sstevel@tonic-gate /* 320 */ 0320, 0321, 0322, 0323, 0324, 0325, 0326, 0327,
2540Sstevel@tonic-gate /* 330 */ 0330, 0331, 0332, 0333, 0334, 0335, 0336, 0337,
2550Sstevel@tonic-gate /* 340 */ 0340, 0341, 0342, 0343, 0344, 0345, 0346, 0347,
2560Sstevel@tonic-gate /* 350 */ 0350, 0351, 0352, 0353, 0354, 0355, 0356, 0357,
2570Sstevel@tonic-gate /* 360 */ 0360, 0361, 0362, 0363, 0364, 0365, 0366, 0367,
2580Sstevel@tonic-gate /*
2590Sstevel@tonic-gate * WARNING: as for above ISO sets, \377 may be used. Translate it to
2600Sstevel@tonic-gate * itself.
2610Sstevel@tonic-gate */
2620Sstevel@tonic-gate /* 370 */ 0370, 0371, 0372, 0373, 0374, 0375, 0376, 0377,
2630Sstevel@tonic-gate };
2640Sstevel@tonic-gate
2650Sstevel@tonic-gate /*
2660Sstevel@tonic-gate * Input mapping table -- if an entry is non-zero, and XCASE is set,
2670Sstevel@tonic-gate * when the corresponding character is typed preceded by "\" the escape
2680Sstevel@tonic-gate * sequence is replaced by the table value. Mostly used for
2690Sstevel@tonic-gate * upper-case only terminals.
2700Sstevel@tonic-gate */
2710Sstevel@tonic-gate static char imaptab[256] = {
2720Sstevel@tonic-gate /* 000 */ 0, 0, 0, 0, 0, 0, 0, 0,
2730Sstevel@tonic-gate /* 010 */ 0, 0, 0, 0, 0, 0, 0, 0,
2740Sstevel@tonic-gate /* 020 */ 0, 0, 0, 0, 0, 0, 0, 0,
2750Sstevel@tonic-gate /* 030 */ 0, 0, 0, 0, 0, 0, 0, 0,
2760Sstevel@tonic-gate /* 040 */ 0, '|', 0, 0, 0, 0, 0, '`',
2770Sstevel@tonic-gate /* 050 */ '{', '}', 0, 0, 0, 0, 0, 0,
2780Sstevel@tonic-gate /* 060 */ 0, 0, 0, 0, 0, 0, 0, 0,
2790Sstevel@tonic-gate /* 070 */ 0, 0, 0, 0, 0, 0, 0, 0,
2800Sstevel@tonic-gate /* 100 */ 0, 0, 0, 0, 0, 0, 0, 0,
2810Sstevel@tonic-gate /* 110 */ 0, 0, 0, 0, 0, 0, 0, 0,
2820Sstevel@tonic-gate /* 120 */ 0, 0, 0, 0, 0, 0, 0, 0,
2830Sstevel@tonic-gate /* 130 */ 0, 0, 0, 0, '\\', 0, '~', 0,
2840Sstevel@tonic-gate /* 140 */ 0, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
2850Sstevel@tonic-gate /* 150 */ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
2860Sstevel@tonic-gate /* 160 */ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
2870Sstevel@tonic-gate /* 170 */ 'X', 'Y', 'Z', 0, 0, 0, 0, 0,
2880Sstevel@tonic-gate /* 200-377 aren't mapped */
2890Sstevel@tonic-gate };
2900Sstevel@tonic-gate
2910Sstevel@tonic-gate /*
2920Sstevel@tonic-gate * Output mapping table -- if an entry is non-zero, and XCASE is set,
2930Sstevel@tonic-gate * the corresponding character is printed as "\" followed by the table
2940Sstevel@tonic-gate * value. Mostly used for upper-case only terminals.
2950Sstevel@tonic-gate */
2960Sstevel@tonic-gate static char omaptab[256] = {
2970Sstevel@tonic-gate /* 000 */ 0, 0, 0, 0, 0, 0, 0, 0,
2980Sstevel@tonic-gate /* 010 */ 0, 0, 0, 0, 0, 0, 0, 0,
2990Sstevel@tonic-gate /* 020 */ 0, 0, 0, 0, 0, 0, 0, 0,
3000Sstevel@tonic-gate /* 030 */ 0, 0, 0, 0, 0, 0, 0, 0,
3010Sstevel@tonic-gate /* 040 */ 0, 0, 0, 0, 0, 0, 0, 0,
3020Sstevel@tonic-gate /* 050 */ 0, 0, 0, 0, 0, 0, 0, 0,
3030Sstevel@tonic-gate /* 060 */ 0, 0, 0, 0, 0, 0, 0, 0,
3040Sstevel@tonic-gate /* 070 */ 0, 0, 0, 0, 0, 0, 0, 0,
3050Sstevel@tonic-gate /* 100 */ 0, 'A', 'B', 'C', 'D', 'E', 'F', 'G',
3060Sstevel@tonic-gate /* 110 */ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
3070Sstevel@tonic-gate /* 120 */ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
3080Sstevel@tonic-gate /* 130 */ 'X', 'Y', 'Z', 0, 0, 0, 0, 0,
3090Sstevel@tonic-gate /* 140 */ '\'', 0, 0, 0, 0, 0, 0, 0,
3100Sstevel@tonic-gate /* 150 */ 0, 0, 0, 0, 0, 0, 0, 0,
3110Sstevel@tonic-gate /* 160 */ 0, 0, 0, 0, 0, 0, 0, 0,
3120Sstevel@tonic-gate /* 170 */ 0, 0, 0, '(', '!', ')', '^', 0,
3130Sstevel@tonic-gate /* 200-377 aren't mapped */
3140Sstevel@tonic-gate };
3150Sstevel@tonic-gate
3160Sstevel@tonic-gate /*
3170Sstevel@tonic-gate * Translation table for TS_MEUC output without OLCUC. All printing ASCII
3180Sstevel@tonic-gate * characters translate to themselves. All other _bytes_ have a zero in
3190Sstevel@tonic-gate * the table, which stops the copying. This and the following table exist
3200Sstevel@tonic-gate * only so we can use the existing movtuc processing with or without OLCUC.
3210Sstevel@tonic-gate * Maybe it speeds up something...because we can copy a block of characters
3220Sstevel@tonic-gate * by only looking for zeros in the table.
3230Sstevel@tonic-gate *
3240Sstevel@tonic-gate * If we took the simple expedient of DISALLOWING "olcuc" with multi-byte
3250Sstevel@tonic-gate * processing, we could rid ourselves of both these tables and save 512 bytes;
3260Sstevel@tonic-gate * seriously, it doesn't make much sense to use olcuc with multi-byte, and
3270Sstevel@tonic-gate * it will probably never be used. Consideration should be given to disallowing
3280Sstevel@tonic-gate * the combination TS_MEUC & OLCUC.
3290Sstevel@tonic-gate */
3300Sstevel@tonic-gate static unsigned char enotrantab[256] = {
3310Sstevel@tonic-gate /* 000 */ 0, 0, 0, 0, 0, 0, 0, 0,
3320Sstevel@tonic-gate /* 010 */ 0, 0, 0, 0, 0, 0, 0, 0,
3330Sstevel@tonic-gate /* 020 */ 0, 0, 0, 0, 0, 0, 0, 0,
3340Sstevel@tonic-gate /* 030 */ 0, 0, 0, 0, 0, 0, 0, 0,
3350Sstevel@tonic-gate /* 040 */ ' ', '!', '"', '#', '$', '%', '&', '\'',
3360Sstevel@tonic-gate /* 050 */ '(', ')', '*', '+', ',', '-', '.', '/',
3370Sstevel@tonic-gate /* 060 */ '0', '1', '2', '3', '4', '5', '6', '7',
3380Sstevel@tonic-gate /* 070 */ '8', '9', ':', ';', '<', '=', '>', '?',
3390Sstevel@tonic-gate /* 100 */ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
3400Sstevel@tonic-gate /* 110 */ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
3410Sstevel@tonic-gate /* 120 */ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
3420Sstevel@tonic-gate /* 130 */ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
3430Sstevel@tonic-gate /* 140 */ '`', 'a', 'b', 'c', 'd', 'e', 'f', 'g',
3440Sstevel@tonic-gate /* 150 */ 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
3450Sstevel@tonic-gate /* 160 */ 'p', 'q', 'r', 's', 't', 'u', 'v', 'w',
3460Sstevel@tonic-gate /* 170 */ 'x', 'y', 'z', '{', '|', '}', '~', 0,
3470Sstevel@tonic-gate /* 200 - 377 aren't mapped (they're stoppers). */
3480Sstevel@tonic-gate };
3490Sstevel@tonic-gate
3500Sstevel@tonic-gate /*
3510Sstevel@tonic-gate * Translation table for TS_MEUC output with OLCUC. All printing ASCII
3520Sstevel@tonic-gate * translate to themselves, except for lower-case letters which translate
3530Sstevel@tonic-gate * to their upper-case equivalents. All other bytes have a zero in
3540Sstevel@tonic-gate * the table, which stops the copying. Useless for ISO Latin Alphabet
3550Sstevel@tonic-gate * translations, but *sigh* OLCUC is really only defined for ASCII anyway.
3560Sstevel@tonic-gate * We only have this table so we can use the existing OLCUC processing with
3570Sstevel@tonic-gate * TS_MEUC set (multi-byte mode). Nobody would ever think of actually
3580Sstevel@tonic-gate * _using_ it...would they?
3590Sstevel@tonic-gate */
3600Sstevel@tonic-gate static unsigned char elcuctab[256] = {
3610Sstevel@tonic-gate /* 000 */ 0, 0, 0, 0, 0, 0, 0, 0,
3620Sstevel@tonic-gate /* 010 */ 0, 0, 0, 0, 0, 0, 0, 0,
3630Sstevel@tonic-gate /* 020 */ 0, 0, 0, 0, 0, 0, 0, 0,
3640Sstevel@tonic-gate /* 030 */ 0, 0, 0, 0, 0, 0, 0, 0,
3650Sstevel@tonic-gate /* 040 */ ' ', '!', '"', '#', '$', '%', '&', '\'',
3660Sstevel@tonic-gate /* 050 */ '(', ')', '*', '+', ',', '-', '.', '/',
3670Sstevel@tonic-gate /* 060 */ '0', '1', '2', '3', '4', '5', '6', '7',
3680Sstevel@tonic-gate /* 070 */ '8', '9', ':', ';', '<', '=', '>', '?',
3690Sstevel@tonic-gate /* 100 */ '@', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
3700Sstevel@tonic-gate /* 110 */ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
3710Sstevel@tonic-gate /* 120 */ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
3720Sstevel@tonic-gate /* 130 */ 'X', 'Y', 'Z', '[', '\\', ']', '^', '_',
3730Sstevel@tonic-gate /* 140 */ '`', 'A', 'B', 'C', 'D', 'E', 'F', 'G',
3740Sstevel@tonic-gate /* 150 */ 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
3750Sstevel@tonic-gate /* 160 */ 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W',
3760Sstevel@tonic-gate /* 170 */ 'X', 'Y', 'Z', '{', '|', '}', '~', 0,
3770Sstevel@tonic-gate /* 200 - 377 aren't mapped (they're stoppers). */
3780Sstevel@tonic-gate };
3790Sstevel@tonic-gate
3800Sstevel@tonic-gate static struct streamtab ldtrinfo;
3810Sstevel@tonic-gate
3820Sstevel@tonic-gate static struct fmodsw fsw = {
3830Sstevel@tonic-gate "ldterm",
3840Sstevel@tonic-gate &ldtrinfo,
3850Sstevel@tonic-gate D_MTQPAIR | D_MP
3860Sstevel@tonic-gate };
3870Sstevel@tonic-gate
3880Sstevel@tonic-gate static struct modlstrmod modlstrmod = {
3890Sstevel@tonic-gate &mod_strmodops, "terminal line discipline", &fsw
3900Sstevel@tonic-gate };
3910Sstevel@tonic-gate
3920Sstevel@tonic-gate
3930Sstevel@tonic-gate static struct modlinkage modlinkage = {
3940Sstevel@tonic-gate MODREV_1, &modlstrmod, NULL
3950Sstevel@tonic-gate };
3960Sstevel@tonic-gate
3970Sstevel@tonic-gate
3980Sstevel@tonic-gate int
_init(void)3990Sstevel@tonic-gate _init(void)
4000Sstevel@tonic-gate {
4010Sstevel@tonic-gate return (mod_install(&modlinkage));
4020Sstevel@tonic-gate }
4030Sstevel@tonic-gate
4040Sstevel@tonic-gate int
_fini(void)4050Sstevel@tonic-gate _fini(void)
4060Sstevel@tonic-gate {
4070Sstevel@tonic-gate return (mod_remove(&modlinkage));
4080Sstevel@tonic-gate }
4090Sstevel@tonic-gate
4100Sstevel@tonic-gate int
_info(struct modinfo * modinfop)4110Sstevel@tonic-gate _info(struct modinfo *modinfop)
4120Sstevel@tonic-gate {
4130Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop));
4140Sstevel@tonic-gate }
4150Sstevel@tonic-gate
4160Sstevel@tonic-gate
4170Sstevel@tonic-gate static int ldtermopen(queue_t *, dev_t *, int, int, cred_t *);
4180Sstevel@tonic-gate static int ldtermclose(queue_t *, int, cred_t *);
4190Sstevel@tonic-gate static void ldtermrput(queue_t *, mblk_t *);
4200Sstevel@tonic-gate static void ldtermrsrv(queue_t *);
4210Sstevel@tonic-gate static int ldtermrmsg(queue_t *, mblk_t *);
4220Sstevel@tonic-gate static void ldtermwput(queue_t *, mblk_t *);
4230Sstevel@tonic-gate static void ldtermwsrv(queue_t *);
4240Sstevel@tonic-gate static int ldtermwmsg(queue_t *, mblk_t *);
4250Sstevel@tonic-gate static mblk_t *ldterm_docanon(unsigned char, mblk_t *, size_t, queue_t *,
4260Sstevel@tonic-gate ldtermstd_state_t *, int *);
4270Sstevel@tonic-gate static int ldterm_unget(ldtermstd_state_t *);
4280Sstevel@tonic-gate static void ldterm_trim(ldtermstd_state_t *);
4290Sstevel@tonic-gate static void ldterm_rubout(unsigned char, queue_t *, size_t,
4300Sstevel@tonic-gate ldtermstd_state_t *);
4310Sstevel@tonic-gate static int ldterm_tabcols(ldtermstd_state_t *);
4320Sstevel@tonic-gate static void ldterm_erase(queue_t *, size_t, ldtermstd_state_t *);
4330Sstevel@tonic-gate static void ldterm_werase(queue_t *, size_t, ldtermstd_state_t *);
4340Sstevel@tonic-gate static void ldterm_kill(queue_t *, size_t, ldtermstd_state_t *);
4350Sstevel@tonic-gate static void ldterm_reprint(queue_t *, size_t, ldtermstd_state_t *);
4360Sstevel@tonic-gate static mblk_t *ldterm_dononcanon(mblk_t *, mblk_t *, size_t, queue_t *,
4370Sstevel@tonic-gate ldtermstd_state_t *);
4380Sstevel@tonic-gate static int ldterm_echo(unsigned char, queue_t *, size_t,
4390Sstevel@tonic-gate ldtermstd_state_t *);
4400Sstevel@tonic-gate static void ldterm_outchar(unsigned char, queue_t *, size_t,
4410Sstevel@tonic-gate ldtermstd_state_t *);
4420Sstevel@tonic-gate static void ldterm_outstring(unsigned char *, int, queue_t *, size_t,
4430Sstevel@tonic-gate ldtermstd_state_t *tp);
4440Sstevel@tonic-gate static mblk_t *newmsg(ldtermstd_state_t *);
4450Sstevel@tonic-gate static void ldterm_msg_upstream(queue_t *, ldtermstd_state_t *);
4460Sstevel@tonic-gate static void ldterm_wenable(void *);
4470Sstevel@tonic-gate static mblk_t *ldterm_output_msg(queue_t *, mblk_t *, mblk_t **,
4480Sstevel@tonic-gate ldtermstd_state_t *, size_t, int);
4490Sstevel@tonic-gate static void ldterm_flush_output(unsigned char, queue_t *,
4500Sstevel@tonic-gate ldtermstd_state_t *);
4510Sstevel@tonic-gate static void ldterm_dosig(queue_t *, int, unsigned char, int, int);
4520Sstevel@tonic-gate static void ldterm_do_ioctl(queue_t *, mblk_t *);
4530Sstevel@tonic-gate static int chgstropts(struct termios *, ldtermstd_state_t *, queue_t *);
4540Sstevel@tonic-gate static void ldterm_ioctl_reply(queue_t *, mblk_t *);
4550Sstevel@tonic-gate static void vmin_satisfied(queue_t *, ldtermstd_state_t *, int);
4560Sstevel@tonic-gate static void vmin_settimer(queue_t *);
4570Sstevel@tonic-gate static void vmin_timed_out(void *);
4580Sstevel@tonic-gate static void ldterm_adjust_modes(ldtermstd_state_t *);
4590Sstevel@tonic-gate static void ldterm_eucwarn(ldtermstd_state_t *);
4600Sstevel@tonic-gate static void cp_eucwioc(eucioc_t *, eucioc_t *, int);
4610Sstevel@tonic-gate static int ldterm_codeset(uchar_t, uchar_t);
4620Sstevel@tonic-gate
4630Sstevel@tonic-gate static void ldterm_csi_erase(queue_t *, size_t, ldtermstd_state_t *);
4640Sstevel@tonic-gate static void ldterm_csi_werase(queue_t *, size_t, ldtermstd_state_t *);
4650Sstevel@tonic-gate
4660Sstevel@tonic-gate static uchar_t ldterm_utf8_width(uchar_t *, int);
4670Sstevel@tonic-gate
4680Sstevel@tonic-gate /* Codeset type specific methods for EUC, PCCS, and, UTF-8 codeset types. */
4690Sstevel@tonic-gate static int __ldterm_dispwidth_euc(uchar_t, void *, int);
4700Sstevel@tonic-gate static int __ldterm_memwidth_euc(uchar_t, void *);
4710Sstevel@tonic-gate
4720Sstevel@tonic-gate static int __ldterm_dispwidth_pccs(uchar_t, void *, int);
4730Sstevel@tonic-gate static int __ldterm_memwidth_pccs(uchar_t, void *);
4740Sstevel@tonic-gate
4750Sstevel@tonic-gate static int __ldterm_dispwidth_utf8(uchar_t, void *, int);
4760Sstevel@tonic-gate static int __ldterm_memwidth_utf8(uchar_t, void *);
4770Sstevel@tonic-gate
4780Sstevel@tonic-gate static const ldterm_cs_methods_t cs_methods[LDTERM_CS_TYPE_MAX + 1] = {
4790Sstevel@tonic-gate {
4800Sstevel@tonic-gate NULL,
4810Sstevel@tonic-gate NULL
4820Sstevel@tonic-gate },
4830Sstevel@tonic-gate {
4840Sstevel@tonic-gate __ldterm_dispwidth_euc,
4850Sstevel@tonic-gate __ldterm_memwidth_euc
4860Sstevel@tonic-gate },
4870Sstevel@tonic-gate {
4880Sstevel@tonic-gate __ldterm_dispwidth_pccs,
4890Sstevel@tonic-gate __ldterm_memwidth_pccs
4900Sstevel@tonic-gate },
4910Sstevel@tonic-gate {
4920Sstevel@tonic-gate __ldterm_dispwidth_utf8,
4930Sstevel@tonic-gate __ldterm_memwidth_utf8
4940Sstevel@tonic-gate }
4950Sstevel@tonic-gate };
4960Sstevel@tonic-gate
4970Sstevel@tonic-gate /*
4980Sstevel@tonic-gate * The default codeset is presumably C locale's ISO 646 in EUC but
4990Sstevel@tonic-gate * the data structure at below defined as the default codeset data also
5000Sstevel@tonic-gate * support any single byte (EUC) locales.
5010Sstevel@tonic-gate */
5020Sstevel@tonic-gate static const ldterm_cs_data_t default_cs_data = {
5030Sstevel@tonic-gate LDTERM_DATA_VERSION,
5040Sstevel@tonic-gate LDTERM_CS_TYPE_EUC,
5050Sstevel@tonic-gate (uchar_t)0,
5060Sstevel@tonic-gate (uchar_t)0,
5070Sstevel@tonic-gate (char *)NULL,
5080Sstevel@tonic-gate {
5090Sstevel@tonic-gate '\0', '\0', '\0', '\0',
5100Sstevel@tonic-gate '\0', '\0', '\0', '\0',
5110Sstevel@tonic-gate '\0', '\0', '\0', '\0',
5120Sstevel@tonic-gate '\0', '\0', '\0', '\0',
5130Sstevel@tonic-gate '\0', '\0', '\0', '\0',
5140Sstevel@tonic-gate '\0', '\0', '\0', '\0',
5150Sstevel@tonic-gate '\0', '\0', '\0', '\0',
5160Sstevel@tonic-gate '\0', '\0', '\0', '\0',
5170Sstevel@tonic-gate '\0', '\0', '\0', '\0',
5180Sstevel@tonic-gate '\0', '\0', '\0', '\0'
5190Sstevel@tonic-gate }
5200Sstevel@tonic-gate };
5210Sstevel@tonic-gate
5220Sstevel@tonic-gate /*
523*7012Sis * The following tables are from either u8_textprep.c or uconv.c at
524*7012Sis * usr/src/common/unicode/. The tables are used to figure out corresponding
525*7012Sis * UTF-8 character byte lengths and also the validity of given character bytes.
5260Sstevel@tonic-gate */
527*7012Sis extern const int8_t u8_number_of_bytes[];
528*7012Sis extern const uchar_t u8_masks_tbl[];
529*7012Sis extern const uint8_t u8_valid_min_2nd_byte[];
530*7012Sis extern const uint8_t u8_valid_max_2nd_byte[];
5310Sstevel@tonic-gate
5320Sstevel@tonic-gate /*
5330Sstevel@tonic-gate * Unicode character width definition tables from uwidth.c:
5340Sstevel@tonic-gate */
5350Sstevel@tonic-gate extern const ldterm_unicode_data_cell_t ldterm_ucode[][16384];
5360Sstevel@tonic-gate
5370Sstevel@tonic-gate #ifdef LDDEBUG
5380Sstevel@tonic-gate int ldterm_debug = 0;
5390Sstevel@tonic-gate #define DEBUG1(a) if (ldterm_debug == 1) printf a
5400Sstevel@tonic-gate #define DEBUG2(a) if (ldterm_debug >= 2) printf a /* allocations */
5410Sstevel@tonic-gate #define DEBUG3(a) if (ldterm_debug >= 3) printf a /* M_CTL Stuff */
5420Sstevel@tonic-gate #define DEBUG4(a) if (ldterm_debug >= 4) printf a /* M_READ Stuff */
5430Sstevel@tonic-gate #define DEBUG5(a) if (ldterm_debug >= 5) printf a
5440Sstevel@tonic-gate #define DEBUG6(a) if (ldterm_debug >= 6) printf a
5450Sstevel@tonic-gate #define DEBUG7(a) if (ldterm_debug >= 7) printf a
5460Sstevel@tonic-gate #else
5470Sstevel@tonic-gate #define DEBUG1(a)
5480Sstevel@tonic-gate #define DEBUG2(a)
5490Sstevel@tonic-gate #define DEBUG3(a)
5500Sstevel@tonic-gate #define DEBUG4(a)
5510Sstevel@tonic-gate #define DEBUG5(a)
5520Sstevel@tonic-gate #define DEBUG6(a)
5530Sstevel@tonic-gate #define DEBUG7(a)
5540Sstevel@tonic-gate #endif /* LDDEBUG */
5550Sstevel@tonic-gate
5560Sstevel@tonic-gate
5570Sstevel@tonic-gate /*
5580Sstevel@tonic-gate * Since most of the buffering occurs either at the stream head or in
5590Sstevel@tonic-gate * the "message currently being assembled" buffer, we have a
5600Sstevel@tonic-gate * relatively small input queue, so that blockages above us get
5610Sstevel@tonic-gate * reflected fairly quickly to the module below us. We also have a
5620Sstevel@tonic-gate * small maximum packet size, since you can put a message of that
5630Sstevel@tonic-gate * size on an empty queue no matter how much bigger than the high
5640Sstevel@tonic-gate * water mark it is.
5650Sstevel@tonic-gate */
5660Sstevel@tonic-gate static struct module_info ldtermmiinfo = {
5670Sstevel@tonic-gate 0x0bad,
5680Sstevel@tonic-gate "ldterm",
5690Sstevel@tonic-gate 0,
5700Sstevel@tonic-gate 256,
5710Sstevel@tonic-gate HIWAT,
5720Sstevel@tonic-gate LOWAT
5730Sstevel@tonic-gate };
5740Sstevel@tonic-gate
5750Sstevel@tonic-gate
5760Sstevel@tonic-gate static struct qinit ldtermrinit = {
5770Sstevel@tonic-gate (int (*)())ldtermrput,
5780Sstevel@tonic-gate (int (*)())ldtermrsrv,
5790Sstevel@tonic-gate ldtermopen,
5800Sstevel@tonic-gate ldtermclose,
5810Sstevel@tonic-gate NULL,
5820Sstevel@tonic-gate &ldtermmiinfo
5830Sstevel@tonic-gate };
5840Sstevel@tonic-gate
5850Sstevel@tonic-gate
5860Sstevel@tonic-gate static struct module_info ldtermmoinfo = {
5870Sstevel@tonic-gate 0x0bad,
5880Sstevel@tonic-gate "ldterm",
5890Sstevel@tonic-gate 0,
5900Sstevel@tonic-gate INFPSZ,
5910Sstevel@tonic-gate 1,
5920Sstevel@tonic-gate 0
5930Sstevel@tonic-gate };
5940Sstevel@tonic-gate
5950Sstevel@tonic-gate
5960Sstevel@tonic-gate static struct qinit ldtermwinit = {
5970Sstevel@tonic-gate (int (*)())ldtermwput,
5980Sstevel@tonic-gate (int (*)())ldtermwsrv,
5990Sstevel@tonic-gate ldtermopen,
6000Sstevel@tonic-gate ldtermclose,
6010Sstevel@tonic-gate NULL,
6020Sstevel@tonic-gate &ldtermmoinfo
6030Sstevel@tonic-gate };
6040Sstevel@tonic-gate
6050Sstevel@tonic-gate
6060Sstevel@tonic-gate static struct streamtab ldtrinfo = {
6070Sstevel@tonic-gate &ldtermrinit,
6080Sstevel@tonic-gate &ldtermwinit,
6090Sstevel@tonic-gate NULL,
6100Sstevel@tonic-gate NULL
6110Sstevel@tonic-gate };
6120Sstevel@tonic-gate
6130Sstevel@tonic-gate /*
6140Sstevel@tonic-gate * Dummy qbufcall callback routine used by open and close.
6150Sstevel@tonic-gate * The framework will wake up qwait_sig when we return from
6160Sstevel@tonic-gate * this routine (as part of leaving the perimeters.)
6170Sstevel@tonic-gate * (The framework enters the perimeters before calling the qbufcall() callback
6180Sstevel@tonic-gate * and leaves the perimeters after the callback routine has executed. The
6190Sstevel@tonic-gate * framework performs an implicit wakeup of any thread in qwait/qwait_sig
6200Sstevel@tonic-gate * when it leaves the perimeter. See qwait(9E).)
6210Sstevel@tonic-gate */
6220Sstevel@tonic-gate /* ARGSUSED */
6230Sstevel@tonic-gate static void
dummy_callback(void * arg)6240Sstevel@tonic-gate dummy_callback(void *arg)
6250Sstevel@tonic-gate {}
6260Sstevel@tonic-gate
6270Sstevel@tonic-gate
6280Sstevel@tonic-gate static mblk_t *
open_ioctl(queue_t * q,uint_t cmd)6290Sstevel@tonic-gate open_ioctl(queue_t *q, uint_t cmd)
6300Sstevel@tonic-gate {
6310Sstevel@tonic-gate mblk_t *mp;
6320Sstevel@tonic-gate bufcall_id_t id;
6330Sstevel@tonic-gate int retv;
6340Sstevel@tonic-gate
6350Sstevel@tonic-gate while ((mp = mkiocb(cmd)) == NULL) {
6360Sstevel@tonic-gate id = qbufcall(q, sizeof (struct iocblk), BPRI_MED,
6370Sstevel@tonic-gate dummy_callback, NULL);
6380Sstevel@tonic-gate retv = qwait_sig(q);
6390Sstevel@tonic-gate qunbufcall(q, id);
6400Sstevel@tonic-gate if (retv == 0)
6410Sstevel@tonic-gate break;
6420Sstevel@tonic-gate }
6430Sstevel@tonic-gate return (mp);
6440Sstevel@tonic-gate }
6450Sstevel@tonic-gate
6460Sstevel@tonic-gate static mblk_t *
open_mblk(queue_t * q,size_t len)6470Sstevel@tonic-gate open_mblk(queue_t *q, size_t len)
6480Sstevel@tonic-gate {
6490Sstevel@tonic-gate mblk_t *mp;
6500Sstevel@tonic-gate bufcall_id_t id;
6510Sstevel@tonic-gate int retv;
6520Sstevel@tonic-gate
6530Sstevel@tonic-gate while ((mp = allocb(len, BPRI_MED)) == NULL) {
6540Sstevel@tonic-gate id = qbufcall(q, len, BPRI_MED, dummy_callback, NULL);
6550Sstevel@tonic-gate retv = qwait_sig(q);
6560Sstevel@tonic-gate qunbufcall(q, id);
6570Sstevel@tonic-gate if (retv == 0)
6580Sstevel@tonic-gate break;
6590Sstevel@tonic-gate }
6600Sstevel@tonic-gate return (mp);
6610Sstevel@tonic-gate }
6620Sstevel@tonic-gate
6630Sstevel@tonic-gate /*
6640Sstevel@tonic-gate * Line discipline open.
6650Sstevel@tonic-gate */
6660Sstevel@tonic-gate /* ARGSUSED1 */
6670Sstevel@tonic-gate static int
ldtermopen(queue_t * q,dev_t * devp,int oflag,int sflag,cred_t * crp)6680Sstevel@tonic-gate ldtermopen(queue_t *q, dev_t *devp, int oflag, int sflag, cred_t *crp)
6690Sstevel@tonic-gate {
6700Sstevel@tonic-gate ldtermstd_state_t *tp;
6710Sstevel@tonic-gate mblk_t *bp, *qryp;
6720Sstevel@tonic-gate int len;
6730Sstevel@tonic-gate struct stroptions *strop;
6740Sstevel@tonic-gate struct termios *termiosp;
6750Sstevel@tonic-gate queue_t *wq;
6760Sstevel@tonic-gate
6770Sstevel@tonic-gate if (q->q_ptr != NULL) {
6780Sstevel@tonic-gate return (0); /* already attached */
6790Sstevel@tonic-gate }
6800Sstevel@tonic-gate
6810Sstevel@tonic-gate tp = (ldtermstd_state_t *)kmem_zalloc(sizeof (ldtermstd_state_t),
682*7012Sis KM_SLEEP);
6830Sstevel@tonic-gate
6840Sstevel@tonic-gate /*
6850Sstevel@tonic-gate * Get termios defaults. These are stored as
6860Sstevel@tonic-gate * a property in the "options" node.
6870Sstevel@tonic-gate */
6880Sstevel@tonic-gate if (ddi_getlongprop(DDI_DEV_T_ANY, ddi_root_node(), DDI_PROP_NOTPROM,
6890Sstevel@tonic-gate "ttymodes", (caddr_t)&termiosp, &len) == DDI_PROP_SUCCESS &&
6900Sstevel@tonic-gate len == sizeof (struct termios)) {
6910Sstevel@tonic-gate tp->t_modes = *termiosp;
6920Sstevel@tonic-gate tp->t_amodes = *termiosp;
6930Sstevel@tonic-gate kmem_free(termiosp, len);
6940Sstevel@tonic-gate } else {
6950Sstevel@tonic-gate /*
6960Sstevel@tonic-gate * Gack! Whine about it.
6970Sstevel@tonic-gate */
6980Sstevel@tonic-gate cmn_err(CE_WARN, "ldterm: Couldn't get ttymodes property!");
6990Sstevel@tonic-gate }
7000Sstevel@tonic-gate bzero(&tp->t_dmodes, sizeof (struct termios));
7010Sstevel@tonic-gate
7020Sstevel@tonic-gate tp->t_state = 0;
7030Sstevel@tonic-gate
7040Sstevel@tonic-gate tp->t_line = 0;
7050Sstevel@tonic-gate tp->t_col = 0;
7060Sstevel@tonic-gate
7070Sstevel@tonic-gate tp->t_rocount = 0;
7080Sstevel@tonic-gate tp->t_rocol = 0;
7090Sstevel@tonic-gate
7100Sstevel@tonic-gate tp->t_message = NULL;
7110Sstevel@tonic-gate tp->t_endmsg = NULL;
7120Sstevel@tonic-gate tp->t_msglen = 0;
7130Sstevel@tonic-gate tp->t_rd_request = 0;
7140Sstevel@tonic-gate
7150Sstevel@tonic-gate tp->t_echomp = NULL;
7160Sstevel@tonic-gate tp->t_iocid = 0;
7170Sstevel@tonic-gate tp->t_wbufcid = 0;
7180Sstevel@tonic-gate tp->t_vtid = 0;
7190Sstevel@tonic-gate
7200Sstevel@tonic-gate q->q_ptr = (caddr_t)tp;
7210Sstevel@tonic-gate WR(q)->q_ptr = (caddr_t)tp;
7220Sstevel@tonic-gate /*
7230Sstevel@tonic-gate * The following for EUC and also non-EUC codesets:
7240Sstevel@tonic-gate */
7250Sstevel@tonic-gate tp->t_codeset = tp->t_eucleft = tp->t_eucign = tp->t_scratch_len = 0;
7260Sstevel@tonic-gate bzero(&tp->eucwioc, EUCSIZE);
7270Sstevel@tonic-gate tp->eucwioc.eucw[0] = 1; /* ASCII mem & screen width */
7280Sstevel@tonic-gate tp->eucwioc.scrw[0] = 1;
7290Sstevel@tonic-gate tp->t_maxeuc = 1; /* the max len in bytes of an EUC char */
7300Sstevel@tonic-gate tp->t_eucp = NULL;
7310Sstevel@tonic-gate tp->t_eucp_mp = NULL;
7320Sstevel@tonic-gate tp->t_eucwarn = 0; /* no bad chars seen yet */
7330Sstevel@tonic-gate
7340Sstevel@tonic-gate tp->t_csdata = default_cs_data;
7350Sstevel@tonic-gate tp->t_csmethods = cs_methods[LDTERM_CS_TYPE_EUC];
7360Sstevel@tonic-gate
7370Sstevel@tonic-gate qprocson(q);
7380Sstevel@tonic-gate
7390Sstevel@tonic-gate /*
7400Sstevel@tonic-gate * Find out if the module below us does canonicalization; if
7410Sstevel@tonic-gate * so, we won't do it ourselves.
7420Sstevel@tonic-gate */
7430Sstevel@tonic-gate
7440Sstevel@tonic-gate if ((qryp = open_ioctl(q, MC_CANONQUERY)) == NULL)
7450Sstevel@tonic-gate goto open_abort;
7460Sstevel@tonic-gate
7470Sstevel@tonic-gate /*
7480Sstevel@tonic-gate * Reformulate as an M_CTL message. The actual data will
7490Sstevel@tonic-gate * be in the b_cont field.
7500Sstevel@tonic-gate */
7510Sstevel@tonic-gate qryp->b_datap->db_type = M_CTL;
7520Sstevel@tonic-gate wq = OTHERQ(q);
7530Sstevel@tonic-gate putnext(wq, qryp);
7540Sstevel@tonic-gate
7550Sstevel@tonic-gate /* allocate a TCSBRK ioctl in case we'll need it on close */
7560Sstevel@tonic-gate if ((qryp = open_ioctl(q, TCSBRK)) == NULL)
7570Sstevel@tonic-gate goto open_abort;
7580Sstevel@tonic-gate tp->t_drainmsg = qryp;
7590Sstevel@tonic-gate if ((bp = open_mblk(q, sizeof (int))) == NULL)
7600Sstevel@tonic-gate goto open_abort;
7610Sstevel@tonic-gate qryp->b_cont = bp;
7620Sstevel@tonic-gate
7630Sstevel@tonic-gate /*
7640Sstevel@tonic-gate * Find out if the underlying driver supports proper POSIX close
7650Sstevel@tonic-gate * semantics. If not, we'll have to approximate it using TCSBRK. If
7660Sstevel@tonic-gate * it does, it will respond with MC_HAS_POSIX, and we'll catch that in
7670Sstevel@tonic-gate * the ldtermrput routine.
7680Sstevel@tonic-gate *
7690Sstevel@tonic-gate * When the ldterm_drain_limit tunable is set to zero, we behave the
7700Sstevel@tonic-gate * same as old ldterm: don't send this new message, and always use
7710Sstevel@tonic-gate * TCSBRK during close.
7720Sstevel@tonic-gate */
7730Sstevel@tonic-gate if (ldterm_drain_limit != 0) {
7740Sstevel@tonic-gate if ((qryp = open_ioctl(q, MC_POSIXQUERY)) == NULL)
7750Sstevel@tonic-gate goto open_abort;
7760Sstevel@tonic-gate qryp->b_datap->db_type = M_CTL;
7770Sstevel@tonic-gate putnext(wq, qryp);
7780Sstevel@tonic-gate }
7790Sstevel@tonic-gate
7800Sstevel@tonic-gate /* prepare to clear the water marks on close */
7810Sstevel@tonic-gate if ((bp = open_mblk(q, sizeof (struct stroptions))) == NULL)
7820Sstevel@tonic-gate goto open_abort;
7830Sstevel@tonic-gate tp->t_closeopts = bp;
7840Sstevel@tonic-gate
7850Sstevel@tonic-gate /*
7860Sstevel@tonic-gate * Set the high-water and low-water marks on the stream head
7870Sstevel@tonic-gate * to values appropriate for a terminal. Also set the "vmin"
7880Sstevel@tonic-gate * and "vtime" values to 1 and 0, turn on message-nondiscard
7890Sstevel@tonic-gate * mode (as we're in ICANON mode), and turn on "old-style
7900Sstevel@tonic-gate * NODELAY" mode.
7910Sstevel@tonic-gate */
7920Sstevel@tonic-gate if ((bp = open_mblk(q, sizeof (struct stroptions))) == NULL)
7930Sstevel@tonic-gate goto open_abort;
7940Sstevel@tonic-gate strop = (struct stroptions *)bp->b_wptr;
7950Sstevel@tonic-gate strop->so_flags = SO_READOPT|SO_HIWAT|SO_LOWAT|SO_NDELON|SO_ISTTY;
7960Sstevel@tonic-gate strop->so_readopt = RMSGN;
7970Sstevel@tonic-gate strop->so_hiwat = HIWAT;
7980Sstevel@tonic-gate strop->so_lowat = LOWAT;
7990Sstevel@tonic-gate bp->b_wptr += sizeof (struct stroptions);
8000Sstevel@tonic-gate bp->b_datap->db_type = M_SETOPTS;
8010Sstevel@tonic-gate putnext(q, bp);
8020Sstevel@tonic-gate
8030Sstevel@tonic-gate return (0); /* this can become a controlling TTY */
8040Sstevel@tonic-gate
8050Sstevel@tonic-gate open_abort:
8060Sstevel@tonic-gate qprocsoff(q);
8070Sstevel@tonic-gate q->q_ptr = NULL;
8080Sstevel@tonic-gate WR(q)->q_ptr = NULL;
8090Sstevel@tonic-gate freemsg(tp->t_closeopts);
8100Sstevel@tonic-gate freemsg(tp->t_drainmsg);
8110Sstevel@tonic-gate /* Dump the state structure */
8120Sstevel@tonic-gate kmem_free(tp, sizeof (ldtermstd_state_t));
8130Sstevel@tonic-gate return (EINTR);
8140Sstevel@tonic-gate }
8150Sstevel@tonic-gate
8160Sstevel@tonic-gate struct close_timer {
8170Sstevel@tonic-gate timeout_id_t id;
8180Sstevel@tonic-gate ldtermstd_state_t *tp;
8190Sstevel@tonic-gate };
8200Sstevel@tonic-gate
8210Sstevel@tonic-gate static void
drain_timed_out(void * arg)8220Sstevel@tonic-gate drain_timed_out(void *arg)
8230Sstevel@tonic-gate {
8240Sstevel@tonic-gate struct close_timer *ctp = arg;
8250Sstevel@tonic-gate
8260Sstevel@tonic-gate ctp->id = 0;
8270Sstevel@tonic-gate ctp->tp->t_state &= ~TS_IOCWAIT;
8280Sstevel@tonic-gate }
8290Sstevel@tonic-gate
8300Sstevel@tonic-gate /* ARGSUSED2 */
8310Sstevel@tonic-gate static int
ldtermclose(queue_t * q,int cflag,cred_t * crp)8320Sstevel@tonic-gate ldtermclose(queue_t *q, int cflag, cred_t *crp)
8330Sstevel@tonic-gate {
8340Sstevel@tonic-gate ldtermstd_state_t *tp = (ldtermstd_state_t *)q->q_ptr;
8350Sstevel@tonic-gate struct stroptions *strop;
8360Sstevel@tonic-gate mblk_t *bp;
8370Sstevel@tonic-gate struct close_timer cltimer;
8380Sstevel@tonic-gate
8390Sstevel@tonic-gate /*
8400Sstevel@tonic-gate * If we have an outstanding vmin timeout, cancel it.
8410Sstevel@tonic-gate */
8420Sstevel@tonic-gate tp->t_state |= TS_CLOSE;
8430Sstevel@tonic-gate if (tp->t_vtid != 0)
8440Sstevel@tonic-gate (void) quntimeout(q, tp->t_vtid);
8450Sstevel@tonic-gate tp->t_vtid = 0;
8460Sstevel@tonic-gate
8470Sstevel@tonic-gate /*
8480Sstevel@tonic-gate * Cancel outstanding qbufcall request.
8490Sstevel@tonic-gate */
8500Sstevel@tonic-gate if (tp->t_wbufcid != 0)
8510Sstevel@tonic-gate qunbufcall(q, tp->t_wbufcid);
8520Sstevel@tonic-gate
8530Sstevel@tonic-gate /*
8540Sstevel@tonic-gate * Reset the high-water and low-water marks on the stream
8550Sstevel@tonic-gate * head (?), turn on byte-stream mode, and turn off
8560Sstevel@tonic-gate * "old-style NODELAY" mode.
8570Sstevel@tonic-gate */
8580Sstevel@tonic-gate bp = tp->t_closeopts;
8590Sstevel@tonic-gate strop = (struct stroptions *)bp->b_wptr;
8600Sstevel@tonic-gate strop->so_flags = SO_READOPT|SO_NDELOFF;
8610Sstevel@tonic-gate strop->so_readopt = RNORM;
8620Sstevel@tonic-gate bp->b_wptr += sizeof (struct stroptions);
8630Sstevel@tonic-gate bp->b_datap->db_type = M_SETOPTS;
8640Sstevel@tonic-gate putnext(q, bp);
8650Sstevel@tonic-gate
8660Sstevel@tonic-gate if (cflag & (FNDELAY|FNONBLOCK)) {
8670Sstevel@tonic-gate freemsg(tp->t_drainmsg);
8680Sstevel@tonic-gate } else if ((bp = tp->t_drainmsg) != NULL) {
8690Sstevel@tonic-gate struct iocblk *iocb;
8700Sstevel@tonic-gate
8710Sstevel@tonic-gate /*
8720Sstevel@tonic-gate * If the driver isn't known to have POSIX close semantics,
8730Sstevel@tonic-gate * then we have to emulate this the old way. This is done by
8740Sstevel@tonic-gate * sending down TCSBRK,1 to drain the output and waiting for
8750Sstevel@tonic-gate * the reply.
8760Sstevel@tonic-gate */
8770Sstevel@tonic-gate iocb = (struct iocblk *)bp->b_rptr;
8780Sstevel@tonic-gate iocb->ioc_count = sizeof (int);
8790Sstevel@tonic-gate *(int *)bp->b_cont->b_rptr = 1;
8800Sstevel@tonic-gate bp->b_cont->b_wptr += sizeof (int);
8810Sstevel@tonic-gate tp->t_state |= TS_IOCWAIT;
8820Sstevel@tonic-gate tp->t_iocid = iocb->ioc_id;
8830Sstevel@tonic-gate if (!putq(WR(q), bp))
8840Sstevel@tonic-gate putnext(WR(q), bp);
8850Sstevel@tonic-gate
8860Sstevel@tonic-gate /*
8870Sstevel@tonic-gate * If we're not able to receive signals at this point, then
8880Sstevel@tonic-gate * launch a timer. This timer will prevent us from waiting
8890Sstevel@tonic-gate * forever for a signal that won't arrive.
8900Sstevel@tonic-gate */
8910Sstevel@tonic-gate cltimer.id = 0;
8920Sstevel@tonic-gate if (!ddi_can_receive_sig() && ldterm_drain_limit != 0) {
8930Sstevel@tonic-gate cltimer.tp = tp;
8940Sstevel@tonic-gate cltimer.id = qtimeout(q, drain_timed_out, &cltimer,
8950Sstevel@tonic-gate drv_usectohz(ldterm_drain_limit));
8960Sstevel@tonic-gate }
8970Sstevel@tonic-gate
8980Sstevel@tonic-gate /*
8990Sstevel@tonic-gate * Note that the read side of ldterm and the qtimeout are
9000Sstevel@tonic-gate * protected by D_MTQPAIR, so no additional locking is needed
9010Sstevel@tonic-gate * here.
9020Sstevel@tonic-gate */
9030Sstevel@tonic-gate while (tp->t_state & TS_IOCWAIT) {
9040Sstevel@tonic-gate if (qwait_sig(q) == 0)
9050Sstevel@tonic-gate break;
9060Sstevel@tonic-gate }
9070Sstevel@tonic-gate if (cltimer.id != 0)
9080Sstevel@tonic-gate (void) quntimeout(q, cltimer.id);
9090Sstevel@tonic-gate }
9100Sstevel@tonic-gate
9110Sstevel@tonic-gate /*
9120Sstevel@tonic-gate * From here to the end, the routine does not sleep and does not
9130Sstevel@tonic-gate * reference STREAMS, so it's guaranteed to run to completion.
9140Sstevel@tonic-gate */
9150Sstevel@tonic-gate
9160Sstevel@tonic-gate qprocsoff(q);
9170Sstevel@tonic-gate
9180Sstevel@tonic-gate freemsg(tp->t_message);
9190Sstevel@tonic-gate freemsg(tp->t_eucp_mp);
9200Sstevel@tonic-gate
9210Sstevel@tonic-gate /* Dump the state structure, then unlink it */
9220Sstevel@tonic-gate if (tp->t_csdata.locale_name != NULL)
9230Sstevel@tonic-gate kmem_free(tp->t_csdata.locale_name,
9240Sstevel@tonic-gate strlen(tp->t_csdata.locale_name) + 1);
9250Sstevel@tonic-gate kmem_free(tp, sizeof (ldtermstd_state_t));
9260Sstevel@tonic-gate q->q_ptr = NULL;
9270Sstevel@tonic-gate return (0);
9280Sstevel@tonic-gate }
9290Sstevel@tonic-gate
9300Sstevel@tonic-gate
9310Sstevel@tonic-gate /*
9320Sstevel@tonic-gate * Put procedure for input from driver end of stream (read queue).
9330Sstevel@tonic-gate */
9340Sstevel@tonic-gate static void
ldtermrput(queue_t * q,mblk_t * mp)9350Sstevel@tonic-gate ldtermrput(queue_t *q, mblk_t *mp)
9360Sstevel@tonic-gate {
9370Sstevel@tonic-gate ldtermstd_state_t *tp;
9380Sstevel@tonic-gate unsigned char c;
9390Sstevel@tonic-gate queue_t *wrq = WR(q); /* write queue of ldterm mod */
9400Sstevel@tonic-gate queue_t *nextq = q->q_next; /* queue below us */
9410Sstevel@tonic-gate mblk_t *bp;
9420Sstevel@tonic-gate struct iocblk *qryp;
9430Sstevel@tonic-gate unsigned char *readp;
9440Sstevel@tonic-gate unsigned char *writep;
9450Sstevel@tonic-gate struct termios *emodes; /* effective modes set by driver */
9460Sstevel@tonic-gate int dbtype;
9470Sstevel@tonic-gate
9480Sstevel@tonic-gate tp = (ldtermstd_state_t *)q->q_ptr;
9490Sstevel@tonic-gate /*
9500Sstevel@tonic-gate * We received our ack from the driver saying there is nothing left to
9510Sstevel@tonic-gate * shovel out, so wake up the close routine.
9520Sstevel@tonic-gate */
9530Sstevel@tonic-gate dbtype = DB_TYPE(mp);
9540Sstevel@tonic-gate if ((dbtype == M_IOCACK || dbtype == M_IOCNAK) &&
9550Sstevel@tonic-gate (tp->t_state & (TS_CLOSE|TS_IOCWAIT)) == (TS_CLOSE|TS_IOCWAIT)) {
9560Sstevel@tonic-gate struct iocblk *iocp = (struct iocblk *)mp->b_rptr;
9570Sstevel@tonic-gate
9580Sstevel@tonic-gate if (iocp->ioc_id == tp->t_iocid) {
9590Sstevel@tonic-gate tp->t_state &= ~TS_IOCWAIT;
9600Sstevel@tonic-gate freemsg(mp);
9610Sstevel@tonic-gate return;
9620Sstevel@tonic-gate }
9630Sstevel@tonic-gate }
9640Sstevel@tonic-gate
9650Sstevel@tonic-gate switch (dbtype) {
9660Sstevel@tonic-gate
9670Sstevel@tonic-gate default:
9680Sstevel@tonic-gate (void) putq(q, mp);
9690Sstevel@tonic-gate return;
9700Sstevel@tonic-gate
9710Sstevel@tonic-gate /*
9720Sstevel@tonic-gate * Send these up unmolested
9730Sstevel@tonic-gate *
9740Sstevel@tonic-gate */
9750Sstevel@tonic-gate case M_PCSIG:
9760Sstevel@tonic-gate case M_SIG:
9770Sstevel@tonic-gate case M_IOCNAK:
9780Sstevel@tonic-gate
9790Sstevel@tonic-gate putnext(q, mp);
9800Sstevel@tonic-gate return;
9810Sstevel@tonic-gate
9820Sstevel@tonic-gate case M_IOCACK:
9830Sstevel@tonic-gate
9840Sstevel@tonic-gate ldterm_ioctl_reply(q, mp);
9850Sstevel@tonic-gate return;
9860Sstevel@tonic-gate
9870Sstevel@tonic-gate case M_BREAK:
9880Sstevel@tonic-gate
9890Sstevel@tonic-gate /*
9900Sstevel@tonic-gate * Parity errors are sent up as M_BREAKS with single
9910Sstevel@tonic-gate * character data (formerly handled in the driver)
9920Sstevel@tonic-gate */
9930Sstevel@tonic-gate if (mp->b_wptr - mp->b_rptr == 1) {
9940Sstevel@tonic-gate /*
9950Sstevel@tonic-gate * IGNPAR PARMRK RESULT
9960Sstevel@tonic-gate * off off 0
9970Sstevel@tonic-gate * off on 3 byte sequence
9980Sstevel@tonic-gate * on either ignored
9990Sstevel@tonic-gate */
10000Sstevel@tonic-gate if (!(tp->t_amodes.c_iflag & IGNPAR)) {
10010Sstevel@tonic-gate mp->b_wptr = mp->b_rptr;
10020Sstevel@tonic-gate if (tp->t_amodes.c_iflag & PARMRK) {
10030Sstevel@tonic-gate unsigned char c;
10040Sstevel@tonic-gate
10050Sstevel@tonic-gate c = *mp->b_rptr;
10060Sstevel@tonic-gate freemsg(mp);
10070Sstevel@tonic-gate if ((mp = allocb(3, BPRI_HI)) == NULL) {
10080Sstevel@tonic-gate cmn_err(CE_WARN,
10090Sstevel@tonic-gate "ldtermrput: no blocks");
10100Sstevel@tonic-gate return;
10110Sstevel@tonic-gate }
10120Sstevel@tonic-gate mp->b_datap->db_type = M_DATA;
10130Sstevel@tonic-gate *mp->b_wptr++ = (uchar_t)'\377';
10140Sstevel@tonic-gate *mp->b_wptr++ = '\0';
10150Sstevel@tonic-gate *mp->b_wptr++ = c;
10160Sstevel@tonic-gate putnext(q, mp);
10170Sstevel@tonic-gate } else {
10180Sstevel@tonic-gate mp->b_datap->db_type = M_DATA;
10190Sstevel@tonic-gate *mp->b_wptr++ = '\0';
10200Sstevel@tonic-gate putnext(q, mp);
10210Sstevel@tonic-gate }
10220Sstevel@tonic-gate } else {
10230Sstevel@tonic-gate freemsg(mp);
10240Sstevel@tonic-gate }
10250Sstevel@tonic-gate return;
10260Sstevel@tonic-gate }
10270Sstevel@tonic-gate /*
10280Sstevel@tonic-gate * We look at the apparent modes here instead of the
10290Sstevel@tonic-gate * effective modes. Effective modes cannot be used if
10300Sstevel@tonic-gate * IGNBRK, BRINT and PARMRK have been negotiated to
10310Sstevel@tonic-gate * be handled by the driver. Since M_BREAK should be
10320Sstevel@tonic-gate * sent upstream only if break processing was not
10330Sstevel@tonic-gate * already done, it should be ok to use the apparent
10340Sstevel@tonic-gate * modes.
10350Sstevel@tonic-gate */
10360Sstevel@tonic-gate
10370Sstevel@tonic-gate if (!(tp->t_amodes.c_iflag & IGNBRK)) {
10380Sstevel@tonic-gate if (tp->t_amodes.c_iflag & BRKINT) {
10390Sstevel@tonic-gate ldterm_dosig(q, SIGINT, '\0', M_PCSIG, FLUSHRW);
10400Sstevel@tonic-gate freemsg(mp);
10410Sstevel@tonic-gate } else if (tp->t_amodes.c_iflag & PARMRK) {
10420Sstevel@tonic-gate /*
10430Sstevel@tonic-gate * Send '\377','\0', '\0'.
10440Sstevel@tonic-gate */
10450Sstevel@tonic-gate freemsg(mp);
10460Sstevel@tonic-gate if ((mp = allocb(3, BPRI_HI)) == NULL) {
10470Sstevel@tonic-gate cmn_err(CE_WARN,
1048*7012Sis "ldtermrput: no blocks");
10490Sstevel@tonic-gate return;
10500Sstevel@tonic-gate }
10510Sstevel@tonic-gate mp->b_datap->db_type = M_DATA;
10520Sstevel@tonic-gate *mp->b_wptr++ = (uchar_t)'\377';
10530Sstevel@tonic-gate *mp->b_wptr++ = '\0';
10540Sstevel@tonic-gate *mp->b_wptr++ = '\0';
10550Sstevel@tonic-gate putnext(q, mp);
10560Sstevel@tonic-gate } else {
10570Sstevel@tonic-gate /*
10580Sstevel@tonic-gate * Act as if a '\0' came in.
10590Sstevel@tonic-gate */
10600Sstevel@tonic-gate freemsg(mp);
10610Sstevel@tonic-gate if ((mp = allocb(1, BPRI_HI)) == NULL) {
10620Sstevel@tonic-gate cmn_err(CE_WARN,
1063*7012Sis "ldtermrput: no blocks");
10640Sstevel@tonic-gate return;
10650Sstevel@tonic-gate }
10660Sstevel@tonic-gate mp->b_datap->db_type = M_DATA;
10670Sstevel@tonic-gate *mp->b_wptr++ = '\0';
10680Sstevel@tonic-gate putnext(q, mp);
10690Sstevel@tonic-gate }
10700Sstevel@tonic-gate } else {
10710Sstevel@tonic-gate freemsg(mp);
10720Sstevel@tonic-gate }
10730Sstevel@tonic-gate return;
10740Sstevel@tonic-gate
10750Sstevel@tonic-gate case M_CTL:
10760Sstevel@tonic-gate DEBUG3(("ldtermrput: M_CTL received\n"));
10770Sstevel@tonic-gate /*
10780Sstevel@tonic-gate * The M_CTL has been standardized to look like an
10790Sstevel@tonic-gate * M_IOCTL message.
10800Sstevel@tonic-gate */
10810Sstevel@tonic-gate
10820Sstevel@tonic-gate if ((mp->b_wptr - mp->b_rptr) != sizeof (struct iocblk)) {
10830Sstevel@tonic-gate DEBUG3((
10840Sstevel@tonic-gate "Non standard M_CTL received by ldterm module\n"));
10850Sstevel@tonic-gate /* May be for someone else; pass it on */
10860Sstevel@tonic-gate putnext(q, mp);
10870Sstevel@tonic-gate return;
10880Sstevel@tonic-gate }
10890Sstevel@tonic-gate qryp = (struct iocblk *)mp->b_rptr;
10900Sstevel@tonic-gate
10910Sstevel@tonic-gate switch (qryp->ioc_cmd) {
10920Sstevel@tonic-gate
10930Sstevel@tonic-gate case MC_PART_CANON:
10940Sstevel@tonic-gate
10950Sstevel@tonic-gate DEBUG3(("ldtermrput: M_CTL Query Reply\n"));
10960Sstevel@tonic-gate if (!mp->b_cont) {
10970Sstevel@tonic-gate DEBUG3(("No information in Query Message\n"));
10980Sstevel@tonic-gate break;
10990Sstevel@tonic-gate }
11000Sstevel@tonic-gate if ((mp->b_cont->b_wptr - mp->b_cont->b_rptr) ==
11010Sstevel@tonic-gate sizeof (struct termios)) {
11020Sstevel@tonic-gate DEBUG3(("ldtermrput: M_CTL GrandScheme\n"));
11030Sstevel@tonic-gate /* elaborate turning off scheme */
11040Sstevel@tonic-gate emodes = (struct termios *)mp->b_cont->b_rptr;
11050Sstevel@tonic-gate bcopy(emodes, &tp->t_dmodes,
11060Sstevel@tonic-gate sizeof (struct termios));
11070Sstevel@tonic-gate ldterm_adjust_modes(tp);
11080Sstevel@tonic-gate break;
11090Sstevel@tonic-gate } else {
11100Sstevel@tonic-gate DEBUG3(("Incorrect query replysize\n"));
11110Sstevel@tonic-gate break;
11120Sstevel@tonic-gate }
11130Sstevel@tonic-gate
11140Sstevel@tonic-gate case MC_NO_CANON:
11150Sstevel@tonic-gate tp->t_state |= TS_NOCANON;
11160Sstevel@tonic-gate /*
11170Sstevel@tonic-gate * Note: this is very nasty. It's not clear
11180Sstevel@tonic-gate * what the right thing to do with a partial
11190Sstevel@tonic-gate * message is; We throw it out
11200Sstevel@tonic-gate */
11210Sstevel@tonic-gate if (tp->t_message != NULL) {
11220Sstevel@tonic-gate freemsg(tp->t_message);
11230Sstevel@tonic-gate tp->t_message = NULL;
11240Sstevel@tonic-gate tp->t_endmsg = NULL;
11250Sstevel@tonic-gate tp->t_msglen = 0;
11260Sstevel@tonic-gate tp->t_rocount = 0;
11270Sstevel@tonic-gate tp->t_rocol = 0;
11280Sstevel@tonic-gate if (tp->t_state & TS_MEUC) {
11290Sstevel@tonic-gate ASSERT(tp->t_eucp_mp);
11300Sstevel@tonic-gate tp->t_eucp = tp->t_eucp_mp->b_rptr;
11310Sstevel@tonic-gate tp->t_codeset = 0;
11320Sstevel@tonic-gate tp->t_eucleft = 0;
11330Sstevel@tonic-gate }
11340Sstevel@tonic-gate }
11350Sstevel@tonic-gate break;
11360Sstevel@tonic-gate
11370Sstevel@tonic-gate case MC_DO_CANON:
11380Sstevel@tonic-gate tp->t_state &= ~TS_NOCANON;
11390Sstevel@tonic-gate break;
11400Sstevel@tonic-gate
11410Sstevel@tonic-gate case MC_HAS_POSIX:
11420Sstevel@tonic-gate /* no longer any reason to drain from ldterm */
11430Sstevel@tonic-gate if (ldterm_drain_limit != 0) {
11440Sstevel@tonic-gate freemsg(tp->t_drainmsg);
11450Sstevel@tonic-gate tp->t_drainmsg = NULL;
11460Sstevel@tonic-gate }
11470Sstevel@tonic-gate break;
11480Sstevel@tonic-gate
11490Sstevel@tonic-gate default:
11500Sstevel@tonic-gate DEBUG3(("Unknown M_CTL Message\n"));
11510Sstevel@tonic-gate break;
11520Sstevel@tonic-gate }
11530Sstevel@tonic-gate putnext(q, mp); /* In case anyone else has to see it */
11540Sstevel@tonic-gate return;
11550Sstevel@tonic-gate
11560Sstevel@tonic-gate case M_FLUSH:
11570Sstevel@tonic-gate /*
11580Sstevel@tonic-gate * Flush everything we haven't looked at yet.
11590Sstevel@tonic-gate */
11600Sstevel@tonic-gate
11610Sstevel@tonic-gate if ((tp->t_state & TS_ISPTSTTY) && (*mp->b_rptr & FLUSHBAND))
11620Sstevel@tonic-gate flushband(q, *(mp->b_rptr + 1), FLUSHDATA);
11630Sstevel@tonic-gate else
11640Sstevel@tonic-gate flushq(q, FLUSHDATA);
11650Sstevel@tonic-gate
11660Sstevel@tonic-gate /*
11670Sstevel@tonic-gate * Flush everything we have looked at.
11680Sstevel@tonic-gate */
11690Sstevel@tonic-gate freemsg(tp->t_message);
11700Sstevel@tonic-gate tp->t_message = NULL;
11710Sstevel@tonic-gate tp->t_endmsg = NULL;
11720Sstevel@tonic-gate tp->t_msglen = 0;
11730Sstevel@tonic-gate tp->t_rocount = 0;
11740Sstevel@tonic-gate tp->t_rocol = 0;
11750Sstevel@tonic-gate if (tp->t_state & TS_MEUC) { /* EUC multi-byte */
11760Sstevel@tonic-gate ASSERT(tp->t_eucp_mp);
11770Sstevel@tonic-gate tp->t_eucp = tp->t_eucp_mp->b_rptr;
11780Sstevel@tonic-gate }
11790Sstevel@tonic-gate putnext(q, mp); /* pass it on */
11800Sstevel@tonic-gate
11810Sstevel@tonic-gate /*
11820Sstevel@tonic-gate * Relieve input flow control
11830Sstevel@tonic-gate */
11840Sstevel@tonic-gate if ((tp->t_modes.c_iflag & IXOFF) &&
11850Sstevel@tonic-gate (tp->t_state & TS_TBLOCK) &&
11860Sstevel@tonic-gate !(tp->t_state & TS_IFBLOCK) && q->q_count <= TTXOLO) {
11870Sstevel@tonic-gate tp->t_state &= ~TS_TBLOCK;
11880Sstevel@tonic-gate (void) putnextctl(wrq, M_STARTI);
11890Sstevel@tonic-gate DEBUG1(("M_STARTI down\n"));
11900Sstevel@tonic-gate }
11910Sstevel@tonic-gate return;
11920Sstevel@tonic-gate
11930Sstevel@tonic-gate case M_DATA:
11940Sstevel@tonic-gate break;
11950Sstevel@tonic-gate }
11960Sstevel@tonic-gate (void) drv_setparm(SYSRAWC, msgdsize(mp));
11970Sstevel@tonic-gate
11980Sstevel@tonic-gate /*
11990Sstevel@tonic-gate * Flow control: send "start input" message if blocked and
12000Sstevel@tonic-gate * our queue is below its low water mark.
12010Sstevel@tonic-gate */
12020Sstevel@tonic-gate if ((tp->t_modes.c_iflag & IXOFF) && (tp->t_state & TS_TBLOCK) &&
12030Sstevel@tonic-gate !(tp->t_state & TS_IFBLOCK) && q->q_count <= TTXOLO) {
12040Sstevel@tonic-gate tp->t_state &= ~TS_TBLOCK;
12050Sstevel@tonic-gate (void) putnextctl(wrq, M_STARTI);
12060Sstevel@tonic-gate DEBUG1(("M_STARTI down\n"));
12070Sstevel@tonic-gate }
12080Sstevel@tonic-gate /*
12090Sstevel@tonic-gate * If somebody below us ("intelligent" communications
12100Sstevel@tonic-gate * board, pseudo-tty controlled by an editor) is doing
12110Sstevel@tonic-gate * canonicalization, don't scan it for special characters.
12120Sstevel@tonic-gate */
12130Sstevel@tonic-gate if (tp->t_state & TS_NOCANON) {
12140Sstevel@tonic-gate (void) putq(q, mp);
12150Sstevel@tonic-gate return;
12160Sstevel@tonic-gate }
12170Sstevel@tonic-gate bp = mp;
12180Sstevel@tonic-gate
12190Sstevel@tonic-gate do {
12200Sstevel@tonic-gate readp = bp->b_rptr;
12210Sstevel@tonic-gate writep = readp;
12220Sstevel@tonic-gate if (tp->t_modes.c_iflag & (INLCR|IGNCR|ICRNL|IUCLC|IXON) ||
12230Sstevel@tonic-gate tp->t_modes.c_lflag & (ISIG|ICANON)) {
12240Sstevel@tonic-gate /*
12250Sstevel@tonic-gate * We're doing some sort of non-trivial
12260Sstevel@tonic-gate * processing of input; look at every
12270Sstevel@tonic-gate * character.
12280Sstevel@tonic-gate */
12290Sstevel@tonic-gate while (readp < bp->b_wptr) {
12300Sstevel@tonic-gate c = *readp++;
12310Sstevel@tonic-gate
12320Sstevel@tonic-gate if (tp->t_modes.c_iflag & ISTRIP)
12330Sstevel@tonic-gate c &= 0177;
12340Sstevel@tonic-gate
12350Sstevel@tonic-gate /*
12360Sstevel@tonic-gate * First, check that this hasn't been
12370Sstevel@tonic-gate * escaped with the "literal next"
12380Sstevel@tonic-gate * character.
12390Sstevel@tonic-gate */
12400Sstevel@tonic-gate if (tp->t_state & TS_PLNCH) {
12410Sstevel@tonic-gate tp->t_state &= ~TS_PLNCH;
12420Sstevel@tonic-gate tp->t_modes.c_lflag &= ~FLUSHO;
12430Sstevel@tonic-gate *writep++ = c;
12440Sstevel@tonic-gate continue;
12450Sstevel@tonic-gate }
12460Sstevel@tonic-gate /*
12470Sstevel@tonic-gate * Setting a special character to NUL
12480Sstevel@tonic-gate * disables it, so if this character
12490Sstevel@tonic-gate * is NUL, it should not be compared
12500Sstevel@tonic-gate * with any of the special characters.
12510Sstevel@tonic-gate * It should, however, restart frozen
12520Sstevel@tonic-gate * output if IXON and IXANY are set.
12530Sstevel@tonic-gate */
12540Sstevel@tonic-gate if (c == _POSIX_VDISABLE) {
12550Sstevel@tonic-gate if (tp->t_modes.c_iflag & IXON &&
12560Sstevel@tonic-gate tp->t_state & TS_TTSTOP &&
12570Sstevel@tonic-gate tp->t_modes.c_lflag & IEXTEN &&
12580Sstevel@tonic-gate tp->t_modes.c_iflag & IXANY) {
12590Sstevel@tonic-gate tp->t_state &=
12600Sstevel@tonic-gate ~(TS_TTSTOP|TS_OFBLOCK);
12610Sstevel@tonic-gate (void) putnextctl(wrq, M_START);
12620Sstevel@tonic-gate }
12630Sstevel@tonic-gate tp->t_modes.c_lflag &= ~FLUSHO;
12640Sstevel@tonic-gate *writep++ = c;
12650Sstevel@tonic-gate continue;
12660Sstevel@tonic-gate }
12670Sstevel@tonic-gate /*
12680Sstevel@tonic-gate * If stopped, start if you can; if
12690Sstevel@tonic-gate * running, stop if you must.
12700Sstevel@tonic-gate */
12710Sstevel@tonic-gate if (tp->t_modes.c_iflag & IXON) {
12720Sstevel@tonic-gate if (tp->t_state & TS_TTSTOP) {
12730Sstevel@tonic-gate if (c ==
12740Sstevel@tonic-gate tp->t_modes.c_cc[VSTART] ||
12750Sstevel@tonic-gate (tp->t_modes.c_lflag &
12760Sstevel@tonic-gate IEXTEN &&
12770Sstevel@tonic-gate tp->t_modes.c_iflag &
12780Sstevel@tonic-gate IXANY)) {
12790Sstevel@tonic-gate tp->t_state &=
1280*7012Sis ~(TS_TTSTOP |
1281*7012Sis TS_OFBLOCK);
12820Sstevel@tonic-gate (void) putnextctl(wrq,
12830Sstevel@tonic-gate M_START);
12840Sstevel@tonic-gate }
12850Sstevel@tonic-gate } else {
12860Sstevel@tonic-gate if (c ==
12870Sstevel@tonic-gate tp->t_modes.c_cc[VSTOP]) {
12880Sstevel@tonic-gate tp->t_state |=
12890Sstevel@tonic-gate TS_TTSTOP;
12900Sstevel@tonic-gate (void) putnextctl(wrq,
12910Sstevel@tonic-gate M_STOP);
12920Sstevel@tonic-gate }
12930Sstevel@tonic-gate }
12940Sstevel@tonic-gate if (c == tp->t_modes.c_cc[VSTOP] ||
12950Sstevel@tonic-gate c == tp->t_modes.c_cc[VSTART])
12960Sstevel@tonic-gate continue;
12970Sstevel@tonic-gate }
12980Sstevel@tonic-gate /*
12990Sstevel@tonic-gate * Check for "literal next" character
13000Sstevel@tonic-gate * and "flush output" character.
13010Sstevel@tonic-gate * Note that we omit checks for ISIG
13020Sstevel@tonic-gate * and ICANON, since the IEXTEN
13030Sstevel@tonic-gate * setting subsumes them.
13040Sstevel@tonic-gate */
13050Sstevel@tonic-gate if (tp->t_modes.c_lflag & IEXTEN) {
13060Sstevel@tonic-gate if (c == tp->t_modes.c_cc[VLNEXT]) {
13070Sstevel@tonic-gate /*
13080Sstevel@tonic-gate * Remember that we saw a
13090Sstevel@tonic-gate * "literal next" while
13100Sstevel@tonic-gate * scanning input, but leave
13110Sstevel@tonic-gate * leave it in the message so
13120Sstevel@tonic-gate * that the service routine
13130Sstevel@tonic-gate * can see it too.
13140Sstevel@tonic-gate */
13150Sstevel@tonic-gate tp->t_state |= TS_PLNCH;
13160Sstevel@tonic-gate tp->t_modes.c_lflag &= ~FLUSHO;
13170Sstevel@tonic-gate *writep++ = c;
13180Sstevel@tonic-gate continue;
13190Sstevel@tonic-gate }
13200Sstevel@tonic-gate if (c == tp->t_modes.c_cc[VDISCARD]) {
13210Sstevel@tonic-gate ldterm_flush_output(c, wrq, tp);
13220Sstevel@tonic-gate continue;
13230Sstevel@tonic-gate }
13240Sstevel@tonic-gate }
13250Sstevel@tonic-gate tp->t_modes.c_lflag &= ~FLUSHO;
13260Sstevel@tonic-gate
13270Sstevel@tonic-gate /*
13280Sstevel@tonic-gate * Check for signal-generating
13290Sstevel@tonic-gate * characters.
13300Sstevel@tonic-gate */
13310Sstevel@tonic-gate if (tp->t_modes.c_lflag & ISIG) {
13320Sstevel@tonic-gate if (c == tp->t_modes.c_cc[VINTR]) {
13330Sstevel@tonic-gate ldterm_dosig(q, SIGINT, c,
13340Sstevel@tonic-gate M_PCSIG, FLUSHRW);
13350Sstevel@tonic-gate continue;
13360Sstevel@tonic-gate }
13370Sstevel@tonic-gate if (c == tp->t_modes.c_cc[VQUIT]) {
13380Sstevel@tonic-gate ldterm_dosig(q, SIGQUIT, c,
13390Sstevel@tonic-gate M_PCSIG, FLUSHRW);
13400Sstevel@tonic-gate continue;
13410Sstevel@tonic-gate }
13420Sstevel@tonic-gate if (c == tp->t_modes.c_cc[VSWTCH]) {
13430Sstevel@tonic-gate /*
13440Sstevel@tonic-gate * Ancient SXT support; discard
13450Sstevel@tonic-gate * character without action.
13460Sstevel@tonic-gate */
13470Sstevel@tonic-gate continue;
13480Sstevel@tonic-gate }
13490Sstevel@tonic-gate if (c == tp->t_modes.c_cc[VSUSP]) {
13500Sstevel@tonic-gate ldterm_dosig(q, SIGTSTP, c,
13510Sstevel@tonic-gate M_PCSIG, FLUSHRW);
13520Sstevel@tonic-gate continue;
13530Sstevel@tonic-gate }
13540Sstevel@tonic-gate if ((tp->t_modes.c_lflag & IEXTEN) &&
13550Sstevel@tonic-gate (c == tp->t_modes.c_cc[VDSUSP])) {
13560Sstevel@tonic-gate ldterm_dosig(q, SIGTSTP, c,
13570Sstevel@tonic-gate M_SIG, 0);
13580Sstevel@tonic-gate continue;
13590Sstevel@tonic-gate }
13600Sstevel@tonic-gate }
13610Sstevel@tonic-gate /*
13620Sstevel@tonic-gate * Throw away CR if IGNCR set, or
13630Sstevel@tonic-gate * turn it into NL if ICRNL set.
13640Sstevel@tonic-gate */
13650Sstevel@tonic-gate if (c == '\r') {
13660Sstevel@tonic-gate if (tp->t_modes.c_iflag & IGNCR)
13670Sstevel@tonic-gate continue;
13680Sstevel@tonic-gate if (tp->t_modes.c_iflag & ICRNL)
13690Sstevel@tonic-gate c = '\n';
13700Sstevel@tonic-gate } else {
13710Sstevel@tonic-gate /*
13720Sstevel@tonic-gate * Turn NL into CR if INLCR
13730Sstevel@tonic-gate * set.
13740Sstevel@tonic-gate */
13750Sstevel@tonic-gate if (c == '\n' &&
13760Sstevel@tonic-gate tp->t_modes.c_iflag & INLCR)
13770Sstevel@tonic-gate c = '\r';
13780Sstevel@tonic-gate }
13790Sstevel@tonic-gate
13800Sstevel@tonic-gate /*
13810Sstevel@tonic-gate * Map upper case input to lower case
13820Sstevel@tonic-gate * if IUCLC flag set.
13830Sstevel@tonic-gate */
13840Sstevel@tonic-gate if (tp->t_modes.c_iflag & IUCLC &&
13850Sstevel@tonic-gate c >= 'A' && c <= 'Z')
13860Sstevel@tonic-gate c += 'a' - 'A';
13870Sstevel@tonic-gate
13880Sstevel@tonic-gate /*
13890Sstevel@tonic-gate * Put the possibly-transformed
13900Sstevel@tonic-gate * character back in the message.
13910Sstevel@tonic-gate */
13920Sstevel@tonic-gate *writep++ = c;
13930Sstevel@tonic-gate }
13940Sstevel@tonic-gate
13950Sstevel@tonic-gate /*
13960Sstevel@tonic-gate * If we didn't copy some characters because
13970Sstevel@tonic-gate * we were ignoring them, fix the size of the
13980Sstevel@tonic-gate * data block by adjusting the write pointer.
13990Sstevel@tonic-gate * XXX This may result in a zero-length
14000Sstevel@tonic-gate * block; will this cause anybody gastric
14010Sstevel@tonic-gate * distress?
14020Sstevel@tonic-gate */
14030Sstevel@tonic-gate bp->b_wptr -= (readp - writep);
14040Sstevel@tonic-gate } else {
14050Sstevel@tonic-gate /*
14060Sstevel@tonic-gate * We won't be doing anything other than
14070Sstevel@tonic-gate * possibly stripping the input.
14080Sstevel@tonic-gate */
14090Sstevel@tonic-gate if (tp->t_modes.c_iflag & ISTRIP) {
14100Sstevel@tonic-gate while (readp < bp->b_wptr)
14110Sstevel@tonic-gate *writep++ = *readp++ & 0177;
14120Sstevel@tonic-gate }
14130Sstevel@tonic-gate tp->t_modes.c_lflag &= ~FLUSHO;
14140Sstevel@tonic-gate }
14150Sstevel@tonic-gate
14160Sstevel@tonic-gate } while ((bp = bp->b_cont) != NULL); /* next block, if any */
14170Sstevel@tonic-gate
14180Sstevel@tonic-gate /*
14190Sstevel@tonic-gate * Queue the message for service procedure if the
14200Sstevel@tonic-gate * queue is not empty or canputnext() fails or
14210Sstevel@tonic-gate * tp->t_state & TS_RESCAN is true.
14220Sstevel@tonic-gate */
14230Sstevel@tonic-gate
14240Sstevel@tonic-gate if (q->q_first != NULL || !bcanputnext(q, mp->b_band) ||
1425*7012Sis (tp->t_state & TS_RESCAN))
14260Sstevel@tonic-gate (void) putq(q, mp);
14270Sstevel@tonic-gate else
14280Sstevel@tonic-gate (void) ldtermrmsg(q, mp);
14290Sstevel@tonic-gate
14300Sstevel@tonic-gate /*
14310Sstevel@tonic-gate * Flow control: send "stop input" message if our queue is
14320Sstevel@tonic-gate * approaching its high-water mark. The message will be
14330Sstevel@tonic-gate * dropped on the floor in the service procedure, if we
14340Sstevel@tonic-gate * cannot ship it up and we have had it upto our neck!
14350Sstevel@tonic-gate *
14360Sstevel@tonic-gate * Set QWANTW to ensure that the read queue service procedure
14370Sstevel@tonic-gate * gets run when nextq empties up again, so that it can
14380Sstevel@tonic-gate * unstop the input.
14390Sstevel@tonic-gate */
14400Sstevel@tonic-gate if ((tp->t_modes.c_iflag & IXOFF) && !(tp->t_state & TS_TBLOCK) &&
14410Sstevel@tonic-gate q->q_count >= TTXOHI) {
14420Sstevel@tonic-gate mutex_enter(QLOCK(nextq));
14430Sstevel@tonic-gate nextq->q_flag |= QWANTW;
14440Sstevel@tonic-gate mutex_exit(QLOCK(nextq));
14450Sstevel@tonic-gate tp->t_state |= TS_TBLOCK;
14460Sstevel@tonic-gate (void) putnextctl(wrq, M_STOPI);
14470Sstevel@tonic-gate DEBUG1(("M_STOPI down\n"));
14480Sstevel@tonic-gate }
14490Sstevel@tonic-gate }
14500Sstevel@tonic-gate
14510Sstevel@tonic-gate
14520Sstevel@tonic-gate /*
14530Sstevel@tonic-gate * Line discipline input server processing. Erase/kill and escape
14540Sstevel@tonic-gate * ('\') processing, gathering into messages, upper/lower case input
14550Sstevel@tonic-gate * mapping.
14560Sstevel@tonic-gate */
14570Sstevel@tonic-gate static void
ldtermrsrv(queue_t * q)14580Sstevel@tonic-gate ldtermrsrv(queue_t *q)
14590Sstevel@tonic-gate {
14600Sstevel@tonic-gate ldtermstd_state_t *tp;
14610Sstevel@tonic-gate mblk_t *mp;
14620Sstevel@tonic-gate
14630Sstevel@tonic-gate tp = (ldtermstd_state_t *)q->q_ptr;
14640Sstevel@tonic-gate
14650Sstevel@tonic-gate if (tp->t_state & TS_RESCAN) {
14660Sstevel@tonic-gate /*
14670Sstevel@tonic-gate * Canonicalization was turned on or off. Put the
14680Sstevel@tonic-gate * message being assembled back in the input queue,
14690Sstevel@tonic-gate * so that we rescan it.
14700Sstevel@tonic-gate */
14710Sstevel@tonic-gate if (tp->t_message != NULL) {
14720Sstevel@tonic-gate DEBUG5(("RESCAN WAS SET; put back in q\n"));
14730Sstevel@tonic-gate if (tp->t_msglen != 0)
14740Sstevel@tonic-gate (void) putbq(q, tp->t_message);
14750Sstevel@tonic-gate else
14760Sstevel@tonic-gate freemsg(tp->t_message);
14770Sstevel@tonic-gate tp->t_message = NULL;
14780Sstevel@tonic-gate tp->t_endmsg = NULL;
14790Sstevel@tonic-gate tp->t_msglen = 0;
14800Sstevel@tonic-gate }
14810Sstevel@tonic-gate if (tp->t_state & TS_MEUC) {
14820Sstevel@tonic-gate ASSERT(tp->t_eucp_mp);
14830Sstevel@tonic-gate tp->t_eucp = tp->t_eucp_mp->b_rptr;
14840Sstevel@tonic-gate tp->t_codeset = 0;
14850Sstevel@tonic-gate tp->t_eucleft = 0;
14860Sstevel@tonic-gate }
14870Sstevel@tonic-gate tp->t_state &= ~TS_RESCAN;
14880Sstevel@tonic-gate }
14890Sstevel@tonic-gate
14900Sstevel@tonic-gate while ((mp = getq(q)) != NULL) {
14910Sstevel@tonic-gate if (!ldtermrmsg(q, mp))
14920Sstevel@tonic-gate break;
14930Sstevel@tonic-gate }
14940Sstevel@tonic-gate
14950Sstevel@tonic-gate /*
14960Sstevel@tonic-gate * Flow control: send start message if blocked and our queue
14970Sstevel@tonic-gate * is below its low water mark.
14980Sstevel@tonic-gate */
14990Sstevel@tonic-gate if ((tp->t_modes.c_iflag & IXOFF) && (tp->t_state & TS_TBLOCK) &&
15000Sstevel@tonic-gate !(tp->t_state & TS_IFBLOCK) && q->q_count <= TTXOLO) {
15010Sstevel@tonic-gate tp->t_state &= ~TS_TBLOCK;
15020Sstevel@tonic-gate (void) putctl(WR(q), M_STARTI);
15030Sstevel@tonic-gate }
15040Sstevel@tonic-gate }
15050Sstevel@tonic-gate
15060Sstevel@tonic-gate /*
15070Sstevel@tonic-gate * This routine is called from both ldtermrput and ldtermrsrv to
15080Sstevel@tonic-gate * do the actual work of dealing with mp. Return 1 on sucesss and
15090Sstevel@tonic-gate * 0 on failure.
15100Sstevel@tonic-gate */
15110Sstevel@tonic-gate static int
ldtermrmsg(queue_t * q,mblk_t * mp)15120Sstevel@tonic-gate ldtermrmsg(queue_t *q, mblk_t *mp)
15130Sstevel@tonic-gate {
15140Sstevel@tonic-gate unsigned char c;
15150Sstevel@tonic-gate int dofree;
15160Sstevel@tonic-gate int status = 1;
15170Sstevel@tonic-gate size_t ebsize;
15180Sstevel@tonic-gate mblk_t *bp;
15190Sstevel@tonic-gate mblk_t *bpt;
15200Sstevel@tonic-gate ldtermstd_state_t *tp;
15210Sstevel@tonic-gate
15220Sstevel@tonic-gate bpt = NULL;
15230Sstevel@tonic-gate
15240Sstevel@tonic-gate tp = (ldtermstd_state_t *)q->q_ptr;
15250Sstevel@tonic-gate
15260Sstevel@tonic-gate if (mp->b_datap->db_type <= QPCTL && !bcanputnext(q, mp->b_band)) {
15270Sstevel@tonic-gate /*
15280Sstevel@tonic-gate * Stream head is flow controlled. If echo is
15290Sstevel@tonic-gate * turned on, flush the read side or send a
15300Sstevel@tonic-gate * bell down the line to stop input and
15310Sstevel@tonic-gate * process the current message.
15320Sstevel@tonic-gate * Otherwise(putbq) the user will not see any
15330Sstevel@tonic-gate * response to to the typed input. Typically
15340Sstevel@tonic-gate * happens if there is no reader process.
15350Sstevel@tonic-gate * Note that you will loose the data in this
15360Sstevel@tonic-gate * case if the data is coming too fast. There
15370Sstevel@tonic-gate * is an assumption here that if ECHO is
15380Sstevel@tonic-gate * turned on its some user typing the data on
15390Sstevel@tonic-gate * a terminal and its not network.
15400Sstevel@tonic-gate */
15410Sstevel@tonic-gate if (tp->t_modes.c_lflag & ECHO) {
15420Sstevel@tonic-gate if ((tp->t_modes.c_iflag & IMAXBEL) &&
15430Sstevel@tonic-gate (tp->t_modes.c_lflag & ICANON)) {
15440Sstevel@tonic-gate freemsg(mp);
15450Sstevel@tonic-gate if (canputnext(WR(q)))
15460Sstevel@tonic-gate ldterm_outchar(CTRL('g'), WR(q), 4, tp);
15470Sstevel@tonic-gate status = 0;
15480Sstevel@tonic-gate goto echo;
15490Sstevel@tonic-gate } else {
15500Sstevel@tonic-gate (void) putctl1(q, M_FLUSH, FLUSHR);
15510Sstevel@tonic-gate }
15520Sstevel@tonic-gate } else {
15530Sstevel@tonic-gate (void) putbq(q, mp);
15540Sstevel@tonic-gate status = 0;
15550Sstevel@tonic-gate goto out; /* read side is blocked */
15560Sstevel@tonic-gate }
15570Sstevel@tonic-gate }
15580Sstevel@tonic-gate switch (mp->b_datap->db_type) {
15590Sstevel@tonic-gate
15600Sstevel@tonic-gate default:
15610Sstevel@tonic-gate putnext(q, mp); /* pass it on */
15620Sstevel@tonic-gate goto out;
15630Sstevel@tonic-gate
15640Sstevel@tonic-gate case M_HANGUP:
15650Sstevel@tonic-gate /*
15660Sstevel@tonic-gate * Flush everything we haven't looked at yet.
15670Sstevel@tonic-gate */
15680Sstevel@tonic-gate flushq(q, FLUSHDATA);
15690Sstevel@tonic-gate
15700Sstevel@tonic-gate /*
15710Sstevel@tonic-gate * Flush everything we have looked at.
15720Sstevel@tonic-gate */
15730Sstevel@tonic-gate freemsg(tp->t_message);
15740Sstevel@tonic-gate tp->t_message = NULL;
15750Sstevel@tonic-gate tp->t_endmsg = NULL;
15760Sstevel@tonic-gate tp->t_msglen = 0;
15770Sstevel@tonic-gate /*
15780Sstevel@tonic-gate * XXX should we set read request
15790Sstevel@tonic-gate * tp->t_rd_request to NULL?
15800Sstevel@tonic-gate */
15810Sstevel@tonic-gate tp->t_rocount = 0; /* if it hasn't been typed */
15820Sstevel@tonic-gate tp->t_rocol = 0; /* it hasn't been echoed :-) */
15830Sstevel@tonic-gate if (tp->t_state & TS_MEUC) {
15840Sstevel@tonic-gate ASSERT(tp->t_eucp_mp);
15850Sstevel@tonic-gate tp->t_eucp = tp->t_eucp_mp->b_rptr;
15860Sstevel@tonic-gate }
15870Sstevel@tonic-gate /*
15880Sstevel@tonic-gate * Restart output, since it's probably got
15890Sstevel@tonic-gate * nowhere to go anyway, and we're probably
15900Sstevel@tonic-gate * not going to see another ^Q for a while.
15910Sstevel@tonic-gate */
15920Sstevel@tonic-gate if (tp->t_state & TS_TTSTOP) {
15930Sstevel@tonic-gate tp->t_state &= ~(TS_TTSTOP|TS_OFBLOCK);
15940Sstevel@tonic-gate (void) putnextctl(WR(q), M_START);
15950Sstevel@tonic-gate }
15960Sstevel@tonic-gate /*
15970Sstevel@tonic-gate * This message will travel up the read
15980Sstevel@tonic-gate * queue, flushing as it goes, get turned
15990Sstevel@tonic-gate * around at the stream head, and travel back
16000Sstevel@tonic-gate * down the write queue, flushing as it goes.
16010Sstevel@tonic-gate */
16020Sstevel@tonic-gate (void) putnextctl1(q, M_FLUSH, FLUSHW);
16030Sstevel@tonic-gate
16040Sstevel@tonic-gate /*
16050Sstevel@tonic-gate * This message will travel down the write
16060Sstevel@tonic-gate * queue, flushing as it goes, get turned
16070Sstevel@tonic-gate * around at the driver, and travel back up
16080Sstevel@tonic-gate * the read queue, flushing as it goes.
16090Sstevel@tonic-gate */
16100Sstevel@tonic-gate (void) putctl1(WR(q), M_FLUSH, FLUSHR);
16110Sstevel@tonic-gate
16120Sstevel@tonic-gate /*
16130Sstevel@tonic-gate * Now that that's done, we send a SIGCONT
16140Sstevel@tonic-gate * upstream, followed by the M_HANGUP.
16150Sstevel@tonic-gate */
16160Sstevel@tonic-gate /* (void) putnextctl1(q, M_PCSIG, SIGCONT); */
16170Sstevel@tonic-gate putnext(q, mp);
16180Sstevel@tonic-gate goto out;
16190Sstevel@tonic-gate
16200Sstevel@tonic-gate case M_IOCACK:
16210Sstevel@tonic-gate
16220Sstevel@tonic-gate /*
16230Sstevel@tonic-gate * Augment whatever information the driver is
16240Sstevel@tonic-gate * returning with the information we supply.
16250Sstevel@tonic-gate */
16260Sstevel@tonic-gate ldterm_ioctl_reply(q, mp);
16270Sstevel@tonic-gate goto out;
16280Sstevel@tonic-gate
16290Sstevel@tonic-gate case M_DATA:
16300Sstevel@tonic-gate break;
16310Sstevel@tonic-gate }
16320Sstevel@tonic-gate
16330Sstevel@tonic-gate /*
16340Sstevel@tonic-gate * This is an M_DATA message.
16350Sstevel@tonic-gate */
16360Sstevel@tonic-gate
16370Sstevel@tonic-gate /*
16380Sstevel@tonic-gate * If somebody below us ("intelligent" communications
16390Sstevel@tonic-gate * board, pseudo-tty controlled by an editor) is
16400Sstevel@tonic-gate * doing canonicalization, don't scan it for special
16410Sstevel@tonic-gate * characters.
16420Sstevel@tonic-gate */
16430Sstevel@tonic-gate if (tp->t_state & TS_NOCANON) {
16440Sstevel@tonic-gate putnext(q, mp);
16450Sstevel@tonic-gate goto out;
16460Sstevel@tonic-gate }
16470Sstevel@tonic-gate bp = mp;
16480Sstevel@tonic-gate
16490Sstevel@tonic-gate if ((bpt = newmsg(tp)) != NULL) {
16500Sstevel@tonic-gate mblk_t *bcont;
16510Sstevel@tonic-gate
16520Sstevel@tonic-gate do {
16530Sstevel@tonic-gate ASSERT(bp->b_wptr >= bp->b_rptr);
16540Sstevel@tonic-gate ebsize = bp->b_wptr - bp->b_rptr;
16550Sstevel@tonic-gate if (ebsize > EBSIZE)
16560Sstevel@tonic-gate ebsize = EBSIZE;
16570Sstevel@tonic-gate bcont = bp->b_cont;
16580Sstevel@tonic-gate if (CANON_MODE) {
16590Sstevel@tonic-gate /*
16600Sstevel@tonic-gate * By default, free the message once processed
16610Sstevel@tonic-gate */
16620Sstevel@tonic-gate dofree = 1;
16630Sstevel@tonic-gate
16640Sstevel@tonic-gate /*
16650Sstevel@tonic-gate * update sysinfo canch
16660Sstevel@tonic-gate * character. The value of
16670Sstevel@tonic-gate * canch may vary as compared
16680Sstevel@tonic-gate * to character tty
16690Sstevel@tonic-gate * implementation.
16700Sstevel@tonic-gate */
16710Sstevel@tonic-gate while (bp->b_rptr < bp->b_wptr) {
16720Sstevel@tonic-gate c = *bp->b_rptr++;
16730Sstevel@tonic-gate if ((bpt = ldterm_docanon(c,
16740Sstevel@tonic-gate bpt, ebsize, q, tp, &dofree)) ==
16750Sstevel@tonic-gate NULL)
16760Sstevel@tonic-gate break;
16770Sstevel@tonic-gate }
16780Sstevel@tonic-gate /*
16790Sstevel@tonic-gate * Release this block or put back on queue.
16800Sstevel@tonic-gate */
16810Sstevel@tonic-gate if (dofree)
16820Sstevel@tonic-gate freeb(bp);
16830Sstevel@tonic-gate else {
16840Sstevel@tonic-gate (void) putbq(q, bp);
16850Sstevel@tonic-gate break;
16860Sstevel@tonic-gate }
16870Sstevel@tonic-gate } else
1688*7012Sis bpt = ldterm_dononcanon(bp, bpt, ebsize, q, tp);
16890Sstevel@tonic-gate if (bpt == NULL) {
16900Sstevel@tonic-gate cmn_err(CE_WARN,
16910Sstevel@tonic-gate "ldtermrsrv: out of blocks");
16920Sstevel@tonic-gate freemsg(bcont);
16930Sstevel@tonic-gate break;
16940Sstevel@tonic-gate }
16950Sstevel@tonic-gate } while ((bp = bcont) != NULL);
16960Sstevel@tonic-gate }
16970Sstevel@tonic-gate echo:
16980Sstevel@tonic-gate /*
16990Sstevel@tonic-gate * Send whatever we echoed downstream.
17000Sstevel@tonic-gate */
17010Sstevel@tonic-gate if (tp->t_echomp != NULL) {
17020Sstevel@tonic-gate if (canputnext(WR(q)))
17030Sstevel@tonic-gate putnext(WR(q), tp->t_echomp);
17040Sstevel@tonic-gate else
17050Sstevel@tonic-gate freemsg(tp->t_echomp);
17060Sstevel@tonic-gate tp->t_echomp = NULL;
17070Sstevel@tonic-gate }
17080Sstevel@tonic-gate
17090Sstevel@tonic-gate out:
17100Sstevel@tonic-gate return (status);
17110Sstevel@tonic-gate }
17120Sstevel@tonic-gate
17130Sstevel@tonic-gate
17140Sstevel@tonic-gate /*
17150Sstevel@tonic-gate * Do canonical mode input; check whether this character is to be
17160Sstevel@tonic-gate * treated as a special character - if so, check whether it's equal
17170Sstevel@tonic-gate * to any of the special characters and handle it accordingly.
17180Sstevel@tonic-gate * Otherwise, just add it to the current line.
17190Sstevel@tonic-gate */
17200Sstevel@tonic-gate static mblk_t *
ldterm_docanon(uchar_t c,mblk_t * bpt,size_t ebsize,queue_t * q,ldtermstd_state_t * tp,int * dofreep)17210Sstevel@tonic-gate ldterm_docanon(uchar_t c, mblk_t *bpt, size_t ebsize, queue_t *q,
17220Sstevel@tonic-gate ldtermstd_state_t *tp, int *dofreep)
17230Sstevel@tonic-gate {
17240Sstevel@tonic-gate queue_t *wrq = WR(q);
17250Sstevel@tonic-gate int i;
17260Sstevel@tonic-gate
17270Sstevel@tonic-gate /*
17280Sstevel@tonic-gate * If the previous character was the "literal next"
17290Sstevel@tonic-gate * character, treat this character as regular input.
17300Sstevel@tonic-gate */
17310Sstevel@tonic-gate if (tp->t_state & TS_SLNCH)
17320Sstevel@tonic-gate goto escaped;
17330Sstevel@tonic-gate
17340Sstevel@tonic-gate /*
17350Sstevel@tonic-gate * Setting a special character to NUL disables it, so if this
17360Sstevel@tonic-gate * character is NUL, it should not be compared with any of
17370Sstevel@tonic-gate * the special characters.
17380Sstevel@tonic-gate */
17390Sstevel@tonic-gate if (c == _POSIX_VDISABLE) {
17400Sstevel@tonic-gate tp->t_state &= ~TS_QUOT;
17410Sstevel@tonic-gate goto escaped;
17420Sstevel@tonic-gate }
17430Sstevel@tonic-gate /*
17440Sstevel@tonic-gate * If this character is the literal next character, echo it
17450Sstevel@tonic-gate * as '^', backspace over it, and record that fact.
17460Sstevel@tonic-gate */
17470Sstevel@tonic-gate if ((tp->t_modes.c_lflag & IEXTEN) && c == tp->t_modes.c_cc[VLNEXT]) {
17480Sstevel@tonic-gate if (tp->t_modes.c_lflag & ECHO)
17490Sstevel@tonic-gate ldterm_outstring((unsigned char *)"^\b", 2, wrq,
1750*7012Sis ebsize, tp);
17510Sstevel@tonic-gate tp->t_state |= TS_SLNCH;
17520Sstevel@tonic-gate goto out;
17530Sstevel@tonic-gate }
17540Sstevel@tonic-gate /*
17550Sstevel@tonic-gate * Check for the editing character. If the display width of
17560Sstevel@tonic-gate * the last byte at the canonical buffer is not one and also
17570Sstevel@tonic-gate * smaller than or equal to UNKNOWN_WIDTH, the character at
17580Sstevel@tonic-gate * the end of the buffer is a multi-byte and/or multi-column
17590Sstevel@tonic-gate * character.
17600Sstevel@tonic-gate */
17610Sstevel@tonic-gate if (c == tp->t_modes.c_cc[VERASE]) {
17620Sstevel@tonic-gate if (tp->t_state & TS_QUOT) {
17630Sstevel@tonic-gate /*
17640Sstevel@tonic-gate * Get rid of the backslash, and put the
17650Sstevel@tonic-gate * erase character in its place.
17660Sstevel@tonic-gate */
17670Sstevel@tonic-gate ldterm_erase(wrq, ebsize, tp);
17680Sstevel@tonic-gate bpt = tp->t_endmsg;
17690Sstevel@tonic-gate goto escaped;
17700Sstevel@tonic-gate } else {
17710Sstevel@tonic-gate if ((tp->t_state & TS_MEUC) && tp->t_msglen &&
17720Sstevel@tonic-gate (*(tp->t_eucp - 1) != 1 &&
17730Sstevel@tonic-gate *(tp->t_eucp - 1) <= UNKNOWN_WIDTH))
17740Sstevel@tonic-gate ldterm_csi_erase(wrq, ebsize, tp);
17750Sstevel@tonic-gate else
17760Sstevel@tonic-gate ldterm_erase(wrq, ebsize, tp);
17770Sstevel@tonic-gate bpt = tp->t_endmsg;
17780Sstevel@tonic-gate goto out;
17790Sstevel@tonic-gate }
17800Sstevel@tonic-gate }
17810Sstevel@tonic-gate if ((tp->t_modes.c_lflag & IEXTEN) && c == tp->t_modes.c_cc[VWERASE]) {
17820Sstevel@tonic-gate /*
17830Sstevel@tonic-gate * Do "ASCII word" or "multibyte character token/chunk" erase.
17840Sstevel@tonic-gate */
17850Sstevel@tonic-gate if (tp->t_state & TS_MEUC)
17860Sstevel@tonic-gate ldterm_csi_werase(wrq, ebsize, tp);
17870Sstevel@tonic-gate else
17880Sstevel@tonic-gate ldterm_werase(wrq, ebsize, tp);
17890Sstevel@tonic-gate bpt = tp->t_endmsg;
17900Sstevel@tonic-gate goto out;
17910Sstevel@tonic-gate }
17920Sstevel@tonic-gate if (c == tp->t_modes.c_cc[VKILL]) {
17930Sstevel@tonic-gate if (tp->t_state & TS_QUOT) {
17940Sstevel@tonic-gate /*
17950Sstevel@tonic-gate * Get rid of the backslash, and put the kill
17960Sstevel@tonic-gate * character in its place.
17970Sstevel@tonic-gate */
17980Sstevel@tonic-gate ldterm_erase(wrq, ebsize, tp);
17990Sstevel@tonic-gate bpt = tp->t_endmsg;
18000Sstevel@tonic-gate goto escaped;
18010Sstevel@tonic-gate } else {
18020Sstevel@tonic-gate ldterm_kill(wrq, ebsize, tp);
18030Sstevel@tonic-gate bpt = tp->t_endmsg;
18040Sstevel@tonic-gate goto out;
18050Sstevel@tonic-gate }
18060Sstevel@tonic-gate }
18070Sstevel@tonic-gate if ((tp->t_modes.c_lflag & IEXTEN) && c == tp->t_modes.c_cc[VREPRINT]) {
18080Sstevel@tonic-gate ldterm_reprint(wrq, ebsize, tp);
18090Sstevel@tonic-gate goto out;
18100Sstevel@tonic-gate }
18110Sstevel@tonic-gate /*
18120Sstevel@tonic-gate * If the preceding character was a backslash: if the current
18130Sstevel@tonic-gate * character is an EOF, get rid of the backslash and treat
18140Sstevel@tonic-gate * the EOF as data; if we're in XCASE mode and the current
18150Sstevel@tonic-gate * character is part of a backslash-X escape sequence,
18160Sstevel@tonic-gate * process it; otherwise, just treat the current character
18170Sstevel@tonic-gate * normally.
18180Sstevel@tonic-gate */
18190Sstevel@tonic-gate if (tp->t_state & TS_QUOT) {
18200Sstevel@tonic-gate tp->t_state &= ~TS_QUOT;
18210Sstevel@tonic-gate if (c == tp->t_modes.c_cc[VEOF]) {
18220Sstevel@tonic-gate /*
18230Sstevel@tonic-gate * EOF character. Since it's escaped, get rid
18240Sstevel@tonic-gate * of the backslash and put the EOF character
18250Sstevel@tonic-gate * in its place.
18260Sstevel@tonic-gate */
18270Sstevel@tonic-gate ldterm_erase(wrq, ebsize, tp);
18280Sstevel@tonic-gate bpt = tp->t_endmsg;
18290Sstevel@tonic-gate } else {
18300Sstevel@tonic-gate /*
18310Sstevel@tonic-gate * If we're in XCASE mode, and the current
18320Sstevel@tonic-gate * character is part of a backslash-X
18330Sstevel@tonic-gate * sequence, get rid of the backslash and
18340Sstevel@tonic-gate * replace the current character with what
18350Sstevel@tonic-gate * that sequence maps to.
18360Sstevel@tonic-gate */
18370Sstevel@tonic-gate if ((tp->t_modes.c_lflag & XCASE) &&
18380Sstevel@tonic-gate imaptab[c] != '\0') {
18390Sstevel@tonic-gate ldterm_erase(wrq, ebsize, tp);
18400Sstevel@tonic-gate bpt = tp->t_endmsg;
18410Sstevel@tonic-gate c = imaptab[c];
18420Sstevel@tonic-gate }
18430Sstevel@tonic-gate }
18440Sstevel@tonic-gate } else {
18450Sstevel@tonic-gate /*
18460Sstevel@tonic-gate * Previous character wasn't backslash; check whether
18470Sstevel@tonic-gate * this was the EOF character.
18480Sstevel@tonic-gate */
18490Sstevel@tonic-gate if (c == tp->t_modes.c_cc[VEOF]) {
18500Sstevel@tonic-gate /*
18510Sstevel@tonic-gate * EOF character. Don't echo it unless
18520Sstevel@tonic-gate * ECHOCTL is set, don't stuff it in the
18530Sstevel@tonic-gate * current line, but send the line up the
18540Sstevel@tonic-gate * stream.
18550Sstevel@tonic-gate */
18560Sstevel@tonic-gate if ((tp->t_modes.c_lflag & ECHOCTL) &&
18570Sstevel@tonic-gate (tp->t_modes.c_lflag & IEXTEN) &&
18580Sstevel@tonic-gate (tp->t_modes.c_lflag & ECHO)) {
18590Sstevel@tonic-gate i = ldterm_echo(c, wrq, ebsize, tp);
18600Sstevel@tonic-gate while (i > 0) {
18610Sstevel@tonic-gate ldterm_outchar('\b', wrq, ebsize, tp);
18620Sstevel@tonic-gate i--;
18630Sstevel@tonic-gate }
18640Sstevel@tonic-gate }
18650Sstevel@tonic-gate bpt->b_datap->db_type = M_DATA;
18660Sstevel@tonic-gate ldterm_msg_upstream(q, tp);
18670Sstevel@tonic-gate if (!canputnext(q)) {
18680Sstevel@tonic-gate bpt = NULL;
18690Sstevel@tonic-gate *dofreep = 0;
18700Sstevel@tonic-gate } else {
18710Sstevel@tonic-gate bpt = newmsg(tp);
18720Sstevel@tonic-gate *dofreep = 1;
18730Sstevel@tonic-gate }
18740Sstevel@tonic-gate goto out;
18750Sstevel@tonic-gate }
18760Sstevel@tonic-gate }
18770Sstevel@tonic-gate
18780Sstevel@tonic-gate escaped:
18790Sstevel@tonic-gate /*
18800Sstevel@tonic-gate * First, make sure we can fit one WHOLE multi-byte char in the
18810Sstevel@tonic-gate * buffer. This is one place where we have overhead even if
18820Sstevel@tonic-gate * not in multi-byte mode; the overhead is subtracting
18830Sstevel@tonic-gate * tp->t_maxeuc from MAX_CANON before checking.
18840Sstevel@tonic-gate *
18850Sstevel@tonic-gate * Allows MAX_CANON bytes in the buffer before throwing awaying
18860Sstevel@tonic-gate * the the overflow of characters.
18870Sstevel@tonic-gate */
18880Sstevel@tonic-gate if ((tp->t_msglen > ((MAX_CANON + 1) - (int)tp->t_maxeuc)) &&
18890Sstevel@tonic-gate !((tp->t_state & TS_MEUC) && tp->t_eucleft)) {
18900Sstevel@tonic-gate
18910Sstevel@tonic-gate /*
18920Sstevel@tonic-gate * Byte will cause line to overflow, or the next EUC
18930Sstevel@tonic-gate * won't fit: Ring the bell or discard all input, and
18940Sstevel@tonic-gate * don't save the byte away.
18950Sstevel@tonic-gate */
18960Sstevel@tonic-gate if (tp->t_modes.c_iflag & IMAXBEL) {
18970Sstevel@tonic-gate if (canputnext(wrq))
18980Sstevel@tonic-gate ldterm_outchar(CTRL('g'), wrq, ebsize, tp);
18990Sstevel@tonic-gate goto out;
19000Sstevel@tonic-gate } else {
19010Sstevel@tonic-gate /*
19020Sstevel@tonic-gate * MAX_CANON processing. free everything in
19030Sstevel@tonic-gate * the current line and start with the
19040Sstevel@tonic-gate * current character as the first character.
19050Sstevel@tonic-gate */
19060Sstevel@tonic-gate DEBUG7(("ldterm_docanon: MAX_CANON processing\n"));
19070Sstevel@tonic-gate freemsg(tp->t_message);
19080Sstevel@tonic-gate tp->t_message = NULL;
19090Sstevel@tonic-gate tp->t_endmsg = NULL;
19100Sstevel@tonic-gate tp->t_msglen = 0;
19110Sstevel@tonic-gate tp->t_rocount = 0; /* if it hasn't been type */
19120Sstevel@tonic-gate tp->t_rocol = 0; /* it hasn't been echoed :-) */
19130Sstevel@tonic-gate if (tp->t_state & TS_MEUC) {
19140Sstevel@tonic-gate ASSERT(tp->t_eucp_mp);
19150Sstevel@tonic-gate tp->t_eucp = tp->t_eucp_mp->b_rptr;
19160Sstevel@tonic-gate }
19170Sstevel@tonic-gate tp->t_state &= ~TS_SLNCH;
19180Sstevel@tonic-gate bpt = newmsg(tp);
19190Sstevel@tonic-gate }
19200Sstevel@tonic-gate }
19210Sstevel@tonic-gate /*
19220Sstevel@tonic-gate * Add the character to the current line.
19230Sstevel@tonic-gate */
19240Sstevel@tonic-gate if (bpt->b_wptr >= bpt->b_datap->db_lim) {
19250Sstevel@tonic-gate /*
19260Sstevel@tonic-gate * No more room in this mblk; save this one away, and
19270Sstevel@tonic-gate * allocate a new one.
19280Sstevel@tonic-gate */
19290Sstevel@tonic-gate bpt->b_datap->db_type = M_DATA;
19300Sstevel@tonic-gate if ((bpt = allocb(IBSIZE, BPRI_MED)) == NULL)
19310Sstevel@tonic-gate goto out;
19320Sstevel@tonic-gate
19330Sstevel@tonic-gate /*
19340Sstevel@tonic-gate * Chain the new one to the end of the old one, and
19350Sstevel@tonic-gate * mark it as the last block in the current line.
19360Sstevel@tonic-gate */
19370Sstevel@tonic-gate tp->t_endmsg->b_cont = bpt;
19380Sstevel@tonic-gate tp->t_endmsg = bpt;
19390Sstevel@tonic-gate }
19400Sstevel@tonic-gate *bpt->b_wptr++ = c;
19410Sstevel@tonic-gate tp->t_msglen++; /* message length in BYTES */
19420Sstevel@tonic-gate
19430Sstevel@tonic-gate /*
19440Sstevel@tonic-gate * In multi-byte mode, we have to keep track of where we are.
19450Sstevel@tonic-gate * The first bytes of multi-byte chars get the full count for the
19460Sstevel@tonic-gate * whole character. We don't do any column calculations
19470Sstevel@tonic-gate * here, but we need the information for when we do. We could
19480Sstevel@tonic-gate * come across cases where we are getting garbage on the
19490Sstevel@tonic-gate * line, but we're in multi-byte mode. In that case, we may
19500Sstevel@tonic-gate * see ASCII controls come in the middle of what should have been a
19510Sstevel@tonic-gate * multi-byte character. Call ldterm_eucwarn...eventually, a
19520Sstevel@tonic-gate * warning message will be printed about it.
19530Sstevel@tonic-gate */
19540Sstevel@tonic-gate if (tp->t_state & TS_MEUC) {
19550Sstevel@tonic-gate if (tp->t_eucleft) { /* if in a multi-byte char already */
19560Sstevel@tonic-gate --tp->t_eucleft;
19570Sstevel@tonic-gate *tp->t_eucp++ = 0; /* is a subsequent byte */
19580Sstevel@tonic-gate if (c < (uchar_t)0x20)
19590Sstevel@tonic-gate ldterm_eucwarn(tp);
19600Sstevel@tonic-gate } else { /* is the first byte of a multi-byte, or is ASCII */
19610Sstevel@tonic-gate if (ISASCII(c)) {
19620Sstevel@tonic-gate *tp->t_eucp++ =
1963*7012Sis tp->t_csmethods.ldterm_dispwidth(c,
1964*7012Sis (void *)tp, tp->t_modes.c_lflag & ECHOCTL);
19650Sstevel@tonic-gate tp->t_codeset = 0;
19660Sstevel@tonic-gate } else {
19670Sstevel@tonic-gate *tp->t_eucp++ =
1968*7012Sis tp->t_csmethods.ldterm_dispwidth(c,
1969*7012Sis (void *)tp, tp->t_modes.c_lflag & ECHOCTL);
19700Sstevel@tonic-gate tp->t_eucleft =
1971*7012Sis tp->t_csmethods.ldterm_memwidth(c,
1972*7012Sis (void *)tp) - 1;
19730Sstevel@tonic-gate tp->t_codeset = ldterm_codeset(
1974*7012Sis tp->t_csdata.codeset_type, c);
19750Sstevel@tonic-gate }
19760Sstevel@tonic-gate }
19770Sstevel@tonic-gate }
19780Sstevel@tonic-gate /*
19790Sstevel@tonic-gate * AT&T is concerned about the following but we aren't since
19800Sstevel@tonic-gate * we have already shipped code that works.
19810Sstevel@tonic-gate *
19820Sstevel@tonic-gate * EOL2/XCASE should be conditioned with IEXTEN to be truly
19830Sstevel@tonic-gate * POSIX conformant. This is going to cause problems for
19840Sstevel@tonic-gate * pre-SVR4.0 programs that don't know about IEXTEN. Hence
19850Sstevel@tonic-gate * EOL2/IEXTEN is not conditioned with IEXTEN.
19860Sstevel@tonic-gate */
19870Sstevel@tonic-gate if (!(tp->t_state & TS_SLNCH) &&
19880Sstevel@tonic-gate (c == '\n' || (c != '\0' && (c == tp->t_modes.c_cc[VEOL] ||
19890Sstevel@tonic-gate (c == tp->t_modes.c_cc[VEOL2]))))) {
19900Sstevel@tonic-gate /*
19910Sstevel@tonic-gate * || ((tp->t_modes.c_lflag & IEXTEN) && c ==
19920Sstevel@tonic-gate * tp->t_modes.c_cc[VEOL2]))))) {
19930Sstevel@tonic-gate */
19940Sstevel@tonic-gate /*
19950Sstevel@tonic-gate * It's a line-termination character; send the line
19960Sstevel@tonic-gate * up the stream.
19970Sstevel@tonic-gate */
19980Sstevel@tonic-gate bpt->b_datap->db_type = M_DATA;
19990Sstevel@tonic-gate ldterm_msg_upstream(q, tp);
20000Sstevel@tonic-gate if (tp->t_state & TS_MEUC) {
20010Sstevel@tonic-gate ASSERT(tp->t_eucp_mp);
20020Sstevel@tonic-gate tp->t_eucp = tp->t_eucp_mp->b_rptr;
20030Sstevel@tonic-gate }
20040Sstevel@tonic-gate if ((bpt = newmsg(tp)) == NULL)
20050Sstevel@tonic-gate goto out;
20060Sstevel@tonic-gate } else {
20070Sstevel@tonic-gate /*
20080Sstevel@tonic-gate * Character was escaped with LNEXT.
20090Sstevel@tonic-gate */
20100Sstevel@tonic-gate if (tp->t_rocount++ == 0)
20110Sstevel@tonic-gate tp->t_rocol = tp->t_col;
20120Sstevel@tonic-gate tp->t_state &= ~(TS_SLNCH|TS_QUOT);
20130Sstevel@tonic-gate /*
20140Sstevel@tonic-gate * If the current character is a single byte and single
20150Sstevel@tonic-gate * column character and it is the backslash character and
20160Sstevel@tonic-gate * IEXTEN, then the state will have TS_QUOT.
20170Sstevel@tonic-gate */
20180Sstevel@tonic-gate if ((c == '\\') && (tp->t_modes.c_lflag & IEXTEN) &&
20190Sstevel@tonic-gate (!(tp->t_state & TS_MEUC) ||
20200Sstevel@tonic-gate ((tp->t_state & TS_MEUC) && (!tp->t_eucleft))))
20210Sstevel@tonic-gate tp->t_state |= TS_QUOT;
20220Sstevel@tonic-gate }
20230Sstevel@tonic-gate
20240Sstevel@tonic-gate /*
20250Sstevel@tonic-gate * Echo it.
20260Sstevel@tonic-gate */
20270Sstevel@tonic-gate if (tp->t_state & TS_ERASE) {
20280Sstevel@tonic-gate tp->t_state &= ~TS_ERASE;
20290Sstevel@tonic-gate if (tp->t_modes.c_lflag & ECHO)
20300Sstevel@tonic-gate ldterm_outchar('/', wrq, ebsize, tp);
20310Sstevel@tonic-gate }
20320Sstevel@tonic-gate if (tp->t_modes.c_lflag & ECHO)
20330Sstevel@tonic-gate (void) ldterm_echo(c, wrq, ebsize, tp);
20340Sstevel@tonic-gate else {
20350Sstevel@tonic-gate /*
20360Sstevel@tonic-gate * Echo NL when ECHO turned off, if ECHONL flag is
20370Sstevel@tonic-gate * set.
20380Sstevel@tonic-gate */
20390Sstevel@tonic-gate if (c == '\n' && (tp->t_modes.c_lflag & ECHONL))
20400Sstevel@tonic-gate ldterm_outchar(c, wrq, ebsize, tp);
20410Sstevel@tonic-gate }
20420Sstevel@tonic-gate
20430Sstevel@tonic-gate out:
20440Sstevel@tonic-gate
20450Sstevel@tonic-gate return (bpt);
20460Sstevel@tonic-gate }
20470Sstevel@tonic-gate
20480Sstevel@tonic-gate
20490Sstevel@tonic-gate static int
ldterm_unget(ldtermstd_state_t * tp)20500Sstevel@tonic-gate ldterm_unget(ldtermstd_state_t *tp)
20510Sstevel@tonic-gate {
20520Sstevel@tonic-gate mblk_t *bpt;
20530Sstevel@tonic-gate
20540Sstevel@tonic-gate if ((bpt = tp->t_endmsg) == NULL)
20550Sstevel@tonic-gate return (-1); /* no buffers */
20560Sstevel@tonic-gate if (bpt->b_rptr == bpt->b_wptr)
20570Sstevel@tonic-gate return (-1); /* zero-length record */
20580Sstevel@tonic-gate tp->t_msglen--; /* one fewer character */
20590Sstevel@tonic-gate return (*--bpt->b_wptr);
20600Sstevel@tonic-gate }
20610Sstevel@tonic-gate
20620Sstevel@tonic-gate
20630Sstevel@tonic-gate static void
ldterm_trim(ldtermstd_state_t * tp)20640Sstevel@tonic-gate ldterm_trim(ldtermstd_state_t *tp)
20650Sstevel@tonic-gate {
20660Sstevel@tonic-gate mblk_t *bpt;
20670Sstevel@tonic-gate mblk_t *bp;
20680Sstevel@tonic-gate
20690Sstevel@tonic-gate ASSERT(tp->t_endmsg);
20700Sstevel@tonic-gate bpt = tp->t_endmsg;
20710Sstevel@tonic-gate
20720Sstevel@tonic-gate if (bpt->b_rptr == bpt->b_wptr) {
20730Sstevel@tonic-gate /*
20740Sstevel@tonic-gate * This mblk is now empty. Find the previous mblk;
20750Sstevel@tonic-gate * throw this one away, unless it's the first one.
20760Sstevel@tonic-gate */
20770Sstevel@tonic-gate bp = tp->t_message;
20780Sstevel@tonic-gate if (bp != bpt) {
20790Sstevel@tonic-gate while (bp->b_cont != bpt) {
20800Sstevel@tonic-gate ASSERT(bp->b_cont);
20810Sstevel@tonic-gate bp = bp->b_cont;
20820Sstevel@tonic-gate }
20830Sstevel@tonic-gate bp->b_cont = NULL;
20840Sstevel@tonic-gate freeb(bpt);
20850Sstevel@tonic-gate tp->t_endmsg = bp; /* point to that mblk */
20860Sstevel@tonic-gate }
20870Sstevel@tonic-gate }
20880Sstevel@tonic-gate }
20890Sstevel@tonic-gate
20900Sstevel@tonic-gate
20910Sstevel@tonic-gate /*
20920Sstevel@tonic-gate * Rubout one character from the current line being built for tp as
20930Sstevel@tonic-gate * cleanly as possible. q is the write queue for tp. Most of this
20940Sstevel@tonic-gate * can't be applied to multi-byte processing. We do our own thing
20950Sstevel@tonic-gate * for that... See the "ldterm_eucerase" routine. We never call
20960Sstevel@tonic-gate * ldterm_rubout on a multi-byte or multi-column character.
20970Sstevel@tonic-gate */
20980Sstevel@tonic-gate static void
ldterm_rubout(uchar_t c,queue_t * q,size_t ebsize,ldtermstd_state_t * tp)20990Sstevel@tonic-gate ldterm_rubout(uchar_t c, queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
21000Sstevel@tonic-gate {
21010Sstevel@tonic-gate int tabcols;
21020Sstevel@tonic-gate static unsigned char crtrubout[] = "\b \b\b \b";
21030Sstevel@tonic-gate #define RUBOUT1 &crtrubout[3] /* rub out one position */
21040Sstevel@tonic-gate #define RUBOUT2 &crtrubout[0] /* rub out two positions */
21050Sstevel@tonic-gate
21060Sstevel@tonic-gate if (!(tp->t_modes.c_lflag & ECHO))
21070Sstevel@tonic-gate return;
21080Sstevel@tonic-gate if (tp->t_modes.c_lflag & ECHOE) {
21090Sstevel@tonic-gate /*
21100Sstevel@tonic-gate * "CRT rubout"; try erasing it from the screen.
21110Sstevel@tonic-gate */
21120Sstevel@tonic-gate if (tp->t_rocount == 0) {
21130Sstevel@tonic-gate /*
21140Sstevel@tonic-gate * After the character being erased was
21150Sstevel@tonic-gate * echoed, some data was written to the
21160Sstevel@tonic-gate * terminal; we can't erase it cleanly, so we
21170Sstevel@tonic-gate * just reprint the whole line as if the user
21180Sstevel@tonic-gate * had typed the reprint character.
21190Sstevel@tonic-gate */
21200Sstevel@tonic-gate ldterm_reprint(q, ebsize, tp);
21210Sstevel@tonic-gate return;
21220Sstevel@tonic-gate } else {
21230Sstevel@tonic-gate /*
21240Sstevel@tonic-gate * XXX what about escaped characters?
21250Sstevel@tonic-gate */
21260Sstevel@tonic-gate switch (typetab[c]) {
21270Sstevel@tonic-gate
21280Sstevel@tonic-gate case ORDINARY:
21290Sstevel@tonic-gate if ((tp->t_modes.c_lflag & XCASE) &&
21300Sstevel@tonic-gate omaptab[c])
21310Sstevel@tonic-gate ldterm_outstring(RUBOUT1, 3, q, ebsize,
2132*7012Sis tp);
21330Sstevel@tonic-gate ldterm_outstring(RUBOUT1, 3, q, ebsize, tp);
21340Sstevel@tonic-gate break;
21350Sstevel@tonic-gate
21360Sstevel@tonic-gate case VTAB:
21370Sstevel@tonic-gate case BACKSPACE:
21380Sstevel@tonic-gate case CONTROL:
21390Sstevel@tonic-gate case RETURN:
21400Sstevel@tonic-gate case NEWLINE:
21410Sstevel@tonic-gate if ((tp->t_modes.c_lflag & ECHOCTL) &&
21420Sstevel@tonic-gate (tp->t_modes.c_lflag & IEXTEN))
21430Sstevel@tonic-gate ldterm_outstring(RUBOUT2, 6, q, ebsize,
2144*7012Sis tp);
21450Sstevel@tonic-gate break;
21460Sstevel@tonic-gate
21470Sstevel@tonic-gate case TAB:
21480Sstevel@tonic-gate if (tp->t_rocount < tp->t_msglen) {
21490Sstevel@tonic-gate /*
21500Sstevel@tonic-gate * While the tab being erased was
21510Sstevel@tonic-gate * expanded, some data was written
21520Sstevel@tonic-gate * to the terminal; we can't erase
21530Sstevel@tonic-gate * it cleanly, so we just reprint
21540Sstevel@tonic-gate * the whole line as if the user
21550Sstevel@tonic-gate * had typed the reprint character.
21560Sstevel@tonic-gate */
21570Sstevel@tonic-gate ldterm_reprint(q, ebsize, tp);
21580Sstevel@tonic-gate return;
21590Sstevel@tonic-gate }
21600Sstevel@tonic-gate tabcols = ldterm_tabcols(tp);
21610Sstevel@tonic-gate while (--tabcols >= 0)
21620Sstevel@tonic-gate ldterm_outchar('\b', q, ebsize, tp);
21630Sstevel@tonic-gate break;
21640Sstevel@tonic-gate }
21650Sstevel@tonic-gate }
21660Sstevel@tonic-gate } else if ((tp->t_modes.c_lflag & ECHOPRT) &&
2167*7012Sis (tp->t_modes.c_lflag & IEXTEN)) {
21680Sstevel@tonic-gate /*
21690Sstevel@tonic-gate * "Printing rubout"; echo it between \ and /.
21700Sstevel@tonic-gate */
21710Sstevel@tonic-gate if (!(tp->t_state & TS_ERASE)) {
21720Sstevel@tonic-gate ldterm_outchar('\\', q, ebsize, tp);
21730Sstevel@tonic-gate tp->t_state |= TS_ERASE;
21740Sstevel@tonic-gate }
21750Sstevel@tonic-gate (void) ldterm_echo(c, q, ebsize, tp);
21760Sstevel@tonic-gate } else
21770Sstevel@tonic-gate (void) ldterm_echo(tp->t_modes.c_cc[VERASE], q, ebsize, tp);
21780Sstevel@tonic-gate tp->t_rocount--; /* we "unechoed" this character */
21790Sstevel@tonic-gate }
21800Sstevel@tonic-gate
21810Sstevel@tonic-gate
21820Sstevel@tonic-gate /*
21830Sstevel@tonic-gate * Find the number of characters the tab we just deleted took up by
21840Sstevel@tonic-gate * zipping through the current line and recomputing the column
21850Sstevel@tonic-gate * number.
21860Sstevel@tonic-gate */
21870Sstevel@tonic-gate static int
ldterm_tabcols(ldtermstd_state_t * tp)21880Sstevel@tonic-gate ldterm_tabcols(ldtermstd_state_t *tp)
21890Sstevel@tonic-gate {
21900Sstevel@tonic-gate int col;
21910Sstevel@tonic-gate int i;
21920Sstevel@tonic-gate mblk_t *bp;
21930Sstevel@tonic-gate unsigned char *readp, *endp;
21940Sstevel@tonic-gate unsigned char c;
21950Sstevel@tonic-gate uchar_t *startp;
21960Sstevel@tonic-gate char errflg;
21970Sstevel@tonic-gate uchar_t u8[LDTERM_CS_MAX_BYTE_LENGTH];
21980Sstevel@tonic-gate
21990Sstevel@tonic-gate col = tp->t_rocol;
22000Sstevel@tonic-gate /*
22010Sstevel@tonic-gate * If we're doing multi-byte stuff, zip through the list of
22020Sstevel@tonic-gate * widths to figure out where we are (we've kept track in most
22030Sstevel@tonic-gate * cases).
22040Sstevel@tonic-gate */
22050Sstevel@tonic-gate if (tp->t_state & TS_MEUC) {
22060Sstevel@tonic-gate ASSERT(tp->t_eucp_mp);
22070Sstevel@tonic-gate bp = tp->t_message;
22080Sstevel@tonic-gate startp = bp->b_datap->db_base;
22090Sstevel@tonic-gate readp = tp->t_eucp_mp->b_rptr;
22100Sstevel@tonic-gate endp = tp->t_eucp;
22110Sstevel@tonic-gate errflg = (char)0;
22120Sstevel@tonic-gate while (readp < endp) {
22130Sstevel@tonic-gate switch (*readp) {
22140Sstevel@tonic-gate case EUC_TWIDTH: /* it's a tab */
22150Sstevel@tonic-gate col |= 07; /* bump up */
22160Sstevel@tonic-gate col++;
22170Sstevel@tonic-gate break;
22180Sstevel@tonic-gate case EUC_BSWIDTH: /* backspace */
22190Sstevel@tonic-gate if (col)
22200Sstevel@tonic-gate col--;
22210Sstevel@tonic-gate break;
22220Sstevel@tonic-gate case EUC_NLWIDTH: /* newline */
22230Sstevel@tonic-gate if (tp->t_modes.c_oflag & ONLRET)
22240Sstevel@tonic-gate col = 0;
22250Sstevel@tonic-gate break;
22260Sstevel@tonic-gate case EUC_CRWIDTH: /* return */
22270Sstevel@tonic-gate col = 0;
22280Sstevel@tonic-gate break;
22290Sstevel@tonic-gate case UNKNOWN_WIDTH: /* UTF-8 unknown width */
22300Sstevel@tonic-gate if (tp->t_csdata.codeset_type !=
22310Sstevel@tonic-gate LDTERM_CS_TYPE_UTF8 || errflg) {
22320Sstevel@tonic-gate *readp = 1;
22330Sstevel@tonic-gate col++;
22340Sstevel@tonic-gate break;
22350Sstevel@tonic-gate }
22360Sstevel@tonic-gate /*
22370Sstevel@tonic-gate * Collect the current UTF-8 character bytes
22380Sstevel@tonic-gate * from (possibly multiple) data buffers so
22390Sstevel@tonic-gate * that we can figure out the display width.
22400Sstevel@tonic-gate */
22410Sstevel@tonic-gate u8[0] = *startp;
22420Sstevel@tonic-gate for (i = 1; (i < LDTERM_CS_MAX_BYTE_LENGTH) &&
2243*7012Sis (*(readp + i) == 0); i++) {
22440Sstevel@tonic-gate startp++;
22450Sstevel@tonic-gate if (startp >= bp->b_datap->db_lim) {
22460Sstevel@tonic-gate if (bp->b_cont) {
22470Sstevel@tonic-gate bp = bp->b_cont;
22480Sstevel@tonic-gate startp =
2249*7012Sis bp->b_datap->
2250*7012Sis db_base;
22510Sstevel@tonic-gate } else {
22520Sstevel@tonic-gate *readp = 1;
22530Sstevel@tonic-gate col++;
22540Sstevel@tonic-gate break;
22550Sstevel@tonic-gate }
22560Sstevel@tonic-gate }
22570Sstevel@tonic-gate u8[i] = *startp;
22580Sstevel@tonic-gate }
22590Sstevel@tonic-gate
22600Sstevel@tonic-gate /* tp->t_eucp_mp contains wrong info?? */
22610Sstevel@tonic-gate if (*readp == 1)
22620Sstevel@tonic-gate break;
22630Sstevel@tonic-gate
22640Sstevel@tonic-gate *readp = ldterm_utf8_width(u8, i);
22650Sstevel@tonic-gate
22660Sstevel@tonic-gate col += *readp;
22670Sstevel@tonic-gate readp += (i - 1);
22680Sstevel@tonic-gate break;
22690Sstevel@tonic-gate default:
22700Sstevel@tonic-gate col += *readp;
22710Sstevel@tonic-gate break;
22720Sstevel@tonic-gate }
22730Sstevel@tonic-gate ++readp;
22740Sstevel@tonic-gate ++startp;
22750Sstevel@tonic-gate if (startp >= bp->b_datap->db_lim) {
22760Sstevel@tonic-gate if (bp->b_cont) {
22770Sstevel@tonic-gate bp = bp->b_cont;
22780Sstevel@tonic-gate startp = bp->b_datap->db_base;
22790Sstevel@tonic-gate } else {
22800Sstevel@tonic-gate /*
22810Sstevel@tonic-gate * This will happen only if
22820Sstevel@tonic-gate * tp->t_eucp_mp contains wrong
22830Sstevel@tonic-gate * display width info.
22840Sstevel@tonic-gate */
22850Sstevel@tonic-gate errflg = (char)1;
22860Sstevel@tonic-gate startp--;
22870Sstevel@tonic-gate }
22880Sstevel@tonic-gate }
22890Sstevel@tonic-gate }
22900Sstevel@tonic-gate goto eucout; /* finished! */
22910Sstevel@tonic-gate }
22920Sstevel@tonic-gate bp = tp->t_message;
22930Sstevel@tonic-gate do {
22940Sstevel@tonic-gate readp = bp->b_rptr;
22950Sstevel@tonic-gate while (readp < bp->b_wptr) {
22960Sstevel@tonic-gate c = *readp++;
22970Sstevel@tonic-gate if ((tp->t_modes.c_lflag & ECHOCTL) &&
22980Sstevel@tonic-gate (tp->t_modes.c_lflag & IEXTEN)) {
22990Sstevel@tonic-gate if (c <= 037 && c != '\t' && c != '\n' ||
23000Sstevel@tonic-gate c == 0177) {
23010Sstevel@tonic-gate col += 2;
23020Sstevel@tonic-gate continue;
23030Sstevel@tonic-gate }
23040Sstevel@tonic-gate }
23050Sstevel@tonic-gate /*
23060Sstevel@tonic-gate * Column position calculated here.
23070Sstevel@tonic-gate */
23080Sstevel@tonic-gate switch (typetab[c]) {
23090Sstevel@tonic-gate
23100Sstevel@tonic-gate /*
23110Sstevel@tonic-gate * Ordinary characters; advance by
23120Sstevel@tonic-gate * one.
23130Sstevel@tonic-gate */
23140Sstevel@tonic-gate case ORDINARY:
23150Sstevel@tonic-gate col++;
23160Sstevel@tonic-gate break;
23170Sstevel@tonic-gate
23180Sstevel@tonic-gate /*
23190Sstevel@tonic-gate * Non-printing characters; nothing
23200Sstevel@tonic-gate * happens.
23210Sstevel@tonic-gate */
23220Sstevel@tonic-gate case CONTROL:
23230Sstevel@tonic-gate break;
23240Sstevel@tonic-gate
23250Sstevel@tonic-gate /* Backspace */
23260Sstevel@tonic-gate case BACKSPACE:
23270Sstevel@tonic-gate if (col != 0)
23280Sstevel@tonic-gate col--;
23290Sstevel@tonic-gate break;
23300Sstevel@tonic-gate
23310Sstevel@tonic-gate /* Newline; column depends on flags. */
23320Sstevel@tonic-gate case NEWLINE:
23330Sstevel@tonic-gate if (tp->t_modes.c_oflag & ONLRET)
23340Sstevel@tonic-gate col = 0;
23350Sstevel@tonic-gate break;
23360Sstevel@tonic-gate
23370Sstevel@tonic-gate /* tab */
23380Sstevel@tonic-gate case TAB:
23390Sstevel@tonic-gate col |= 07;
23400Sstevel@tonic-gate col++;
23410Sstevel@tonic-gate break;
23420Sstevel@tonic-gate
23430Sstevel@tonic-gate /* vertical motion */
23440Sstevel@tonic-gate case VTAB:
23450Sstevel@tonic-gate break;
23460Sstevel@tonic-gate
23470Sstevel@tonic-gate /* carriage return */
23480Sstevel@tonic-gate case RETURN:
23490Sstevel@tonic-gate col = 0;
23500Sstevel@tonic-gate break;
23510Sstevel@tonic-gate }
23520Sstevel@tonic-gate }
23530Sstevel@tonic-gate } while ((bp = bp->b_cont) != NULL); /* next block, if any */
23540Sstevel@tonic-gate
23550Sstevel@tonic-gate /*
23560Sstevel@tonic-gate * "col" is now the column number before the tab. "tp->t_col"
23570Sstevel@tonic-gate * is still the column number after the tab, since we haven't
23580Sstevel@tonic-gate * erased the tab yet. Thus "tp->t_col - col" is the number
23590Sstevel@tonic-gate * of positions the tab moved.
23600Sstevel@tonic-gate */
23610Sstevel@tonic-gate eucout:
23620Sstevel@tonic-gate col = tp->t_col - col;
23630Sstevel@tonic-gate if (col > 8)
23640Sstevel@tonic-gate col = 8; /* overflow screw */
23650Sstevel@tonic-gate return (col);
23660Sstevel@tonic-gate }
23670Sstevel@tonic-gate
23680Sstevel@tonic-gate
23690Sstevel@tonic-gate /*
23700Sstevel@tonic-gate * Erase a single character; We ONLY ONLY deal with ASCII or
23710Sstevel@tonic-gate * single-column single-byte codeset character. For multi-byte characters,
23720Sstevel@tonic-gate * see "ldterm_csi_erase".
23730Sstevel@tonic-gate */
23740Sstevel@tonic-gate static void
ldterm_erase(queue_t * q,size_t ebsize,ldtermstd_state_t * tp)23750Sstevel@tonic-gate ldterm_erase(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
23760Sstevel@tonic-gate {
23770Sstevel@tonic-gate int c;
23780Sstevel@tonic-gate
23790Sstevel@tonic-gate if ((c = ldterm_unget(tp)) != -1) {
23800Sstevel@tonic-gate ldterm_rubout((unsigned char) c, q, ebsize, tp);
23810Sstevel@tonic-gate ldterm_trim(tp);
23820Sstevel@tonic-gate if (tp->t_state & TS_MEUC)
23830Sstevel@tonic-gate --tp->t_eucp;
23840Sstevel@tonic-gate }
23850Sstevel@tonic-gate }
23860Sstevel@tonic-gate
23870Sstevel@tonic-gate
23880Sstevel@tonic-gate /*
23890Sstevel@tonic-gate * Erase an entire word, single-byte EUC only please.
23900Sstevel@tonic-gate */
23910Sstevel@tonic-gate static void
ldterm_werase(queue_t * q,size_t ebsize,ldtermstd_state_t * tp)23920Sstevel@tonic-gate ldterm_werase(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
23930Sstevel@tonic-gate {
23940Sstevel@tonic-gate int c;
23950Sstevel@tonic-gate
23960Sstevel@tonic-gate /*
23970Sstevel@tonic-gate * Erase trailing white space, if any.
23980Sstevel@tonic-gate */
23990Sstevel@tonic-gate while ((c = ldterm_unget(tp)) == ' ' || c == '\t') {
24000Sstevel@tonic-gate ldterm_rubout((unsigned char) c, q, ebsize, tp);
24010Sstevel@tonic-gate ldterm_trim(tp);
24020Sstevel@tonic-gate }
24030Sstevel@tonic-gate
24040Sstevel@tonic-gate /*
24050Sstevel@tonic-gate * Erase non-white-space characters, if any.
24060Sstevel@tonic-gate */
24070Sstevel@tonic-gate while (c != -1 && c != ' ' && c != '\t') {
24080Sstevel@tonic-gate ldterm_rubout((unsigned char) c, q, ebsize, tp);
24090Sstevel@tonic-gate ldterm_trim(tp);
24100Sstevel@tonic-gate c = ldterm_unget(tp);
24110Sstevel@tonic-gate }
24120Sstevel@tonic-gate if (c != -1) {
24130Sstevel@tonic-gate /*
24140Sstevel@tonic-gate * We removed one too many characters; put the last
24150Sstevel@tonic-gate * one back.
24160Sstevel@tonic-gate */
24170Sstevel@tonic-gate tp->t_endmsg->b_wptr++; /* put 'c' back */
24180Sstevel@tonic-gate tp->t_msglen++;
24190Sstevel@tonic-gate }
24200Sstevel@tonic-gate }
24210Sstevel@tonic-gate
24220Sstevel@tonic-gate
24230Sstevel@tonic-gate /*
24240Sstevel@tonic-gate * ldterm_csi_werase - This is multi-byte equivalent of "word erase".
24250Sstevel@tonic-gate * "Word erase" only makes sense in languages which space between words,
24260Sstevel@tonic-gate * and it's presumptuous for us to attempt "word erase" when we don't
24270Sstevel@tonic-gate * know anything about what's really going on. It makes no sense for
24280Sstevel@tonic-gate * many languages, as the criteria for defining words and tokens may
24290Sstevel@tonic-gate * be completely different.
24300Sstevel@tonic-gate *
24310Sstevel@tonic-gate * In the TS_MEUC case (which is how we got here), we define a token to
24320Sstevel@tonic-gate * be space- or tab-delimited, and erase one of them. It helps to
24330Sstevel@tonic-gate * have this for command lines, but it's otherwise useless for text
24340Sstevel@tonic-gate * editing applications; you need more sophistication than we can
24350Sstevel@tonic-gate * provide here.
24360Sstevel@tonic-gate */
24370Sstevel@tonic-gate static void
ldterm_csi_werase(queue_t * q,size_t ebsize,ldtermstd_state_t * tp)24380Sstevel@tonic-gate ldterm_csi_werase(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
24390Sstevel@tonic-gate {
24400Sstevel@tonic-gate int c, i;
24410Sstevel@tonic-gate int len;
24420Sstevel@tonic-gate uchar_t *ip;
24430Sstevel@tonic-gate uchar_t u8[LDTERM_CS_MAX_BYTE_LENGTH];
24440Sstevel@tonic-gate uchar_t u8_2[LDTERM_CS_MAX_BYTE_LENGTH];
24450Sstevel@tonic-gate
24460Sstevel@tonic-gate /*
24470Sstevel@tonic-gate * ip points to the width of the actual bytes. t_eucp points
24480Sstevel@tonic-gate * one byte beyond, where the next thing will be inserted.
24490Sstevel@tonic-gate */
24500Sstevel@tonic-gate ip = tp->t_eucp - 1;
24510Sstevel@tonic-gate /*
24520Sstevel@tonic-gate * Erase trailing white space, if any.
24530Sstevel@tonic-gate */
24540Sstevel@tonic-gate while ((c = ldterm_unget(tp)) == ' ' || c == '\t') {
24550Sstevel@tonic-gate tp->t_eucp--;
24560Sstevel@tonic-gate ldterm_rubout((unsigned char) c, q, ebsize, tp);
24570Sstevel@tonic-gate ldterm_trim(tp);
24580Sstevel@tonic-gate --ip;
24590Sstevel@tonic-gate }
24600Sstevel@tonic-gate
24610Sstevel@tonic-gate /*
24620Sstevel@tonic-gate * Erase non-white-space characters, if any. The outer loop
24630Sstevel@tonic-gate * bops through each byte in the buffer. Multi-byte is removed, as
24640Sstevel@tonic-gate * is ASCII, one byte at a time. The inner loop (for) is only
24650Sstevel@tonic-gate * executed for first bytes of multi-byte. The inner loop erases
24660Sstevel@tonic-gate * the number of columns required for the multi-byte char. We check
24670Sstevel@tonic-gate * for ASCII first, and ldterm_rubout knows about ASCII.
24680Sstevel@tonic-gate */
24690Sstevel@tonic-gate len = 0;
24700Sstevel@tonic-gate while (c != -1 && c != ' ' && c != '\t') {
24710Sstevel@tonic-gate tp->t_eucp--;
24720Sstevel@tonic-gate if (len < LDTERM_CS_MAX_BYTE_LENGTH) {
24730Sstevel@tonic-gate u8[len++] = (uchar_t)c;
24740Sstevel@tonic-gate }
24750Sstevel@tonic-gate /*
24760Sstevel@tonic-gate * Unlike EUC, except the leading byte, some bytes of
24770Sstevel@tonic-gate * a non-EUC multi-byte characters are in the ASCII code
24780Sstevel@tonic-gate * range, esp., 0x41 ~ 0x7a. Thus, we cannot simply check
24790Sstevel@tonic-gate * ISASCII().
24800Sstevel@tonic-gate * Checking the (*ip == 1 || *ip == 2 || *ip > UNKNOWN_WIDTH)
24810Sstevel@tonic-gate * will ensure that it is a single byte character (even though
24820Sstevel@tonic-gate * it is on display width not byte length) and can be further
24830Sstevel@tonic-gate * checked whether it is an ASCII character or not.
24840Sstevel@tonic-gate *
24850Sstevel@tonic-gate * When ECHOCTL is on and 'c' is an ASCII control character,
24860Sstevel@tonic-gate * *ip == 2 happens.
24870Sstevel@tonic-gate */
24880Sstevel@tonic-gate if ((*ip == 1 || *ip == 2 || *ip > UNKNOWN_WIDTH) &&
24890Sstevel@tonic-gate ISASCII(c)) {
24900Sstevel@tonic-gate ldterm_rubout((unsigned char) c, q, ebsize, tp);
24910Sstevel@tonic-gate len = 0;
24920Sstevel@tonic-gate } else if (*ip) {
24930Sstevel@tonic-gate if (*ip == UNKNOWN_WIDTH) {
24940Sstevel@tonic-gate if (tp->t_csdata.codeset_type ==
24950Sstevel@tonic-gate LDTERM_CS_TYPE_UTF8) {
24960Sstevel@tonic-gate for (i = 0; i < len; i++)
24970Sstevel@tonic-gate u8_2[i] = u8[len - i - 1];
24980Sstevel@tonic-gate *ip = ldterm_utf8_width(u8_2, len);
24990Sstevel@tonic-gate } else {
25000Sstevel@tonic-gate *ip = 1;
25010Sstevel@tonic-gate }
25020Sstevel@tonic-gate }
25030Sstevel@tonic-gate /*
25040Sstevel@tonic-gate * erase for number of columns required for
25050Sstevel@tonic-gate * this multi-byte character. Hopefully, matches
25060Sstevel@tonic-gate * ldterm_dispwidth!
25070Sstevel@tonic-gate */
25080Sstevel@tonic-gate for (i = 0; i < (int)*ip; i++)
25090Sstevel@tonic-gate ldterm_rubout(' ', q, ebsize, tp);
25100Sstevel@tonic-gate len = 0;
25110Sstevel@tonic-gate }
25120Sstevel@tonic-gate ldterm_trim(tp);
25130Sstevel@tonic-gate --ip;
25140Sstevel@tonic-gate c = ldterm_unget(tp);
25150Sstevel@tonic-gate }
25160Sstevel@tonic-gate if (c != -1) {
25170Sstevel@tonic-gate /*
25180Sstevel@tonic-gate * We removed one too many characters; put the last
25190Sstevel@tonic-gate * one back.
25200Sstevel@tonic-gate */
25210Sstevel@tonic-gate tp->t_endmsg->b_wptr++; /* put 'c' back */
25220Sstevel@tonic-gate tp->t_msglen++;
25230Sstevel@tonic-gate }
25240Sstevel@tonic-gate }
25250Sstevel@tonic-gate
25260Sstevel@tonic-gate
25270Sstevel@tonic-gate /*
25280Sstevel@tonic-gate * Kill an entire line, erasing each character one-by-one (if ECHOKE
25290Sstevel@tonic-gate * is set) or just echoing the kill character, followed by a newline
25300Sstevel@tonic-gate * (if ECHOK is set). Multi-byte processing is included here.
25310Sstevel@tonic-gate */
25320Sstevel@tonic-gate
25330Sstevel@tonic-gate static void
ldterm_kill(queue_t * q,size_t ebsize,ldtermstd_state_t * tp)25340Sstevel@tonic-gate ldterm_kill(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
25350Sstevel@tonic-gate {
25360Sstevel@tonic-gate int c, i;
25370Sstevel@tonic-gate int len;
25380Sstevel@tonic-gate uchar_t *ip;
25390Sstevel@tonic-gate uchar_t u8[LDTERM_CS_MAX_BYTE_LENGTH];
25400Sstevel@tonic-gate uchar_t u8_2[LDTERM_CS_MAX_BYTE_LENGTH];
25410Sstevel@tonic-gate
25420Sstevel@tonic-gate if ((tp->t_modes.c_lflag & ECHOKE) &&
25430Sstevel@tonic-gate (tp->t_modes.c_lflag & IEXTEN) &&
25440Sstevel@tonic-gate (tp->t_msglen == tp->t_rocount)) {
25450Sstevel@tonic-gate if (tp->t_state & TS_MEUC) {
25460Sstevel@tonic-gate ip = tp->t_eucp - 1;
25470Sstevel@tonic-gate /*
25480Sstevel@tonic-gate * This loop similar to "ldterm_csi_werase" above.
25490Sstevel@tonic-gate */
25500Sstevel@tonic-gate len = 0;
25510Sstevel@tonic-gate while ((c = ldterm_unget(tp)) != (-1)) {
25520Sstevel@tonic-gate tp->t_eucp--;
25530Sstevel@tonic-gate if (len < LDTERM_CS_MAX_BYTE_LENGTH) {
25540Sstevel@tonic-gate u8[len++] = (uchar_t)c;
25550Sstevel@tonic-gate }
25560Sstevel@tonic-gate if ((*ip == 1 || *ip == 2 ||
25570Sstevel@tonic-gate *ip > UNKNOWN_WIDTH) && ISASCII(c)) {
25580Sstevel@tonic-gate ldterm_rubout((unsigned char) c, q,
2559*7012Sis ebsize, tp);
25600Sstevel@tonic-gate len = 0;
25610Sstevel@tonic-gate } else if (*ip) {
25620Sstevel@tonic-gate if (*ip == UNKNOWN_WIDTH) {
25630Sstevel@tonic-gate if (tp->t_csdata.codeset_type
25640Sstevel@tonic-gate == LDTERM_CS_TYPE_UTF8) {
25650Sstevel@tonic-gate for (i = 0; i < len;
25660Sstevel@tonic-gate i++)
25670Sstevel@tonic-gate u8_2[i] =
25680Sstevel@tonic-gate u8[len-i-1];
25690Sstevel@tonic-gate *ip = ldterm_utf8_width(
2570*7012Sis u8_2, len);
25710Sstevel@tonic-gate } else {
25720Sstevel@tonic-gate *ip = 1;
25730Sstevel@tonic-gate }
25740Sstevel@tonic-gate }
25750Sstevel@tonic-gate for (i = 0; i < (int)*ip; i++)
25760Sstevel@tonic-gate ldterm_rubout(' ', q, ebsize,
25770Sstevel@tonic-gate tp);
25780Sstevel@tonic-gate len = 0;
25790Sstevel@tonic-gate }
25800Sstevel@tonic-gate ldterm_trim(tp);
25810Sstevel@tonic-gate --ip;
25820Sstevel@tonic-gate }
25830Sstevel@tonic-gate } else {
25840Sstevel@tonic-gate while ((c = ldterm_unget(tp)) != -1) {
25850Sstevel@tonic-gate ldterm_rubout((unsigned char) c, q, ebsize, tp);
25860Sstevel@tonic-gate ldterm_trim(tp);
25870Sstevel@tonic-gate }
25880Sstevel@tonic-gate }
25890Sstevel@tonic-gate } else {
25900Sstevel@tonic-gate (void) ldterm_echo(tp->t_modes.c_cc[VKILL], q, ebsize, tp);
25910Sstevel@tonic-gate if (tp->t_modes.c_lflag & ECHOK)
25920Sstevel@tonic-gate (void) ldterm_echo('\n', q, ebsize, tp);
25930Sstevel@tonic-gate while (ldterm_unget(tp) != -1) {
25940Sstevel@tonic-gate if (tp->t_state & TS_MEUC)
25950Sstevel@tonic-gate --tp->t_eucp;
25960Sstevel@tonic-gate ldterm_trim(tp);
25970Sstevel@tonic-gate }
25980Sstevel@tonic-gate tp->t_rocount = 0;
25990Sstevel@tonic-gate if (tp->t_state & TS_MEUC)
26000Sstevel@tonic-gate tp->t_eucp = tp->t_eucp_mp->b_rptr;
26010Sstevel@tonic-gate }
26020Sstevel@tonic-gate tp->t_state &= ~(TS_QUOT|TS_ERASE|TS_SLNCH);
26030Sstevel@tonic-gate }
26040Sstevel@tonic-gate
26050Sstevel@tonic-gate
26060Sstevel@tonic-gate /*
26070Sstevel@tonic-gate * Reprint the current input line. We assume c_cc has already been
26080Sstevel@tonic-gate * checked. XXX just the current line, not the whole queue? What
26090Sstevel@tonic-gate * about DEFECHO mode?
26100Sstevel@tonic-gate */
26110Sstevel@tonic-gate static void
ldterm_reprint(queue_t * q,size_t ebsize,ldtermstd_state_t * tp)26120Sstevel@tonic-gate ldterm_reprint(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
26130Sstevel@tonic-gate {
26140Sstevel@tonic-gate mblk_t *bp;
26150Sstevel@tonic-gate unsigned char *readp;
26160Sstevel@tonic-gate
26170Sstevel@tonic-gate if (tp->t_modes.c_cc[VREPRINT] != (unsigned char) 0)
26180Sstevel@tonic-gate (void) ldterm_echo(tp->t_modes.c_cc[VREPRINT], q, ebsize, tp);
26190Sstevel@tonic-gate ldterm_outchar('\n', q, ebsize, tp);
26200Sstevel@tonic-gate
26210Sstevel@tonic-gate bp = tp->t_message;
26220Sstevel@tonic-gate do {
26230Sstevel@tonic-gate readp = bp->b_rptr;
26240Sstevel@tonic-gate while (readp < bp->b_wptr)
26250Sstevel@tonic-gate (void) ldterm_echo(*readp++, q, ebsize, tp);
26260Sstevel@tonic-gate } while ((bp = bp->b_cont) != NULL); /* next block, if any */
26270Sstevel@tonic-gate
26280Sstevel@tonic-gate tp->t_state &= ~TS_ERASE;
26290Sstevel@tonic-gate tp->t_rocount = tp->t_msglen; /* we reechoed the entire line */
26300Sstevel@tonic-gate tp->t_rocol = 0;
26310Sstevel@tonic-gate }
26320Sstevel@tonic-gate
26330Sstevel@tonic-gate
26340Sstevel@tonic-gate /*
26350Sstevel@tonic-gate * Non canonical processing. Called with q locked from ldtermrsrv.
26360Sstevel@tonic-gate *
26370Sstevel@tonic-gate */
26380Sstevel@tonic-gate static mblk_t *
ldterm_dononcanon(mblk_t * bp,mblk_t * bpt,size_t ebsize,queue_t * q,ldtermstd_state_t * tp)26390Sstevel@tonic-gate ldterm_dononcanon(mblk_t *bp, mblk_t *bpt, size_t ebsize, queue_t *q,
26400Sstevel@tonic-gate ldtermstd_state_t *tp)
26410Sstevel@tonic-gate {
26420Sstevel@tonic-gate queue_t *wrq = WR(q);
26430Sstevel@tonic-gate unsigned char *rptr;
26440Sstevel@tonic-gate size_t bytes_in_bp;
26450Sstevel@tonic-gate size_t roomleft;
26460Sstevel@tonic-gate size_t bytes_to_move;
26470Sstevel@tonic-gate int free_flag = 0;
26480Sstevel@tonic-gate
26490Sstevel@tonic-gate if (tp->t_modes.c_lflag & (ECHO|ECHONL|IEXTEN)) {
26500Sstevel@tonic-gate unsigned char *wptr;
26510Sstevel@tonic-gate unsigned char c;
26520Sstevel@tonic-gate
26530Sstevel@tonic-gate /*
26540Sstevel@tonic-gate * Either we must echo the characters, or we must
26550Sstevel@tonic-gate * echo NL, or we must check for VLNEXT. Process
26560Sstevel@tonic-gate * characters one at a time.
26570Sstevel@tonic-gate */
26580Sstevel@tonic-gate rptr = bp->b_rptr;
26590Sstevel@tonic-gate wptr = bp->b_rptr;
26600Sstevel@tonic-gate while (rptr < bp->b_wptr) {
26610Sstevel@tonic-gate c = *rptr++;
26620Sstevel@tonic-gate /*
26630Sstevel@tonic-gate * If this character is the literal next
26640Sstevel@tonic-gate * character, echo it as '^' and backspace
26650Sstevel@tonic-gate * over it if echoing is enabled, indicate
26660Sstevel@tonic-gate * that the next character is to be treated
26670Sstevel@tonic-gate * literally, and remove the LNEXT from the
26680Sstevel@tonic-gate * input stream.
26690Sstevel@tonic-gate *
26700Sstevel@tonic-gate * If the *previous* character was the literal
26710Sstevel@tonic-gate * next character, don't check whether this
26720Sstevel@tonic-gate * is a literal next or not.
26730Sstevel@tonic-gate */
26740Sstevel@tonic-gate if ((tp->t_modes.c_lflag & IEXTEN) &&
26750Sstevel@tonic-gate !(tp->t_state & TS_SLNCH) &&
26760Sstevel@tonic-gate c != _POSIX_VDISABLE &&
26770Sstevel@tonic-gate c == tp->t_modes.c_cc[VLNEXT]) {
26780Sstevel@tonic-gate if (tp->t_modes.c_lflag & ECHO)
26790Sstevel@tonic-gate ldterm_outstring(
26800Sstevel@tonic-gate (unsigned char *)"^\b",
2681*7012Sis 2, wrq, ebsize, tp);
26820Sstevel@tonic-gate tp->t_state |= TS_SLNCH;
26830Sstevel@tonic-gate continue; /* and ignore it */
26840Sstevel@tonic-gate }
26850Sstevel@tonic-gate /*
26860Sstevel@tonic-gate * Not a "literal next" character, so it
26870Sstevel@tonic-gate * should show up as input. If it was
26880Sstevel@tonic-gate * literal-nexted, turn off the literal-next
26890Sstevel@tonic-gate * flag.
26900Sstevel@tonic-gate */
26910Sstevel@tonic-gate tp->t_state &= ~TS_SLNCH;
26920Sstevel@tonic-gate *wptr++ = c;
26930Sstevel@tonic-gate if (tp->t_modes.c_lflag & ECHO) {
26940Sstevel@tonic-gate /*
26950Sstevel@tonic-gate * Echo the character.
26960Sstevel@tonic-gate */
26970Sstevel@tonic-gate (void) ldterm_echo(c, wrq, ebsize, tp);
26980Sstevel@tonic-gate } else if (tp->t_modes.c_lflag & ECHONL) {
26990Sstevel@tonic-gate /*
27000Sstevel@tonic-gate * Echo NL, even though ECHO is not
27010Sstevel@tonic-gate * set.
27020Sstevel@tonic-gate */
27030Sstevel@tonic-gate if (c == '\n')
2704*7012Sis ldterm_outchar('\n', wrq, 1, tp);
27050Sstevel@tonic-gate }
27060Sstevel@tonic-gate }
27070Sstevel@tonic-gate bp->b_wptr = wptr;
27080Sstevel@tonic-gate } else {
27090Sstevel@tonic-gate /*
27100Sstevel@tonic-gate * If there are any characters in this buffer, and
27110Sstevel@tonic-gate * the first of them was literal-nexted, turn off the
27120Sstevel@tonic-gate * literal-next flag.
27130Sstevel@tonic-gate */
27140Sstevel@tonic-gate if (bp->b_rptr != bp->b_wptr)
27150Sstevel@tonic-gate tp->t_state &= ~TS_SLNCH;
27160Sstevel@tonic-gate }
27170Sstevel@tonic-gate
27180Sstevel@tonic-gate ASSERT(bp->b_wptr >= bp->b_rptr);
27190Sstevel@tonic-gate bytes_in_bp = bp->b_wptr - bp->b_rptr;
27200Sstevel@tonic-gate rptr = bp->b_rptr;
27210Sstevel@tonic-gate while (bytes_in_bp != 0) {
27220Sstevel@tonic-gate roomleft = bpt->b_datap->db_lim - bpt->b_wptr;
27230Sstevel@tonic-gate if (roomleft == 0) {
27240Sstevel@tonic-gate /*
27250Sstevel@tonic-gate * No more room in this mblk; save this one
27260Sstevel@tonic-gate * away, and allocate a new one.
27270Sstevel@tonic-gate */
27280Sstevel@tonic-gate if ((bpt = allocb(IBSIZE, BPRI_MED)) == NULL) {
27290Sstevel@tonic-gate freeb(bp);
27300Sstevel@tonic-gate DEBUG4(("ldterm_do_noncanon: allcob failed\n"));
27310Sstevel@tonic-gate return (bpt);
27320Sstevel@tonic-gate }
27330Sstevel@tonic-gate /*
27340Sstevel@tonic-gate * Chain the new one to the end of the old
27350Sstevel@tonic-gate * one, and mark it as the last block in the
27360Sstevel@tonic-gate * current lump.
27370Sstevel@tonic-gate */
27380Sstevel@tonic-gate tp->t_endmsg->b_cont = bpt;
27390Sstevel@tonic-gate tp->t_endmsg = bpt;
27400Sstevel@tonic-gate roomleft = IBSIZE;
27410Sstevel@tonic-gate }
27420Sstevel@tonic-gate DEBUG5(("roomleft=%d, bytes_in_bp=%d, tp->t_rd_request=%d\n",
2743*7012Sis roomleft, bytes_in_bp, tp->t_rd_request));
27440Sstevel@tonic-gate /*
27450Sstevel@tonic-gate * if there is a read pending before this data got
27460Sstevel@tonic-gate * here move bytes according to the minimum of room
27470Sstevel@tonic-gate * left in this buffer, bytes in the message and byte
27480Sstevel@tonic-gate * count requested in the read. If there is no read
27490Sstevel@tonic-gate * pending, move the minimum of the first two
27500Sstevel@tonic-gate */
27510Sstevel@tonic-gate if (tp->t_rd_request == 0)
27520Sstevel@tonic-gate bytes_to_move = MIN(roomleft, bytes_in_bp);
27530Sstevel@tonic-gate else
27540Sstevel@tonic-gate bytes_to_move =
27550Sstevel@tonic-gate MIN(MIN(roomleft, bytes_in_bp), tp->t_rd_request);
27560Sstevel@tonic-gate DEBUG5(("Bytes to move = %lu\n", bytes_to_move));
27570Sstevel@tonic-gate if (bytes_to_move == 0)
27580Sstevel@tonic-gate break;
27590Sstevel@tonic-gate bcopy(rptr, bpt->b_wptr, bytes_to_move);
27600Sstevel@tonic-gate bpt->b_wptr += bytes_to_move;
27610Sstevel@tonic-gate rptr += bytes_to_move;
27620Sstevel@tonic-gate tp->t_msglen += bytes_to_move;
27630Sstevel@tonic-gate bytes_in_bp -= bytes_to_move;
27640Sstevel@tonic-gate }
27650Sstevel@tonic-gate if (bytes_in_bp == 0) {
27660Sstevel@tonic-gate DEBUG4(("bytes_in_bp is zero\n"));
27670Sstevel@tonic-gate freeb(bp);
27680Sstevel@tonic-gate } else
27690Sstevel@tonic-gate free_flag = 1; /* for debugging olny */
27700Sstevel@tonic-gate
27710Sstevel@tonic-gate DEBUG4(("ldterm_do_noncanon: VMIN = %d, VTIME = %d, msglen = %d, \
27720Sstevel@tonic-gate tid = %d\n", V_MIN, V_TIME, tp->t_msglen, tp->t_vtid));
27730Sstevel@tonic-gate /*
27740Sstevel@tonic-gate * If there is a pending read request at the stream head we
27750Sstevel@tonic-gate * need to do VMIN/VTIME processing. The four possible cases
27760Sstevel@tonic-gate * are:
27770Sstevel@tonic-gate * MIN = 0, TIME > 0
27780Sstevel@tonic-gate * MIN = >, TIME = 0
27790Sstevel@tonic-gate * MIN > 0, TIME > 0
27800Sstevel@tonic-gate * MIN = 0, TIME = 0
27810Sstevel@tonic-gate * If we can satisfy VMIN, send it up, and start a new
27820Sstevel@tonic-gate * timer if necessary. These four cases of VMIN/VTIME
27830Sstevel@tonic-gate * are also dealt with in the write side put routine
27840Sstevel@tonic-gate * when the M_READ is first seen.
27850Sstevel@tonic-gate */
27860Sstevel@tonic-gate
27870Sstevel@tonic-gate DEBUG4(("Incoming data while M_READ'ing\n"));
27880Sstevel@tonic-gate /*
27890Sstevel@tonic-gate * Case 1: Any data will satisfy the read, so send
27900Sstevel@tonic-gate * it upstream.
27910Sstevel@tonic-gate */
27920Sstevel@tonic-gate if (V_MIN == 0 && V_TIME > 0) {
27930Sstevel@tonic-gate if (tp->t_msglen)
27940Sstevel@tonic-gate vmin_satisfied(q, tp, 1);
27950Sstevel@tonic-gate else {
27960Sstevel@tonic-gate /* EMPTY */
27970Sstevel@tonic-gate DEBUG4(("ldterm_do_noncanon called, but no data!\n"));
27980Sstevel@tonic-gate }
27990Sstevel@tonic-gate /*
28000Sstevel@tonic-gate * Case 2: This should never time out, so
28010Sstevel@tonic-gate * until there's enough data, do nothing.
28020Sstevel@tonic-gate */
28030Sstevel@tonic-gate } else if (V_MIN > 0 && V_TIME == 0) {
28040Sstevel@tonic-gate if (tp->t_msglen >= (int)V_MIN)
28050Sstevel@tonic-gate vmin_satisfied(q, tp, 1);
28060Sstevel@tonic-gate
28070Sstevel@tonic-gate /*
28080Sstevel@tonic-gate * Case 3: If MIN is satisfied, send it up.
28090Sstevel@tonic-gate * Also, remember to start a new timer *every*
28100Sstevel@tonic-gate * time we see something if MIN isn't
28110Sstevel@tonic-gate * safisfied
28120Sstevel@tonic-gate */
28130Sstevel@tonic-gate } else if (V_MIN > 0 && V_TIME > 0) {
28140Sstevel@tonic-gate if (tp->t_msglen >= (int)V_MIN)
28150Sstevel@tonic-gate vmin_satisfied(q, tp, 1);
28160Sstevel@tonic-gate else
28170Sstevel@tonic-gate vmin_settimer(q);
28180Sstevel@tonic-gate /*
28190Sstevel@tonic-gate * Case 4: Not possible. This request
28200Sstevel@tonic-gate * should always be satisfied from the write
28210Sstevel@tonic-gate * side, left here for debugging.
28220Sstevel@tonic-gate */
28230Sstevel@tonic-gate } else { /* V_MIN == 0 && V_TIME == 0 */
28240Sstevel@tonic-gate vmin_satisfied(q, tp, 1);
28250Sstevel@tonic-gate }
28260Sstevel@tonic-gate
28270Sstevel@tonic-gate if (free_flag) {
28280Sstevel@tonic-gate /* EMPTY */
28290Sstevel@tonic-gate DEBUG4(("CAUTION message block not freed\n"));
28300Sstevel@tonic-gate }
28310Sstevel@tonic-gate return (newmsg(tp));
28320Sstevel@tonic-gate }
28330Sstevel@tonic-gate
28340Sstevel@tonic-gate
28350Sstevel@tonic-gate /*
28360Sstevel@tonic-gate * Echo a typed byte to the terminal. Returns the number of bytes
28370Sstevel@tonic-gate * printed. Bytes of EUC characters drop through the ECHOCTL stuff
28380Sstevel@tonic-gate * and are just output as themselves.
28390Sstevel@tonic-gate */
28400Sstevel@tonic-gate static int
ldterm_echo(uchar_t c,queue_t * q,size_t ebsize,ldtermstd_state_t * tp)28410Sstevel@tonic-gate ldterm_echo(uchar_t c, queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
28420Sstevel@tonic-gate {
28430Sstevel@tonic-gate int i;
28440Sstevel@tonic-gate
28450Sstevel@tonic-gate if (!(tp->t_modes.c_lflag & ECHO))
28460Sstevel@tonic-gate return (0);
28470Sstevel@tonic-gate i = 0;
28480Sstevel@tonic-gate
28490Sstevel@tonic-gate /*
28500Sstevel@tonic-gate * Echo control characters (c <= 37) only if the ECHOCTRL
28510Sstevel@tonic-gate * flag is set as ^X.
28520Sstevel@tonic-gate */
28530Sstevel@tonic-gate
28540Sstevel@tonic-gate if ((tp->t_modes.c_lflag & ECHOCTL) &&
28550Sstevel@tonic-gate (tp->t_modes.c_lflag & IEXTEN)) {
28560Sstevel@tonic-gate if (c <= 037 && c != '\t' && c != '\n') {
28570Sstevel@tonic-gate ldterm_outchar('^', q, ebsize, tp);
28580Sstevel@tonic-gate i++;
28590Sstevel@tonic-gate if (tp->t_modes.c_oflag & OLCUC)
28600Sstevel@tonic-gate c += 'a' - 1;
28610Sstevel@tonic-gate else
28620Sstevel@tonic-gate c += 'A' - 1;
28630Sstevel@tonic-gate } else if (c == 0177) {
28640Sstevel@tonic-gate ldterm_outchar('^', q, ebsize, tp);
28650Sstevel@tonic-gate i++;
28660Sstevel@tonic-gate c = '?';
28670Sstevel@tonic-gate }
28680Sstevel@tonic-gate ldterm_outchar(c, q, ebsize, tp);
28690Sstevel@tonic-gate return (i + 1);
28700Sstevel@tonic-gate /* echo only special control character and the Bell */
28710Sstevel@tonic-gate } else if ((c > 037 && c != 0177) || c == '\t' || c == '\n' ||
2872*7012Sis c == '\r' || c == '\b' || c == 007 ||
2873*7012Sis c == tp->t_modes.c_cc[VKILL]) {
28740Sstevel@tonic-gate ldterm_outchar(c, q, ebsize, tp);
28750Sstevel@tonic-gate return (i + 1);
28760Sstevel@tonic-gate }
28770Sstevel@tonic-gate return (i);
28780Sstevel@tonic-gate }
28790Sstevel@tonic-gate
28800Sstevel@tonic-gate
28810Sstevel@tonic-gate /*
28820Sstevel@tonic-gate * Put a character on the output queue.
28830Sstevel@tonic-gate */
28840Sstevel@tonic-gate static void
ldterm_outchar(uchar_t c,queue_t * q,size_t bsize,ldtermstd_state_t * tp)28850Sstevel@tonic-gate ldterm_outchar(uchar_t c, queue_t *q, size_t bsize, ldtermstd_state_t *tp)
28860Sstevel@tonic-gate {
28870Sstevel@tonic-gate mblk_t *curbp;
28880Sstevel@tonic-gate
28890Sstevel@tonic-gate /*
28900Sstevel@tonic-gate * Don't even look at the characters unless we have something
28910Sstevel@tonic-gate * useful to do with them.
28920Sstevel@tonic-gate */
28930Sstevel@tonic-gate if ((tp->t_modes.c_oflag & OPOST) ||
28940Sstevel@tonic-gate ((tp->t_modes.c_lflag & XCASE) &&
28950Sstevel@tonic-gate (tp->t_modes.c_lflag & ICANON))) {
28960Sstevel@tonic-gate mblk_t *mp;
28970Sstevel@tonic-gate
28980Sstevel@tonic-gate if ((mp = allocb(4, BPRI_HI)) == NULL) {
28990Sstevel@tonic-gate cmn_err(CE_WARN,
29000Sstevel@tonic-gate "ldterm: (ldterm_outchar) out of blocks");
29010Sstevel@tonic-gate return;
29020Sstevel@tonic-gate }
29030Sstevel@tonic-gate *mp->b_wptr++ = c;
29040Sstevel@tonic-gate mp = ldterm_output_msg(q, mp, &tp->t_echomp, tp, bsize, 1);
29050Sstevel@tonic-gate if (mp != NULL)
29060Sstevel@tonic-gate freemsg(mp);
29070Sstevel@tonic-gate
29080Sstevel@tonic-gate } else {
29090Sstevel@tonic-gate if ((curbp = tp->t_echomp) != NULL) {
29100Sstevel@tonic-gate while (curbp->b_cont != NULL)
29110Sstevel@tonic-gate curbp = curbp->b_cont;
29120Sstevel@tonic-gate if (curbp->b_datap->db_lim == curbp->b_wptr) {
29130Sstevel@tonic-gate mblk_t *newbp;
29140Sstevel@tonic-gate
29150Sstevel@tonic-gate if ((newbp = allocb(bsize, BPRI_HI)) == NULL) {
29160Sstevel@tonic-gate cmn_err(CE_WARN,
29170Sstevel@tonic-gate "ldterm_outchar: out of blocks");
29180Sstevel@tonic-gate return;
29190Sstevel@tonic-gate }
29200Sstevel@tonic-gate curbp->b_cont = newbp;
29210Sstevel@tonic-gate curbp = newbp;
29220Sstevel@tonic-gate }
29230Sstevel@tonic-gate } else {
29240Sstevel@tonic-gate if ((curbp = allocb(bsize, BPRI_HI)) == NULL) {
29250Sstevel@tonic-gate cmn_err(CE_WARN,
29260Sstevel@tonic-gate "ldterm_outchar: out of blocks");
29270Sstevel@tonic-gate return;
29280Sstevel@tonic-gate }
29290Sstevel@tonic-gate tp->t_echomp = curbp;
29300Sstevel@tonic-gate }
29310Sstevel@tonic-gate *curbp->b_wptr++ = c;
29320Sstevel@tonic-gate }
29330Sstevel@tonic-gate }
29340Sstevel@tonic-gate
29350Sstevel@tonic-gate
29360Sstevel@tonic-gate /*
29370Sstevel@tonic-gate * Copy a string, of length len, to the output queue.
29380Sstevel@tonic-gate */
29390Sstevel@tonic-gate static void
ldterm_outstring(uchar_t * cp,int len,queue_t * q,size_t bsize,ldtermstd_state_t * tp)29400Sstevel@tonic-gate ldterm_outstring(uchar_t *cp, int len, queue_t *q, size_t bsize,
29410Sstevel@tonic-gate ldtermstd_state_t *tp)
29420Sstevel@tonic-gate {
29430Sstevel@tonic-gate while (len > 0) {
29440Sstevel@tonic-gate ldterm_outchar(*cp++, q, bsize, tp);
29450Sstevel@tonic-gate len--;
29460Sstevel@tonic-gate }
29470Sstevel@tonic-gate }
29480Sstevel@tonic-gate
29490Sstevel@tonic-gate
29500Sstevel@tonic-gate static mblk_t *
newmsg(ldtermstd_state_t * tp)29510Sstevel@tonic-gate newmsg(ldtermstd_state_t *tp)
29520Sstevel@tonic-gate {
29530Sstevel@tonic-gate mblk_t *bp;
29540Sstevel@tonic-gate
29550Sstevel@tonic-gate /*
29560Sstevel@tonic-gate * If no current message, allocate a block for it.
29570Sstevel@tonic-gate */
29580Sstevel@tonic-gate if ((bp = tp->t_endmsg) == NULL) {
29590Sstevel@tonic-gate if ((bp = allocb(IBSIZE, BPRI_MED)) == NULL) {
29600Sstevel@tonic-gate cmn_err(CE_WARN,
29610Sstevel@tonic-gate "ldterm: (ldtermrsrv/newmsg) out of blocks");
29620Sstevel@tonic-gate return (bp);
29630Sstevel@tonic-gate }
29640Sstevel@tonic-gate tp->t_message = bp;
29650Sstevel@tonic-gate tp->t_endmsg = bp;
29660Sstevel@tonic-gate }
29670Sstevel@tonic-gate return (bp);
29680Sstevel@tonic-gate }
29690Sstevel@tonic-gate
29700Sstevel@tonic-gate
29710Sstevel@tonic-gate static void
ldterm_msg_upstream(queue_t * q,ldtermstd_state_t * tp)29720Sstevel@tonic-gate ldterm_msg_upstream(queue_t *q, ldtermstd_state_t *tp)
29730Sstevel@tonic-gate {
29740Sstevel@tonic-gate ssize_t s;
29750Sstevel@tonic-gate mblk_t *bp;
29760Sstevel@tonic-gate
29770Sstevel@tonic-gate bp = tp->t_message;
29780Sstevel@tonic-gate s = msgdsize(bp);
29790Sstevel@tonic-gate if (bp)
29800Sstevel@tonic-gate putnext(q, tp->t_message);
29810Sstevel@tonic-gate
29820Sstevel@tonic-gate /*
29830Sstevel@tonic-gate * update sysinfo canch character.
29840Sstevel@tonic-gate */
29850Sstevel@tonic-gate if (CANON_MODE)
29860Sstevel@tonic-gate (void) drv_setparm(SYSCANC, s);
29870Sstevel@tonic-gate tp->t_message = NULL;
29880Sstevel@tonic-gate tp->t_endmsg = NULL;
29890Sstevel@tonic-gate tp->t_msglen = 0;
29900Sstevel@tonic-gate tp->t_rocount = 0;
29910Sstevel@tonic-gate tp->t_rd_request = 0;
29920Sstevel@tonic-gate if (tp->t_state & TS_MEUC) {
29930Sstevel@tonic-gate ASSERT(tp->t_eucp_mp);
29940Sstevel@tonic-gate tp->t_eucp = tp->t_eucp_mp->b_rptr;
29950Sstevel@tonic-gate /* can't reset everything, as we may have other input */
29960Sstevel@tonic-gate }
29970Sstevel@tonic-gate }
29980Sstevel@tonic-gate
29990Sstevel@tonic-gate
30000Sstevel@tonic-gate /*
30010Sstevel@tonic-gate * Re-enable the write-side service procedure. When an allocation
30020Sstevel@tonic-gate * failure causes write-side processing to stall, we disable the
30030Sstevel@tonic-gate * write side and arrange to call this function when allocation once
30040Sstevel@tonic-gate * again becomes possible.
30050Sstevel@tonic-gate */
30060Sstevel@tonic-gate static void
ldterm_wenable(void * addr)30070Sstevel@tonic-gate ldterm_wenable(void *addr)
30080Sstevel@tonic-gate {
30090Sstevel@tonic-gate queue_t *q = addr;
30100Sstevel@tonic-gate ldtermstd_state_t *tp;
30110Sstevel@tonic-gate
30120Sstevel@tonic-gate tp = (ldtermstd_state_t *)q->q_ptr;
30130Sstevel@tonic-gate /*
30140Sstevel@tonic-gate * The bufcall is no longer pending.
30150Sstevel@tonic-gate */
30160Sstevel@tonic-gate tp->t_wbufcid = 0;
30170Sstevel@tonic-gate enableok(q);
30180Sstevel@tonic-gate qenable(q);
30190Sstevel@tonic-gate }
30200Sstevel@tonic-gate
30210Sstevel@tonic-gate
30220Sstevel@tonic-gate /*
30230Sstevel@tonic-gate * Line discipline output queue put procedure. Attempts to process
30240Sstevel@tonic-gate * the message directly and send it on downstream, queueing it only
30250Sstevel@tonic-gate * if there's already something pending or if its downstream neighbor
30260Sstevel@tonic-gate * is clogged.
30270Sstevel@tonic-gate */
30280Sstevel@tonic-gate static void
ldtermwput(queue_t * q,mblk_t * mp)30290Sstevel@tonic-gate ldtermwput(queue_t *q, mblk_t *mp)
30300Sstevel@tonic-gate {
30310Sstevel@tonic-gate ldtermstd_state_t *tp;
30320Sstevel@tonic-gate unsigned char type = mp->b_datap->db_type;
30330Sstevel@tonic-gate
30340Sstevel@tonic-gate tp = (ldtermstd_state_t *)q->q_ptr;
30350Sstevel@tonic-gate
30360Sstevel@tonic-gate /*
30370Sstevel@tonic-gate * Always process priority messages, regardless of whether or
30380Sstevel@tonic-gate * not our queue is nonempty.
30390Sstevel@tonic-gate */
30400Sstevel@tonic-gate if (type >= QPCTL) {
30410Sstevel@tonic-gate switch (type) {
30420Sstevel@tonic-gate
30430Sstevel@tonic-gate case M_FLUSH:
30440Sstevel@tonic-gate /*
30450Sstevel@tonic-gate * Get rid of it, see comment in
30460Sstevel@tonic-gate * ldterm_dosig().
30470Sstevel@tonic-gate */
30480Sstevel@tonic-gate if ((tp->t_state & TS_FLUSHWAIT) &&
30490Sstevel@tonic-gate (*mp->b_rptr == FLUSHW)) {
30500Sstevel@tonic-gate tp->t_state &= ~TS_FLUSHWAIT;
30510Sstevel@tonic-gate freemsg(mp);
30520Sstevel@tonic-gate return;
30530Sstevel@tonic-gate }
30540Sstevel@tonic-gate /*
30550Sstevel@tonic-gate * This is coming from above, so we only
30560Sstevel@tonic-gate * handle the write queue here. If FLUSHR is
30570Sstevel@tonic-gate * set, it will get turned around at the
30580Sstevel@tonic-gate * driver, and the read procedure will see it
30590Sstevel@tonic-gate * eventually.
30600Sstevel@tonic-gate */
30610Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW) {
3062*7012Sis if ((tp->t_state & TS_ISPTSTTY) &&
3063*7012Sis (*mp->b_rptr & FLUSHBAND))
3064*7012Sis flushband(q, *(mp->b_rptr + 1),
3065*7012Sis FLUSHDATA);
3066*7012Sis else
3067*7012Sis flushq(q, FLUSHDATA);
30680Sstevel@tonic-gate }
30690Sstevel@tonic-gate
30700Sstevel@tonic-gate putnext(q, mp);
30710Sstevel@tonic-gate /*
30720Sstevel@tonic-gate * If a timed read is interrupted, there is
30730Sstevel@tonic-gate * no way to cancel an existing M_READ
30740Sstevel@tonic-gate * request. We kludge by allowing a flush to
30750Sstevel@tonic-gate * do so.
30760Sstevel@tonic-gate */
30770Sstevel@tonic-gate if (tp->t_state & TS_MREAD)
30780Sstevel@tonic-gate vmin_satisfied(RD(q), tp, 0);
30790Sstevel@tonic-gate break;
30800Sstevel@tonic-gate
30810Sstevel@tonic-gate case M_READ:
30820Sstevel@tonic-gate DEBUG1(("ldtermwmsg:M_READ RECEIVED\n"));
30830Sstevel@tonic-gate /*
30840Sstevel@tonic-gate * Stream head needs data to satisfy timed
30850Sstevel@tonic-gate * read. Has meaning only if ICANON flag is
30860Sstevel@tonic-gate * off indicating raw mode
30870Sstevel@tonic-gate */
30880Sstevel@tonic-gate
30890Sstevel@tonic-gate DEBUG4((
30900Sstevel@tonic-gate "M_READ: RAW_MODE=%d, CNT=%d, VMIN=%d, VTIME=%d\n",
30910Sstevel@tonic-gate RAW_MODE, *(unsigned int *)mp->b_rptr, V_MIN,
30920Sstevel@tonic-gate V_TIME));
30930Sstevel@tonic-gate
30940Sstevel@tonic-gate tp->t_rd_request = *(unsigned int *)mp->b_rptr;
30950Sstevel@tonic-gate
30960Sstevel@tonic-gate if (RAW_MODE) {
30970Sstevel@tonic-gate if (newmsg(tp) != NULL) {
30980Sstevel@tonic-gate /*
30990Sstevel@tonic-gate * VMIN/VTIME processing...
31000Sstevel@tonic-gate * The four possible cases are:
31010Sstevel@tonic-gate * MIN = 0, TIME > 0
31020Sstevel@tonic-gate * MIN = >, TIME = 0
31030Sstevel@tonic-gate * MIN > 0, TIME > 0
31040Sstevel@tonic-gate * MIN = 0, TIME = 0
31050Sstevel@tonic-gate * These four conditions must be dealt
31060Sstevel@tonic-gate * with on the read side as well in
31070Sstevel@tonic-gate * ldterm_do_noncanon(). Set TS_MREAD
31080Sstevel@tonic-gate * so that the read side will know
31090Sstevel@tonic-gate * there is a pending read request
31100Sstevel@tonic-gate * waiting at the stream head. If we
31110Sstevel@tonic-gate * can satisfy MIN do it here, rather
31120Sstevel@tonic-gate * than on the read side. If we can't,
31130Sstevel@tonic-gate * start timers if necessary and let
31140Sstevel@tonic-gate * the other side deal with it.
31150Sstevel@tonic-gate *
31160Sstevel@tonic-gate * We got another M_READ before the
31170Sstevel@tonic-gate * pending one completed, cancel any
31180Sstevel@tonic-gate * existing timeout.
31190Sstevel@tonic-gate */
31200Sstevel@tonic-gate if (tp->t_state & TS_MREAD) {
31210Sstevel@tonic-gate vmin_satisfied(RD(q),
31220Sstevel@tonic-gate tp, 0);
31230Sstevel@tonic-gate }
31240Sstevel@tonic-gate tp->t_state |= TS_MREAD;
31250Sstevel@tonic-gate /*
31260Sstevel@tonic-gate * Case 1: Any data will
31270Sstevel@tonic-gate * satisfy read, otherwise
31280Sstevel@tonic-gate * start timer
31290Sstevel@tonic-gate */
31300Sstevel@tonic-gate if (V_MIN == 0 && V_TIME > 0) {
31310Sstevel@tonic-gate if (tp->t_msglen)
31320Sstevel@tonic-gate vmin_satisfied(RD(q),
31330Sstevel@tonic-gate tp, 1);
31340Sstevel@tonic-gate else
31350Sstevel@tonic-gate vmin_settimer(RD(q));
31360Sstevel@tonic-gate
31370Sstevel@tonic-gate /*
31380Sstevel@tonic-gate * Case 2: If we have enough
31390Sstevel@tonic-gate * data, send up now.
31400Sstevel@tonic-gate * Otherwise, the read side
31410Sstevel@tonic-gate * should wait forever until MIN
31420Sstevel@tonic-gate * is satisified.
31430Sstevel@tonic-gate */
31440Sstevel@tonic-gate } else if (V_MIN > 0 && V_TIME == 0) {
31450Sstevel@tonic-gate if (tp->t_msglen >= (int)V_MIN)
31460Sstevel@tonic-gate vmin_satisfied(RD(q),
31470Sstevel@tonic-gate tp, 1);
31480Sstevel@tonic-gate
31490Sstevel@tonic-gate /*
31500Sstevel@tonic-gate * Case 3: If we can satisfy
31510Sstevel@tonic-gate * the read, send it up. If we
31520Sstevel@tonic-gate * don't have enough data, but
31530Sstevel@tonic-gate * there is at least one char,
31540Sstevel@tonic-gate * start a timer. Otherwise,
31550Sstevel@tonic-gate * let the read side start
31560Sstevel@tonic-gate * the timer.
31570Sstevel@tonic-gate */
31580Sstevel@tonic-gate } else if (V_MIN > 0 && V_TIME > 0) {
31590Sstevel@tonic-gate if (tp->t_msglen >= (int)V_MIN)
31600Sstevel@tonic-gate vmin_satisfied(RD(q),
31610Sstevel@tonic-gate tp, 1);
31620Sstevel@tonic-gate else if (tp->t_msglen)
31630Sstevel@tonic-gate vmin_settimer(RD(q));
31640Sstevel@tonic-gate /*
31650Sstevel@tonic-gate * Case 4: Read returns
31660Sstevel@tonic-gate * whatever data is available
31670Sstevel@tonic-gate * or zero if none.
31680Sstevel@tonic-gate */
31690Sstevel@tonic-gate } else { /* V_MIN == 0 && V_TIME == 0 */
31700Sstevel@tonic-gate vmin_satisfied(RD(q), tp, 1);
31710Sstevel@tonic-gate }
31720Sstevel@tonic-gate
31730Sstevel@tonic-gate } else /* should do bufcall, really! */
31740Sstevel@tonic-gate cmn_err(CE_WARN,
31750Sstevel@tonic-gate "ldtermwmsg: out of blocks");
31760Sstevel@tonic-gate }
31770Sstevel@tonic-gate /*
31780Sstevel@tonic-gate * pass M_READ down
31790Sstevel@tonic-gate */
31800Sstevel@tonic-gate putnext(q, mp);
31810Sstevel@tonic-gate break;
31820Sstevel@tonic-gate
31830Sstevel@tonic-gate default:
31840Sstevel@tonic-gate /* Pass it through unmolested. */
31850Sstevel@tonic-gate putnext(q, mp);
31860Sstevel@tonic-gate break;
31870Sstevel@tonic-gate }
31880Sstevel@tonic-gate return;
31890Sstevel@tonic-gate }
31900Sstevel@tonic-gate /*
31910Sstevel@tonic-gate * If our queue is nonempty or there's a traffic jam
31920Sstevel@tonic-gate * downstream, this message must get in line.
31930Sstevel@tonic-gate */
31940Sstevel@tonic-gate if (q->q_first != NULL || !bcanputnext(q, mp->b_band)) {
31950Sstevel@tonic-gate /*
31960Sstevel@tonic-gate * Exception: ioctls, except for those defined to
31970Sstevel@tonic-gate * take effect after output has drained, should be
31980Sstevel@tonic-gate * processed immediately.
31990Sstevel@tonic-gate */
32000Sstevel@tonic-gate if (type == M_IOCTL) {
32010Sstevel@tonic-gate struct iocblk *iocp;
32020Sstevel@tonic-gate
32030Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr;
32040Sstevel@tonic-gate switch (iocp->ioc_cmd) {
32050Sstevel@tonic-gate
32060Sstevel@tonic-gate /*
32070Sstevel@tonic-gate * Queue these.
32080Sstevel@tonic-gate */
32090Sstevel@tonic-gate case TCSETSW:
32100Sstevel@tonic-gate case TCSETSF:
32110Sstevel@tonic-gate case TCSETAW:
32120Sstevel@tonic-gate case TCSETAF:
32130Sstevel@tonic-gate case TCSBRK:
32140Sstevel@tonic-gate break;
32150Sstevel@tonic-gate
32160Sstevel@tonic-gate /*
32170Sstevel@tonic-gate * Handle all others immediately.
32180Sstevel@tonic-gate */
32190Sstevel@tonic-gate default:
32200Sstevel@tonic-gate (void) ldtermwmsg(q, mp);
32210Sstevel@tonic-gate return;
32220Sstevel@tonic-gate }
32230Sstevel@tonic-gate }
32240Sstevel@tonic-gate (void) putq(q, mp);
32250Sstevel@tonic-gate return;
32260Sstevel@tonic-gate }
32270Sstevel@tonic-gate /*
32280Sstevel@tonic-gate * We can take the fast path through, by simply calling
32290Sstevel@tonic-gate * ldtermwmsg to dispose of mp.
32300Sstevel@tonic-gate */
32310Sstevel@tonic-gate (void) ldtermwmsg(q, mp);
32320Sstevel@tonic-gate }
32330Sstevel@tonic-gate
32340Sstevel@tonic-gate
32350Sstevel@tonic-gate /*
32360Sstevel@tonic-gate * Line discipline output queue service procedure.
32370Sstevel@tonic-gate */
32380Sstevel@tonic-gate static void
ldtermwsrv(queue_t * q)32390Sstevel@tonic-gate ldtermwsrv(queue_t *q)
32400Sstevel@tonic-gate {
32410Sstevel@tonic-gate mblk_t *mp;
32420Sstevel@tonic-gate
32430Sstevel@tonic-gate /*
32440Sstevel@tonic-gate * We expect this loop to iterate at most once, but must be
32450Sstevel@tonic-gate * prepared for more in case our upstream neighbor isn't
32460Sstevel@tonic-gate * paying strict attention to what canput tells it.
32470Sstevel@tonic-gate */
32480Sstevel@tonic-gate while ((mp = getq(q)) != NULL) {
32490Sstevel@tonic-gate /*
32500Sstevel@tonic-gate * N.B.: ldtermwput has already handled high-priority
32510Sstevel@tonic-gate * messages, so we don't have to worry about them
32520Sstevel@tonic-gate * here. Hence, the putbq call is safe.
32530Sstevel@tonic-gate */
32540Sstevel@tonic-gate if (!bcanputnext(q, mp->b_band)) {
32550Sstevel@tonic-gate (void) putbq(q, mp);
32560Sstevel@tonic-gate break;
32570Sstevel@tonic-gate }
32580Sstevel@tonic-gate if (!ldtermwmsg(q, mp)) {
32590Sstevel@tonic-gate /*
32600Sstevel@tonic-gate * Couldn't handle the whole thing; give up
32610Sstevel@tonic-gate * for now and wait to be rescheduled.
32620Sstevel@tonic-gate */
32630Sstevel@tonic-gate break;
32640Sstevel@tonic-gate }
32650Sstevel@tonic-gate }
32660Sstevel@tonic-gate }
32670Sstevel@tonic-gate
32680Sstevel@tonic-gate
32690Sstevel@tonic-gate /*
32700Sstevel@tonic-gate * Process the write-side message denoted by mp. If mp can't be
32710Sstevel@tonic-gate * processed completely (due to allocation failures), put the
32720Sstevel@tonic-gate * residual unprocessed part on the front of the write queue, disable
32730Sstevel@tonic-gate * the queue, and schedule a qbufcall to arrange to complete its
32740Sstevel@tonic-gate * processing later.
32750Sstevel@tonic-gate *
32760Sstevel@tonic-gate * Return 1 if the message was processed completely and 0 if not.
32770Sstevel@tonic-gate *
32780Sstevel@tonic-gate * This routine is called from both ldtermwput and ldtermwsrv to do the
32790Sstevel@tonic-gate * actual work of dealing with mp. ldtermwput will have already
32800Sstevel@tonic-gate * dealt with high priority messages.
32810Sstevel@tonic-gate */
32820Sstevel@tonic-gate static int
ldtermwmsg(queue_t * q,mblk_t * mp)32830Sstevel@tonic-gate ldtermwmsg(queue_t *q, mblk_t *mp)
32840Sstevel@tonic-gate {
32850Sstevel@tonic-gate ldtermstd_state_t *tp;
32860Sstevel@tonic-gate mblk_t *residmp = NULL;
32870Sstevel@tonic-gate size_t size;
32880Sstevel@tonic-gate
32890Sstevel@tonic-gate tp = (ldtermstd_state_t *)q->q_ptr;
32900Sstevel@tonic-gate
32910Sstevel@tonic-gate switch (mp->b_datap->db_type) {
32920Sstevel@tonic-gate
32930Sstevel@tonic-gate case M_IOCTL:
32940Sstevel@tonic-gate ldterm_do_ioctl(q, mp);
32950Sstevel@tonic-gate break;
32960Sstevel@tonic-gate
32970Sstevel@tonic-gate case M_DATA:
32980Sstevel@tonic-gate {
32990Sstevel@tonic-gate mblk_t *omp = NULL;
33000Sstevel@tonic-gate
33010Sstevel@tonic-gate if ((tp->t_modes.c_lflag & FLUSHO) &&
33020Sstevel@tonic-gate (tp->t_modes.c_lflag & IEXTEN)) {
33030Sstevel@tonic-gate freemsg(mp); /* drop on floor */
33040Sstevel@tonic-gate break;
33050Sstevel@tonic-gate }
33060Sstevel@tonic-gate tp->t_rocount = 0;
33070Sstevel@tonic-gate /*
33080Sstevel@tonic-gate * Don't even look at the characters unless
33090Sstevel@tonic-gate * we have something useful to do with them.
33100Sstevel@tonic-gate */
33110Sstevel@tonic-gate if (((tp->t_modes.c_oflag & OPOST) ||
33120Sstevel@tonic-gate ((tp->t_modes.c_lflag & XCASE) &&
33130Sstevel@tonic-gate (tp->t_modes.c_lflag & ICANON))) &&
33140Sstevel@tonic-gate (msgdsize(mp) || !(tp->t_state & TS_ISPTSTTY))) {
33150Sstevel@tonic-gate unsigned char band = mp->b_band;
33160Sstevel@tonic-gate short flag = mp->b_flag;
33170Sstevel@tonic-gate
33180Sstevel@tonic-gate residmp = ldterm_output_msg(q, mp, &omp,
3319*7012Sis tp, OBSIZE, 0);
33200Sstevel@tonic-gate if ((mp = omp) == NULL)
33210Sstevel@tonic-gate break;
33220Sstevel@tonic-gate mp->b_band |= band;
33230Sstevel@tonic-gate mp->b_flag |= flag;
33240Sstevel@tonic-gate }
33250Sstevel@tonic-gate /* Update sysinfo outch */
33260Sstevel@tonic-gate (void) drv_setparm(SYSOUTC, msgdsize(mp));
33270Sstevel@tonic-gate putnext(q, mp);
33280Sstevel@tonic-gate break;
33290Sstevel@tonic-gate }
33300Sstevel@tonic-gate
33310Sstevel@tonic-gate default:
33320Sstevel@tonic-gate putnext(q, mp); /* pass it through unmolested */
33330Sstevel@tonic-gate break;
33340Sstevel@tonic-gate }
33350Sstevel@tonic-gate
33360Sstevel@tonic-gate if (residmp == NULL)
33370Sstevel@tonic-gate return (1);
33380Sstevel@tonic-gate
33390Sstevel@tonic-gate /*
33400Sstevel@tonic-gate * An allocation failure occurred that prevented the message
33410Sstevel@tonic-gate * from being completely processed. First, disable our
33420Sstevel@tonic-gate * queue, since it's pointless to attempt further processing
33430Sstevel@tonic-gate * until the allocation situation is resolved. (This must
33440Sstevel@tonic-gate * precede the putbq call below, which would otherwise mark
33450Sstevel@tonic-gate * the queue to be serviced.)
33460Sstevel@tonic-gate */
33470Sstevel@tonic-gate noenable(q);
33480Sstevel@tonic-gate /*
33490Sstevel@tonic-gate * Stuff the remnant on our write queue so that we can
33500Sstevel@tonic-gate * complete it later when times become less lean. Note that
33510Sstevel@tonic-gate * this sets QFULL, so that our upstream neighbor will be
33520Sstevel@tonic-gate * blocked by flow control.
33530Sstevel@tonic-gate */
33540Sstevel@tonic-gate (void) putbq(q, residmp);
33550Sstevel@tonic-gate /*
33560Sstevel@tonic-gate * Schedule a qbufcall to re-enable the queue. The failure
33570Sstevel@tonic-gate * won't have been for an allocation of more than OBSIZE
33580Sstevel@tonic-gate * bytes, so don't ask for more than that from bufcall.
33590Sstevel@tonic-gate */
33600Sstevel@tonic-gate size = msgdsize(residmp);
33610Sstevel@tonic-gate if (size > OBSIZE)
33620Sstevel@tonic-gate size = OBSIZE;
33630Sstevel@tonic-gate if (tp->t_wbufcid)
33640Sstevel@tonic-gate qunbufcall(q, tp->t_wbufcid);
33650Sstevel@tonic-gate tp->t_wbufcid = qbufcall(q, size, BPRI_MED, ldterm_wenable, q);
33660Sstevel@tonic-gate
33670Sstevel@tonic-gate return (0);
33680Sstevel@tonic-gate }
33690Sstevel@tonic-gate
33700Sstevel@tonic-gate
33710Sstevel@tonic-gate /*
33720Sstevel@tonic-gate * Perform output processing on a message, accumulating the output
33730Sstevel@tonic-gate * characters in a new message.
33740Sstevel@tonic-gate */
33750Sstevel@tonic-gate static mblk_t *
ldterm_output_msg(queue_t * q,mblk_t * imp,mblk_t ** omp,ldtermstd_state_t * tp,size_t bsize,int echoing)33760Sstevel@tonic-gate ldterm_output_msg(queue_t *q, mblk_t *imp, mblk_t **omp,
33770Sstevel@tonic-gate ldtermstd_state_t *tp, size_t bsize, int echoing)
33780Sstevel@tonic-gate {
33790Sstevel@tonic-gate mblk_t *ibp; /* block we're examining from input message */
33800Sstevel@tonic-gate mblk_t *obp; /* block we're filling in output message */
33810Sstevel@tonic-gate mblk_t *cbp; /* continuation block */
33820Sstevel@tonic-gate mblk_t *oobp; /* old value of obp; valid if NEW_BLOCK fails */
33830Sstevel@tonic-gate mblk_t **contpp; /* where to stuff ptr to newly-allocated blk */
33840Sstevel@tonic-gate unsigned char c, n;
33850Sstevel@tonic-gate int count, ctype;
33860Sstevel@tonic-gate ssize_t bytes_left;
33870Sstevel@tonic-gate
33880Sstevel@tonic-gate mblk_t *bp; /* block to stuff an M_DELAY message in */
33890Sstevel@tonic-gate
33900Sstevel@tonic-gate
33910Sstevel@tonic-gate /*
33920Sstevel@tonic-gate * Allocate a new block into which to put bytes. If we can't,
33930Sstevel@tonic-gate * we just drop the rest of the message on the floor. If x is
33940Sstevel@tonic-gate * non-zero, just fall thru; failure requires cleanup before
33950Sstevel@tonic-gate * going out
33960Sstevel@tonic-gate */
33970Sstevel@tonic-gate
33980Sstevel@tonic-gate #define NEW_BLOCK(x) \
33990Sstevel@tonic-gate { \
34000Sstevel@tonic-gate oobp = obp; \
34010Sstevel@tonic-gate if ((obp = allocb(bsize, BPRI_MED)) == NULL) { \
34020Sstevel@tonic-gate if (x == 0) \
34030Sstevel@tonic-gate goto outofbufs; \
34040Sstevel@tonic-gate } else { \
34050Sstevel@tonic-gate *contpp = obp; \
34060Sstevel@tonic-gate contpp = &obp->b_cont; \
34070Sstevel@tonic-gate bytes_left = obp->b_datap->db_lim - obp->b_wptr; \
34080Sstevel@tonic-gate } \
34090Sstevel@tonic-gate }
34100Sstevel@tonic-gate
34110Sstevel@tonic-gate ibp = imp;
34120Sstevel@tonic-gate
34130Sstevel@tonic-gate /*
34140Sstevel@tonic-gate * When we allocate the first block of a message, we should
34150Sstevel@tonic-gate * stuff the pointer to it in "*omp". All subsequent blocks
34160Sstevel@tonic-gate * should have the pointer to them stuffed into the "b_cont"
34170Sstevel@tonic-gate * field of the previous block. "contpp" points to the place
34180Sstevel@tonic-gate * where we should stuff the pointer.
34190Sstevel@tonic-gate *
34200Sstevel@tonic-gate * If we already have a message we're filling in, continue doing
34210Sstevel@tonic-gate * so.
34220Sstevel@tonic-gate */
34230Sstevel@tonic-gate if ((obp = *omp) != NULL) {
34240Sstevel@tonic-gate while (obp->b_cont != NULL)
34250Sstevel@tonic-gate obp = obp->b_cont;
34260Sstevel@tonic-gate contpp = &obp->b_cont;
34270Sstevel@tonic-gate bytes_left = obp->b_datap->db_lim - obp->b_wptr;
34280Sstevel@tonic-gate } else {
34290Sstevel@tonic-gate contpp = omp;
34300Sstevel@tonic-gate bytes_left = 0;
34310Sstevel@tonic-gate }
34320Sstevel@tonic-gate
34330Sstevel@tonic-gate do {
34340Sstevel@tonic-gate while (ibp->b_rptr < ibp->b_wptr) {
34350Sstevel@tonic-gate /*
34360Sstevel@tonic-gate * Make sure there's room for one more
34370Sstevel@tonic-gate * character. At most, we'll need "t_maxeuc"
34380Sstevel@tonic-gate * bytes.
34390Sstevel@tonic-gate */
34400Sstevel@tonic-gate if ((bytes_left < (int)tp->t_maxeuc)) {
34410Sstevel@tonic-gate /* LINTED */
34420Sstevel@tonic-gate NEW_BLOCK(0);
34430Sstevel@tonic-gate }
34440Sstevel@tonic-gate /*
34450Sstevel@tonic-gate * If doing XCASE processing (not very
34460Sstevel@tonic-gate * likely, in this day and age), look at each
34470Sstevel@tonic-gate * character individually.
34480Sstevel@tonic-gate */
34490Sstevel@tonic-gate if ((tp->t_modes.c_lflag & XCASE) &&
34500Sstevel@tonic-gate (tp->t_modes.c_lflag & ICANON)) {
34510Sstevel@tonic-gate c = *ibp->b_rptr++;
34520Sstevel@tonic-gate
34530Sstevel@tonic-gate /*
34540Sstevel@tonic-gate * We need to make sure that this is not
34550Sstevel@tonic-gate * a following byte of a multibyte character
34560Sstevel@tonic-gate * before applying an XCASE processing.
34570Sstevel@tonic-gate *
34580Sstevel@tonic-gate * tp->t_eucign will be 0 if and only
34590Sstevel@tonic-gate * if the current 'c' is an ASCII character
34600Sstevel@tonic-gate * and also a byte. Otherwise, it will have
34610Sstevel@tonic-gate * the byte length of a multibyte character.
34620Sstevel@tonic-gate */
34630Sstevel@tonic-gate if ((tp->t_state & TS_MEUC) &&
34640Sstevel@tonic-gate tp->t_eucign == 0 && NOTASCII(c)) {
34650Sstevel@tonic-gate tp->t_eucign =
3466*7012Sis tp->t_csmethods.ldterm_memwidth(
3467*7012Sis c, (void *)tp);
34680Sstevel@tonic-gate tp->t_scratch_len = tp->t_eucign;
34690Sstevel@tonic-gate
34700Sstevel@tonic-gate if (tp->t_csdata.codeset_type !=
34710Sstevel@tonic-gate LDTERM_CS_TYPE_UTF8) {
34720Sstevel@tonic-gate tp->t_col +=
3473*7012Sis tp->
3474*7012Sis t_csmethods.
3475*7012Sis ldterm_dispwidth(c,
3476*7012Sis (void *)tp,
3477*7012Sis tp->t_modes.c_lflag &
3478*7012Sis ECHOCTL);
34790Sstevel@tonic-gate }
34800Sstevel@tonic-gate }
34810Sstevel@tonic-gate
34820Sstevel@tonic-gate /*
34830Sstevel@tonic-gate * If character is mapped on output,
34840Sstevel@tonic-gate * put out a backslash followed by
34850Sstevel@tonic-gate * what it is mapped to.
34860Sstevel@tonic-gate */
34870Sstevel@tonic-gate if (tp->t_eucign == 0 && omaptab[c] != 0 &&
34880Sstevel@tonic-gate (!echoing || c != '\\')) {
34890Sstevel@tonic-gate /* backslash is an ordinary character */
34900Sstevel@tonic-gate tp->t_col++;
34910Sstevel@tonic-gate *obp->b_wptr++ = '\\';
34920Sstevel@tonic-gate bytes_left--;
34930Sstevel@tonic-gate if (bytes_left == 0) {
34940Sstevel@tonic-gate /* LINTED */
34950Sstevel@tonic-gate NEW_BLOCK(1);
34960Sstevel@tonic-gate }
34970Sstevel@tonic-gate /*
34980Sstevel@tonic-gate * Allocation failed, make
34990Sstevel@tonic-gate * state consistent before
35000Sstevel@tonic-gate * returning
35010Sstevel@tonic-gate */
35020Sstevel@tonic-gate if (obp == NULL) {
35030Sstevel@tonic-gate ibp->b_rptr--;
35040Sstevel@tonic-gate tp->t_col--;
35050Sstevel@tonic-gate oobp->b_wptr--;
35060Sstevel@tonic-gate goto outofbufs;
35070Sstevel@tonic-gate }
35080Sstevel@tonic-gate c = omaptab[c];
35090Sstevel@tonic-gate }
35100Sstevel@tonic-gate /*
35110Sstevel@tonic-gate * If no other output processing is
35120Sstevel@tonic-gate * required, push the character into
35130Sstevel@tonic-gate * the block and get another.
35140Sstevel@tonic-gate */
35150Sstevel@tonic-gate if (!(tp->t_modes.c_oflag & OPOST)) {
35160Sstevel@tonic-gate if (tp->t_eucign > 0) {
35170Sstevel@tonic-gate --tp->t_eucign;
35180Sstevel@tonic-gate } else {
35190Sstevel@tonic-gate tp->t_col++;
35200Sstevel@tonic-gate }
35210Sstevel@tonic-gate *obp->b_wptr++ = c;
35220Sstevel@tonic-gate bytes_left--;
35230Sstevel@tonic-gate continue;
35240Sstevel@tonic-gate }
35250Sstevel@tonic-gate /*
35260Sstevel@tonic-gate * OPOST output flag is set. Map
35270Sstevel@tonic-gate * lower case to upper case if OLCUC
35280Sstevel@tonic-gate * flag is set and the 'c' is a lowercase
35290Sstevel@tonic-gate * ASCII character.
35300Sstevel@tonic-gate */
35310Sstevel@tonic-gate if (tp->t_eucign == 0 &&
35320Sstevel@tonic-gate (tp->t_modes.c_oflag & OLCUC) &&
35330Sstevel@tonic-gate c >= 'a' && c <= 'z')
35340Sstevel@tonic-gate c -= 'a' - 'A';
35350Sstevel@tonic-gate } else {
35360Sstevel@tonic-gate /*
35370Sstevel@tonic-gate * Copy all the ORDINARY characters,
35380Sstevel@tonic-gate * possibly mapping upper case to
35390Sstevel@tonic-gate * lower case. We use "movtuc",
35400Sstevel@tonic-gate * STOPPING when we can't move some
35410Sstevel@tonic-gate * character. For multi-byte or
35420Sstevel@tonic-gate * multi-column EUC, we can't depend
35430Sstevel@tonic-gate * on the regular tables. Rather than
35440Sstevel@tonic-gate * just drop through to the "big
35450Sstevel@tonic-gate * switch" for all characters, it
35460Sstevel@tonic-gate * _might_ be faster to let "movtuc"
35470Sstevel@tonic-gate * move a bunch of characters.
35480Sstevel@tonic-gate * Chances are, even in multi-byte
35490Sstevel@tonic-gate * mode we'll have lots of ASCII
35500Sstevel@tonic-gate * going through. We check the flag
35510Sstevel@tonic-gate * once, and call movtuc with the
35520Sstevel@tonic-gate * appropriate table as an argument.
35530Sstevel@tonic-gate *
35540Sstevel@tonic-gate * "movtuc will work for all codeset
35550Sstevel@tonic-gate * types since it stops at the beginning
35560Sstevel@tonic-gate * byte of a multibyte character.
35570Sstevel@tonic-gate */
35580Sstevel@tonic-gate size_t bytes_to_move;
35590Sstevel@tonic-gate size_t bytes_moved;
35600Sstevel@tonic-gate
35610Sstevel@tonic-gate ASSERT(ibp->b_wptr >= ibp->b_rptr);
35620Sstevel@tonic-gate bytes_to_move = ibp->b_wptr - ibp->b_rptr;
35630Sstevel@tonic-gate if (bytes_to_move > bytes_left)
35640Sstevel@tonic-gate bytes_to_move = bytes_left;
35650Sstevel@tonic-gate if (tp->t_state & TS_MEUC) {
35660Sstevel@tonic-gate bytes_moved = movtuc(bytes_to_move,
3567*7012Sis ibp->b_rptr, obp->b_wptr,
3568*7012Sis (tp->t_modes.c_oflag & OLCUC ?
3569*7012Sis elcuctab : enotrantab));
35700Sstevel@tonic-gate } else {
35710Sstevel@tonic-gate bytes_moved = movtuc(bytes_to_move,
35720Sstevel@tonic-gate ibp->b_rptr, obp->b_wptr,
35730Sstevel@tonic-gate (tp->t_modes.c_oflag & OLCUC ?
35740Sstevel@tonic-gate lcuctab : notrantab));
35750Sstevel@tonic-gate }
35760Sstevel@tonic-gate /*
35770Sstevel@tonic-gate * We're save to just do this column
35780Sstevel@tonic-gate * calculation, because if TS_MEUC is
35790Sstevel@tonic-gate * set, we used the proper EUC
35800Sstevel@tonic-gate * tables, and won't have copied any
35810Sstevel@tonic-gate * EUC bytes.
35820Sstevel@tonic-gate */
35830Sstevel@tonic-gate tp->t_col += bytes_moved;
35840Sstevel@tonic-gate ibp->b_rptr += bytes_moved;
35850Sstevel@tonic-gate obp->b_wptr += bytes_moved;
35860Sstevel@tonic-gate bytes_left -= bytes_moved;
35870Sstevel@tonic-gate if (ibp->b_rptr >= ibp->b_wptr)
35880Sstevel@tonic-gate continue; /* moved all of block */
35890Sstevel@tonic-gate if (bytes_left == 0) {
35900Sstevel@tonic-gate /* LINTED */
35910Sstevel@tonic-gate NEW_BLOCK(0);
35920Sstevel@tonic-gate }
35930Sstevel@tonic-gate c = *ibp->b_rptr++; /* stopper */
35940Sstevel@tonic-gate }
35950Sstevel@tonic-gate
35960Sstevel@tonic-gate /*
35970Sstevel@tonic-gate * Again, we need to make sure that this is not
35980Sstevel@tonic-gate * a following byte of a multibyte character at
35990Sstevel@tonic-gate * here.
36000Sstevel@tonic-gate *
36010Sstevel@tonic-gate * 'tp->t_eucign' will be 0 iff the current 'c' is
36020Sstevel@tonic-gate * an ASCII character. Otherwise, it will have
36030Sstevel@tonic-gate * the byte length of a multibyte character.
36040Sstevel@tonic-gate * We also add the display width to 'tp->t_col' if
36050Sstevel@tonic-gate * the current codeset is not UTF-8 since this is
36060Sstevel@tonic-gate * a leading byte of a multibyte character.
36070Sstevel@tonic-gate * For UTF-8 codeset type, we add the display width
36080Sstevel@tonic-gate * when we get the last byte of a character.
36090Sstevel@tonic-gate */
36100Sstevel@tonic-gate if ((tp->t_state & TS_MEUC) && tp->t_eucign == 0 &&
36110Sstevel@tonic-gate NOTASCII(c)) {
36120Sstevel@tonic-gate tp->t_eucign = tp->t_csmethods.ldterm_memwidth(
3613*7012Sis c, (void *)tp);
36140Sstevel@tonic-gate tp->t_scratch_len = tp->t_eucign;
36150Sstevel@tonic-gate
36160Sstevel@tonic-gate if (tp->t_csdata.codeset_type !=
36170Sstevel@tonic-gate LDTERM_CS_TYPE_UTF8) {
36180Sstevel@tonic-gate tp->t_col +=
36190Sstevel@tonic-gate tp->t_csmethods.ldterm_dispwidth(c,
3620*7012Sis (void *)tp,
3621*7012Sis tp->t_modes.c_lflag & ECHOCTL);
36220Sstevel@tonic-gate }
36230Sstevel@tonic-gate }
36240Sstevel@tonic-gate
36250Sstevel@tonic-gate /*
36260Sstevel@tonic-gate * If the driver has requested, don't process
36270Sstevel@tonic-gate * output flags. However, if we're in
36280Sstevel@tonic-gate * multi-byte mode, we HAVE to look at
36290Sstevel@tonic-gate * EVERYTHING going out to maintain column
36300Sstevel@tonic-gate * position properly. Therefore IF the driver
36310Sstevel@tonic-gate * says don't AND we're not doing multi-byte,
36320Sstevel@tonic-gate * then don't do it. Otherwise, do it.
36330Sstevel@tonic-gate *
36340Sstevel@tonic-gate * NOTE: Hardware USUALLY doesn't expand tabs
36350Sstevel@tonic-gate * properly for multi-byte situations anyway;
36360Sstevel@tonic-gate * that's a known problem with the 3B2
36370Sstevel@tonic-gate * "PORTS" board firmware, and any other
36380Sstevel@tonic-gate * hardware that doesn't ACTUALLY know about
36390Sstevel@tonic-gate * the current EUC mapping that WE are using
36400Sstevel@tonic-gate * at this very moment. The problem is that
36410Sstevel@tonic-gate * memory width is INDEPENDENT of screen
36420Sstevel@tonic-gate * width - no relation - so WE know how wide
36430Sstevel@tonic-gate * the characters are, but an off-the-host
36440Sstevel@tonic-gate * board probably doesn't. So, until we're
36450Sstevel@tonic-gate * SURE that the hardware below us can
36460Sstevel@tonic-gate * correctly expand tabs in a
36470Sstevel@tonic-gate * multi-byte/multi-column EUC situation, we
36480Sstevel@tonic-gate * do it ourselves.
36490Sstevel@tonic-gate */
36500Sstevel@tonic-gate /*
36510Sstevel@tonic-gate * Map <CR>to<NL> on output if OCRNL flag
36520Sstevel@tonic-gate * set. ONLCR processing is not done if OCRNL
36530Sstevel@tonic-gate * is set.
36540Sstevel@tonic-gate */
36550Sstevel@tonic-gate if (c == '\r' && (tp->t_modes.c_oflag & OCRNL)) {
36560Sstevel@tonic-gate c = '\n';
36570Sstevel@tonic-gate ctype = typetab[c];
36580Sstevel@tonic-gate goto jocrnl;
36590Sstevel@tonic-gate }
36600Sstevel@tonic-gate
36610Sstevel@tonic-gate if (tp->t_csdata.codeset_type == LDTERM_CS_TYPE_EUC) {
36620Sstevel@tonic-gate ctype = typetab[c];
36630Sstevel@tonic-gate } else {
36640Sstevel@tonic-gate /*
36650Sstevel@tonic-gate * In other codeset types, we safely assume
36660Sstevel@tonic-gate * any byte of a multibyte character will have
36670Sstevel@tonic-gate * 'ORDINARY' type. For ASCII characters, we
36680Sstevel@tonic-gate * still use the typetab[].
36690Sstevel@tonic-gate */
36700Sstevel@tonic-gate if (tp->t_eucign == 0)
36710Sstevel@tonic-gate ctype = typetab[c];
36720Sstevel@tonic-gate else
36730Sstevel@tonic-gate ctype = ORDINARY;
36740Sstevel@tonic-gate }
36750Sstevel@tonic-gate
36760Sstevel@tonic-gate /*
36770Sstevel@tonic-gate * Map <NL> to <CR><NL> on output if ONLCR
36780Sstevel@tonic-gate * flag is set.
36790Sstevel@tonic-gate */
36800Sstevel@tonic-gate if (c == '\n' && (tp->t_modes.c_oflag & ONLCR)) {
36810Sstevel@tonic-gate if (!(tp->t_state & TS_TTCR)) {
36820Sstevel@tonic-gate tp->t_state |= TS_TTCR;
36830Sstevel@tonic-gate c = '\r';
36840Sstevel@tonic-gate ctype = typetab['\r'];
36850Sstevel@tonic-gate --ibp->b_rptr;
36860Sstevel@tonic-gate } else
36870Sstevel@tonic-gate tp->t_state &= ~TS_TTCR;
36880Sstevel@tonic-gate }
36890Sstevel@tonic-gate /*
36900Sstevel@tonic-gate * Delay values and column position
36910Sstevel@tonic-gate * calculated here. For EUC chars in
36920Sstevel@tonic-gate * multi-byte mode, we use "t_eucign" to help
36930Sstevel@tonic-gate * calculate columns. When we see the first
36940Sstevel@tonic-gate * byte of an EUC, we set t_eucign to the
36950Sstevel@tonic-gate * number of bytes that will FOLLOW it, and
36960Sstevel@tonic-gate * we add the screen width of the WHOLE EUC
36970Sstevel@tonic-gate * character to the column position. In
36980Sstevel@tonic-gate * particular, we can't count SS2 or SS3 as
36990Sstevel@tonic-gate * printing characters. Remember, folks, the
37000Sstevel@tonic-gate * screen width and memory width are
37010Sstevel@tonic-gate * independent - no relation. We could have
37020Sstevel@tonic-gate * dropped through for ASCII, but we want to
37030Sstevel@tonic-gate * catch any bad characters (i.e., t_eucign
37040Sstevel@tonic-gate * set and an ASCII char received) and
37050Sstevel@tonic-gate * possibly report the garbage situation.
37060Sstevel@tonic-gate */
37070Sstevel@tonic-gate jocrnl:
37080Sstevel@tonic-gate
37090Sstevel@tonic-gate count = 0;
37100Sstevel@tonic-gate switch (ctype) {
37110Sstevel@tonic-gate
37120Sstevel@tonic-gate case T_SS2:
37130Sstevel@tonic-gate case T_SS3:
37140Sstevel@tonic-gate case ORDINARY:
37150Sstevel@tonic-gate if (tp->t_state & TS_MEUC) {
37160Sstevel@tonic-gate if (tp->t_eucign) {
37170Sstevel@tonic-gate *obp->b_wptr++ = c;
37180Sstevel@tonic-gate bytes_left--;
37190Sstevel@tonic-gate
37200Sstevel@tonic-gate tp->t_scratch[tp->t_scratch_len
37210Sstevel@tonic-gate - tp->t_eucign] = c;
37220Sstevel@tonic-gate
37230Sstevel@tonic-gate --tp->t_eucign;
37240Sstevel@tonic-gate
37250Sstevel@tonic-gate if (tp->t_csdata.codeset_type
37260Sstevel@tonic-gate == LDTERM_CS_TYPE_UTF8 &&
37270Sstevel@tonic-gate tp->t_eucign <= 0) {
37280Sstevel@tonic-gate tp->t_col +=
37290Sstevel@tonic-gate ldterm_utf8_width(
37300Sstevel@tonic-gate tp->t_scratch,
37310Sstevel@tonic-gate tp->t_scratch_len);
37320Sstevel@tonic-gate }
37330Sstevel@tonic-gate } else {
37340Sstevel@tonic-gate if (tp->t_modes.c_oflag & OLCUC)
37350Sstevel@tonic-gate n = elcuctab[c];
37360Sstevel@tonic-gate else
37370Sstevel@tonic-gate n = enotrantab[c];
37380Sstevel@tonic-gate if (n)
37390Sstevel@tonic-gate c = n;
37400Sstevel@tonic-gate tp->t_col++;
37410Sstevel@tonic-gate *obp->b_wptr++ = c;
37420Sstevel@tonic-gate bytes_left--;
37430Sstevel@tonic-gate }
37440Sstevel@tonic-gate } else { /* ho hum, ASCII mode... */
37450Sstevel@tonic-gate if (tp->t_modes.c_oflag & OLCUC)
37460Sstevel@tonic-gate n = lcuctab[c];
37470Sstevel@tonic-gate else
37480Sstevel@tonic-gate n = notrantab[c];
37490Sstevel@tonic-gate if (n)
37500Sstevel@tonic-gate c = n;
37510Sstevel@tonic-gate tp->t_col++;
37520Sstevel@tonic-gate *obp->b_wptr++ = c;
37530Sstevel@tonic-gate bytes_left--;
37540Sstevel@tonic-gate }
37550Sstevel@tonic-gate break;
37560Sstevel@tonic-gate
37570Sstevel@tonic-gate /*
37580Sstevel@tonic-gate * If we're doing ECHOCTL, we've
37590Sstevel@tonic-gate * already mapped the thing during
37600Sstevel@tonic-gate * the process of canonising. Don't
37610Sstevel@tonic-gate * bother here, as it's not one that
37620Sstevel@tonic-gate * we did.
37630Sstevel@tonic-gate */
37640Sstevel@tonic-gate case CONTROL:
37650Sstevel@tonic-gate *obp->b_wptr++ = c;
37660Sstevel@tonic-gate bytes_left--;
37670Sstevel@tonic-gate break;
37680Sstevel@tonic-gate
37690Sstevel@tonic-gate /*
37700Sstevel@tonic-gate * This is probably a backspace
37710Sstevel@tonic-gate * received, not one that we're
37720Sstevel@tonic-gate * echoing. Let it go as a
37730Sstevel@tonic-gate * single-column backspace.
37740Sstevel@tonic-gate */
37750Sstevel@tonic-gate case BACKSPACE:
37760Sstevel@tonic-gate if (tp->t_col)
37770Sstevel@tonic-gate tp->t_col--;
37780Sstevel@tonic-gate if (tp->t_modes.c_oflag & BSDLY) {
37790Sstevel@tonic-gate if (tp->t_modes.c_oflag & OFILL)
37800Sstevel@tonic-gate count = 1;
37810Sstevel@tonic-gate }
37820Sstevel@tonic-gate *obp->b_wptr++ = c;
37830Sstevel@tonic-gate bytes_left--;
37840Sstevel@tonic-gate break;
37850Sstevel@tonic-gate
37860Sstevel@tonic-gate case NEWLINE:
37870Sstevel@tonic-gate if (tp->t_modes.c_oflag & ONLRET)
37880Sstevel@tonic-gate goto cr;
37890Sstevel@tonic-gate if ((tp->t_modes.c_oflag & NLDLY) == NL1)
37900Sstevel@tonic-gate count = 2;
37910Sstevel@tonic-gate *obp->b_wptr++ = c;
37920Sstevel@tonic-gate bytes_left--;
37930Sstevel@tonic-gate break;
37940Sstevel@tonic-gate
37950Sstevel@tonic-gate case TAB:
37960Sstevel@tonic-gate /*
37970Sstevel@tonic-gate * Map '\t' to spaces if XTABS flag
37980Sstevel@tonic-gate * is set. The calculation of
37990Sstevel@tonic-gate * "t_eucign" has probably insured
38000Sstevel@tonic-gate * that column will be correct, as we
38010Sstevel@tonic-gate * bumped t_col by the DISP width,
38020Sstevel@tonic-gate * not the memory width.
38030Sstevel@tonic-gate */
38040Sstevel@tonic-gate if ((tp->t_modes.c_oflag & TABDLY) == XTABS) {
38050Sstevel@tonic-gate for (;;) {
38060Sstevel@tonic-gate *obp->b_wptr++ = ' ';
38070Sstevel@tonic-gate bytes_left--;
38080Sstevel@tonic-gate tp->t_col++;
38090Sstevel@tonic-gate if ((tp->t_col & 07) == 0)
38100Sstevel@tonic-gate break; /* every 8th */
38110Sstevel@tonic-gate /*
38120Sstevel@tonic-gate * If we don't have
38130Sstevel@tonic-gate * room to fully
38140Sstevel@tonic-gate * expand this tab in
38150Sstevel@tonic-gate * this block, back
38160Sstevel@tonic-gate * up to continue
38170Sstevel@tonic-gate * expanding it into
38180Sstevel@tonic-gate * the next block.
38190Sstevel@tonic-gate */
38200Sstevel@tonic-gate if (obp->b_wptr >=
38210Sstevel@tonic-gate obp->b_datap->db_lim) {
38220Sstevel@tonic-gate ibp->b_rptr--;
38230Sstevel@tonic-gate break;
38240Sstevel@tonic-gate }
38250Sstevel@tonic-gate }
38260Sstevel@tonic-gate } else {
38270Sstevel@tonic-gate tp->t_col |= 07;
38280Sstevel@tonic-gate tp->t_col++;
38290Sstevel@tonic-gate if (tp->t_modes.c_oflag & OFILL) {
38300Sstevel@tonic-gate if (tp->t_modes.c_oflag &
38310Sstevel@tonic-gate TABDLY)
38320Sstevel@tonic-gate count = 2;
38330Sstevel@tonic-gate } else {
38340Sstevel@tonic-gate switch (tp->t_modes.c_oflag &
38350Sstevel@tonic-gate TABDLY) {
38360Sstevel@tonic-gate case TAB2:
38370Sstevel@tonic-gate count = 6;
38380Sstevel@tonic-gate break;
38390Sstevel@tonic-gate
38400Sstevel@tonic-gate case TAB1:
38410Sstevel@tonic-gate count = 1 + (tp->t_col |
38420Sstevel@tonic-gate ~07);
38430Sstevel@tonic-gate if (count < 5)
38440Sstevel@tonic-gate count = 0;
38450Sstevel@tonic-gate break;
38460Sstevel@tonic-gate }
38470Sstevel@tonic-gate }
38480Sstevel@tonic-gate *obp->b_wptr++ = c;
38490Sstevel@tonic-gate bytes_left--;
38500Sstevel@tonic-gate }
38510Sstevel@tonic-gate break;
38520Sstevel@tonic-gate
38530Sstevel@tonic-gate case VTAB:
38540Sstevel@tonic-gate if ((tp->t_modes.c_oflag & VTDLY) &&
38550Sstevel@tonic-gate !(tp->t_modes.c_oflag & OFILL))
38560Sstevel@tonic-gate count = 127;
38570Sstevel@tonic-gate *obp->b_wptr++ = c;
38580Sstevel@tonic-gate bytes_left--;
38590Sstevel@tonic-gate break;
38600Sstevel@tonic-gate
38610Sstevel@tonic-gate case RETURN:
38620Sstevel@tonic-gate /*
38630Sstevel@tonic-gate * Ignore <CR> in column 0 if ONOCR
38640Sstevel@tonic-gate * flag set.
38650Sstevel@tonic-gate */
38660Sstevel@tonic-gate if (tp->t_col == 0 &&
38670Sstevel@tonic-gate (tp->t_modes.c_oflag & ONOCR))
38680Sstevel@tonic-gate break;
38690Sstevel@tonic-gate
38700Sstevel@tonic-gate cr:
38710Sstevel@tonic-gate switch (tp->t_modes.c_oflag & CRDLY) {
38720Sstevel@tonic-gate
38730Sstevel@tonic-gate case CR1:
38740Sstevel@tonic-gate if (tp->t_modes.c_oflag & OFILL)
38750Sstevel@tonic-gate count = 2;
38760Sstevel@tonic-gate else
38770Sstevel@tonic-gate count = tp->t_col % 2;
38780Sstevel@tonic-gate break;
38790Sstevel@tonic-gate
38800Sstevel@tonic-gate case CR2:
38810Sstevel@tonic-gate if (tp->t_modes.c_oflag & OFILL)
38820Sstevel@tonic-gate count = 4;
38830Sstevel@tonic-gate else
38840Sstevel@tonic-gate count = 6;
38850Sstevel@tonic-gate break;
38860Sstevel@tonic-gate
38870Sstevel@tonic-gate case CR3:
38880Sstevel@tonic-gate if (tp->t_modes.c_oflag & OFILL)
38890Sstevel@tonic-gate count = 0;
38900Sstevel@tonic-gate else
38910Sstevel@tonic-gate count = 9;
38920Sstevel@tonic-gate break;
38930Sstevel@tonic-gate }
38940Sstevel@tonic-gate tp->t_col = 0;
38950Sstevel@tonic-gate *obp->b_wptr++ = c;
38960Sstevel@tonic-gate bytes_left--;
38970Sstevel@tonic-gate break;
38980Sstevel@tonic-gate }
38990Sstevel@tonic-gate
39000Sstevel@tonic-gate if (count != 0) {
39010Sstevel@tonic-gate if (tp->t_modes.c_oflag & OFILL) {
39020Sstevel@tonic-gate do {
39030Sstevel@tonic-gate if (bytes_left == 0) {
39040Sstevel@tonic-gate /* LINTED */
39050Sstevel@tonic-gate NEW_BLOCK(0);
39060Sstevel@tonic-gate }
39070Sstevel@tonic-gate if (tp->t_modes.c_oflag & OFDEL)
39080Sstevel@tonic-gate *obp->b_wptr++ = CDEL;
39090Sstevel@tonic-gate else
39100Sstevel@tonic-gate *obp->b_wptr++ = CNUL;
39110Sstevel@tonic-gate bytes_left--;
39120Sstevel@tonic-gate } while (--count != 0);
39130Sstevel@tonic-gate } else {
39140Sstevel@tonic-gate if ((tp->t_modes.c_lflag & FLUSHO) &&
39150Sstevel@tonic-gate (tp->t_modes.c_lflag & IEXTEN)) {
39160Sstevel@tonic-gate /* drop on floor */
39170Sstevel@tonic-gate freemsg(*omp);
39180Sstevel@tonic-gate } else {
39190Sstevel@tonic-gate /*
39200Sstevel@tonic-gate * Update sysinfo
39210Sstevel@tonic-gate * outch
39220Sstevel@tonic-gate */
39230Sstevel@tonic-gate (void) drv_setparm(SYSOUTC,
39240Sstevel@tonic-gate msgdsize(*omp));
39250Sstevel@tonic-gate putnext(q, *omp);
39260Sstevel@tonic-gate /*
39270Sstevel@tonic-gate * Send M_DELAY
39280Sstevel@tonic-gate * downstream
39290Sstevel@tonic-gate */
39300Sstevel@tonic-gate if ((bp =
39310Sstevel@tonic-gate allocb(1, BPRI_MED)) !=
39320Sstevel@tonic-gate NULL) {
39330Sstevel@tonic-gate bp->b_datap->db_type =
39340Sstevel@tonic-gate M_DELAY;
39350Sstevel@tonic-gate *bp->b_wptr++ =
3936*7012Sis (uchar_t)count;
39370Sstevel@tonic-gate putnext(q, bp);
39380Sstevel@tonic-gate }
39390Sstevel@tonic-gate }
39400Sstevel@tonic-gate bytes_left = 0;
39410Sstevel@tonic-gate /*
39420Sstevel@tonic-gate * We have to start a new
39430Sstevel@tonic-gate * message; the delay
39440Sstevel@tonic-gate * introduces a break between
39450Sstevel@tonic-gate * messages.
39460Sstevel@tonic-gate */
39470Sstevel@tonic-gate *omp = NULL;
39480Sstevel@tonic-gate contpp = omp;
39490Sstevel@tonic-gate }
39500Sstevel@tonic-gate }
39510Sstevel@tonic-gate }
39520Sstevel@tonic-gate cbp = ibp->b_cont;
39530Sstevel@tonic-gate freeb(ibp);
39540Sstevel@tonic-gate } while ((ibp = cbp) != NULL); /* next block, if any */
39550Sstevel@tonic-gate
39560Sstevel@tonic-gate outofbufs:
39570Sstevel@tonic-gate return (ibp);
39580Sstevel@tonic-gate #undef NEW_BLOCK
39590Sstevel@tonic-gate }
39600Sstevel@tonic-gate
39610Sstevel@tonic-gate
39620Sstevel@tonic-gate #if !defined(__sparc)
39630Sstevel@tonic-gate int
movtuc(size_t size,unsigned char * from,unsigned char * origto,unsigned char * table)39640Sstevel@tonic-gate movtuc(size_t size, unsigned char *from, unsigned char *origto,
39650Sstevel@tonic-gate unsigned char *table)
39660Sstevel@tonic-gate {
39670Sstevel@tonic-gate unsigned char *to = origto;
39680Sstevel@tonic-gate unsigned char c;
39690Sstevel@tonic-gate
39700Sstevel@tonic-gate while (size != 0 && (c = table[*from++]) != 0) {
39710Sstevel@tonic-gate *to++ = c;
39720Sstevel@tonic-gate size--;
39730Sstevel@tonic-gate }
39740Sstevel@tonic-gate return (to - origto);
39750Sstevel@tonic-gate }
39760Sstevel@tonic-gate #endif
39770Sstevel@tonic-gate
39780Sstevel@tonic-gate static void
ldterm_flush_output(uchar_t c,queue_t * q,ldtermstd_state_t * tp)39790Sstevel@tonic-gate ldterm_flush_output(uchar_t c, queue_t *q, ldtermstd_state_t *tp)
39800Sstevel@tonic-gate {
39810Sstevel@tonic-gate /* Already conditioned with IEXTEN during VDISCARD processing */
39820Sstevel@tonic-gate if (tp->t_modes.c_lflag & FLUSHO)
39830Sstevel@tonic-gate tp->t_modes.c_lflag &= ~FLUSHO;
39840Sstevel@tonic-gate else {
39850Sstevel@tonic-gate flushq(q, FLUSHDATA); /* flush our write queue */
39860Sstevel@tonic-gate /* flush ones below us */
39870Sstevel@tonic-gate (void) putnextctl1(q, M_FLUSH, FLUSHW);
39880Sstevel@tonic-gate if ((tp->t_echomp = allocb(EBSIZE, BPRI_HI)) != NULL) {
39890Sstevel@tonic-gate (void) ldterm_echo(c, q, 1, tp);
39900Sstevel@tonic-gate if (tp->t_msglen != 0)
39910Sstevel@tonic-gate ldterm_reprint(q, EBSIZE, tp);
39920Sstevel@tonic-gate if (tp->t_echomp != NULL) {
39930Sstevel@tonic-gate putnext(q, tp->t_echomp);
39940Sstevel@tonic-gate tp->t_echomp = NULL;
39950Sstevel@tonic-gate }
39960Sstevel@tonic-gate }
39970Sstevel@tonic-gate tp->t_modes.c_lflag |= FLUSHO;
39980Sstevel@tonic-gate }
39990Sstevel@tonic-gate }
40000Sstevel@tonic-gate
40010Sstevel@tonic-gate
40020Sstevel@tonic-gate /*
40030Sstevel@tonic-gate * Signal generated by the reader: M_PCSIG and M_FLUSH messages sent.
40040Sstevel@tonic-gate */
40050Sstevel@tonic-gate static void
ldterm_dosig(queue_t * q,int sig,uchar_t c,int mtype,int mode)40060Sstevel@tonic-gate ldterm_dosig(queue_t *q, int sig, uchar_t c, int mtype, int mode)
40070Sstevel@tonic-gate {
40080Sstevel@tonic-gate ldtermstd_state_t *tp = (ldtermstd_state_t *)q->q_ptr;
40090Sstevel@tonic-gate int sndsig = 0;
40100Sstevel@tonic-gate
40110Sstevel@tonic-gate /*
40120Sstevel@tonic-gate * c == \0 is brk case; need to flush on BRKINT even if
40130Sstevel@tonic-gate * noflsh is set.
40140Sstevel@tonic-gate */
40150Sstevel@tonic-gate if ((!(tp->t_modes.c_lflag & NOFLSH)) || (c == '\0')) {
40160Sstevel@tonic-gate if (mode) {
40170Sstevel@tonic-gate if (tp->t_state & TS_TTSTOP) {
40180Sstevel@tonic-gate sndsig = 1;
40190Sstevel@tonic-gate (void) putnextctl1(q, mtype, sig);
40200Sstevel@tonic-gate }
40210Sstevel@tonic-gate /*
40220Sstevel@tonic-gate * Flush read or write side.
40230Sstevel@tonic-gate * Restart the input or output.
40240Sstevel@tonic-gate */
40250Sstevel@tonic-gate if (mode & FLUSHR) {
40260Sstevel@tonic-gate flushq(q, FLUSHDATA);
40270Sstevel@tonic-gate (void) putnextctl1(WR(q), M_FLUSH, mode);
40280Sstevel@tonic-gate if (tp->t_state & (TS_TBLOCK|TS_IFBLOCK)) {
40290Sstevel@tonic-gate (void) putnextctl(WR(q), M_STARTI);
40300Sstevel@tonic-gate tp->t_state &= ~(TS_TBLOCK|TS_IFBLOCK);
40310Sstevel@tonic-gate }
40320Sstevel@tonic-gate }
40330Sstevel@tonic-gate if (mode & FLUSHW) {
40340Sstevel@tonic-gate flushq(WR(q), FLUSHDATA);
40350Sstevel@tonic-gate /*
40360Sstevel@tonic-gate * XXX This is extremely gross.
40370Sstevel@tonic-gate * Since we can't be sure our M_FLUSH
40380Sstevel@tonic-gate * will have run its course by the
40390Sstevel@tonic-gate * time we do the echo below, we set
40400Sstevel@tonic-gate * state and toss it in the write put
40410Sstevel@tonic-gate * routine to prevent flushing our
40420Sstevel@tonic-gate * own data. Note that downstream
40430Sstevel@tonic-gate * modules on the write side will be
40440Sstevel@tonic-gate * flushed by the M_FLUSH sent above.
40450Sstevel@tonic-gate */
40460Sstevel@tonic-gate tp->t_state |= TS_FLUSHWAIT;
40470Sstevel@tonic-gate (void) putnextctl1(q, M_FLUSH, FLUSHW);
40480Sstevel@tonic-gate if (tp->t_state & TS_TTSTOP) {
40490Sstevel@tonic-gate (void) putnextctl(WR(q), M_START);
40500Sstevel@tonic-gate tp->t_state &= ~(TS_TTSTOP|TS_OFBLOCK);
40510Sstevel@tonic-gate }
40520Sstevel@tonic-gate }
40530Sstevel@tonic-gate }
40540Sstevel@tonic-gate }
40550Sstevel@tonic-gate tp->t_state &= ~TS_QUOT;
40560Sstevel@tonic-gate if (sndsig == 0)
40570Sstevel@tonic-gate (void) putnextctl1(q, mtype, sig);
40580Sstevel@tonic-gate
40590Sstevel@tonic-gate if (c != '\0') {
40600Sstevel@tonic-gate if ((tp->t_echomp = allocb(4, BPRI_HI)) != NULL) {
40610Sstevel@tonic-gate (void) ldterm_echo(c, WR(q), 4, tp);
40620Sstevel@tonic-gate putnext(WR(q), tp->t_echomp);
40630Sstevel@tonic-gate tp->t_echomp = NULL;
40640Sstevel@tonic-gate }
40650Sstevel@tonic-gate }
40660Sstevel@tonic-gate }
40670Sstevel@tonic-gate
40680Sstevel@tonic-gate
40690Sstevel@tonic-gate /*
40700Sstevel@tonic-gate * Called when an M_IOCTL message is seen on the write queue; does
40710Sstevel@tonic-gate * whatever we're supposed to do with it, and either replies
40720Sstevel@tonic-gate * immediately or passes it to the next module down.
40730Sstevel@tonic-gate */
40740Sstevel@tonic-gate static void
ldterm_do_ioctl(queue_t * q,mblk_t * mp)40750Sstevel@tonic-gate ldterm_do_ioctl(queue_t *q, mblk_t *mp)
40760Sstevel@tonic-gate {
40770Sstevel@tonic-gate ldtermstd_state_t *tp;
40780Sstevel@tonic-gate struct iocblk *iocp;
40790Sstevel@tonic-gate struct eucioc *euciocp; /* needed for EUC ioctls */
40800Sstevel@tonic-gate ldterm_cs_data_user_t *csdp;
40810Sstevel@tonic-gate int i;
40820Sstevel@tonic-gate int locale_name_sz;
40830Sstevel@tonic-gate uchar_t maxbytelen;
40840Sstevel@tonic-gate uchar_t maxscreenlen;
40850Sstevel@tonic-gate int error;
40860Sstevel@tonic-gate
40870Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr;
40880Sstevel@tonic-gate tp = (ldtermstd_state_t *)q->q_ptr;
40890Sstevel@tonic-gate
40900Sstevel@tonic-gate switch (iocp->ioc_cmd) {
40910Sstevel@tonic-gate
40920Sstevel@tonic-gate case TCSETS:
40930Sstevel@tonic-gate case TCSETSW:
40940Sstevel@tonic-gate case TCSETSF:
40950Sstevel@tonic-gate {
40960Sstevel@tonic-gate /*
40970Sstevel@tonic-gate * Set current parameters and special
40980Sstevel@tonic-gate * characters.
40990Sstevel@tonic-gate */
41000Sstevel@tonic-gate struct termios *cb;
41010Sstevel@tonic-gate struct termios oldmodes;
41020Sstevel@tonic-gate
41030Sstevel@tonic-gate error = miocpullup(mp, sizeof (struct termios));
41040Sstevel@tonic-gate if (error != 0) {
41050Sstevel@tonic-gate miocnak(q, mp, 0, error);
41060Sstevel@tonic-gate return;
41070Sstevel@tonic-gate }
41080Sstevel@tonic-gate
41090Sstevel@tonic-gate cb = (struct termios *)mp->b_cont->b_rptr;
41100Sstevel@tonic-gate
41110Sstevel@tonic-gate oldmodes = tp->t_amodes;
41120Sstevel@tonic-gate tp->t_amodes = *cb;
41130Sstevel@tonic-gate if ((tp->t_amodes.c_lflag & PENDIN) &&
41140Sstevel@tonic-gate (tp->t_modes.c_lflag & IEXTEN)) {
41150Sstevel@tonic-gate /*
41160Sstevel@tonic-gate * Yuk. The C shell file completion
41170Sstevel@tonic-gate * code actually uses this "feature",
41180Sstevel@tonic-gate * so we have to support it.
41190Sstevel@tonic-gate */
41200Sstevel@tonic-gate if (tp->t_message != NULL) {
41210Sstevel@tonic-gate tp->t_state |= TS_RESCAN;
41220Sstevel@tonic-gate qenable(RD(q));
41230Sstevel@tonic-gate }
41240Sstevel@tonic-gate tp->t_amodes.c_lflag &= ~PENDIN;
41250Sstevel@tonic-gate }
41260Sstevel@tonic-gate bcopy(tp->t_amodes.c_cc, tp->t_modes.c_cc, NCCS);
41270Sstevel@tonic-gate
41280Sstevel@tonic-gate /*
41290Sstevel@tonic-gate * ldterm_adjust_modes does not deal with
41300Sstevel@tonic-gate * cflags
41310Sstevel@tonic-gate */
41320Sstevel@tonic-gate tp->t_modes.c_cflag = tp->t_amodes.c_cflag;
41330Sstevel@tonic-gate
41340Sstevel@tonic-gate ldterm_adjust_modes(tp);
41350Sstevel@tonic-gate if (chgstropts(&oldmodes, tp, RD(q)) == (-1)) {
41360Sstevel@tonic-gate miocnak(q, mp, 0, EAGAIN);
41370Sstevel@tonic-gate return;
41380Sstevel@tonic-gate }
41390Sstevel@tonic-gate /*
41400Sstevel@tonic-gate * The driver may want to know about the
41410Sstevel@tonic-gate * following iflags: IGNBRK, BRKINT, IGNPAR,
41420Sstevel@tonic-gate * PARMRK, INPCK, IXON, IXANY.
41430Sstevel@tonic-gate */
41440Sstevel@tonic-gate break;
41450Sstevel@tonic-gate }
41460Sstevel@tonic-gate
41470Sstevel@tonic-gate case TCSETA:
41480Sstevel@tonic-gate case TCSETAW:
41490Sstevel@tonic-gate case TCSETAF:
41500Sstevel@tonic-gate {
41510Sstevel@tonic-gate /*
41520Sstevel@tonic-gate * Old-style "ioctl" to set current
41530Sstevel@tonic-gate * parameters and special characters. Don't
41540Sstevel@tonic-gate * clear out the unset portions, leave them
41550Sstevel@tonic-gate * as they are.
41560Sstevel@tonic-gate */
41570Sstevel@tonic-gate struct termio *cb;
41580Sstevel@tonic-gate struct termios oldmodes;
41590Sstevel@tonic-gate
41600Sstevel@tonic-gate error = miocpullup(mp, sizeof (struct termio));
41610Sstevel@tonic-gate if (error != 0) {
41620Sstevel@tonic-gate miocnak(q, mp, 0, error);
41630Sstevel@tonic-gate return;
41640Sstevel@tonic-gate }
41650Sstevel@tonic-gate
41660Sstevel@tonic-gate cb = (struct termio *)mp->b_cont->b_rptr;
41670Sstevel@tonic-gate
41680Sstevel@tonic-gate oldmodes = tp->t_amodes;
41690Sstevel@tonic-gate tp->t_amodes.c_iflag =
4170*7012Sis (tp->t_amodes.c_iflag & 0xffff0000 | cb->c_iflag);
41710Sstevel@tonic-gate tp->t_amodes.c_oflag =
4172*7012Sis (tp->t_amodes.c_oflag & 0xffff0000 | cb->c_oflag);
41730Sstevel@tonic-gate tp->t_amodes.c_cflag =
4174*7012Sis (tp->t_amodes.c_cflag & 0xffff0000 | cb->c_cflag);
41750Sstevel@tonic-gate tp->t_amodes.c_lflag =
4176*7012Sis (tp->t_amodes.c_lflag & 0xffff0000 | cb->c_lflag);
41770Sstevel@tonic-gate
41780Sstevel@tonic-gate bcopy(cb->c_cc, tp->t_modes.c_cc, NCC);
41790Sstevel@tonic-gate /* TCGETS returns amodes, so update that too */
41800Sstevel@tonic-gate bcopy(cb->c_cc, tp->t_amodes.c_cc, NCC);
41810Sstevel@tonic-gate
41820Sstevel@tonic-gate /* ldterm_adjust_modes does not deal with cflags */
41830Sstevel@tonic-gate
41840Sstevel@tonic-gate tp->t_modes.c_cflag = tp->t_amodes.c_cflag;
41850Sstevel@tonic-gate
41860Sstevel@tonic-gate ldterm_adjust_modes(tp);
41870Sstevel@tonic-gate if (chgstropts(&oldmodes, tp, RD(q)) == (-1)) {
41880Sstevel@tonic-gate miocnak(q, mp, 0, EAGAIN);
41890Sstevel@tonic-gate return;
41900Sstevel@tonic-gate }
41910Sstevel@tonic-gate /*
41920Sstevel@tonic-gate * The driver may want to know about the
41930Sstevel@tonic-gate * following iflags: IGNBRK, BRKINT, IGNPAR,
41940Sstevel@tonic-gate * PARMRK, INPCK, IXON, IXANY.
41950Sstevel@tonic-gate */
41960Sstevel@tonic-gate break;
41970Sstevel@tonic-gate }
41980Sstevel@tonic-gate
41990Sstevel@tonic-gate case TCFLSH:
42000Sstevel@tonic-gate /*
42010Sstevel@tonic-gate * Do the flush on the write queue immediately, and
42020Sstevel@tonic-gate * queue up any flush on the read queue for the
42030Sstevel@tonic-gate * service procedure to see. Then turn it into the
42040Sstevel@tonic-gate * appropriate M_FLUSH message, so that the module
42050Sstevel@tonic-gate * below us doesn't have to know about TCFLSH.
42060Sstevel@tonic-gate */
42070Sstevel@tonic-gate error = miocpullup(mp, sizeof (int));
42080Sstevel@tonic-gate if (error != 0) {
42090Sstevel@tonic-gate miocnak(q, mp, 0, error);
42100Sstevel@tonic-gate return;
42110Sstevel@tonic-gate }
42120Sstevel@tonic-gate
42130Sstevel@tonic-gate ASSERT(mp->b_datap != NULL);
42140Sstevel@tonic-gate if (*(int *)mp->b_cont->b_rptr == 0) {
42150Sstevel@tonic-gate ASSERT(mp->b_datap != NULL);
42160Sstevel@tonic-gate (void) putnextctl1(q, M_FLUSH, FLUSHR);
42170Sstevel@tonic-gate (void) putctl1(RD(q), M_FLUSH, FLUSHR);
42180Sstevel@tonic-gate } else if (*(int *)mp->b_cont->b_rptr == 1) {
42190Sstevel@tonic-gate flushq(q, FLUSHDATA);
42200Sstevel@tonic-gate ASSERT(mp->b_datap != NULL);
42210Sstevel@tonic-gate tp->t_state |= TS_FLUSHWAIT;
42220Sstevel@tonic-gate (void) putnextctl1(RD(q), M_FLUSH, FLUSHW);
42230Sstevel@tonic-gate (void) putnextctl1(q, M_FLUSH, FLUSHW);
42240Sstevel@tonic-gate } else if (*(int *)mp->b_cont->b_rptr == 2) {
42250Sstevel@tonic-gate flushq(q, FLUSHDATA);
42260Sstevel@tonic-gate ASSERT(mp->b_datap != NULL);
42270Sstevel@tonic-gate (void) putnextctl1(q, M_FLUSH, FLUSHRW);
42280Sstevel@tonic-gate tp->t_state |= TS_FLUSHWAIT;
42290Sstevel@tonic-gate (void) putnextctl1(RD(q), M_FLUSH, FLUSHRW);
42300Sstevel@tonic-gate } else {
42310Sstevel@tonic-gate miocnak(q, mp, 0, EINVAL);
42320Sstevel@tonic-gate return;
42330Sstevel@tonic-gate }
42340Sstevel@tonic-gate ASSERT(mp->b_datap != NULL);
42350Sstevel@tonic-gate iocp->ioc_rval = 0;
42360Sstevel@tonic-gate miocack(q, mp, 0, 0);
42370Sstevel@tonic-gate return;
42380Sstevel@tonic-gate
42390Sstevel@tonic-gate case TCXONC:
42400Sstevel@tonic-gate error = miocpullup(mp, sizeof (int));
42410Sstevel@tonic-gate if (error != 0) {
42420Sstevel@tonic-gate miocnak(q, mp, 0, error);
42430Sstevel@tonic-gate return;
42440Sstevel@tonic-gate }
42450Sstevel@tonic-gate
42460Sstevel@tonic-gate switch (*(int *)mp->b_cont->b_rptr) {
42470Sstevel@tonic-gate case 0:
42480Sstevel@tonic-gate if (!(tp->t_state & TS_TTSTOP)) {
42490Sstevel@tonic-gate (void) putnextctl(q, M_STOP);
42500Sstevel@tonic-gate tp->t_state |= (TS_TTSTOP|TS_OFBLOCK);
42510Sstevel@tonic-gate }
42520Sstevel@tonic-gate break;
42530Sstevel@tonic-gate
42540Sstevel@tonic-gate case 1:
42550Sstevel@tonic-gate if (tp->t_state & TS_TTSTOP) {
42560Sstevel@tonic-gate (void) putnextctl(q, M_START);
42570Sstevel@tonic-gate tp->t_state &= ~(TS_TTSTOP|TS_OFBLOCK);
42580Sstevel@tonic-gate }
42590Sstevel@tonic-gate break;
42600Sstevel@tonic-gate
42610Sstevel@tonic-gate case 2:
42620Sstevel@tonic-gate (void) putnextctl(q, M_STOPI);
42630Sstevel@tonic-gate tp->t_state |= (TS_TBLOCK|TS_IFBLOCK);
42640Sstevel@tonic-gate break;
42650Sstevel@tonic-gate
42660Sstevel@tonic-gate case 3:
42670Sstevel@tonic-gate (void) putnextctl(q, M_STARTI);
42680Sstevel@tonic-gate tp->t_state &= ~(TS_TBLOCK|TS_IFBLOCK);
42690Sstevel@tonic-gate break;
42700Sstevel@tonic-gate
42710Sstevel@tonic-gate default:
42720Sstevel@tonic-gate miocnak(q, mp, 0, EINVAL);
42730Sstevel@tonic-gate return;
42740Sstevel@tonic-gate }
42750Sstevel@tonic-gate ASSERT(mp->b_datap != NULL);
42760Sstevel@tonic-gate iocp->ioc_rval = 0;
42770Sstevel@tonic-gate miocack(q, mp, 0, 0);
42780Sstevel@tonic-gate return;
42790Sstevel@tonic-gate /*
42800Sstevel@tonic-gate * TCSBRK is expected to be handled by the driver.
42810Sstevel@tonic-gate * The reason its left for the driver is that when
42820Sstevel@tonic-gate * the argument to TCSBRK is zero driver has to drain
42830Sstevel@tonic-gate * the data and sending a M_IOCACK from LDTERM before
42840Sstevel@tonic-gate * the driver drains the data is going to cause
42850Sstevel@tonic-gate * problems.
42860Sstevel@tonic-gate */
42870Sstevel@tonic-gate
42880Sstevel@tonic-gate /*
42890Sstevel@tonic-gate * The following are EUC related ioctls. For
42900Sstevel@tonic-gate * EUC_WSET, we have to pass the information on, even
42910Sstevel@tonic-gate * though we ACK the call. It's vital in the EUC
42920Sstevel@tonic-gate * environment that everybody downstream knows about
42930Sstevel@tonic-gate * the EUC codeset widths currently in use; we
42940Sstevel@tonic-gate * therefore pass down the information in an M_CTL
42950Sstevel@tonic-gate * message. It will bottom out in the driver.
42960Sstevel@tonic-gate */
42970Sstevel@tonic-gate case EUC_WSET:
42980Sstevel@tonic-gate {
42990Sstevel@tonic-gate
43000Sstevel@tonic-gate /* only needed for EUC_WSET */
43010Sstevel@tonic-gate struct iocblk *riocp;
43020Sstevel@tonic-gate
43030Sstevel@tonic-gate mblk_t *dmp, *dmp_cont;
43040Sstevel@tonic-gate
43050Sstevel@tonic-gate /*
43060Sstevel@tonic-gate * If the user didn't supply any information,
43070Sstevel@tonic-gate * NAK it.
43080Sstevel@tonic-gate */
43090Sstevel@tonic-gate error = miocpullup(mp, sizeof (struct eucioc));
43100Sstevel@tonic-gate if (error != 0) {
43110Sstevel@tonic-gate miocnak(q, mp, 0, error);
43120Sstevel@tonic-gate return;
43130Sstevel@tonic-gate }
43140Sstevel@tonic-gate
43150Sstevel@tonic-gate euciocp = (struct eucioc *)mp->b_cont->b_rptr;
43160Sstevel@tonic-gate /*
43170Sstevel@tonic-gate * Check here for something reasonable. If
43180Sstevel@tonic-gate * anything will take more than EUC_MAXW
43190Sstevel@tonic-gate * columns or more than EUC_MAXW bytes
43200Sstevel@tonic-gate * following SS2 or SS3, then just reject it
43210Sstevel@tonic-gate * out of hand. It's not impossible for us to
43220Sstevel@tonic-gate * do it, it just isn't reasonable. So far,
43230Sstevel@tonic-gate * in the world, we've seen the absolute max
43240Sstevel@tonic-gate * columns to be 2 and the max number of
43250Sstevel@tonic-gate * bytes to be 3. This allows room for some
43260Sstevel@tonic-gate * expansion of that, but it probably won't
43270Sstevel@tonic-gate * even be necessary. At the moment, we
43280Sstevel@tonic-gate * return a "range" error. If you really
43290Sstevel@tonic-gate * need to, you can push EUC_MAXW up to over
43300Sstevel@tonic-gate * 200; it doesn't make sense, though, with
43310Sstevel@tonic-gate * only a CANBSIZ sized input limit (usually
43320Sstevel@tonic-gate * 256)!
43330Sstevel@tonic-gate */
43340Sstevel@tonic-gate for (i = 0; i < 4; i++) {
43350Sstevel@tonic-gate if ((euciocp->eucw[i] > EUC_MAXW) ||
43360Sstevel@tonic-gate (euciocp->scrw[i] > EUC_MAXW)) {
43370Sstevel@tonic-gate miocnak(q, mp, 0, ERANGE);
43380Sstevel@tonic-gate return;
43390Sstevel@tonic-gate }
43400Sstevel@tonic-gate }
43410Sstevel@tonic-gate /*
43420Sstevel@tonic-gate * Otherwise, save the information in tp,
43430Sstevel@tonic-gate * force codeset 0 (ASCII) to be one byte,
43440Sstevel@tonic-gate * one column.
43450Sstevel@tonic-gate */
43460Sstevel@tonic-gate cp_eucwioc(euciocp, &tp->eucwioc, EUCIN);
43470Sstevel@tonic-gate tp->eucwioc.eucw[0] = tp->eucwioc.scrw[0] = 1;
43480Sstevel@tonic-gate /*
43490Sstevel@tonic-gate * Now, check out whether we're doing
43500Sstevel@tonic-gate * multibyte processing. if we are, we need
43510Sstevel@tonic-gate * to allocate a block to hold the parallel
43520Sstevel@tonic-gate * array. By convention, we've been passed
43530Sstevel@tonic-gate * what amounts to a CSWIDTH definition. We
43540Sstevel@tonic-gate * actually NEED the number of bytes for
43550Sstevel@tonic-gate * Codesets 2 & 3.
43560Sstevel@tonic-gate */
43570Sstevel@tonic-gate tp->t_maxeuc = 0; /* reset to say we're NOT */
43580Sstevel@tonic-gate
43590Sstevel@tonic-gate tp->t_state &= ~TS_MEUC;
43600Sstevel@tonic-gate /*
43610Sstevel@tonic-gate * We'll set TS_MEUC if we're doing
43620Sstevel@tonic-gate * multi-column OR multi- byte OR both. It
43630Sstevel@tonic-gate * makes things easier... NOTE: If we fail
43640Sstevel@tonic-gate * to get the buffer we need to hold display
43650Sstevel@tonic-gate * widths, then DON'T let the TS_MEUC bit get
43660Sstevel@tonic-gate * set!
43670Sstevel@tonic-gate */
43680Sstevel@tonic-gate for (i = 0; i < 4; i++) {
43690Sstevel@tonic-gate if (tp->eucwioc.eucw[i] > tp->t_maxeuc)
43700Sstevel@tonic-gate tp->t_maxeuc = tp->eucwioc.eucw[i];
43710Sstevel@tonic-gate if (tp->eucwioc.scrw[i] > 1)
43720Sstevel@tonic-gate tp->t_state |= TS_MEUC;
43730Sstevel@tonic-gate }
43740Sstevel@tonic-gate if ((tp->t_maxeuc > 1) || (tp->t_state & TS_MEUC)) {
43750Sstevel@tonic-gate if (!tp->t_eucp_mp) {
43760Sstevel@tonic-gate if (!(tp->t_eucp_mp = allocb(CANBSIZ,
43770Sstevel@tonic-gate BPRI_HI))) {
43780Sstevel@tonic-gate tp->t_maxeuc = 1;
43790Sstevel@tonic-gate tp->t_state &= ~TS_MEUC;
43800Sstevel@tonic-gate cmn_err(CE_WARN,
43810Sstevel@tonic-gate "Can't allocate eucp_mp");
43820Sstevel@tonic-gate miocnak(q, mp, 0, ENOSR);
43830Sstevel@tonic-gate return;
43840Sstevel@tonic-gate }
43850Sstevel@tonic-gate /*
43860Sstevel@tonic-gate * here, if there's junk in
43870Sstevel@tonic-gate * the canonical buffer, then
43880Sstevel@tonic-gate * move the eucp pointer past
43890Sstevel@tonic-gate * it, so we don't run off
43900Sstevel@tonic-gate * the beginning. This is a
43910Sstevel@tonic-gate * total botch, but will
43920Sstevel@tonic-gate * hopefully keep stuff from
43930Sstevel@tonic-gate * getting too messed up
43940Sstevel@tonic-gate * until the user flushes
43950Sstevel@tonic-gate * this line!
43960Sstevel@tonic-gate */
43970Sstevel@tonic-gate if (tp->t_msglen) {
4398*7012Sis tp->t_eucp =
4399*7012Sis tp->t_eucp_mp->b_rptr;
44000Sstevel@tonic-gate for (i = tp->t_msglen; i; i--)
44010Sstevel@tonic-gate *tp->t_eucp++ = 1;
4402*7012Sis } else {
4403*7012Sis tp->t_eucp =
4404*7012Sis tp->t_eucp_mp->b_rptr;
4405*7012Sis }
44060Sstevel@tonic-gate }
44070Sstevel@tonic-gate /* doing multi-byte handling */
44080Sstevel@tonic-gate tp->t_state |= TS_MEUC;
44090Sstevel@tonic-gate
44100Sstevel@tonic-gate } else if (tp->t_eucp_mp) {
44110Sstevel@tonic-gate freemsg(tp->t_eucp_mp);
44120Sstevel@tonic-gate tp->t_eucp_mp = NULL;
44130Sstevel@tonic-gate tp->t_eucp = NULL;
44140Sstevel@tonic-gate }
44150Sstevel@tonic-gate
44160Sstevel@tonic-gate /*
44170Sstevel@tonic-gate * Save the EUC width data we have at
44180Sstevel@tonic-gate * the t_csdata, set t_csdata.codeset_type to
44190Sstevel@tonic-gate * EUC one, and, switch the codeset methods at
44200Sstevel@tonic-gate * t_csmethods.
44210Sstevel@tonic-gate */
44220Sstevel@tonic-gate bzero(&tp->t_csdata.eucpc_data,
44230Sstevel@tonic-gate (sizeof (ldterm_eucpc_data_t) *
4424*7012Sis LDTERM_CS_MAX_CODESETS));
44250Sstevel@tonic-gate tp->t_csdata.eucpc_data[0].byte_length =
4426*7012Sis tp->eucwioc.eucw[1];
44270Sstevel@tonic-gate tp->t_csdata.eucpc_data[0].screen_width =
4428*7012Sis tp->eucwioc.scrw[1];
44290Sstevel@tonic-gate tp->t_csdata.eucpc_data[1].byte_length =
4430*7012Sis tp->eucwioc.eucw[2];
44310Sstevel@tonic-gate tp->t_csdata.eucpc_data[1].screen_width =
4432*7012Sis tp->eucwioc.scrw[2];
44330Sstevel@tonic-gate tp->t_csdata.eucpc_data[2].byte_length =
4434*7012Sis tp->eucwioc.eucw[3];
44350Sstevel@tonic-gate tp->t_csdata.eucpc_data[2].screen_width =
4436*7012Sis tp->eucwioc.scrw[3];
44370Sstevel@tonic-gate tp->t_csdata.version = LDTERM_DATA_VERSION;
44380Sstevel@tonic-gate tp->t_csdata.codeset_type = LDTERM_CS_TYPE_EUC;
44390Sstevel@tonic-gate /*
44400Sstevel@tonic-gate * We are not using the 'csinfo_num' anyway if the
44410Sstevel@tonic-gate * current codeset type is EUC. So, set it to
44420Sstevel@tonic-gate * the maximum possible.
44430Sstevel@tonic-gate */
44440Sstevel@tonic-gate tp->t_csdata.csinfo_num =
4445*7012Sis LDTERM_CS_TYPE_EUC_MAX_SUBCS;
44460Sstevel@tonic-gate if (tp->t_csdata.locale_name != (char *)NULL) {
44470Sstevel@tonic-gate kmem_free(tp->t_csdata.locale_name,
44480Sstevel@tonic-gate strlen(tp->t_csdata.locale_name) + 1);
44490Sstevel@tonic-gate tp->t_csdata.locale_name = (char *)NULL;
44500Sstevel@tonic-gate }
44510Sstevel@tonic-gate tp->t_csmethods = cs_methods[LDTERM_CS_TYPE_EUC];
44520Sstevel@tonic-gate
44530Sstevel@tonic-gate /*
44540Sstevel@tonic-gate * If we are able to allocate two blocks (the
44550Sstevel@tonic-gate * iocblk and the associated data), then pass
44560Sstevel@tonic-gate * it downstream, otherwise we'll need to NAK
44570Sstevel@tonic-gate * it, and drop whatever we WERE able to
44580Sstevel@tonic-gate * allocate.
44590Sstevel@tonic-gate */
44600Sstevel@tonic-gate if ((dmp = mkiocb(EUC_WSET)) == NULL) {
44610Sstevel@tonic-gate miocnak(q, mp, 0, ENOSR);
44620Sstevel@tonic-gate return;
44630Sstevel@tonic-gate }
44640Sstevel@tonic-gate if ((dmp_cont = allocb(EUCSIZE, BPRI_HI)) == NULL) {
44650Sstevel@tonic-gate freemsg(dmp);
44660Sstevel@tonic-gate miocnak(q, mp, 0, ENOSR);
44670Sstevel@tonic-gate return;
44680Sstevel@tonic-gate }
44690Sstevel@tonic-gate
44700Sstevel@tonic-gate /*
44710Sstevel@tonic-gate * We got both buffers. Copy out the EUC
44720Sstevel@tonic-gate * information (as we received it, not what
44730Sstevel@tonic-gate * we're using!) & pass it on.
44740Sstevel@tonic-gate */
44750Sstevel@tonic-gate bcopy(mp->b_cont->b_rptr, dmp_cont->b_rptr, EUCSIZE);
44760Sstevel@tonic-gate dmp_cont->b_wptr += EUCSIZE;
44770Sstevel@tonic-gate dmp->b_cont = dmp_cont;
44780Sstevel@tonic-gate dmp->b_datap->db_type = M_CTL;
44790Sstevel@tonic-gate dmp_cont->b_datap->db_type = M_DATA;
44800Sstevel@tonic-gate riocp = (struct iocblk *)dmp->b_rptr;
44810Sstevel@tonic-gate riocp->ioc_count = EUCSIZE;
44820Sstevel@tonic-gate putnext(q, dmp);
44830Sstevel@tonic-gate
44840Sstevel@tonic-gate /*
44850Sstevel@tonic-gate * Now ACK the ioctl.
44860Sstevel@tonic-gate */
44870Sstevel@tonic-gate iocp->ioc_rval = 0;
44880Sstevel@tonic-gate miocack(q, mp, 0, 0);
44890Sstevel@tonic-gate return;
44900Sstevel@tonic-gate }
44910Sstevel@tonic-gate
44920Sstevel@tonic-gate case EUC_WGET:
44930Sstevel@tonic-gate error = miocpullup(mp, sizeof (struct eucioc));
44940Sstevel@tonic-gate if (error != 0) {
44950Sstevel@tonic-gate miocnak(q, mp, 0, error);
44960Sstevel@tonic-gate return;
44970Sstevel@tonic-gate }
44980Sstevel@tonic-gate euciocp = (struct eucioc *)mp->b_cont->b_rptr;
44990Sstevel@tonic-gate cp_eucwioc(&tp->eucwioc, euciocp, EUCOUT);
45000Sstevel@tonic-gate iocp->ioc_rval = 0;
45010Sstevel@tonic-gate miocack(q, mp, EUCSIZE, 0);
45020Sstevel@tonic-gate return;
45030Sstevel@tonic-gate
45040Sstevel@tonic-gate case CSDATA_SET:
45050Sstevel@tonic-gate error = miocpullup(mp, sizeof (ldterm_cs_data_user_t));
45060Sstevel@tonic-gate if (error != 0) {
45070Sstevel@tonic-gate miocnak(q, mp, 0, error);
45080Sstevel@tonic-gate return;
45090Sstevel@tonic-gate }
45100Sstevel@tonic-gate
45110Sstevel@tonic-gate csdp = (ldterm_cs_data_user_t *)mp->b_cont->b_rptr;
45120Sstevel@tonic-gate
45130Sstevel@tonic-gate /* Validate the codeset data provided. */
45140Sstevel@tonic-gate if (csdp->version > LDTERM_DATA_VERSION ||
45150Sstevel@tonic-gate csdp->codeset_type < LDTERM_CS_TYPE_MIN ||
45160Sstevel@tonic-gate csdp->codeset_type > LDTERM_CS_TYPE_MAX) {
45170Sstevel@tonic-gate miocnak(q, mp, 0, ERANGE);
45180Sstevel@tonic-gate return;
45190Sstevel@tonic-gate }
45200Sstevel@tonic-gate
45210Sstevel@tonic-gate if ((csdp->codeset_type == LDTERM_CS_TYPE_EUC &&
4522*7012Sis csdp->csinfo_num > LDTERM_CS_TYPE_EUC_MAX_SUBCS) ||
45230Sstevel@tonic-gate (csdp->codeset_type == LDTERM_CS_TYPE_PCCS &&
4524*7012Sis (csdp->csinfo_num < LDTERM_CS_TYPE_PCCS_MIN_SUBCS ||
4525*7012Sis csdp->csinfo_num > LDTERM_CS_TYPE_PCCS_MAX_SUBCS))) {
45260Sstevel@tonic-gate miocnak(q, mp, 0, ERANGE);
45270Sstevel@tonic-gate return;
45280Sstevel@tonic-gate }
45290Sstevel@tonic-gate
45300Sstevel@tonic-gate maxbytelen = maxscreenlen = 0;
45310Sstevel@tonic-gate if (csdp->codeset_type == LDTERM_CS_TYPE_EUC) {
45320Sstevel@tonic-gate for (i = 0; i < LDTERM_CS_TYPE_EUC_MAX_SUBCS; i++) {
45330Sstevel@tonic-gate if (csdp->eucpc_data[i].byte_length >
45340Sstevel@tonic-gate EUC_MAXW ||
45350Sstevel@tonic-gate csdp->eucpc_data[i].screen_width >
45360Sstevel@tonic-gate EUC_MAXW) {
45370Sstevel@tonic-gate miocnak(q, mp, 0, ERANGE);
45380Sstevel@tonic-gate return;
45390Sstevel@tonic-gate }
45400Sstevel@tonic-gate
45410Sstevel@tonic-gate if (csdp->eucpc_data[i].byte_length >
45420Sstevel@tonic-gate maxbytelen)
45430Sstevel@tonic-gate maxbytelen =
45440Sstevel@tonic-gate csdp->eucpc_data[i].byte_length;
45450Sstevel@tonic-gate if (csdp->eucpc_data[i].screen_width >
45460Sstevel@tonic-gate maxscreenlen)
45470Sstevel@tonic-gate maxscreenlen =
45480Sstevel@tonic-gate csdp->eucpc_data[i].screen_width;
45490Sstevel@tonic-gate }
45500Sstevel@tonic-gate /* POSIX/C locale? */
45510Sstevel@tonic-gate if (maxbytelen == 0 && maxscreenlen == 0)
45520Sstevel@tonic-gate maxbytelen = maxscreenlen = 1;
45530Sstevel@tonic-gate } else if (csdp->codeset_type == LDTERM_CS_TYPE_PCCS) {
45540Sstevel@tonic-gate for (i = 0; i < LDTERM_CS_MAX_CODESETS; i++) {
45550Sstevel@tonic-gate if (csdp->eucpc_data[i].byte_length >
45560Sstevel@tonic-gate LDTERM_CS_MAX_BYTE_LENGTH) {
45570Sstevel@tonic-gate miocnak(q, mp, 0, ERANGE);
45580Sstevel@tonic-gate return;
45590Sstevel@tonic-gate }
45600Sstevel@tonic-gate if (csdp->eucpc_data[i].byte_length >
45610Sstevel@tonic-gate maxbytelen)
45620Sstevel@tonic-gate maxbytelen =
45630Sstevel@tonic-gate csdp->eucpc_data[i].byte_length;
45640Sstevel@tonic-gate if (csdp->eucpc_data[i].screen_width >
45650Sstevel@tonic-gate maxscreenlen)
45660Sstevel@tonic-gate maxscreenlen =
45670Sstevel@tonic-gate csdp->eucpc_data[i].screen_width;
45680Sstevel@tonic-gate }
45690Sstevel@tonic-gate } else if (csdp->codeset_type == LDTERM_CS_TYPE_UTF8) {
45700Sstevel@tonic-gate maxbytelen = 4;
45710Sstevel@tonic-gate maxscreenlen = 2;
45720Sstevel@tonic-gate }
45730Sstevel@tonic-gate
45740Sstevel@tonic-gate locale_name_sz = 0;
45750Sstevel@tonic-gate if (csdp->locale_name) {
45760Sstevel@tonic-gate for (i = 0; i < MAXNAMELEN; i++)
45770Sstevel@tonic-gate if (csdp->locale_name[i] == '\0')
45780Sstevel@tonic-gate break;
45790Sstevel@tonic-gate /*
45800Sstevel@tonic-gate * We cannot have any string that is not NULL byte
45810Sstevel@tonic-gate * terminated.
45820Sstevel@tonic-gate */
45830Sstevel@tonic-gate if (i >= MAXNAMELEN) {
45840Sstevel@tonic-gate miocnak(q, mp, 0, ERANGE);
45850Sstevel@tonic-gate return;
45860Sstevel@tonic-gate }
45870Sstevel@tonic-gate
45880Sstevel@tonic-gate locale_name_sz = i + 1;
45890Sstevel@tonic-gate }
45900Sstevel@tonic-gate
45910Sstevel@tonic-gate /*
45920Sstevel@tonic-gate * As the final check, if there was invalid codeset_type
45930Sstevel@tonic-gate * given, or invalid byte_length was specified, it's an error.
45940Sstevel@tonic-gate */
45950Sstevel@tonic-gate if (maxbytelen <= 0 || maxscreenlen <= 0) {
45960Sstevel@tonic-gate miocnak(q, mp, 0, ERANGE);
45970Sstevel@tonic-gate return;
45980Sstevel@tonic-gate }
45990Sstevel@tonic-gate
46000Sstevel@tonic-gate /* Do the switching. */
46010Sstevel@tonic-gate tp->t_maxeuc = maxbytelen;
46020Sstevel@tonic-gate tp->t_state &= ~TS_MEUC;
46030Sstevel@tonic-gate if (maxbytelen > 1 || maxscreenlen > 1) {
46040Sstevel@tonic-gate if (!tp->t_eucp_mp) {
46050Sstevel@tonic-gate if (!(tp->t_eucp_mp = allocb(CANBSIZ,
46060Sstevel@tonic-gate BPRI_HI))) {
46070Sstevel@tonic-gate cmn_err(CE_WARN,
4608*7012Sis "Can't allocate eucp_mp");
46090Sstevel@tonic-gate miocnak(q, mp, 0, ENOSR);
46100Sstevel@tonic-gate return;
46110Sstevel@tonic-gate }
46120Sstevel@tonic-gate /*
46130Sstevel@tonic-gate * If there's junk in the canonical buffer,
46140Sstevel@tonic-gate * then move the eucp pointer past it,
46150Sstevel@tonic-gate * so we don't run off the beginning. This is
46160Sstevel@tonic-gate * a total botch, but will hopefully keep
46170Sstevel@tonic-gate * stuff from getting too messed up until
46180Sstevel@tonic-gate * the user flushes this line!
46190Sstevel@tonic-gate */
46200Sstevel@tonic-gate if (tp->t_msglen) {
46210Sstevel@tonic-gate tp->t_eucp = tp->t_eucp_mp->b_rptr;
46220Sstevel@tonic-gate for (i = tp->t_msglen; i; i--)
46230Sstevel@tonic-gate *tp->t_eucp++ = 1;
46240Sstevel@tonic-gate } else {
46250Sstevel@tonic-gate tp->t_eucp = tp->t_eucp_mp->b_rptr;
46260Sstevel@tonic-gate }
46270Sstevel@tonic-gate }
46280Sstevel@tonic-gate
46290Sstevel@tonic-gate /*
46300Sstevel@tonic-gate * We only set TS_MEUC for a multibyte/multi-column
46310Sstevel@tonic-gate * codeset.
46320Sstevel@tonic-gate */
46330Sstevel@tonic-gate tp->t_state |= TS_MEUC;
46340Sstevel@tonic-gate
46350Sstevel@tonic-gate tp->t_csdata.version = csdp->version;
46360Sstevel@tonic-gate tp->t_csdata.codeset_type = csdp->codeset_type;
46370Sstevel@tonic-gate tp->t_csdata.csinfo_num = csdp->csinfo_num;
46380Sstevel@tonic-gate bcopy(csdp->eucpc_data, tp->t_csdata.eucpc_data,
4639*7012Sis sizeof (ldterm_eucpc_data_t) *
4640*7012Sis LDTERM_CS_MAX_CODESETS);
46410Sstevel@tonic-gate tp->t_csmethods = cs_methods[csdp->codeset_type];
46420Sstevel@tonic-gate
46430Sstevel@tonic-gate if (csdp->codeset_type == LDTERM_CS_TYPE_EUC) {
46440Sstevel@tonic-gate tp->eucwioc.eucw[0] = 1;
46450Sstevel@tonic-gate tp->eucwioc.scrw[0] = 1;
46460Sstevel@tonic-gate
46470Sstevel@tonic-gate tp->eucwioc.eucw[1] =
4648*7012Sis csdp->eucpc_data[0].byte_length;
46490Sstevel@tonic-gate tp->eucwioc.scrw[1] =
4650*7012Sis csdp->eucpc_data[0].screen_width;
46510Sstevel@tonic-gate
46520Sstevel@tonic-gate tp->eucwioc.eucw[2] =
4653*7012Sis csdp->eucpc_data[1].byte_length + 1;
46540Sstevel@tonic-gate tp->eucwioc.scrw[2] =
4655*7012Sis csdp->eucpc_data[1].screen_width;
46560Sstevel@tonic-gate
46570Sstevel@tonic-gate tp->eucwioc.eucw[3] =
4658*7012Sis csdp->eucpc_data[2].byte_length + 1;
46590Sstevel@tonic-gate tp->eucwioc.scrw[3] =
4660*7012Sis csdp->eucpc_data[2].screen_width;
46610Sstevel@tonic-gate } else {
46620Sstevel@tonic-gate /*
46630Sstevel@tonic-gate * We are not going to use this data
46640Sstevel@tonic-gate * structure. So, clear it. Also, stty(1) will
46650Sstevel@tonic-gate * make use of the cleared tp->eucwioc when
46660Sstevel@tonic-gate * it prints out codeset width setting.
46670Sstevel@tonic-gate */
46680Sstevel@tonic-gate bzero(&tp->eucwioc, EUCSIZE);
46690Sstevel@tonic-gate }
46700Sstevel@tonic-gate } else {
46710Sstevel@tonic-gate /*
46720Sstevel@tonic-gate * If this codeset is a single byte codeset that
46730Sstevel@tonic-gate * requires only single display column for all
46740Sstevel@tonic-gate * characters, we switch to default EUC codeset
46750Sstevel@tonic-gate * methods and data setting.
46760Sstevel@tonic-gate */
46770Sstevel@tonic-gate
46780Sstevel@tonic-gate if (tp->t_eucp_mp) {
46790Sstevel@tonic-gate freemsg(tp->t_eucp_mp);
46800Sstevel@tonic-gate tp->t_eucp_mp = NULL;
46810Sstevel@tonic-gate tp->t_eucp = NULL;
46820Sstevel@tonic-gate }
46830Sstevel@tonic-gate
46840Sstevel@tonic-gate bzero(&tp->eucwioc, EUCSIZE);
46850Sstevel@tonic-gate tp->eucwioc.eucw[0] = 1;
46860Sstevel@tonic-gate tp->eucwioc.scrw[0] = 1;
46870Sstevel@tonic-gate if (tp->t_csdata.locale_name != (char *)NULL) {
46880Sstevel@tonic-gate kmem_free(tp->t_csdata.locale_name,
46890Sstevel@tonic-gate strlen(tp->t_csdata.locale_name) + 1);
46900Sstevel@tonic-gate }
46910Sstevel@tonic-gate tp->t_csdata = default_cs_data;
46920Sstevel@tonic-gate tp->t_csmethods = cs_methods[LDTERM_CS_TYPE_EUC];
46930Sstevel@tonic-gate }
46940Sstevel@tonic-gate
46950Sstevel@tonic-gate /* Copy over locale_name. */
46960Sstevel@tonic-gate if (tp->t_csdata.locale_name != (char *)NULL) {
46970Sstevel@tonic-gate kmem_free(tp->t_csdata.locale_name,
46980Sstevel@tonic-gate strlen(tp->t_csdata.locale_name) + 1);
46990Sstevel@tonic-gate }
47000Sstevel@tonic-gate if (locale_name_sz > 1) {
47010Sstevel@tonic-gate tp->t_csdata.locale_name = (char *)kmem_alloc(
4702*7012Sis locale_name_sz, KM_SLEEP);
47030Sstevel@tonic-gate (void) strcpy(tp->t_csdata.locale_name,
47040Sstevel@tonic-gate csdp->locale_name);
47050Sstevel@tonic-gate } else {
47060Sstevel@tonic-gate tp->t_csdata.locale_name = (char *)NULL;
47070Sstevel@tonic-gate }
47080Sstevel@tonic-gate
47090Sstevel@tonic-gate /*
47100Sstevel@tonic-gate * Now ACK the ioctl.
47110Sstevel@tonic-gate */
47120Sstevel@tonic-gate iocp->ioc_rval = 0;
47130Sstevel@tonic-gate miocack(q, mp, 0, 0);
47140Sstevel@tonic-gate return;
47150Sstevel@tonic-gate
47160Sstevel@tonic-gate case CSDATA_GET:
47170Sstevel@tonic-gate error = miocpullup(mp, sizeof (ldterm_cs_data_user_t));
47180Sstevel@tonic-gate if (error != 0) {
47190Sstevel@tonic-gate miocnak(q, mp, 0, error);
47200Sstevel@tonic-gate return;
47210Sstevel@tonic-gate }
47220Sstevel@tonic-gate
47230Sstevel@tonic-gate csdp = (ldterm_cs_data_user_t *)mp->b_cont->b_rptr;
47240Sstevel@tonic-gate
47250Sstevel@tonic-gate csdp->version = tp->t_csdata.version;
47260Sstevel@tonic-gate csdp->codeset_type = tp->t_csdata.codeset_type;
47270Sstevel@tonic-gate csdp->csinfo_num = tp->t_csdata.csinfo_num;
47280Sstevel@tonic-gate csdp->pad = tp->t_csdata.pad;
47290Sstevel@tonic-gate if (tp->t_csdata.locale_name) {
47300Sstevel@tonic-gate (void) strcpy(csdp->locale_name,
4731*7012Sis tp->t_csdata.locale_name);
47320Sstevel@tonic-gate } else {
47330Sstevel@tonic-gate csdp->locale_name[0] = '\0';
47340Sstevel@tonic-gate }
47350Sstevel@tonic-gate bcopy(tp->t_csdata.eucpc_data, csdp->eucpc_data,
4736*7012Sis sizeof (ldterm_eucpc_data_t) * LDTERM_CS_MAX_CODESETS);
47370Sstevel@tonic-gate /*
47380Sstevel@tonic-gate * If the codeset is an EUC codeset and if it has 2nd and/or
47390Sstevel@tonic-gate * 3rd supplementary codesets, we subtract one from each
47400Sstevel@tonic-gate * byte length of the supplementary codesets. This is
47410Sstevel@tonic-gate * because single shift characters, SS2 and SS3, are not
47420Sstevel@tonic-gate * included in the byte lengths in the user space.
47430Sstevel@tonic-gate */
47440Sstevel@tonic-gate if (csdp->codeset_type == LDTERM_CS_TYPE_EUC) {
47450Sstevel@tonic-gate if (csdp->eucpc_data[1].byte_length)
47460Sstevel@tonic-gate csdp->eucpc_data[1].byte_length -= 1;
47470Sstevel@tonic-gate if (csdp->eucpc_data[2].byte_length)
47480Sstevel@tonic-gate csdp->eucpc_data[2].byte_length -= 1;
47490Sstevel@tonic-gate }
47500Sstevel@tonic-gate iocp->ioc_rval = 0;
47510Sstevel@tonic-gate miocack(q, mp, sizeof (ldterm_cs_data_user_t), 0);
47520Sstevel@tonic-gate return;
47530Sstevel@tonic-gate
47540Sstevel@tonic-gate case PTSSTTY:
47550Sstevel@tonic-gate tp->t_state |= TS_ISPTSTTY;
47560Sstevel@tonic-gate break;
47570Sstevel@tonic-gate
47580Sstevel@tonic-gate }
47590Sstevel@tonic-gate
47600Sstevel@tonic-gate putnext(q, mp);
47610Sstevel@tonic-gate }
47620Sstevel@tonic-gate
47630Sstevel@tonic-gate
47640Sstevel@tonic-gate /*
47650Sstevel@tonic-gate * Send an M_SETOPTS message upstream if any mode changes are being
47660Sstevel@tonic-gate * made that affect the stream head options. returns -1 if allocb
47670Sstevel@tonic-gate * fails, else returns 0.
47680Sstevel@tonic-gate */
47690Sstevel@tonic-gate static int
chgstropts(struct termios * oldmodep,ldtermstd_state_t * tp,queue_t * q)47700Sstevel@tonic-gate chgstropts(struct termios *oldmodep, ldtermstd_state_t *tp, queue_t *q)
47710Sstevel@tonic-gate {
47720Sstevel@tonic-gate struct stroptions optbuf;
47730Sstevel@tonic-gate mblk_t *bp;
47740Sstevel@tonic-gate
47750Sstevel@tonic-gate optbuf.so_flags = 0;
47760Sstevel@tonic-gate if ((oldmodep->c_lflag ^ tp->t_modes.c_lflag) & ICANON) {
47770Sstevel@tonic-gate /*
47780Sstevel@tonic-gate * Canonical mode is changing state; switch the
47790Sstevel@tonic-gate * stream head to message-nondiscard or byte-stream
47800Sstevel@tonic-gate * mode. Also, rerun the service procedure so it can
47810Sstevel@tonic-gate * change its mind about whether to send data
47820Sstevel@tonic-gate * upstream or not.
47830Sstevel@tonic-gate */
47840Sstevel@tonic-gate if (tp->t_modes.c_lflag & ICANON) {
47850Sstevel@tonic-gate DEBUG4(("CHANGING TO CANON MODE\n"));
47860Sstevel@tonic-gate optbuf.so_flags = SO_READOPT|SO_MREADOFF;
47870Sstevel@tonic-gate optbuf.so_readopt = RMSGN;
47880Sstevel@tonic-gate
47890Sstevel@tonic-gate /*
47900Sstevel@tonic-gate * if there is a pending raw mode timeout,
47910Sstevel@tonic-gate * clear it
47920Sstevel@tonic-gate */
47930Sstevel@tonic-gate
47940Sstevel@tonic-gate /*
47950Sstevel@tonic-gate * Clear VMIN/VTIME state, cancel timers
47960Sstevel@tonic-gate */
47970Sstevel@tonic-gate vmin_satisfied(q, tp, 0);
47980Sstevel@tonic-gate } else {
47990Sstevel@tonic-gate DEBUG4(("CHANGING TO RAW MODE\n"));
48000Sstevel@tonic-gate optbuf.so_flags = SO_READOPT|SO_MREADON;
48010Sstevel@tonic-gate optbuf.so_readopt = RNORM;
48020Sstevel@tonic-gate }
48030Sstevel@tonic-gate }
48040Sstevel@tonic-gate if ((oldmodep->c_lflag ^ tp->t_modes.c_lflag) & TOSTOP) {
48050Sstevel@tonic-gate /*
48060Sstevel@tonic-gate * The "stop on background write" bit is changing.
48070Sstevel@tonic-gate */
48080Sstevel@tonic-gate if (tp->t_modes.c_lflag & TOSTOP)
48090Sstevel@tonic-gate optbuf.so_flags |= SO_TOSTOP;
48100Sstevel@tonic-gate else
48110Sstevel@tonic-gate optbuf.so_flags |= SO_TONSTOP;
48120Sstevel@tonic-gate }
48130Sstevel@tonic-gate if (optbuf.so_flags != 0) {
48140Sstevel@tonic-gate if ((bp = allocb(sizeof (struct stroptions), BPRI_HI)) ==
48150Sstevel@tonic-gate NULL) {
48160Sstevel@tonic-gate return (-1);
48170Sstevel@tonic-gate }
48180Sstevel@tonic-gate *(struct stroptions *)bp->b_wptr = optbuf;
48190Sstevel@tonic-gate bp->b_wptr += sizeof (struct stroptions);
48200Sstevel@tonic-gate bp->b_datap->db_type = M_SETOPTS;
48210Sstevel@tonic-gate DEBUG4(("M_SETOPTS to stream head\n"));
48220Sstevel@tonic-gate putnext(q, bp);
48230Sstevel@tonic-gate }
48240Sstevel@tonic-gate return (0);
48250Sstevel@tonic-gate }
48260Sstevel@tonic-gate
48270Sstevel@tonic-gate
48280Sstevel@tonic-gate /*
48290Sstevel@tonic-gate * Called when an M_IOCACK message is seen on the read queue;
48300Sstevel@tonic-gate * modifies the data being returned, if necessary, and passes the
48310Sstevel@tonic-gate * reply up.
48320Sstevel@tonic-gate */
48330Sstevel@tonic-gate static void
ldterm_ioctl_reply(queue_t * q,mblk_t * mp)48340Sstevel@tonic-gate ldterm_ioctl_reply(queue_t *q, mblk_t *mp)
48350Sstevel@tonic-gate {
48360Sstevel@tonic-gate ldtermstd_state_t *tp;
48370Sstevel@tonic-gate struct iocblk *iocp;
48380Sstevel@tonic-gate
48390Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr;
48400Sstevel@tonic-gate tp = (ldtermstd_state_t *)q->q_ptr;
48410Sstevel@tonic-gate
48420Sstevel@tonic-gate switch (iocp->ioc_cmd) {
48430Sstevel@tonic-gate
48440Sstevel@tonic-gate case TCGETS:
48450Sstevel@tonic-gate {
48460Sstevel@tonic-gate /*
48470Sstevel@tonic-gate * Get current parameters and return them to
48480Sstevel@tonic-gate * stream head eventually.
48490Sstevel@tonic-gate */
48500Sstevel@tonic-gate struct termios *cb =
4851*7012Sis (struct termios *)mp->b_cont->b_rptr;
48520Sstevel@tonic-gate
48530Sstevel@tonic-gate /*
48540Sstevel@tonic-gate * cflag has cflags sent upstream by the
48550Sstevel@tonic-gate * driver
48560Sstevel@tonic-gate */
48570Sstevel@tonic-gate tcflag_t cflag = cb->c_cflag;
48580Sstevel@tonic-gate
48590Sstevel@tonic-gate *cb = tp->t_amodes;
48600Sstevel@tonic-gate if (cflag != 0)
48610Sstevel@tonic-gate cb->c_cflag = cflag; /* set by driver */
48620Sstevel@tonic-gate break;
48630Sstevel@tonic-gate }
48640Sstevel@tonic-gate
48650Sstevel@tonic-gate case TCGETA:
48660Sstevel@tonic-gate {
48670Sstevel@tonic-gate /*
48680Sstevel@tonic-gate * Old-style "ioctl" to get current
48690Sstevel@tonic-gate * parameters and return them to stream head
48700Sstevel@tonic-gate * eventually.
48710Sstevel@tonic-gate */
48720Sstevel@tonic-gate struct termio *cb =
4873*7012Sis (struct termio *)mp->b_cont->b_rptr;
48740Sstevel@tonic-gate
48750Sstevel@tonic-gate cb->c_iflag = tp->t_amodes.c_iflag; /* all except the */
48760Sstevel@tonic-gate cb->c_oflag = tp->t_amodes.c_oflag; /* cb->c_cflag */
48770Sstevel@tonic-gate cb->c_lflag = tp->t_amodes.c_lflag;
48780Sstevel@tonic-gate
48790Sstevel@tonic-gate if (cb->c_cflag == 0) /* not set by driver */
48800Sstevel@tonic-gate cb->c_cflag = tp->t_amodes.c_cflag;
48810Sstevel@tonic-gate
48820Sstevel@tonic-gate cb->c_line = 0;
48830Sstevel@tonic-gate bcopy(tp->t_amodes.c_cc, cb->c_cc, NCC);
48840Sstevel@tonic-gate break;
48850Sstevel@tonic-gate }
48860Sstevel@tonic-gate }
48870Sstevel@tonic-gate putnext(q, mp);
48880Sstevel@tonic-gate }
48890Sstevel@tonic-gate
48900Sstevel@tonic-gate
48910Sstevel@tonic-gate /*
48920Sstevel@tonic-gate * A VMIN/VTIME request has been satisfied. Cancel outstanding timers
48930Sstevel@tonic-gate * if they exist, clear TS_MREAD state, and send upstream. If a NULL
48940Sstevel@tonic-gate * queue ptr is passed, just reset VMIN/VTIME state.
48950Sstevel@tonic-gate */
48960Sstevel@tonic-gate static void
vmin_satisfied(queue_t * q,ldtermstd_state_t * tp,int sendup)48970Sstevel@tonic-gate vmin_satisfied(queue_t *q, ldtermstd_state_t *tp, int sendup)
48980Sstevel@tonic-gate {
48990Sstevel@tonic-gate ASSERT(q);
49000Sstevel@tonic-gate if (tp->t_vtid != 0) {
4901*7012Sis DEBUG4(("vmin_satisfied: cancelled timer id %d\n", tp->t_vtid));
49020Sstevel@tonic-gate (void) quntimeout(q, tp->t_vtid);
49030Sstevel@tonic-gate tp->t_vtid = 0;
49040Sstevel@tonic-gate }
49050Sstevel@tonic-gate if (sendup) {
49060Sstevel@tonic-gate if (tp->t_msglen == 0 && V_MIN) {
49070Sstevel@tonic-gate /* EMPTY */
49080Sstevel@tonic-gate DEBUG4(("vmin_satisfied: data swiped, msglen = 0\n"));
49090Sstevel@tonic-gate } else {
49100Sstevel@tonic-gate if ((!q->q_first) ||
49110Sstevel@tonic-gate (q->q_first->b_datap->db_type != M_DATA) ||
49120Sstevel@tonic-gate (tp->t_msglen >= LDCHUNK)) {
49130Sstevel@tonic-gate ldterm_msg_upstream(q, tp);
49140Sstevel@tonic-gate DEBUG4(("vmin_satisfied: delivering data\n"));
49150Sstevel@tonic-gate }
49160Sstevel@tonic-gate }
49170Sstevel@tonic-gate } else {
49180Sstevel@tonic-gate /* EMPTY */
49190Sstevel@tonic-gate DEBUG4(("vmin_satisfied: VMIN/TIME state reset\n"));
49200Sstevel@tonic-gate }
49210Sstevel@tonic-gate tp->t_state &= ~TS_MREAD;
49220Sstevel@tonic-gate }
49230Sstevel@tonic-gate
49240Sstevel@tonic-gate static void
vmin_settimer(queue_t * q)49250Sstevel@tonic-gate vmin_settimer(queue_t *q)
49260Sstevel@tonic-gate {
49270Sstevel@tonic-gate ldtermstd_state_t *tp;
49280Sstevel@tonic-gate
49290Sstevel@tonic-gate tp = (ldtermstd_state_t *)q->q_ptr;
49300Sstevel@tonic-gate
49310Sstevel@tonic-gate /*
49320Sstevel@tonic-gate * Don't start any time bombs.
49330Sstevel@tonic-gate */
49340Sstevel@tonic-gate if (tp->t_state & TS_CLOSE)
49350Sstevel@tonic-gate return;
49360Sstevel@tonic-gate
49370Sstevel@tonic-gate /*
49380Sstevel@tonic-gate * tp->t_vtid should NOT be set here unless VMIN > 0 and
49390Sstevel@tonic-gate * VTIME > 0.
49400Sstevel@tonic-gate */
49410Sstevel@tonic-gate if (tp->t_vtid) {
49420Sstevel@tonic-gate if (V_MIN && V_TIME) {
49430Sstevel@tonic-gate /* EMPTY */
49440Sstevel@tonic-gate DEBUG4(("vmin_settimer: timer restarted, old tid=%d\n",
4945*7012Sis tp->t_vtid));
49460Sstevel@tonic-gate } else {
49470Sstevel@tonic-gate /* EMPTY */
49480Sstevel@tonic-gate DEBUG4(("vmin_settimer: tid = %d was still active!\n",
4949*7012Sis tp->t_vtid));
49500Sstevel@tonic-gate }
49510Sstevel@tonic-gate (void) quntimeout(q, tp->t_vtid);
49520Sstevel@tonic-gate tp->t_vtid = 0;
49530Sstevel@tonic-gate }
49540Sstevel@tonic-gate tp->t_vtid = qtimeout(q, vmin_timed_out, q,
49550Sstevel@tonic-gate (clock_t)(V_TIME * (hz / 10)));
49560Sstevel@tonic-gate DEBUG4(("vmin_settimer: timer started, tid = %d\n", tp->t_vtid));
49570Sstevel@tonic-gate }
49580Sstevel@tonic-gate
49590Sstevel@tonic-gate
49600Sstevel@tonic-gate /*
49610Sstevel@tonic-gate * BRRrrringgg!! VTIME was satisfied instead of VMIN
49620Sstevel@tonic-gate */
49630Sstevel@tonic-gate static void
vmin_timed_out(void * arg)49640Sstevel@tonic-gate vmin_timed_out(void *arg)
49650Sstevel@tonic-gate {
49660Sstevel@tonic-gate queue_t *q = arg;
49670Sstevel@tonic-gate ldtermstd_state_t *tp;
49680Sstevel@tonic-gate
49690Sstevel@tonic-gate tp = (ldtermstd_state_t *)q->q_ptr;
49700Sstevel@tonic-gate
49710Sstevel@tonic-gate DEBUG4(("vmin_timed_out: tid = %d\n", tp->t_vtid));
49720Sstevel@tonic-gate /* don't call untimeout now that we are in the timeout */
49730Sstevel@tonic-gate tp->t_vtid = 0;
49740Sstevel@tonic-gate vmin_satisfied(q, tp, 1);
49750Sstevel@tonic-gate }
49760Sstevel@tonic-gate
49770Sstevel@tonic-gate
49780Sstevel@tonic-gate /*
49790Sstevel@tonic-gate * Routine to adjust termios flags to be processed by the line
49800Sstevel@tonic-gate * discipline. Driver below sends a termios structure, with the flags
49810Sstevel@tonic-gate * the driver intends to process. XOR'ing the driver sent termios
49820Sstevel@tonic-gate * structure with current termios structure with the default values
49830Sstevel@tonic-gate * (or set by ioctls from userland), we come up with a new termios
49840Sstevel@tonic-gate * structrue, the flags of which will be used by the line discipline
49850Sstevel@tonic-gate * in processing input and output. On return from this routine, we
49860Sstevel@tonic-gate * will have the following fields set in tp structure -->
49870Sstevel@tonic-gate * tp->t_modes: modes the line discipline will process tp->t_amodes:
49880Sstevel@tonic-gate * modes the user process thinks the line discipline is processing
49890Sstevel@tonic-gate */
49900Sstevel@tonic-gate
49910Sstevel@tonic-gate static void
ldterm_adjust_modes(ldtermstd_state_t * tp)49920Sstevel@tonic-gate ldterm_adjust_modes(ldtermstd_state_t *tp)
49930Sstevel@tonic-gate {
49940Sstevel@tonic-gate
49950Sstevel@tonic-gate DEBUG6(("original iflag = %o\n", tp->t_modes.c_iflag));
49960Sstevel@tonic-gate tp->t_modes.c_iflag = tp->t_amodes.c_iflag & ~(tp->t_dmodes.c_iflag);
49970Sstevel@tonic-gate tp->t_modes.c_oflag = tp->t_amodes.c_oflag & ~(tp->t_dmodes.c_oflag);
49980Sstevel@tonic-gate tp->t_modes.c_lflag = tp->t_amodes.c_lflag & ~(tp->t_dmodes.c_lflag);
49990Sstevel@tonic-gate DEBUG6(("driver iflag = %o\n", tp->t_dmodes.c_iflag));
50000Sstevel@tonic-gate DEBUG6(("apparent iflag = %o\n", tp->t_amodes.c_iflag));
50010Sstevel@tonic-gate DEBUG6(("effective iflag = %o\n", tp->t_modes.c_iflag));
50020Sstevel@tonic-gate
50030Sstevel@tonic-gate /* No negotiation of clfags c_cc array special characters */
50040Sstevel@tonic-gate /*
50050Sstevel@tonic-gate * Copy from amodes to modes already done by TCSETA/TCSETS
50060Sstevel@tonic-gate * code
50070Sstevel@tonic-gate */
50080Sstevel@tonic-gate }
50090Sstevel@tonic-gate
50100Sstevel@tonic-gate
50110Sstevel@tonic-gate /*
50120Sstevel@tonic-gate * Erase one multi-byte character. If TS_MEUC is set AND this
50130Sstevel@tonic-gate * is a multi-byte character, then this should be called instead of
50140Sstevel@tonic-gate * ldterm_erase. "ldterm_erase" will handle ASCII nicely, thank you.
50150Sstevel@tonic-gate *
50160Sstevel@tonic-gate * We'd better be pointing to the last byte. If we aren't, it will get
50170Sstevel@tonic-gate * screwed up.
50180Sstevel@tonic-gate */
50190Sstevel@tonic-gate static void
ldterm_csi_erase(queue_t * q,size_t ebsize,ldtermstd_state_t * tp)50200Sstevel@tonic-gate ldterm_csi_erase(queue_t *q, size_t ebsize, ldtermstd_state_t *tp)
50210Sstevel@tonic-gate {
50220Sstevel@tonic-gate int i, ung;
50230Sstevel@tonic-gate uchar_t *p, *bottom;
50240Sstevel@tonic-gate uchar_t u8[LDTERM_CS_MAX_BYTE_LENGTH];
50250Sstevel@tonic-gate int c;
50260Sstevel@tonic-gate int j;
50270Sstevel@tonic-gate int len;
50280Sstevel@tonic-gate
50290Sstevel@tonic-gate if (tp->t_eucleft) {
50300Sstevel@tonic-gate /* XXX Ick. We're in the middle of an EUC! */
50310Sstevel@tonic-gate /* What to do now? */
50320Sstevel@tonic-gate ldterm_eucwarn(tp);
50330Sstevel@tonic-gate return; /* ignore it??? */
50340Sstevel@tonic-gate }
50350Sstevel@tonic-gate bottom = tp->t_eucp_mp->b_rptr;
50360Sstevel@tonic-gate p = tp->t_eucp - 1; /* previous byte */
50370Sstevel@tonic-gate if (p < bottom)
50380Sstevel@tonic-gate return;
50390Sstevel@tonic-gate ung = 1; /* number of bytes to un-get from buffer */
50400Sstevel@tonic-gate /*
50410Sstevel@tonic-gate * go through the buffer until we find the beginning of the
50420Sstevel@tonic-gate * multi-byte char.
50430Sstevel@tonic-gate */
50440Sstevel@tonic-gate while ((*p == 0) && (p > bottom)) {
50450Sstevel@tonic-gate p--;
50460Sstevel@tonic-gate ++ung;
50470Sstevel@tonic-gate }
50480Sstevel@tonic-gate
50490Sstevel@tonic-gate /*
50500Sstevel@tonic-gate * Now, "ung" is the number of bytes to unget from the buffer
50510Sstevel@tonic-gate * and "*p" is the disp width of it. Fool "ldterm_rubout"
50520Sstevel@tonic-gate * into thinking we're rubbing out ASCII characters. Do that
50530Sstevel@tonic-gate * for the display width of the character.
50540Sstevel@tonic-gate *
50550Sstevel@tonic-gate * Also we accumulate bytes of the character so that if the character
50560Sstevel@tonic-gate * is a UTF-8 character, we will get the display width of the UTF-8
50570Sstevel@tonic-gate * character.
50580Sstevel@tonic-gate */
50590Sstevel@tonic-gate if (ung >= LDTERM_CS_MAX_BYTE_LENGTH) {
50600Sstevel@tonic-gate j = len = LDTERM_CS_MAX_BYTE_LENGTH;
50610Sstevel@tonic-gate } else {
50620Sstevel@tonic-gate j = len = ung;
50630Sstevel@tonic-gate }
50640Sstevel@tonic-gate for (i = 0; i < ung; i++) { /* remove from buf */
50650Sstevel@tonic-gate if ((c = ldterm_unget(tp)) != (-1)) {
50660Sstevel@tonic-gate ldterm_trim(tp);
50670Sstevel@tonic-gate if (j > 0)
50680Sstevel@tonic-gate u8[--j] = (uchar_t)c;
50690Sstevel@tonic-gate }
50700Sstevel@tonic-gate }
50710Sstevel@tonic-gate if (*p == UNKNOWN_WIDTH) {
50720Sstevel@tonic-gate if (tp->t_csdata.codeset_type == LDTERM_CS_TYPE_UTF8) {
50730Sstevel@tonic-gate *p = ldterm_utf8_width(u8, len);
50740Sstevel@tonic-gate } else {
50750Sstevel@tonic-gate *p = 1;
50760Sstevel@tonic-gate }
50770Sstevel@tonic-gate }
50780Sstevel@tonic-gate for (i = 0; i < (int)*p; i++) /* remove from screen */
50790Sstevel@tonic-gate ldterm_rubout(' ', q, ebsize, tp);
50800Sstevel@tonic-gate /*
50810Sstevel@tonic-gate * Adjust the parallel array pointer. Zero out the contents
50820Sstevel@tonic-gate * of parallel array for this position, just to make sure...
50830Sstevel@tonic-gate */
50840Sstevel@tonic-gate tp->t_eucp = p;
50850Sstevel@tonic-gate *p = 0;
50860Sstevel@tonic-gate }
50870Sstevel@tonic-gate
50880Sstevel@tonic-gate
50890Sstevel@tonic-gate /*
50900Sstevel@tonic-gate * This is kind of a safety valve. Whenever we see a bad sequence
50910Sstevel@tonic-gate * come up, we call eucwarn. It just tallies the junk until a
50920Sstevel@tonic-gate * threshold is reached. Then it prints ONE message on the console
50930Sstevel@tonic-gate * and not any more. Hopefully, we can catch garbage; maybe it will
50940Sstevel@tonic-gate * be useful to somebody.
50950Sstevel@tonic-gate */
50960Sstevel@tonic-gate static void
ldterm_eucwarn(ldtermstd_state_t * tp)50970Sstevel@tonic-gate ldterm_eucwarn(ldtermstd_state_t *tp)
50980Sstevel@tonic-gate {
50990Sstevel@tonic-gate ++tp->t_eucwarn;
51000Sstevel@tonic-gate #ifdef DEBUG
51010Sstevel@tonic-gate if ((tp->t_eucwarn > EUC_WARNCNT) && !(tp->t_state & TS_WARNED)) {
51020Sstevel@tonic-gate cmn_err(CE_WARN,
51030Sstevel@tonic-gate "ldterm: tty at addr %p in multi-byte mode --",
51040Sstevel@tonic-gate (void *)tp);
51050Sstevel@tonic-gate cmn_err(CE_WARN,
51060Sstevel@tonic-gate "Over %d bad EUC characters this session", EUC_WARNCNT);
51070Sstevel@tonic-gate tp->t_state |= TS_WARNED;
51080Sstevel@tonic-gate }
51090Sstevel@tonic-gate #endif
51100Sstevel@tonic-gate }
51110Sstevel@tonic-gate
51120Sstevel@tonic-gate
51130Sstevel@tonic-gate /*
51140Sstevel@tonic-gate * Copy an "eucioc_t" structure. We use the structure with
51150Sstevel@tonic-gate * incremented values for Codesets 2 & 3. The specification in
51160Sstevel@tonic-gate * eucioctl is that the sames values as the CSWIDTH definition at
51170Sstevel@tonic-gate * user level are passed to us. When we copy it "in" to ourselves, we
51180Sstevel@tonic-gate * do the increment. That allows us to avoid treating each character
51190Sstevel@tonic-gate * set separately for "t_eucleft" purposes. When we copy it "out" to
51200Sstevel@tonic-gate * return it to the user, we decrement the values so the user gets
51210Sstevel@tonic-gate * what it expects, and it matches CSWIDTH in the environment (if
51220Sstevel@tonic-gate * things are consistent!).
51230Sstevel@tonic-gate */
51240Sstevel@tonic-gate static void
cp_eucwioc(eucioc_t * from,eucioc_t * to,int dir)51250Sstevel@tonic-gate cp_eucwioc(eucioc_t *from, eucioc_t *to, int dir)
51260Sstevel@tonic-gate {
51270Sstevel@tonic-gate bcopy(from, to, EUCSIZE);
51280Sstevel@tonic-gate if (dir == EUCOUT) { /* copying out to user */
51290Sstevel@tonic-gate if (to->eucw[2])
51300Sstevel@tonic-gate --to->eucw[2];
51310Sstevel@tonic-gate if (to->eucw[3])
51320Sstevel@tonic-gate --to->eucw[3];
51330Sstevel@tonic-gate } else { /* copying in */
51340Sstevel@tonic-gate if (to->eucw[2])
51350Sstevel@tonic-gate ++to->eucw[2];
51360Sstevel@tonic-gate if (to->eucw[3])
51370Sstevel@tonic-gate ++to->eucw[3];
51380Sstevel@tonic-gate }
51390Sstevel@tonic-gate }
51400Sstevel@tonic-gate
51410Sstevel@tonic-gate
51420Sstevel@tonic-gate /*
51430Sstevel@tonic-gate * Take the first byte of a multi-byte, or an ASCII char. Return its
51440Sstevel@tonic-gate * codeset. If it's NOT the first byte of an EUC, then the return
51450Sstevel@tonic-gate * value may be garbage, as it's probably not SS2 or SS3, and
51460Sstevel@tonic-gate * therefore must be in codeset 1. Another bizarre catch here is the
51470Sstevel@tonic-gate * fact that we don't do anything about the "C1" control codes. In
51480Sstevel@tonic-gate * real life, we should; but nobody's come up with a good way of
51490Sstevel@tonic-gate * treating them.
51500Sstevel@tonic-gate */
51510Sstevel@tonic-gate
51520Sstevel@tonic-gate static int
ldterm_codeset(uchar_t codeset_type,uchar_t c)51530Sstevel@tonic-gate ldterm_codeset(uchar_t codeset_type, uchar_t c)
51540Sstevel@tonic-gate {
51550Sstevel@tonic-gate
51560Sstevel@tonic-gate if (ISASCII(c))
51570Sstevel@tonic-gate return (0);
51580Sstevel@tonic-gate
51590Sstevel@tonic-gate if (codeset_type != LDTERM_CS_TYPE_EUC)
51600Sstevel@tonic-gate return (1);
51610Sstevel@tonic-gate
51620Sstevel@tonic-gate switch (c) {
51630Sstevel@tonic-gate case SS2:
51640Sstevel@tonic-gate return (2);
51650Sstevel@tonic-gate case SS3:
51660Sstevel@tonic-gate return (3);
51670Sstevel@tonic-gate default:
51680Sstevel@tonic-gate return (1);
51690Sstevel@tonic-gate }
51700Sstevel@tonic-gate }
51710Sstevel@tonic-gate
51720Sstevel@tonic-gate /* The following two functions are additional EUC codeset specific methods. */
51730Sstevel@tonic-gate /*
51740Sstevel@tonic-gate * ldterm_dispwidth - Take the first byte of an EUC (or ASCII) and
51750Sstevel@tonic-gate * return the display width. Since this is intended mostly for
51760Sstevel@tonic-gate * multi-byte handling, it returns EUC_TWIDTH for tabs so they can be
51770Sstevel@tonic-gate * differentiated from EUC characters (assumption: EUC require fewer
51780Sstevel@tonic-gate * than 255 columns). Also, if it's a backspace and !flag, it
51790Sstevel@tonic-gate * returns EUC_BSWIDTH. Newline & CR also depend on flag. This
51800Sstevel@tonic-gate * routine SHOULD be cleaner than this, but we have the situation
51810Sstevel@tonic-gate * where we may or may not be counting control characters as having a
51820Sstevel@tonic-gate * column width. Therefore, the computation of ASCII is pretty messy.
51830Sstevel@tonic-gate * The caller will be storing the value, and then switching on it
51840Sstevel@tonic-gate * when it's used. We really should define the EUC_TWIDTH and other
51850Sstevel@tonic-gate * constants in a header so that the routine could be used in other
51860Sstevel@tonic-gate * modules in the kernel.
51870Sstevel@tonic-gate */
51880Sstevel@tonic-gate static int
__ldterm_dispwidth_euc(uchar_t c,void * p,int mode)51890Sstevel@tonic-gate __ldterm_dispwidth_euc(uchar_t c, void *p, int mode)
51900Sstevel@tonic-gate {
51910Sstevel@tonic-gate ldtermstd_state_t *tp = (ldtermstd_state_t *)p;
51920Sstevel@tonic-gate
51930Sstevel@tonic-gate if (ISASCII(c)) {
51940Sstevel@tonic-gate if (c <= '\037') {
51950Sstevel@tonic-gate switch (c) {
51960Sstevel@tonic-gate case '\t':
51970Sstevel@tonic-gate return (EUC_TWIDTH);
51980Sstevel@tonic-gate case '\b':
51990Sstevel@tonic-gate return (mode ? 2 : EUC_BSWIDTH);
52000Sstevel@tonic-gate case '\n':
52010Sstevel@tonic-gate return (EUC_NLWIDTH);
52020Sstevel@tonic-gate case '\r':
52030Sstevel@tonic-gate return (mode ? 2 : EUC_CRWIDTH);
52040Sstevel@tonic-gate default:
52050Sstevel@tonic-gate return (mode ? 2 : 0);
52060Sstevel@tonic-gate }
52070Sstevel@tonic-gate }
52080Sstevel@tonic-gate return (1);
52090Sstevel@tonic-gate }
52100Sstevel@tonic-gate switch (c) {
52110Sstevel@tonic-gate case SS2:
52120Sstevel@tonic-gate return (tp->eucwioc.scrw[2]);
52130Sstevel@tonic-gate case SS3:
52140Sstevel@tonic-gate return (tp->eucwioc.scrw[3]);
52150Sstevel@tonic-gate default:
52160Sstevel@tonic-gate return (tp->eucwioc.scrw[1]);
52170Sstevel@tonic-gate }
52180Sstevel@tonic-gate }
52190Sstevel@tonic-gate
52200Sstevel@tonic-gate /*
52210Sstevel@tonic-gate * ldterm_memwidth_euc - Take the first byte of an EUC (or an ASCII char)
52220Sstevel@tonic-gate * and return its memory width. The routine could have been
52230Sstevel@tonic-gate * implemented to use only the codeset number, but that would require
52240Sstevel@tonic-gate * the caller to have that value available. Perhaps the user doesn't
52250Sstevel@tonic-gate * want to make the extra call or keep the value of codeset around.
52260Sstevel@tonic-gate * Therefore, we use the actual character with which they're
52270Sstevel@tonic-gate * concerned. This should never be called with anything but the
52280Sstevel@tonic-gate * first byte of an EUC, otherwise it will return a garbage value.
52290Sstevel@tonic-gate */
52300Sstevel@tonic-gate static int
__ldterm_memwidth_euc(uchar_t c,void * p)52310Sstevel@tonic-gate __ldterm_memwidth_euc(uchar_t c, void *p)
52320Sstevel@tonic-gate {
52330Sstevel@tonic-gate ldtermstd_state_t *tp = (ldtermstd_state_t *)p;
52340Sstevel@tonic-gate
52350Sstevel@tonic-gate if (ISASCII(c))
52360Sstevel@tonic-gate return (1);
52370Sstevel@tonic-gate switch (c) {
52380Sstevel@tonic-gate case SS2:
52390Sstevel@tonic-gate return (tp->eucwioc.eucw[2]);
52400Sstevel@tonic-gate case SS3:
52410Sstevel@tonic-gate return (tp->eucwioc.eucw[3]);
52420Sstevel@tonic-gate default:
52430Sstevel@tonic-gate return (tp->eucwioc.eucw[1]);
52440Sstevel@tonic-gate }
52450Sstevel@tonic-gate }
52460Sstevel@tonic-gate
52470Sstevel@tonic-gate
52480Sstevel@tonic-gate /* The following two functions are PCCS codeset specific methods. */
52490Sstevel@tonic-gate static int
__ldterm_dispwidth_pccs(uchar_t c,void * p,int mode)52500Sstevel@tonic-gate __ldterm_dispwidth_pccs(uchar_t c, void *p, int mode)
52510Sstevel@tonic-gate {
52520Sstevel@tonic-gate ldtermstd_state_t *tp = (ldtermstd_state_t *)p;
52530Sstevel@tonic-gate int i;
52540Sstevel@tonic-gate
52550Sstevel@tonic-gate if (ISASCII(c)) {
52560Sstevel@tonic-gate if (c <= '\037') {
52570Sstevel@tonic-gate switch (c) {
52580Sstevel@tonic-gate case '\t':
52590Sstevel@tonic-gate return (EUC_TWIDTH);
52600Sstevel@tonic-gate case '\b':
52610Sstevel@tonic-gate return (mode ? 2 : EUC_BSWIDTH);
52620Sstevel@tonic-gate case '\n':
52630Sstevel@tonic-gate return (EUC_NLWIDTH);
52640Sstevel@tonic-gate case '\r':
52650Sstevel@tonic-gate return (mode ? 2 : EUC_CRWIDTH);
52660Sstevel@tonic-gate default:
52670Sstevel@tonic-gate return (mode ? 2 : 0);
52680Sstevel@tonic-gate }
52690Sstevel@tonic-gate }
52700Sstevel@tonic-gate return (1);
52710Sstevel@tonic-gate }
52720Sstevel@tonic-gate
52730Sstevel@tonic-gate for (i = 0; i < tp->t_csdata.csinfo_num; i++) {
52740Sstevel@tonic-gate if (c >= tp->t_csdata.eucpc_data[i].msb_start &&
52750Sstevel@tonic-gate c <= tp->t_csdata.eucpc_data[i].msb_end)
52760Sstevel@tonic-gate return (tp->t_csdata.eucpc_data[i].screen_width);
52770Sstevel@tonic-gate }
52780Sstevel@tonic-gate
52790Sstevel@tonic-gate /*
52800Sstevel@tonic-gate * If this leading byte is not in the range list, either provided
52810Sstevel@tonic-gate * locale data is not sufficient or we encountered an invalid
52820Sstevel@tonic-gate * character. We return 1 in this case as a fallback value.
52830Sstevel@tonic-gate */
52840Sstevel@tonic-gate return (1);
52850Sstevel@tonic-gate }
52860Sstevel@tonic-gate
52870Sstevel@tonic-gate static int
__ldterm_memwidth_pccs(uchar_t c,void * p)52880Sstevel@tonic-gate __ldterm_memwidth_pccs(uchar_t c, void *p)
52890Sstevel@tonic-gate {
52900Sstevel@tonic-gate ldtermstd_state_t *tp = (ldtermstd_state_t *)p;
52910Sstevel@tonic-gate int i;
52920Sstevel@tonic-gate
52930Sstevel@tonic-gate for (i = 0; i < tp->t_csdata.csinfo_num; i++) {
52940Sstevel@tonic-gate if (c >= tp->t_csdata.eucpc_data[i].msb_start &&
52950Sstevel@tonic-gate c <= tp->t_csdata.eucpc_data[i].msb_end)
52960Sstevel@tonic-gate return (tp->t_csdata.eucpc_data[i].byte_length);
52970Sstevel@tonic-gate }
52980Sstevel@tonic-gate
52990Sstevel@tonic-gate /*
53000Sstevel@tonic-gate * If this leading byte is not in the range list, either provided
53010Sstevel@tonic-gate * locale data is not sufficient or we encountered an invalid
53020Sstevel@tonic-gate * character. We return 1 in this case as a fallback value.
53030Sstevel@tonic-gate */
53040Sstevel@tonic-gate return (1);
53050Sstevel@tonic-gate }
53060Sstevel@tonic-gate
53070Sstevel@tonic-gate
53080Sstevel@tonic-gate /* The following two functions are UTF-8 codeset specific methods. */
53090Sstevel@tonic-gate static int
__ldterm_dispwidth_utf8(uchar_t c,void * p,int mode)53100Sstevel@tonic-gate __ldterm_dispwidth_utf8(uchar_t c, void *p, int mode)
53110Sstevel@tonic-gate {
53120Sstevel@tonic-gate ldtermstd_state_t *tp = (ldtermstd_state_t *)p;
53130Sstevel@tonic-gate
53140Sstevel@tonic-gate if (ISASCII(c)) {
53150Sstevel@tonic-gate if (c <= '\037') {
53160Sstevel@tonic-gate switch (c) {
53170Sstevel@tonic-gate case '\t':
53180Sstevel@tonic-gate return (EUC_TWIDTH);
53190Sstevel@tonic-gate case '\b':
53200Sstevel@tonic-gate return (mode ? 2 : EUC_BSWIDTH);
53210Sstevel@tonic-gate case '\n':
53220Sstevel@tonic-gate return (EUC_NLWIDTH);
53230Sstevel@tonic-gate case '\r':
53240Sstevel@tonic-gate return (mode ? 2 : EUC_CRWIDTH);
53250Sstevel@tonic-gate default:
53260Sstevel@tonic-gate return (mode ? 2 : 0);
53270Sstevel@tonic-gate }
53280Sstevel@tonic-gate }
53290Sstevel@tonic-gate return (1);
53300Sstevel@tonic-gate }
53310Sstevel@tonic-gate
53320Sstevel@tonic-gate /* This is to silence the lint. */
53330Sstevel@tonic-gate if (tp->t_csdata.codeset_type != LDTERM_CS_TYPE_UTF8)
53340Sstevel@tonic-gate return (1);
53350Sstevel@tonic-gate
53360Sstevel@tonic-gate /*
53370Sstevel@tonic-gate * If it is a valid leading byte of a UTF-8 character, we set
53380Sstevel@tonic-gate * the width as 'UNKNOWN_WIDTH' for now. We need to have all
53390Sstevel@tonic-gate * the bytes to figure out the display width.
53400Sstevel@tonic-gate */
53410Sstevel@tonic-gate if (c >= (uchar_t)0xc0 && c <= (uchar_t)0xfd)
53420Sstevel@tonic-gate return (UNKNOWN_WIDTH);
53430Sstevel@tonic-gate
53440Sstevel@tonic-gate /*
53450Sstevel@tonic-gate * If it is an invalid leading byte, we just do our best by
53460Sstevel@tonic-gate * giving the display width of 1.
53470Sstevel@tonic-gate */
53480Sstevel@tonic-gate return (1);
53490Sstevel@tonic-gate }
53500Sstevel@tonic-gate
53510Sstevel@tonic-gate
53520Sstevel@tonic-gate static int
__ldterm_memwidth_utf8(uchar_t c,void * p)53530Sstevel@tonic-gate __ldterm_memwidth_utf8(uchar_t c, void *p)
53540Sstevel@tonic-gate {
53550Sstevel@tonic-gate ldtermstd_state_t *tp = (ldtermstd_state_t *)p;
5356*7012Sis int len;
5357*7012Sis
5358*7012Sis /*
5359*7012Sis * If the codeset type doesn't match, we treat them as
5360*7012Sis * an illegal character and return 1.
5361*7012Sis */
53620Sstevel@tonic-gate if (tp->t_csdata.codeset_type != LDTERM_CS_TYPE_UTF8)
53630Sstevel@tonic-gate return (1);
53640Sstevel@tonic-gate
5365*7012Sis len = u8_number_of_bytes[c];
5366*7012Sis
5367*7012Sis /*
5368*7012Sis * If this is a start of an illegal character, we treat
5369*7012Sis * such as an 1 byte character and screen out.
5370*7012Sis */
5371*7012Sis return ((len <= 0) ? 1 : len);
53720Sstevel@tonic-gate }
53730Sstevel@tonic-gate
53740Sstevel@tonic-gate static uchar_t
ldterm_utf8_width(uchar_t * u8,int length)53750Sstevel@tonic-gate ldterm_utf8_width(uchar_t *u8, int length)
53760Sstevel@tonic-gate {
53770Sstevel@tonic-gate int i;
53780Sstevel@tonic-gate int j;
53790Sstevel@tonic-gate uint_t intcode = 0;
53800Sstevel@tonic-gate
53810Sstevel@tonic-gate if (length == 0)
53820Sstevel@tonic-gate return ('\0');
53830Sstevel@tonic-gate
5384*7012Sis j = u8_number_of_bytes[u8[0]] - 1;
53850Sstevel@tonic-gate
53860Sstevel@tonic-gate /*
53870Sstevel@tonic-gate * If the UTF-8 character is out of UTF-16 code range, or,
53880Sstevel@tonic-gate * if it is either an ASCII character or an invalid leading byte for
53890Sstevel@tonic-gate * a UTF-8 character, return 1.
53900Sstevel@tonic-gate */
5391*7012Sis if (length > 4 || j <= 0)
53920Sstevel@tonic-gate return ('\1');
53930Sstevel@tonic-gate
5394*7012Sis intcode = u8[0] & u8_masks_tbl[j];
53950Sstevel@tonic-gate for (i = 1; j > 0; j--, i++) {
53960Sstevel@tonic-gate /*
5397*7012Sis * The following additional checking is needed to conform to
5398*7012Sis * the "UTF-8 Corrigendum" introduced at the Unicode 3.1 and
5399*7012Sis * then updated one more time at the Unicode 3.2.
54000Sstevel@tonic-gate */
54010Sstevel@tonic-gate if (i == 1) {
5402*7012Sis if (u8[i] < u8_valid_min_2nd_byte[u8[0]] ||
5403*7012Sis u8[i] > u8_valid_max_2nd_byte[u8[0]])
54040Sstevel@tonic-gate return ('\1');
54050Sstevel@tonic-gate } else if (u8[i] < (uchar_t)LDTERM_CS_TYPE_UTF8_MIN_BYTE ||
5406*7012Sis u8[i] > (uchar_t)LDTERM_CS_TYPE_UTF8_MAX_BYTE)
54070Sstevel@tonic-gate return ('\1');
54080Sstevel@tonic-gate
54090Sstevel@tonic-gate /*
54100Sstevel@tonic-gate * All subsequent bytes of UTF-8 character has the following
54110Sstevel@tonic-gate * binary encoding:
54120Sstevel@tonic-gate *
54130Sstevel@tonic-gate * 10xx xxxx
54140Sstevel@tonic-gate *
54150Sstevel@tonic-gate * hence left shift six bits to make space and then get
54160Sstevel@tonic-gate * six bits from the new byte.
54170Sstevel@tonic-gate */
54180Sstevel@tonic-gate intcode = (intcode << LDTERM_CS_TYPE_UTF8_SHIFT_BITS) |
5419*7012Sis (u8[i] & LDTERM_CS_TYPE_UTF8_BIT_MASK);
54200Sstevel@tonic-gate }
54210Sstevel@tonic-gate
5422*7012Sis i = 0;
54230Sstevel@tonic-gate if (intcode <= LDTERM_CS_TYPE_UTF8_MAX_P00) {
54240Sstevel@tonic-gate /* Basic Multilingual Plane. */
54250Sstevel@tonic-gate i = intcode / 4;
54260Sstevel@tonic-gate j = intcode % 4;
54270Sstevel@tonic-gate switch (j) {
54280Sstevel@tonic-gate case 0:
5429*7012Sis i = ldterm_ucode[0][i].u0;
5430*7012Sis break;
54310Sstevel@tonic-gate case 1:
5432*7012Sis i = ldterm_ucode[0][i].u1;
5433*7012Sis break;
54340Sstevel@tonic-gate case 2:
5435*7012Sis i = ldterm_ucode[0][i].u2;
5436*7012Sis break;
54370Sstevel@tonic-gate case 3:
5438*7012Sis i = ldterm_ucode[0][i].u3;
5439*7012Sis break;
54400Sstevel@tonic-gate }
54410Sstevel@tonic-gate } else if (intcode <= LDTERM_CS_TYPE_UTF8_MAX_P01) {
54420Sstevel@tonic-gate /* Secondary Multilingual Plane. */
54430Sstevel@tonic-gate intcode = intcode & (uint_t)0xffff;
54440Sstevel@tonic-gate i = intcode / 4;
54450Sstevel@tonic-gate j = intcode % 4;
54460Sstevel@tonic-gate switch (j) {
54470Sstevel@tonic-gate case 0:
5448*7012Sis i = ldterm_ucode[1][i].u0;
5449*7012Sis break;
54500Sstevel@tonic-gate case 1:
5451*7012Sis i = ldterm_ucode[1][i].u1;
5452*7012Sis break;
54530Sstevel@tonic-gate case 2:
5454*7012Sis i = ldterm_ucode[1][i].u2;
5455*7012Sis break;
54560Sstevel@tonic-gate case 3:
5457*7012Sis i = ldterm_ucode[1][i].u3;
5458*7012Sis break;
54590Sstevel@tonic-gate }
54600Sstevel@tonic-gate } else if ((intcode >= LDTERM_CS_TYPE_UTF8_MIN_CJKEXTB &&
5461*7012Sis intcode <= LDTERM_CS_TYPE_UTF8_MAX_CJKEXTB) ||
5462*7012Sis (intcode >= LDTERM_CS_TYPE_UTF8_MIN_CJKCOMP &&
5463*7012Sis intcode <= LDTERM_CS_TYPE_UTF8_MAX_CJKCOMP) ||
5464*7012Sis (intcode >= LDTERM_CS_TYPE_UTF8_MIN_P15 &&
5465*7012Sis intcode <= LDTERM_CS_TYPE_UTF8_MAX_P15) ||
5466*7012Sis (intcode >= LDTERM_CS_TYPE_UTF8_MIN_P16 &&
5467*7012Sis intcode <= LDTERM_CS_TYPE_UTF8_MAX_P16)) {
54680Sstevel@tonic-gate /*
54690Sstevel@tonic-gate * Supplementary Plane for CJK Ideographs and
54700Sstevel@tonic-gate * Private Use Planes.
54710Sstevel@tonic-gate */
54720Sstevel@tonic-gate return ('\2');
54730Sstevel@tonic-gate } else if ((intcode >= LDTERM_CS_TYPE_UTF8_MIN_P14 &&
5474*7012Sis intcode <= LDTERM_CS_TYPE_UTF8_MAX_P14) ||
5475*7012Sis (intcode >= LDTERM_CS_TYPE_UTF8_MIN_VARSEL &&
5476*7012Sis intcode <= LDTERM_CS_TYPE_UTF8_MAX_VARSEL)) {
5477*7012Sis /*
5478*7012Sis * Some Special Purpose Plane characters:
5479*7012Sis * These are like control characters and not printable.
5480*7012Sis */
54810Sstevel@tonic-gate return ('\0');
54820Sstevel@tonic-gate }
54830Sstevel@tonic-gate
5484*7012Sis /*
5485*7012Sis * We return the display width of 1 for all character code points
5486*7012Sis * that we didn't catch from the above logic and also for combining
5487*7012Sis * and conjoining characters with width value of zero.
5488*7012Sis *
5489*7012Sis * In particular, the reason why we are returning 1 for combining
5490*7012Sis * and conjoining characters is because the GUI-based terminal
5491*7012Sis * emulators are not yet capable of properly handling such characters
5492*7012Sis * and in most of the cases, they just treat such characters as if
5493*7012Sis * they occupy a display cell. If the terminal emulators are capable of
5494*7012Sis * handling the characters correctly, then, this logic of returning
5495*7012Sis * 1 should be revisited and changed. See CR 6660526 for more
5496*7012Sis * details on this.
5497*7012Sis */
5498*7012Sis return ((i == 0) ? '\1' : (uchar_t)i);
54990Sstevel@tonic-gate }
5500