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