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 if (eq("erase2") && --argc
)
86 cb
->c_cc
[VERASE2
] = gct(*++argv
, term
);
87 else if (eq("intr") && --argc
)
88 cb
->c_cc
[VINTR
] = gct(*++argv
, term
);
89 else if (eq("quit") && --argc
)
90 cb
->c_cc
[VQUIT
] = gct(*++argv
, term
);
91 else if (eq("eof") && --argc
)
92 cb
->c_cc
[VEOF
] = gct(*++argv
, term
);
93 else if (eq("min") && --argc
) {
94 if (isdigit((unsigned char)argv
[1][0]))
95 cb
->c_cc
[VMIN
] = atoi(*++argv
);
97 cb
->c_cc
[VMIN
] = gct(*++argv
, term
);
98 } else if (eq("eol") && --argc
)
99 cb
->c_cc
[VEOL
] = gct(*++argv
, term
);
100 else if (eq("eol2") && --argc
)
101 cb
->c_cc
[VEOL2
] = gct(*++argv
, term
);
102 else if (eq("time") && --argc
) {
103 if (isdigit((unsigned char)argv
[1][0]))
104 cb
->c_cc
[VTIME
] = atoi(*++argv
);
106 cb
->c_cc
[VTIME
] = gct(*++argv
, term
);
107 } else if (eq("kill") && --argc
)
108 cb
->c_cc
[VKILL
] = gct(*++argv
, term
);
109 else if (eq("swtch") && --argc
)
110 cb
->c_cc
[VSWTCH
] = gct(*++argv
, term
);
113 if (term
& TERMIOS
) {
114 if (eq("start") && --argc
)
115 cb
->c_cc
[VSTART
] = gct(*++argv
, term
);
116 else if (eq("stop") && --argc
)
117 cb
->c_cc
[VSTOP
] = gct(*++argv
, term
);
118 else if (eq("susp") && --argc
)
119 cb
->c_cc
[VSUSP
] = gct(*++argv
, term
);
120 else if (eq("dsusp") && --argc
)
121 cb
->c_cc
[VDSUSP
] = gct(*++argv
, term
);
122 else if (eq("rprnt") && --argc
)
123 cb
->c_cc
[VREPRINT
] = gct(*++argv
, term
);
124 else if (eq("reprint") && --argc
)
125 cb
->c_cc
[VREPRINT
] = gct(*++argv
, term
);
126 else if (eq("discard") && --argc
)
127 cb
->c_cc
[VDISCARD
] = gct(*++argv
, term
);
128 else if (eq("flush") && --argc
)
129 cb
->c_cc
[VDISCARD
] = gct(*++argv
, term
);
130 else if (eq("werase") && --argc
)
131 cb
->c_cc
[VWERASE
] = gct(*++argv
, term
);
132 else if (eq("lnext") && --argc
)
133 cb
->c_cc
[VLNEXT
] = gct(*++argv
, term
);
134 else if (eq("status") && --argc
)
135 cb
->c_cc
[VSTATUS
] = gct(*++argv
, term
);
136 else if (eq("erase2") && --argc
)
137 cb
->c_cc
[VERASE2
] = gct(*++argv
, term
);
142 cb
->c_cc
[VERASE
] = CERASE
;
144 cb
->c_cc
[VERASE2
] = CERASE2
;
145 cb
->c_cc
[VKILL
] = CKILL
;
146 } else if (eq("line") &&
147 !(term
& TERMIOS
) && --argc
) {
148 ocb
->c_line
= atoi(*++argv
);
150 } else if (eq("raw")) {
153 } else if (eq("-raw") | eq("cooked")) {
154 cb
->c_cc
[VEOF
] = CEOF
;
155 cb
->c_cc
[VEOL
] = CNUL
;
156 } else if (eq("sane")) {
157 cb
->c_cc
[VERASE
] = CERASE
;
159 cb
->c_cc
[VERASE2
] = CERASE2
;
160 cb
->c_cc
[VKILL
] = CKILL
;
161 cb
->c_cc
[VQUIT
] = CQUIT
;
162 cb
->c_cc
[VINTR
] = CINTR
;
163 cb
->c_cc
[VEOF
] = CEOF
;
164 cb
->c_cc
[VEOL
] = CNUL
;
165 cb
->c_cc
[VSTATUS
] = CSTATUS
;
166 /* SWTCH purposely not set */
168 } else if (eq("defeucw")) {
169 kwp
->eucw
[0] = '\001';
171 (unsigned char)(wp
->_eucw1
& 0177);
173 (unsigned char)(wp
->_eucw2
& 0177);
175 (unsigned char)(wp
->_eucw3
& 0177);
177 kwp
->scrw
[0] = '\001';
179 (unsigned char)(wp
->_scrw1
& 0177);
181 (unsigned char)(wp
->_scrw2
& 0177);
183 (unsigned char)(wp
->_scrw3
& 0177);
185 (void) memcpy((void *)kcswp
, (const void *)cswp
,
186 sizeof (ldterm_cs_data_user_t
));
188 } else if ((term
& TERMIOS
) && eq("ospeed") && --argc
) {
190 for (match
= 0, i
= 0; speeds
[i
].string
; i
++) {
191 if (eq(speeds
[i
].string
)) {
192 (void) cfsetospeed(cb
,
201 } else if ((term
& TERMIOS
) && eq("ispeed") && --argc
) {
203 for (match
= 0, i
= 0; speeds
[i
].string
; i
++) {
204 if (eq(speeds
[i
].string
)) {
205 (void) cfsetispeed(cb
,
215 for (match
= 0, i
= 0; speeds
[i
].string
; i
++) {
216 if (eq(speeds
[i
].string
)) {
217 (void) cfsetospeed(cb
,
219 (void) cfsetispeed(cb
,
226 if (!(term
& ASYNC
) && eq("ctab") && --argc
) {
227 cb
->c_cc
[7] = gct(*++argv
, term
);
231 for (i
= 0; imodes
[i
].string
; i
++)
232 if (eq(imodes
[i
].string
)) {
233 cb
->c_iflag
&= ~imodes
[i
].reset
;
234 cb
->c_iflag
|= imodes
[i
].set
;
236 if (wp
->_multibyte
&&
237 (eq("-raw") || eq("cooked") || eq("sane")))
238 cb
->c_iflag
&= ~ISTRIP
;
241 if (term
& TERMIOS
) {
242 for (i
= 0; nimodes
[i
].string
; i
++)
243 if (eq(nimodes
[i
].string
)) {
244 cb
->c_iflag
&= ~nimodes
[i
].reset
;
245 cb
->c_iflag
|= nimodes
[i
].set
;
249 for (i
= 0; omodes
[i
].string
; i
++)
250 if (eq(omodes
[i
].string
)) {
251 cb
->c_oflag
&= ~omodes
[i
].reset
;
252 cb
->c_oflag
|= omodes
[i
].set
;
254 if (!(term
& ASYNC
) && eq("sane")) {
258 for (i
= 0; cmodes
[i
].string
; i
++)
259 if (eq(cmodes
[i
].string
)) {
260 cb
->c_cflag
&= ~cmodes
[i
].reset
;
261 cb
->c_cflag
|= cmodes
[i
].set
;
263 if (wp
->_multibyte
&&
264 (eq("-raw") || eq("cooked") ||
266 cb
->c_cflag
&= ~(CS7
|PARENB
);
272 for (i
= 0; ncmodes
[i
].string
; i
++)
273 if (eq(ncmodes
[i
].string
)) {
274 cb
->c_cflag
&= ~ncmodes
[i
].reset
;
275 cb
->c_cflag
|= ncmodes
[i
].set
;
277 for (i
= 0; lmodes
[i
].string
; i
++)
278 if (eq(lmodes
[i
].string
)) {
279 cb
->c_lflag
&= ~lmodes
[i
].reset
;
280 cb
->c_lflag
|= lmodes
[i
].set
;
283 for (i
= 0; nlmodes
[i
].string
; i
++)
284 if (eq(nlmodes
[i
].string
)) {
285 cb
->c_lflag
&= ~nlmodes
[i
].reset
;
286 cb
->c_lflag
|= nlmodes
[i
].set
;
289 for (i
= 0; hmodes
[i
].string
; i
++)
290 if (eq(hmodes
[i
].string
)) {
291 termiox
->x_hflag
&= ~hmodes
[i
].reset
;
292 termiox
->x_hflag
|= hmodes
[i
].set
;
294 for (i
= 0; clkmodes
[i
].string
; i
++)
295 if (eq(clkmodes
[i
].string
)) {
296 termiox
->x_cflag
&= ~clkmodes
[i
].reset
;
297 termiox
->x_cflag
|= clkmodes
[i
].set
;
302 if (eq("rows") && --argc
)
303 winsize
->ws_row
= atoi(*++argv
);
304 else if ((eq("columns") || eq("cols")) && --argc
)
305 winsize
->ws_col
= atoi(*++argv
);
306 else if (eq("xpixels") && --argc
)
307 winsize
->ws_xpixel
= atoi(*++argv
);
308 else if (eq("ypixels") && --argc
)
309 winsize
->ws_ypixel
= atoi(*++argv
);
313 if (!parse_encoded(cb
, kcswp
, term
)) {
315 if (!parse_encoded(cb
)) {
317 return (s_arg
); /* parsing failed */
325 eq(const char *string
)
333 if (s_arg
[i
] != string
[i
])
335 if (s_arg
[i
++] != '\0')
341 /* get pseudo control characters from terminal */
342 /* and convert to internal representation */
344 gct(char *cp
, int term
)
352 c
= 0177; /* map '^?' to 0177 */
354 /* map '^-' to undefined */
355 c
= (term
& TERMIOS
) ? _POSIX_VDISABLE
: 0200;
358 } else if (strcmp(cp
, "undef") == 0) {
359 /* map "undef" to undefined */
360 c
= (term
& TERMIOS
) ? _POSIX_VDISABLE
: 0200;
365 /* get modes of tty device and fill in applicable structures */
367 get_ttymode(int fd
, struct termio
*termio
, struct termios
*termios
,
368 struct stio
*stermio
, struct termiox
*termiox
, struct winsize
*winsize
370 /* */, struct eucioc
*kwp
, ldterm_cs_data_user_t
*kcswp
379 if (ioctl(fd
, STGET
, stermio
) == -1) {
381 if (ioctl(fd
, TCGETS
, termios
) == -1) {
382 if (ioctl(fd
, TCGETA
, termio
) == -1)
384 termios
->c_lflag
= termio
->c_lflag
;
385 termios
->c_oflag
= termio
->c_oflag
;
386 termios
->c_iflag
= termio
->c_iflag
;
387 termios
->c_cflag
= termio
->c_cflag
;
388 for (i
= 0; i
< NCC
; i
++)
389 termios
->c_cc
[i
] = termio
->c_cc
[i
];
393 termios
->c_cc
[7] = (unsigned)stermio
->tab
;
394 termios
->c_lflag
= stermio
->lmode
;
395 termios
->c_oflag
= stermio
->omode
;
396 termios
->c_iflag
= stermio
->imode
;
399 if (ioctl(fd
, TCGETX
, termiox
) == 0)
402 if (ioctl(fd
, TIOCGWINSZ
, winsize
) == 0)
405 cmd
.ic_cmd
= EUC_WGET
;
407 cmd
.ic_len
= sizeof (struct eucioc
);
408 cmd
.ic_dp
= (char *)kwp
;
410 if (ioctl(fd
, I_STR
, &cmd
) == 0)
413 cmd
.ic_cmd
= CSDATA_GET
;
415 cmd
.ic_len
= sizeof (ldterm_cs_data_user_t
);
416 cmd
.ic_dp
= (char *)kcswp
;
418 if (ioctl(fd
, I_STR
, &cmd
) == 0)
421 (void) memset(kcswp
, 0, sizeof (ldterm_cs_data_user_t
));
428 set_ttymode(int fd
, int term
, struct termio
*termio
, struct termios
*termios
,
429 struct stio
*stermio
, struct termiox
*termiox
, struct winsize
*winsize
,
430 struct winsize
*owinsize
432 /* */, struct eucioc
*kwp
, ldterm_cs_data_user_t
*kcswp
,
433 int invalid_ldterm_dat_file
443 if (term
& TERMIOS
) {
444 if (ioctl(fd
, TCSETSW
, termios
) == -1)
447 termio
->c_lflag
= termios
->c_lflag
;
448 termio
->c_oflag
= termios
->c_oflag
;
449 termio
->c_iflag
= termios
->c_iflag
;
450 termio
->c_cflag
= termios
->c_cflag
;
451 for (i
= 0; i
< NCC
; i
++)
452 termio
->c_cc
[i
] = termios
->c_cc
[i
];
453 if (ioctl(fd
, TCSETAW
, termio
) == -1)
458 stermio
->imode
= termios
->c_iflag
;
459 stermio
->omode
= termios
->c_oflag
;
460 stermio
->lmode
= termios
->c_lflag
;
461 stermio
->tab
= termios
->c_cc
[7];
462 if (ioctl(fd
, STSET
, stermio
) == -1)
466 if (ioctl(fd
, TCSETXW
, termiox
) == -1)
469 if ((owinsize
->ws_col
!= winsize
->ws_col
||
470 owinsize
->ws_row
!= winsize
->ws_row
||
471 owinsize
->ws_xpixel
!= winsize
->ws_xpixel
||
472 owinsize
->ws_ypixel
!= winsize
->ws_ypixel
) &&
473 ioctl(0, TIOCSWINSZ
, winsize
) != 0)
477 * If the ldterm.dat file contains valid, non-EUC codeset info,
478 * send downstream CSDATA_SET. Otherwise, try EUC_WSET.
480 if (invalid_ldterm_dat_file
) {
481 (void) fprintf(stderr
, gettext(
482 "stty: can't set codeset width due to invalid ldterm.dat.\n"));
484 } else if ((term
& CSIW
) && kcswp
->version
) {
485 cmd
.ic_cmd
= CSDATA_SET
;
487 cmd
.ic_len
= sizeof (ldterm_cs_data_user_t
);
488 cmd
.ic_dp
= (char *)kcswp
;
489 if (ioctl(fd
, I_STR
, &cmd
) != 0) {
490 (void) fprintf(stderr
, gettext(
491 "stty: can't set codeset width.\n"));
494 } else if (term
& EUCW
) {
495 cmd
.ic_cmd
= EUC_WSET
;
497 cmd
.ic_len
= sizeof (struct eucioc
);
498 cmd
.ic_dp
= (char *)kwp
;
499 if (ioctl(fd
, I_STR
, &cmd
) != 0) {
500 (void) fprintf(stderr
, gettext(
501 "stty: can't set EUC codeset width.\n"));
510 parse_encoded(struct termios
*cb
512 /* */, ldterm_cs_data_user_t
*kcswp
, int term
516 unsigned long grab
[NUM_FIELDS
];
524 ldterm_cs_data_user_t ecswp
;
528 * Although there are only 16 control chars defined as of April 1995,
529 * parse_encoded() and prencode() will not have to be changed if up to
530 * MAX_CC control chars are defined in the future.
531 * Scan the fields of "stty -g" output into the grab array.
532 * Set a total of NUM_FIELDS fields (NUM_MODES modes + MAX_CC
535 i
= sscanf(s_arg
, "%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:"
536 "%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx:%lx",
537 &grab
[0], &grab
[1], &grab
[2], &grab
[3], &grab
[4], &grab
[5],
538 &grab
[6], &grab
[7], &grab
[8], &grab
[9], &grab
[10], &grab
[11],
539 &grab
[12], &grab
[13], &grab
[14], &grab
[15], &grab
[16], &grab
[17],
540 &grab
[18], &grab
[19], &grab
[20], &grab
[21]);
544 cb
->c_iflag
= grab
[0];
545 cb
->c_oflag
= grab
[1];
546 cb
->c_cflag
= grab
[2];
547 cb
->c_lflag
= grab
[3];
549 last
= i
- NUM_MODES
;
550 for (i
= 0; i
< last
; i
++)
551 cb
->c_cc
[i
] = (unsigned char) grab
[i
+NUM_MODES
];
554 /* This is to fulfill PSARC/1999/140 TCR2. */
558 (void) fprintf(stderr
, gettext(
559 "no more memory - try again later\n"));
563 for (i
= 0; t
!= NULL
&& i
< 22; i
++) {
564 t
= strtok(NULL
, ":");
571 ecswp
.version
= (uchar_t
)strtol(t
, (char **)NULL
, 16);
572 if (ecswp
.version
> LDTERM_DATA_VERSION
||
573 ecswp
.version
== 0) {
578 if ((t
= strtok(NULL
, ":")) == NULL
) {
582 ecswp
.codeset_type
= (uchar_t
)strtol(t
, (char **)NULL
, 16);
583 if (ecswp
.codeset_type
< LDTERM_CS_TYPE_MIN
||
584 ecswp
.codeset_type
> LDTERM_CS_TYPE_MAX
) {
589 if ((t
= strtok(NULL
, ":")) == NULL
) {
593 ecswp
.csinfo_num
= (uchar_t
)strtol(t
, (char **)NULL
, 16);
594 if ((ecswp
.codeset_type
== LDTERM_CS_TYPE_EUC
&&
595 ecswp
.csinfo_num
> 3) ||
596 (ecswp
.codeset_type
== LDTERM_CS_TYPE_PCCS
&&
597 (ecswp
.csinfo_num
< 1 || ecswp
.csinfo_num
> 10))) {
602 if ((t
= strtok(NULL
, ":")) == NULL
) {
607 for (i
= 0; *t
!= 0 && i
< MAXNAMELEN
; i
++) {
608 if (*(t
+ 1) == '\0') {
614 ecswp
.locale_name
[i
] = (char)strtol(s
, (char **)NULL
,
617 if (i
>= MAXNAMELEN
) {
621 ecswp
.locale_name
[i
] = '\0';
623 g
= (uchar_t
*)ecswp
.eucpc_data
;
624 for (i
= 0; i
< (LDTERM_CS_MAX_CODESETS
* 4); i
++) {
625 if ((t
= strtok(NULL
, ":")) == NULL
) {
629 l
= strtol(t
, (char **)NULL
, 16);
630 if (l
< 0 || l
> 255) {
637 /* We got the 'ecswp' all filled up now; let's copy. */
638 (void) memcpy((void *)kcswp
, (const void *)&ecswp
,
639 sizeof (ldterm_cs_data_user_t
));