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