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