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] || c == tp->t_modes.c_cc[VERASE2]) {
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 }