xref: /illumos-gate/usr/src/cmd/ttymon/sttyparse.c (revision 20a7641f9918de8574b8b3b47dbe35c4bfc78df1)
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, Version 1.0 only
6  * (the "License").  You may not use this file except in compliance
7  * with the License.
8  *
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.
13  *
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]
19  *
20  * CDDL HEADER END
21  */
22 /*
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.
26  */
27 
28 /*
29  * Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T
30  * All Rights Reserved
31  *
32  */
33 
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>
56 
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);
66 
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 	/* */)
76 {
77 	int i;
78 
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);
136 			}
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);
174 
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);
182 
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;
193 					}
194 				}
195 				if (!match)
196 					return (s_arg);
197 				continue;
198 
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;
206 					}
207 				}
208 				if (!match)
209 					return (s_arg);
210 				continue;
211 
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;
220 					}
221 				}
222 			}
223 		}
224 		if (!(term & ASYNC) && eq("ctab") && --argc) {
225 			cb->c_cc[7] = gct(*++argv, term);
226 			continue;
227 		}
228 
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 */
238 			}
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;
244 				}
245 		}
246 
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;
251 			}
252 		if (!(term & ASYNC) && eq("sane")) {
253 			cb->c_oflag |= TAB3;
254 			continue;
255 		}
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;
266 				}
267 #endif /* EUC */
268 			}
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;
274 				}
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;
279 			}
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;
285 				}
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;
291 				}
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;
296 				}
297 
298 		}
299 
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);
308 
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 */
316 			}
317 		}
318 	}
319 	return ((char *)0);
320 }
321 
322 static int
323 eq(const char *string)
324 {
325 	int i;
326 
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);
337 }
338 
339 /* get pseudo control characters from terminal  */
340 /* and convert to internal representation	*/
341 static int
342 gct(char *cp, int term)
343 {
344 	int c;
345 
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;
359 	}
360 	return (c);
361 }
362 
363 /* get modes of tty device and fill in applicable structures */
364 int
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 	/* */)
371 {
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;
395 	}
396 
397 	if (ioctl(fd, TCGETX, termiox) == 0)
398 		term |= FLOW;
399 
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;
407 
408 	if (ioctl(fd, I_STR, &cmd) == 0)
409 		term |= EUCW;
410 
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;
415 
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);
422 }
423 
424 /* set tty modes */
425 int
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 	/* */)
434 {
435 	int i;
436 #ifdef EUC
437 	struct strioctl cmd;
438 #endif /* EUC */
439 
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);
453 		}
454 
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);
462 	}
463 	if (term & FLOW) {
464 		if (ioctl(fd, TCSETXW, termiox) == -1)
465 			return (-1);
466 	}
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
474 	/*
475 	 * If the ldterm.dat file contains valid, non-EUC codeset info,
476 	 * send downstream CSDATA_SET. Otherwise, try EUC_WSET.
477 	 */
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);
491 		}
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);
501 		}
502 	}
503 #endif /* EUC */
504 	return (0);
505 }
506 
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 	/* */)
513 {
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 */
524 
525 	/*
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).
532 	 */
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]);
539 
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];
546 
547 	last = i - NUM_MODES;
548 	for (i = 0; i < last; i++)
549 		cb->c_cc[i] = (unsigned char) grab[i+NUM_MODES];
550 
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);
559 		}
560 		t = strtok(r, ":");
561 		for (i = 0; t != NULL && i < 22; i++) {
562 			t = strtok(NULL, ":");
563 		}
564 
565 		if (t == NULL) {
566 			free((void *)r);
567 			return (0);
568 		}
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);
574 		}
575 
576 		if ((t = strtok(NULL, ":")) == NULL) {
577 			free((void *)r);
578 			return (0);
579 		}
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);
585 		}
586 
587 		if ((t = strtok(NULL, ":")) == NULL) {
588 			free((void *)r);
589 			return (0);
590 		}
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);
598 		}
599 
600 		if ((t = strtok(NULL, ":")) == NULL) {
601 			free((void *)r);
602 			return (0);
603 		}
604 		s[2] = '\0';
605 		for (i = 0; *t != 0 && i < MAXNAMELEN; i++) {
606 			if (*(t + 1) == '\0') {
607 				free((void *)r);
608 				return (0);
609 			}
610 			s[0] = *t++;
611 			s[1] = *t++;
612 			ecswp.locale_name[i] = (char)strtol(s, (char **)NULL,
613 			    16);
614 		}
615 		if (i >= MAXNAMELEN) {
616 			free((void *)r);
617 			return (0);
618 		}
619 		ecswp.locale_name[i] = '\0';
620 
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);
626 			}
627 			l = strtol(t, (char **)NULL, 16);
628 			if (l < 0 || l > 255) {
629 				free((void *)r);
630 				return (0);
631 			}
632 			*g++ = (uchar_t)l;
633 		}
634 
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));
638 	}
639 #endif /* EUC */
640 
641 	return (1);
642 }
643