8706 libc lint library missing endian.h functions
[unleashed.git] / usr / src / cmd / ttymon / sttyparse.c
blob84599af8251a0f5de71934c3c3bd924ad51e0e80
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 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);
94 else
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);
103 else
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);
109 if (match)
110 continue;
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);
137 if (match)
138 continue;
139 if (eq("ek")) {
140 cb->c_cc[VERASE] = CERASE;
141 if (term & TERMIOS)
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);
147 continue;
148 } else if (eq("raw")) {
149 cb->c_cc[VMIN] = 1;
150 cb->c_cc[VTIME] = 0;
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;
156 if (term & TERMIOS)
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 */
165 #ifdef EUC
166 } else if (eq("defeucw")) {
167 kwp->eucw[0] = '\001';
168 kwp->eucw[1] =
169 (unsigned char)(wp->_eucw1 & 0177);
170 kwp->eucw[2] =
171 (unsigned char)(wp->_eucw2 & 0177);
172 kwp->eucw[3] =
173 (unsigned char)(wp->_eucw3 & 0177);
175 kwp->scrw[0] = '\001';
176 kwp->scrw[1] =
177 (unsigned char)(wp->_scrw1 & 0177);
178 kwp->scrw[2] =
179 (unsigned char)(wp->_scrw2 & 0177);
180 kwp->scrw[3] =
181 (unsigned char)(wp->_scrw3 & 0177);
183 (void) memcpy((void *)kcswp, (const void *)cswp,
184 sizeof (ldterm_cs_data_user_t));
185 #endif /* EUC */
186 } else if ((term & TERMIOS) && eq("ospeed") && --argc) {
187 s_arg = *++argv;
188 for (match = 0, i = 0; speeds[i].string; i++) {
189 if (eq(speeds[i].string)) {
190 (void) cfsetospeed(cb,
191 speeds[i].code);
192 break;
195 if (!match)
196 return (s_arg);
197 continue;
199 } else if ((term & TERMIOS) && eq("ispeed") && --argc) {
200 s_arg = *++argv;
201 for (match = 0, i = 0; speeds[i].string; i++) {
202 if (eq(speeds[i].string)) {
203 (void) cfsetispeed(cb,
204 speeds[i].code);
205 break;
208 if (!match)
209 return (s_arg);
210 continue;
212 } else {
213 for (match = 0, i = 0; speeds[i].string; i++) {
214 if (eq(speeds[i].string)) {
215 (void) cfsetospeed(cb,
216 speeds[i].code);
217 (void) cfsetispeed(cb,
218 speeds[i].code);
219 break;
224 if (!(term & ASYNC) && eq("ctab") && --argc) {
225 cb->c_cc[7] = gct(*++argv, term);
226 continue;
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;
233 #ifdef EUC
234 if (wp->_multibyte &&
235 (eq("-raw") || eq("cooked") || eq("sane")))
236 cb->c_iflag &= ~ISTRIP;
237 #endif /* EUC */
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")) {
253 cb->c_oflag |= TAB3;
254 continue;
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;
260 #ifdef EUC
261 if (wp->_multibyte &&
262 (eq("-raw") || eq("cooked") ||
263 eq("sane"))) {
264 cb->c_cflag &= ~(CS7|PARENB);
265 cb->c_cflag |= CS8;
267 #endif /* EUC */
269 if (term & TERMIOS)
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;
280 if (term & TERMIOS)
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;
286 if (term & FLOW) {
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);
309 if (!match) {
310 #ifdef EUC
311 if (!parse_encoded(cb, kcswp, term)) {
312 #else
313 if (!parse_encoded(cb)) {
314 #endif /* EUC */
315 return (s_arg); /* parsing failed */
319 return ((char *)0);
322 static int
323 eq(const char *string)
325 int i;
327 if (!s_arg)
328 return (0);
329 i = 0;
330 loop:
331 if (s_arg[i] != string[i])
332 return (0);
333 if (s_arg[i++] != '\0')
334 goto loop;
335 match++;
336 return (1);
339 /* get pseudo control characters from terminal */
340 /* and convert to internal representation */
341 static int
342 gct(char *cp, int term)
344 int c;
346 c = *cp;
347 if (c == '^') {
348 c = *++cp;
349 if (c == '?')
350 c = 0177; /* map '^?' to 0177 */
351 else if (c == '-') {
352 /* map '^-' to undefined */
353 c = (term & TERMIOS) ? _POSIX_VDISABLE : 0200;
354 } else
355 c &= 037;
356 } else if (strcmp(cp, "undef") == 0) {
357 /* map "undef" to undefined */
358 c = (term & TERMIOS) ? _POSIX_VDISABLE : 0200;
360 return (c);
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
367 #ifdef EUC
368 /* */, struct eucioc *kwp, ldterm_cs_data_user_t *kcswp
369 #endif /* EUC */
370 /* */)
372 int i;
373 int term = 0;
374 #ifdef EUC
375 struct strioctl cmd;
376 #endif /* EUC */
377 if (ioctl(fd, STGET, stermio) == -1) {
378 term |= ASYNC;
379 if (ioctl(fd, TCGETS, termios) == -1) {
380 if (ioctl(fd, TCGETA, termio) == -1)
381 return (-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];
388 } else
389 term |= TERMIOS;
390 } else {
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)
398 term |= FLOW;
400 if (ioctl(fd, TIOCGWINSZ, winsize) == 0)
401 term |= WINDOW;
402 #ifdef EUC
403 cmd.ic_cmd = EUC_WGET;
404 cmd.ic_timout = 0;
405 cmd.ic_len = sizeof (struct eucioc);
406 cmd.ic_dp = (char *)kwp;
408 if (ioctl(fd, I_STR, &cmd) == 0)
409 term |= EUCW;
411 cmd.ic_cmd = CSDATA_GET;
412 cmd.ic_timout = 0;
413 cmd.ic_len = sizeof (ldterm_cs_data_user_t);
414 cmd.ic_dp = (char *)kcswp;
416 if (ioctl(fd, I_STR, &cmd) == 0)
417 term |= CSIW;
418 else
419 (void) memset((void *)kcswp, 0, sizeof (ldterm_cs_data_user_t));
420 #endif /* EUC */
421 return (term);
424 /* set tty modes */
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
429 #ifdef EUC
430 /* */, struct eucioc *kwp, ldterm_cs_data_user_t *kcswp,
431 int invalid_ldterm_dat_file
432 #endif /* EUC */
433 /* */)
435 int i;
436 #ifdef EUC
437 struct strioctl cmd;
438 #endif /* EUC */
440 if (term & ASYNC) {
441 if (term & TERMIOS) {
442 if (ioctl(fd, TCSETSW, termios) == -1)
443 return (-1);
444 } else {
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)
452 return (-1);
455 } else {
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)
461 return (-1);
463 if (term & FLOW) {
464 if (ioctl(fd, TCSETXW, termiox) == -1)
465 return (-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)
472 return (-1);
473 #ifdef EUC
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"));
481 return (-1);
482 } else if ((term & CSIW) && kcswp->version) {
483 cmd.ic_cmd = CSDATA_SET;
484 cmd.ic_timout = 0;
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"));
490 return (-1);
492 } else if (term & EUCW) {
493 cmd.ic_cmd = EUC_WSET;
494 cmd.ic_timout = 0;
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"));
500 return (-1);
503 #endif /* EUC */
504 return (0);
507 static int
508 parse_encoded(struct termios *cb
509 #ifdef EUC
510 /* */, ldterm_cs_data_user_t *kcswp, int term
511 #endif /* EUC */
512 /* */)
514 unsigned long grab[NUM_FIELDS];
515 int last, i;
516 #ifdef EUC
517 long l;
518 char s[3];
519 char *t;
520 char *r;
521 uchar_t *g;
522 ldterm_cs_data_user_t ecswp;
523 #endif /* EUC */
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
531 * control chars).
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]);
540 if (i < 12)
541 return (0);
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];
551 #ifdef EUC
552 /* This is to fulfill PSARC/1999/140 TCR2. */
553 if (term & CSIW) {
554 r = strdup(s_arg);
555 if (r == (char *)NULL) {
556 (void) fprintf(stderr, gettext(
557 "no more memory - try again later\n"));
558 return (0);
560 t = strtok(r, ":");
561 for (i = 0; t != NULL && i < 22; i++) {
562 t = strtok(NULL, ":");
565 if (t == NULL) {
566 free((void *)r);
567 return (0);
569 ecswp.version = (uchar_t)strtol(t, (char **)NULL, 16);
570 if (ecswp.version > LDTERM_DATA_VERSION ||
571 ecswp.version == 0) {
572 free((void *)r);
573 return (0);
576 if ((t = strtok(NULL, ":")) == NULL) {
577 free((void *)r);
578 return (0);
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) {
583 free((void *)r);
584 return (0);
587 if ((t = strtok(NULL, ":")) == NULL) {
588 free((void *)r);
589 return (0);
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))) {
596 free((void *)r);
597 return (0);
600 if ((t = strtok(NULL, ":")) == NULL) {
601 free((void *)r);
602 return (0);
604 s[2] = '\0';
605 for (i = 0; *t != 0 && i < MAXNAMELEN; i++) {
606 if (*(t + 1) == (char)NULL) {
607 free((void *)r);
608 return (0);
610 s[0] = *t++;
611 s[1] = *t++;
612 ecswp.locale_name[i] = (char)strtol(s, (char **)NULL,
613 16);
615 if (i >= MAXNAMELEN) {
616 free((void *)r);
617 return (0);
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) {
624 free((void *)r);
625 return (0);
627 l = strtol(t, (char **)NULL, 16);
628 if (l < 0 || l > 255) {
629 free((void *)r);
630 return (0);
632 *g++ = (uchar_t)l;
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));
639 #endif /* EUC */
641 return (1);