libuutil: move under bmake
[unleashed.git] / usr / src / cmd / ttymon / sttyparse.c
blob564969c87fe374f65b42d69b7cdfdf38de3e8b7a
1 /*
2 * CDDL HEADER START
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
7 * with the License.
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]
20 * CDDL HEADER END
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
30 * All Rights Reserved
34 #include <stdio.h>
35 #include <unistd.h>
36 #include <stdlib.h>
37 #include <libintl.h>
38 #include <sys/types.h>
39 #include <ctype.h>
40 #include <termio.h>
41 #include <sys/stermio.h>
42 #include <sys/termiox.h>
43 #ifdef EUC
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>
51 #include <getwidth.h>
52 #endif /* EUC */
53 #include "stty.h"
54 #include <locale.h>
55 #include <string.h>
57 static char *s_arg; /* s_arg: ptr to mode to be set */
58 static int match;
59 #ifdef EUC
60 static int parse_encoded(struct termios *, ldterm_cs_data_user_t *, int);
61 #else
62 static int parse_encoded(struct termios *);
63 #endif /* EUC */
64 static int eq(const char *string);
65 static int gct(char *cp, int term);
67 /* set terminal modes for supplied options */
68 char *
69 sttyparse(int argc, char *argv[], int term, struct termio *ocb,
70 struct termios *cb, struct termiox *termiox, struct winsize *winsize
71 #ifdef EUC
72 /* */, eucwidth_t *wp, struct eucioc *kwp, ldterm_cs_data_user_t *cswp,
73 ldterm_cs_data_user_t *kcswp
74 #endif /* EUC */
75 /* */)
77 int i;
79 while (--argc > 0) {
80 s_arg = *++argv;
81 match = 0;
82 if (term & ASYNC) {
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);
96 else
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);
105 else
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);
111 if (match)
112 continue;
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);
139 if (match)
140 continue;
141 if (eq("ek")) {
142 cb->c_cc[VERASE] = CERASE;
143 if (term & TERMIOS)
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);
149 continue;
150 } else if (eq("raw")) {
151 cb->c_cc[VMIN] = 1;
152 cb->c_cc[VTIME] = 0;
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;
158 if (term & TERMIOS)
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 */
167 #ifdef EUC
168 } else if (eq("defeucw")) {
169 kwp->eucw[0] = '\001';
170 kwp->eucw[1] =
171 (unsigned char)(wp->_eucw1 & 0177);
172 kwp->eucw[2] =
173 (unsigned char)(wp->_eucw2 & 0177);
174 kwp->eucw[3] =
175 (unsigned char)(wp->_eucw3 & 0177);
177 kwp->scrw[0] = '\001';
178 kwp->scrw[1] =
179 (unsigned char)(wp->_scrw1 & 0177);
180 kwp->scrw[2] =
181 (unsigned char)(wp->_scrw2 & 0177);
182 kwp->scrw[3] =
183 (unsigned char)(wp->_scrw3 & 0177);
185 (void) memcpy((void *)kcswp, (const void *)cswp,
186 sizeof (ldterm_cs_data_user_t));
187 #endif /* EUC */
188 } else if ((term & TERMIOS) && eq("ospeed") && --argc) {
189 s_arg = *++argv;
190 for (match = 0, i = 0; speeds[i].string; i++) {
191 if (eq(speeds[i].string)) {
192 (void) cfsetospeed(cb,
193 speeds[i].code);
194 break;
197 if (!match)
198 return (s_arg);
199 continue;
201 } else if ((term & TERMIOS) && eq("ispeed") && --argc) {
202 s_arg = *++argv;
203 for (match = 0, i = 0; speeds[i].string; i++) {
204 if (eq(speeds[i].string)) {
205 (void) cfsetispeed(cb,
206 speeds[i].code);
207 break;
210 if (!match)
211 return (s_arg);
212 continue;
214 } else {
215 for (match = 0, i = 0; speeds[i].string; i++) {
216 if (eq(speeds[i].string)) {
217 (void) cfsetospeed(cb,
218 speeds[i].code);
219 (void) cfsetispeed(cb,
220 speeds[i].code);
221 break;
226 if (!(term & ASYNC) && eq("ctab") && --argc) {
227 cb->c_cc[7] = gct(*++argv, term);
228 continue;
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;
235 #ifdef EUC
236 if (wp->_multibyte &&
237 (eq("-raw") || eq("cooked") || eq("sane")))
238 cb->c_iflag &= ~ISTRIP;
239 #endif /* EUC */
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")) {
255 cb->c_oflag |= TAB3;
256 continue;
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;
262 #ifdef EUC
263 if (wp->_multibyte &&
264 (eq("-raw") || eq("cooked") ||
265 eq("sane"))) {
266 cb->c_cflag &= ~(CS7|PARENB);
267 cb->c_cflag |= CS8;
269 #endif /* EUC */
271 if (term & TERMIOS)
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;
282 if (term & TERMIOS)
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;
288 if (term & FLOW) {
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);
311 if (!match) {
312 #ifdef EUC
313 if (!parse_encoded(cb, kcswp, term)) {
314 #else
315 if (!parse_encoded(cb)) {
316 #endif /* EUC */
317 return (s_arg); /* parsing failed */
321 return (NULL);
324 static int
325 eq(const char *string)
327 int i;
329 if (!s_arg)
330 return (0);
331 i = 0;
332 loop:
333 if (s_arg[i] != string[i])
334 return (0);
335 if (s_arg[i++] != '\0')
336 goto loop;
337 match++;
338 return (1);
341 /* get pseudo control characters from terminal */
342 /* and convert to internal representation */
343 static int
344 gct(char *cp, int term)
346 int c;
348 c = *cp;
349 if (c == '^') {
350 c = *++cp;
351 if (c == '?')
352 c = 0177; /* map '^?' to 0177 */
353 else if (c == '-') {
354 /* map '^-' to undefined */
355 c = (term & TERMIOS) ? _POSIX_VDISABLE : 0200;
356 } else
357 c &= 037;
358 } else if (strcmp(cp, "undef") == 0) {
359 /* map "undef" to undefined */
360 c = (term & TERMIOS) ? _POSIX_VDISABLE : 0200;
362 return (c);
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
369 #ifdef EUC
370 /* */, struct eucioc *kwp, ldterm_cs_data_user_t *kcswp
371 #endif /* EUC */
372 /* */)
374 int i;
375 int term = 0;
376 #ifdef EUC
377 struct strioctl cmd;
378 #endif /* EUC */
379 if (ioctl(fd, STGET, stermio) == -1) {
380 term |= ASYNC;
381 if (ioctl(fd, TCGETS, termios) == -1) {
382 if (ioctl(fd, TCGETA, termio) == -1)
383 return (-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];
390 } else
391 term |= TERMIOS;
392 } else {
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)
400 term |= FLOW;
402 if (ioctl(fd, TIOCGWINSZ, winsize) == 0)
403 term |= WINDOW;
404 #ifdef EUC
405 cmd.ic_cmd = EUC_WGET;
406 cmd.ic_timout = 0;
407 cmd.ic_len = sizeof (struct eucioc);
408 cmd.ic_dp = (char *)kwp;
410 if (ioctl(fd, I_STR, &cmd) == 0)
411 term |= EUCW;
413 cmd.ic_cmd = CSDATA_GET;
414 cmd.ic_timout = 0;
415 cmd.ic_len = sizeof (ldterm_cs_data_user_t);
416 cmd.ic_dp = (char *)kcswp;
418 if (ioctl(fd, I_STR, &cmd) == 0)
419 term |= CSIW;
420 else
421 (void) memset(kcswp, 0, sizeof (ldterm_cs_data_user_t));
422 #endif /* EUC */
423 return (term);
426 /* set tty modes */
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
431 #ifdef EUC
432 /* */, struct eucioc *kwp, ldterm_cs_data_user_t *kcswp,
433 int invalid_ldterm_dat_file
434 #endif /* EUC */
435 /* */)
437 int i;
438 #ifdef EUC
439 struct strioctl cmd;
440 #endif /* EUC */
442 if (term & ASYNC) {
443 if (term & TERMIOS) {
444 if (ioctl(fd, TCSETSW, termios) == -1)
445 return (-1);
446 } else {
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)
454 return (-1);
457 } else {
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)
463 return (-1);
465 if (term & FLOW) {
466 if (ioctl(fd, TCSETXW, termiox) == -1)
467 return (-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)
474 return (-1);
475 #ifdef EUC
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"));
483 return (-1);
484 } else if ((term & CSIW) && kcswp->version) {
485 cmd.ic_cmd = CSDATA_SET;
486 cmd.ic_timout = 0;
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"));
492 return (-1);
494 } else if (term & EUCW) {
495 cmd.ic_cmd = EUC_WSET;
496 cmd.ic_timout = 0;
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"));
502 return (-1);
505 #endif /* EUC */
506 return (0);
509 static int
510 parse_encoded(struct termios *cb
511 #ifdef EUC
512 /* */, ldterm_cs_data_user_t *kcswp, int term
513 #endif /* EUC */
514 /* */)
516 unsigned long grab[NUM_FIELDS];
517 int last, i;
518 #ifdef EUC
519 long l;
520 char s[3];
521 char *t;
522 char *r;
523 uchar_t *g;
524 ldterm_cs_data_user_t ecswp;
525 #endif /* EUC */
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
533 * control chars).
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]);
542 if (i < 12)
543 return (0);
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];
553 #ifdef EUC
554 /* This is to fulfill PSARC/1999/140 TCR2. */
555 if (term & CSIW) {
556 r = strdup(s_arg);
557 if (r == NULL) {
558 (void) fprintf(stderr, gettext(
559 "no more memory - try again later\n"));
560 return (0);
562 t = strtok(r, ":");
563 for (i = 0; t != NULL && i < 22; i++) {
564 t = strtok(NULL, ":");
567 if (t == NULL) {
568 free((void *)r);
569 return (0);
571 ecswp.version = (uchar_t)strtol(t, (char **)NULL, 16);
572 if (ecswp.version > LDTERM_DATA_VERSION ||
573 ecswp.version == 0) {
574 free((void *)r);
575 return (0);
578 if ((t = strtok(NULL, ":")) == NULL) {
579 free((void *)r);
580 return (0);
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) {
585 free((void *)r);
586 return (0);
589 if ((t = strtok(NULL, ":")) == NULL) {
590 free((void *)r);
591 return (0);
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))) {
598 free((void *)r);
599 return (0);
602 if ((t = strtok(NULL, ":")) == NULL) {
603 free((void *)r);
604 return (0);
606 s[2] = '\0';
607 for (i = 0; *t != 0 && i < MAXNAMELEN; i++) {
608 if (*(t + 1) == '\0') {
609 free((void *)r);
610 return (0);
612 s[0] = *t++;
613 s[1] = *t++;
614 ecswp.locale_name[i] = (char)strtol(s, (char **)NULL,
615 16);
617 if (i >= MAXNAMELEN) {
618 free((void *)r);
619 return (0);
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) {
626 free((void *)r);
627 return (0);
629 l = strtol(t, (char **)NULL, 16);
630 if (l < 0 || l > 255) {
631 free((void *)r);
632 return (0);
634 *g++ = (uchar_t)l;
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));
641 #endif /* EUC */
643 return (1);