4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License"). You may not use this file except in compliance
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
23 * Copyright 1999-2002 Sun Microsystems, Inc. All rights reserved.
24 * Use is subject to license terms.
25 * Copyright (c) 2014, Joyent, Inc. All rights reserved.
29 * Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
38 #include <sys/types.h>
41 #include <sys/stermio.h>
42 #include <sys/termiox.h>
44 #include <sys/param.h>
45 #include <sys/stropts.h>
46 #include <sys/eucioctl.h>
47 #include <sys/csiioctl.h>
48 #include <sys/stream.h>
49 #include <sys/termios.h>
50 #include <sys/ldterm.h>
57 static char *s_arg
; /* s_arg: ptr to mode to be set */
60 static int parse_encoded(struct termios
*, ldterm_cs_data_user_t
*, int);
62 static int parse_encoded(struct termios
*);
64 static int eq(const char *string
);
65 static int gct(char *cp
, int term
);
67 /* set terminal modes for supplied options */
69 sttyparse(int argc
, char *argv
[], int term
, struct termio
*ocb
,
70 struct termios
*cb
, struct termiox
*termiox
, struct winsize
*winsize
72 /* */, eucwidth_t
*wp
, struct eucioc
*kwp
, ldterm_cs_data_user_t
*cswp
,
73 ldterm_cs_data_user_t
*kcswp
83 if (eq("erase") && --argc
)
84 cb
->c_cc
[VERASE
] = gct(*++argv
, term
);
85 else if (eq("intr") && --argc
)
86 cb
->c_cc
[VINTR
] = gct(*++argv
, term
);
87 else if (eq("quit") && --argc
)
88 cb
->c_cc
[VQUIT
] = gct(*++argv
, term
);
89 else if (eq("eof") && --argc
)
90 cb
->c_cc
[VEOF
] = gct(*++argv
, term
);
91 else if (eq("min") && --argc
) {
92 if (isdigit((unsigned char)argv
[1][0]))
93 cb
->c_cc
[VMIN
] = atoi(*++argv
);
95 cb
->c_cc
[VMIN
] = gct(*++argv
, term
);
96 } else if (eq("eol") && --argc
)
97 cb
->c_cc
[VEOL
] = gct(*++argv
, term
);
98 else if (eq("eol2") && --argc
)
99 cb
->c_cc
[VEOL2
] = gct(*++argv
, term
);
100 else if (eq("time") && --argc
) {
101 if (isdigit((unsigned char)argv
[1][0]))
102 cb
->c_cc
[VTIME
] = atoi(*++argv
);
104 cb
->c_cc
[VTIME
] = gct(*++argv
, term
);
105 } else if (eq("kill") && --argc
)
106 cb
->c_cc
[VKILL
] = gct(*++argv
, term
);
107 else if (eq("swtch") && --argc
)
108 cb
->c_cc
[VSWTCH
] = gct(*++argv
, term
);
111 if (term
& TERMIOS
) {
112 if (eq("start") && --argc
)
113 cb
->c_cc
[VSTART
] = gct(*++argv
, term
);
114 else if (eq("stop") && --argc
)
115 cb
->c_cc
[VSTOP
] = gct(*++argv
, term
);
116 else if (eq("susp") && --argc
)
117 cb
->c_cc
[VSUSP
] = gct(*++argv
, term
);
118 else if (eq("dsusp") && --argc
)
119 cb
->c_cc
[VDSUSP
] = gct(*++argv
, term
);
120 else if (eq("rprnt") && --argc
)
121 cb
->c_cc
[VREPRINT
] = gct(*++argv
, term
);
122 else if (eq("reprint") && --argc
)
123 cb
->c_cc
[VREPRINT
] = gct(*++argv
, term
);
124 else if (eq("discard") && --argc
)
125 cb
->c_cc
[VDISCARD
] = gct(*++argv
, term
);
126 else if (eq("flush") && --argc
)
127 cb
->c_cc
[VDISCARD
] = gct(*++argv
, term
);
128 else if (eq("werase") && --argc
)
129 cb
->c_cc
[VWERASE
] = gct(*++argv
, term
);
130 else if (eq("lnext") && --argc
)
131 cb
->c_cc
[VLNEXT
] = gct(*++argv
, term
);
132 else if (eq("status") && --argc
)
133 cb
->c_cc
[VSTATUS
] = gct(*++argv
, term
);
134 else if (eq("erase2") && --argc
)
135 cb
->c_cc
[VERASE2
] = gct(*++argv
, term
);
140 cb
->c_cc
[VERASE
] = CERASE
;
142 cb
->c_cc
[VERASE2
] = CERASE2
;
143 cb
->c_cc
[VKILL
] = CKILL
;
144 } else if (eq("line") &&
145 !(term
& TERMIOS
) && --argc
) {
146 ocb
->c_line
= atoi(*++argv
);
148 } else if (eq("raw")) {
151 } else if (eq("-raw") | eq("cooked")) {
152 cb
->c_cc
[VEOF
] = CEOF
;
153 cb
->c_cc
[VEOL
] = CNUL
;
154 } else if (eq("sane")) {
155 cb
->c_cc
[VERASE
] = CERASE
;
157 cb
->c_cc
[VERASE2
] = CERASE2
;
158 cb
->c_cc
[VKILL
] = CKILL
;
159 cb
->c_cc
[VQUIT
] = CQUIT
;
160 cb
->c_cc
[VINTR
] = CINTR
;
161 cb
->c_cc
[VEOF
] = CEOF
;
162 cb
->c_cc
[VEOL
] = CNUL
;
163 cb
->c_cc
[VSTATUS
] = CSTATUS
;
164 /* SWTCH purposely not set */
166 } else if (eq("defeucw")) {
167 kwp
->eucw
[0] = '\001';
169 (unsigned char)(wp
->_eucw1
& 0177);
171 (unsigned char)(wp
->_eucw2
& 0177);
173 (unsigned char)(wp
->_eucw3
& 0177);
175 kwp
->scrw
[0] = '\001';
177 (unsigned char)(wp
->_scrw1
& 0177);
179 (unsigned char)(wp
->_scrw2
& 0177);
181 (unsigned char)(wp
->_scrw3
& 0177);
183 (void) memcpy((void *)kcswp
, (const void *)cswp
,
184 sizeof (ldterm_cs_data_user_t
));
186 } else if ((term
& TERMIOS
) && eq("ospeed") && --argc
) {
188 for (match
= 0, i
= 0; speeds
[i
].string
; i
++) {
189 if (eq(speeds
[i
].string
)) {
190 (void) cfsetospeed(cb
,
199 } else if ((term
& TERMIOS
) && eq("ispeed") && --argc
) {
201 for (match
= 0, i
= 0; speeds
[i
].string
; i
++) {
202 if (eq(speeds
[i
].string
)) {
203 (void) cfsetispeed(cb
,
213 for (match
= 0, i
= 0; speeds
[i
].string
; i
++) {
214 if (eq(speeds
[i
].string
)) {
215 (void) cfsetospeed(cb
,
217 (void) cfsetispeed(cb
,
224 if (!(term
& ASYNC
) && eq("ctab") && --argc
) {
225 cb
->c_cc
[7] = gct(*++argv
, term
);
229 for (i
= 0; imodes
[i
].string
; i
++)
230 if (eq(imodes
[i
].string
)) {
231 cb
->c_iflag
&= ~imodes
[i
].reset
;
232 cb
->c_iflag
|= imodes
[i
].set
;
234 if (wp
->_multibyte
&&
235 (eq("-raw") || eq("cooked") || eq("sane")))
236 cb
->c_iflag
&= ~ISTRIP
;
239 if (term
& TERMIOS
) {
240 for (i
= 0; nimodes
[i
].string
; i
++)
241 if (eq(nimodes
[i
].string
)) {
242 cb
->c_iflag
&= ~nimodes
[i
].reset
;
243 cb
->c_iflag
|= nimodes
[i
].set
;
247 for (i
= 0; omodes
[i
].string
; i
++)
248 if (eq(omodes
[i
].string
)) {
249 cb
->c_oflag
&= ~omodes
[i
].reset
;
250 cb
->c_oflag
|= omodes
[i
].set
;
252 if (!(term
& ASYNC
) && eq("sane")) {
256 for (i
= 0; cmodes
[i
].string
; i
++)
257 if (eq(cmodes
[i
].string
)) {
258 cb
->c_cflag
&= ~cmodes
[i
].reset
;
259 cb
->c_cflag
|= cmodes
[i
].set
;
261 if (wp
->_multibyte
&&
262 (eq("-raw") || eq("cooked") ||
264 cb
->c_cflag
&= ~(CS7
|PARENB
);
270 for (i
= 0; ncmodes
[i
].string
; i
++)
271 if (eq(ncmodes
[i
].string
)) {
272 cb
->c_cflag
&= ~ncmodes
[i
].reset
;
273 cb
->c_cflag
|= ncmodes
[i
].set
;
275 for (i
= 0; lmodes
[i
].string
; i
++)
276 if (eq(lmodes
[i
].string
)) {
277 cb
->c_lflag
&= ~lmodes
[i
].reset
;
278 cb
->c_lflag
|= lmodes
[i
].set
;
281 for (i
= 0; nlmodes
[i
].string
; i
++)
282 if (eq(nlmodes
[i
].string
)) {
283 cb
->c_lflag
&= ~nlmodes
[i
].reset
;
284 cb
->c_lflag
|= nlmodes
[i
].set
;
287 for (i
= 0; hmodes
[i
].string
; i
++)
288 if (eq(hmodes
[i
].string
)) {
289 termiox
->x_hflag
&= ~hmodes
[i
].reset
;
290 termiox
->x_hflag
|= hmodes
[i
].set
;
292 for (i
= 0; clkmodes
[i
].string
; i
++)
293 if (eq(clkmodes
[i
].string
)) {
294 termiox
->x_cflag
&= ~clkmodes
[i
].reset
;
295 termiox
->x_cflag
|= clkmodes
[i
].set
;
300 if (eq("rows") && --argc
)
301 winsize
->ws_row
= atoi(*++argv
);
302 else if ((eq("columns") || eq("cols")) && --argc
)
303 winsize
->ws_col
= atoi(*++argv
);
304 else if (eq("xpixels") && --argc
)
305 winsize
->ws_xpixel
= atoi(*++argv
);
306 else if (eq("ypixels") && --argc
)
307 winsize
->ws_ypixel
= atoi(*++argv
);
311 if (!parse_encoded(cb
, kcswp
, term
)) {
313 if (!parse_encoded(cb
)) {
315 return (s_arg
); /* parsing failed */
323 eq(const char *string
)
331 if (s_arg
[i
] != string
[i
])
333 if (s_arg
[i
++] != '\0')
339 /* get pseudo control characters from terminal */
340 /* and convert to internal representation */
342 gct(char *cp
, int term
)
350 c
= 0177; /* map '^?' to 0177 */
352 /* map '^-' to undefined */
353 c
= (term
& TERMIOS
) ? _POSIX_VDISABLE
: 0200;
356 } else if (strcmp(cp
, "undef") == 0) {
357 /* map "undef" to undefined */
358 c
= (term
& TERMIOS
) ? _POSIX_VDISABLE
: 0200;
363 /* get modes of tty device and fill in applicable structures */
365 get_ttymode(int fd
, struct termio
*termio
, struct termios
*termios
,
366 struct stio
*stermio
, struct termiox
*termiox
, struct winsize
*winsize
368 /* */, struct eucioc
*kwp
, ldterm_cs_data_user_t
*kcswp
377 if (ioctl(fd
, STGET
, stermio
) == -1) {
379 if (ioctl(fd
, TCGETS
, termios
) == -1) {
380 if (ioctl(fd
, TCGETA
, termio
) == -1)
382 termios
->c_lflag
= termio
->c_lflag
;
383 termios
->c_oflag
= termio
->c_oflag
;
384 termios
->c_iflag
= termio
->c_iflag
;
385 termios
->c_cflag
= termio
->c_cflag
;
386 for (i
= 0; i
< NCC
; i
++)
387 termios
->c_cc
[i
] = termio
->c_cc
[i
];
391 termios
->c_cc
[7] = (unsigned)stermio
->tab
;
392 termios
->c_lflag
= stermio
->lmode
;
393 termios
->c_oflag
= stermio
->omode
;
394 termios
->c_iflag
= stermio
->imode
;
397 if (ioctl(fd
, TCGETX
, termiox
) == 0)
400 if (ioctl(fd
, TIOCGWINSZ
, winsize
) == 0)
403 cmd
.ic_cmd
= EUC_WGET
;
405 cmd
.ic_len
= sizeof (struct eucioc
);
406 cmd
.ic_dp
= (char *)kwp
;
408 if (ioctl(fd
, I_STR
, &cmd
) == 0)
411 cmd
.ic_cmd
= CSDATA_GET
;
413 cmd
.ic_len
= sizeof (ldterm_cs_data_user_t
);
414 cmd
.ic_dp
= (char *)kcswp
;
416 if (ioctl(fd
, I_STR
, &cmd
) == 0)
419 (void) memset((void *)kcswp
, 0, sizeof (ldterm_cs_data_user_t
));
426 set_ttymode(int fd
, int term
, struct termio
*termio
, struct termios
*termios
,
427 struct stio
*stermio
, struct termiox
*termiox
, struct winsize
*winsize
,
428 struct winsize
*owinsize
430 /* */, struct eucioc
*kwp
, ldterm_cs_data_user_t
*kcswp
,
431 int invalid_ldterm_dat_file
441 if (term
& TERMIOS
) {
442 if (ioctl(fd
, TCSETSW
, termios
) == -1)
445 termio
->c_lflag
= termios
->c_lflag
;
446 termio
->c_oflag
= termios
->c_oflag
;
447 termio
->c_iflag
= termios
->c_iflag
;
448 termio
->c_cflag
= termios
->c_cflag
;
449 for (i
= 0; i
< NCC
; i
++)
450 termio
->c_cc
[i
] = termios
->c_cc
[i
];
451 if (ioctl(fd
, TCSETAW
, termio
) == -1)
456 stermio
->imode
= termios
->c_iflag
;
457 stermio
->omode
= termios
->c_oflag
;
458 stermio
->lmode
= termios
->c_lflag
;
459 stermio
->tab
= termios
->c_cc
[7];
460 if (ioctl(fd
, STSET
, stermio
) == -1)
464 if (ioctl(fd
, TCSETXW
, termiox
) == -1)
467 if ((owinsize
->ws_col
!= winsize
->ws_col
||
468 owinsize
->ws_row
!= winsize
->ws_row
||
469 owinsize
->ws_xpixel
!= winsize
->ws_xpixel
||
470 owinsize
->ws_ypixel
!= winsize
->ws_ypixel
) &&
471 ioctl(0, TIOCSWINSZ
, winsize
) != 0)
475 * If the ldterm.dat file contains valid, non-EUC codeset info,
476 * send downstream CSDATA_SET. Otherwise, try EUC_WSET.
478 if (invalid_ldterm_dat_file
) {
479 (void) fprintf(stderr
, gettext(
480 "stty: can't set codeset width due to invalid ldterm.dat.\n"));
482 } else if ((term
& CSIW
) && kcswp
->version
) {
483 cmd
.ic_cmd
= CSDATA_SET
;
485 cmd
.ic_len
= sizeof (ldterm_cs_data_user_t
);
486 cmd
.ic_dp
= (char *)kcswp
;
487 if (ioctl(fd
, I_STR
, &cmd
) != 0) {
488 (void) fprintf(stderr
, gettext(
489 "stty: can't set codeset width.\n"));
492 } else if (term
& EUCW
) {
493 cmd
.ic_cmd
= EUC_WSET
;
495 cmd
.ic_len
= sizeof (struct eucioc
);
496 cmd
.ic_dp
= (char *)kwp
;
497 if (ioctl(fd
, I_STR
, &cmd
) != 0) {
498 (void) fprintf(stderr
, gettext(
499 "stty: can't set EUC codeset width.\n"));
508 parse_encoded(struct termios
*cb
510 /* */, ldterm_cs_data_user_t
*kcswp
, int term
514 unsigned long grab
[NUM_FIELDS
];
522 ldterm_cs_data_user_t ecswp
;
526 * Although there are only 16 control chars defined as of April 1995,
527 * parse_encoded() and prencode() will not have to be changed if up to
528 * MAX_CC control chars are defined in the future.
529 * Scan the fields of "stty -g" output into the grab array.
530 * Set a total of NUM_FIELDS fields (NUM_MODES modes + MAX_CC
533 i
= sscanf(s_arg
, "%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:"
534 "%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx",
535 &grab
[0], &grab
[1], &grab
[2], &grab
[3], &grab
[4], &grab
[5],
536 &grab
[6], &grab
[7], &grab
[8], &grab
[9], &grab
[10], &grab
[11],
537 &grab
[12], &grab
[13], &grab
[14], &grab
[15], &grab
[16], &grab
[17],
538 &grab
[18], &grab
[19], &grab
[20], &grab
[21]);
542 cb
->c_iflag
= grab
[0];
543 cb
->c_oflag
= grab
[1];
544 cb
->c_cflag
= grab
[2];
545 cb
->c_lflag
= grab
[3];
547 last
= i
- NUM_MODES
;
548 for (i
= 0; i
< last
; i
++)
549 cb
->c_cc
[i
] = (unsigned char) grab
[i
+NUM_MODES
];
552 /* This is to fulfill PSARC/1999/140 TCR2. */
555 if (r
== (char *)NULL
) {
556 (void) fprintf(stderr
, gettext(
557 "no more memory - try again later\n"));
561 for (i
= 0; t
!= NULL
&& i
< 22; i
++) {
562 t
= strtok(NULL
, ":");
569 ecswp
.version
= (uchar_t
)strtol(t
, (char **)NULL
, 16);
570 if (ecswp
.version
> LDTERM_DATA_VERSION
||
571 ecswp
.version
== 0) {
576 if ((t
= strtok(NULL
, ":")) == NULL
) {
580 ecswp
.codeset_type
= (uchar_t
)strtol(t
, (char **)NULL
, 16);
581 if (ecswp
.codeset_type
< LDTERM_CS_TYPE_MIN
||
582 ecswp
.codeset_type
> LDTERM_CS_TYPE_MAX
) {
587 if ((t
= strtok(NULL
, ":")) == NULL
) {
591 ecswp
.csinfo_num
= (uchar_t
)strtol(t
, (char **)NULL
, 16);
592 if ((ecswp
.codeset_type
== LDTERM_CS_TYPE_EUC
&&
593 ecswp
.csinfo_num
> 3) ||
594 (ecswp
.codeset_type
== LDTERM_CS_TYPE_PCCS
&&
595 (ecswp
.csinfo_num
< 1 || ecswp
.csinfo_num
> 10))) {
600 if ((t
= strtok(NULL
, ":")) == NULL
) {
605 for (i
= 0; *t
!= 0 && i
< MAXNAMELEN
; i
++) {
606 if (*(t
+ 1) == (char)NULL
) {
612 ecswp
.locale_name
[i
] = (char)strtol(s
, (char **)NULL
,
615 if (i
>= MAXNAMELEN
) {
619 ecswp
.locale_name
[i
] = '\0';
621 g
= (uchar_t
*)ecswp
.eucpc_data
;
622 for (i
= 0; i
< (LDTERM_CS_MAX_CODESETS
* 4); i
++) {
623 if ((t
= strtok(NULL
, ":")) == NULL
) {
627 l
= strtol(t
, (char **)NULL
, 16);
628 if (l
< 0 || l
> 255) {
635 /* We got the 'ecswp' all filled up now; let's copy. */
636 (void) memcpy((void *)kcswp
, (const void *)&ecswp
,
637 sizeof (ldterm_cs_data_user_t
));