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