xref: /titanic_52/usr/src/cmd/csh/sh.tchar.c (revision 1a7c1b724419d3cb5fa6eea75123c6b2060ba31b)
1 /*
2  * Copyright 2000 Sun Microsystems, Inc.  All rights reserved.
3  * Use is subject to license terms.
4  */
5 
6 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
7 /*	  All Rights Reserved  	*/
8 
9 /*
10  * Copyright (c) 1980 Regents of the University of California.
11  * All rights reserved. The Berkeley Software License Agreement
12  * specifies the terms and conditions for redistribution.
13  */
14 
15 #pragma ident	"%Z%%M%	%I%	%E% SMI"
16 
17 /*
18  * This module provides with system/library function substitutes for tchar
19  * datatype. This also includes two conversion functions between tchar and
20  * char arrays.
21  *
22  * T. Kurosaka, Palo Alto, California, USA
23  * March 1989
24  *
25  * Implementation Notes:
26  *	Many functions defined here use a "char" buffer chbuf[].  In the
27  * first attempt, there used to be only one chbuf defined as static
28  * (private) variable and shared by these functions.  csh linked with that
29  * version of this file misbehaved in interpreting "eval `tset ....`".
30  * (in general, builtin function with back-quoted expression).
31  *	This bug seemed to be caused by sharing of chbuf
32  * by these functions simultanously (thru vfork() mechanism?).  We could not
33  * identify which two functions interfere each other so we decided to
34  * have each of these function its private instance of chbuf.
35  * The size of chbuf[] might be much bigger than necessary for some functions.
36  */
37 #ifdef DBG
38 #include <stdio.h>	/* For <assert.h> needs stderr defined. */
39 #else /* !DBG */
40 #define	NDEBUG		/* Disable assert(). */
41 #endif /* !DBG */
42 
43 #include <assert.h>
44 #include "sh.h"
45 
46 #ifdef MBCHAR
47 #include <widec.h>	/* For wcsetno() */
48 #endif
49 
50 #include <sys/param.h>	/* MAXPATHLEN */
51 #include <fcntl.h>
52 #include <unistd.h>
53 
54 
55 /*
56  * strtots(to, from): convert a char string 'from' into a tchar buffer 'to'.
57  *	'to' is assumed to have the enough size to hold the conversion result.
58  *	When 'to' is NOSTR(=(tchar *)0), strtots() attempts to allocate a space
59  *	automatically using xalloc().  It is caller's responsibility to
60  *	free the space allocated in this way, by calling XFREE(ptr).
61  *	In either case, strtots() returns the pointer to the conversion
62  *	result (i.e. 'to', if 'to' wasn't NOSTR, or the allocated space.).
63  *	When a conversion or allocateion failed,  NOSTR is returned.
64  */
65 
66 tchar	*
67 strtots(tchar *to, char *from)
68 {
69 	int	i;
70 
71 	if (to == NOSTR) {	/* Need to xalloc(). */
72 		int	i;
73 
74 		i = mbstotcs(NOSTR, from, 0);
75 		if (i < 0) {
76 			return (NOSTR);
77 		}
78 
79 		/* Allocate space for the resulting tchar array. */
80 		to = (tchar *)xalloc(i * sizeof (tchar));
81 	}
82 	i = mbstotcs(to, from, INT_MAX);
83 	if (i < 0) {
84 		return (NOSTR);
85 	}
86 	return (to);
87 }
88 
89 char	*
90 tstostr(char *to, tchar *from)
91 {
92 	tchar	*ptc;
93 	wchar_t	wc;
94 	char	*pmb;
95 	int	len;
96 
97 	if (to == (char *)NULL) {	/* Need to xalloc(). */
98 		int	i;
99 		int	i1;
100 		char	junk[MB_LEN_MAX];
101 
102 		/* Get sum of byte counts for each char in from. */
103 		i = 0;
104 		ptc = from;
105 		while (wc = (wchar_t)((*ptc++)&TRIM)) {
106 			if ((i1 = wctomb(junk, wc)) <= 0) {
107 				i1 = 1;
108 			}
109 			i += i1;
110 		}
111 
112 		/* Allocate that much. */
113 		to = (char *)xalloc(i + 1);
114 	}
115 
116 	ptc = from;
117 	pmb = to;
118 	while (wc = (wchar_t)((*ptc++)&TRIM)) {
119 		if ((len = wctomb(pmb, wc)) <= 0) {
120 			*pmb = (unsigned char)wc;
121 			len = 1;
122 		}
123 		pmb += len;
124 	}
125 	*pmb = (char)0;
126 	return (to);
127 }
128 
129 /*
130  * mbstotcs(to, from, tosize) is similar to strtots() except that
131  * this returns # of tchars of the resulting tchar string.
132  * When NULL is give as the destination, no real conversion is carried out,
133  * and the function reports how many tchar characters would be made in
134  * the converted result including the terminating 0.
135  *	tchar	*to;	- Destination buffer, or NULL.
136  *	char	*from;	- Source string.
137  *	int	tosize; - Size of to, in terms of # of tchars.
138  */
139 int
140 mbstotcs(tchar *to, char *from, int tosize)
141 {
142 	tchar	*ptc = to;
143 	char	*pmb = from;
144 	wchar_t	wc;
145 	int	chcnt = 0;
146 	int	j;
147 
148 
149 	/* Just count how many tchar would be in the result. */
150 	if (to == (tchar *)NULL) {
151 		while (*pmb) {
152 			if ((j = mbtowc(&wc, pmb, MB_CUR_MAX)) <= 0) {
153 				j = 1;
154 			}
155 			pmb += j;
156 			chcnt++;
157 		}
158 		chcnt++;	/* For terminator. */
159 		return (chcnt);	/* # of chars including terminating zero. */
160 	} else {	/* Do the real conversion. */
161 		while (*pmb) {
162 			if ((j = mbtowc(&wc, pmb, MB_CUR_MAX)) <= 0) {
163 				wc = (unsigned char)*pmb;
164 				j = 1;
165 			}
166 			pmb += j;
167 			*(ptc++) = (tchar)wc;
168 			if (++chcnt >= tosize) {
169 				break;
170 			}
171 		}
172 		/* Terminate with zero only when space is left. */
173 		if (chcnt < tosize) {
174 			*ptc = (tchar)0;
175 			++chcnt;
176 		}
177 		return (chcnt); /* # of chars including terminating zero. */
178 	}
179 }
180 
181 
182 /* tchar version of STRING functions. */
183 
184 /*
185  * Returns the number of
186  * non-NULL tchar elements in tchar string argument.
187  */
188 int
189 strlen_(tchar *s)
190 {
191 	int n;
192 
193 	n = 0;
194 	while (*s++) {
195 		n++;
196 	}
197 	return (n);
198 }
199 
200 /*
201  * Concatenate tchar string s2 on the end of s1.  S1's space must be large
202  * enough.  Return s1.
203  */
204 tchar *
205 strcat_(tchar *s1, tchar *s2)
206 {
207 	tchar *os1;
208 
209 	os1 = s1;
210 	while (*s1++)
211 		;
212 	--s1;
213 	while (*s1++ = *s2++)
214 		;
215 	return (os1);
216 }
217 
218 /*
219  * Compare tchar strings:  s1>s2: >0  s1==s2: 0  s1<s2: <0
220  * BUGS: Comparison between two characters are done by subtracting two chars
221  *	after converting each to an unsigned long int value.  It might not make
222  *	a whole lot of sense to do that if the characters are in represented
223  *	as wide characters and the two characters belong to different codesets.
224  *	Therefore, this function should be used only to test the equallness.
225  */
226 int
227 strcmp_(tchar *s1, tchar *s2)
228 {
229 	while (*s1 == *s2++) {
230 		if (*s1++ == (tchar)0) {
231 			return (0);
232 		}
233 	}
234 	return (((unsigned long)*s1) - ((unsigned long)*(--s2)));
235 }
236 
237 /*
238  * This is only used in sh.glob.c for sorting purpose.
239  */
240 int
241 strcoll_(tchar *s1, tchar *s2)
242 {
243 	char buf1[BUFSIZ];
244 	char buf2[BUFSIZ];
245 
246 	tstostr(buf1, s1);
247 	tstostr(buf2, s2);
248 	return (strcoll(buf1, buf2));
249 }
250 
251 /*
252  * Copy tchar string s2 to s1.  s1 must be large enough.
253  * return s1
254  */
255 tchar *
256 strcpy_(tchar *s1, tchar *s2)
257 {
258 	tchar *os1;
259 
260 	os1 = s1;
261 	while (*s1++ = *s2++)
262 		;
263 	return (os1);
264 }
265 
266 /*
267  * Return the ptr in sp at which the character c appears;
268  * NULL if not found
269  */
270 tchar *
271 index_(tchar *sp, tchar c)
272 {
273 
274 	do {
275 		if (*sp == c) {
276 			return (sp);
277 		}
278 	} while (*sp++);
279 	return (NULL);
280 }
281 
282 /*
283  * Return the ptr in sp at which the character c last
284  * appears; NOSTR if not found
285  */
286 
287 tchar *
288 rindex_(tchar *sp, tchar c)
289 {
290 	tchar *r;
291 
292 	r = NOSTR;
293 	do {
294 		if (*sp == c) {
295 			r = sp;
296 		}
297 	} while (*sp++);
298 	return (r);
299 }
300 
301 /* Additional misc functions. */
302 
303 /* Calculate the display width of a string.  */
304 tswidth(tchar *ts)
305 {
306 #ifdef MBCHAR
307 	wchar_t	tc;
308 	int	w = 0;
309 	int	p_col;
310 
311 	while (tc = *ts++) {
312 		if ((p_col = wcwidth((wchar_t)tc)) > 0)
313 			w += p_col;
314 	}
315 	return (w);
316 #else /* !MBCHAR --- one char always occupies one column. */
317 	return (strlen_(ts));
318 #endif
319 }
320 
321 /*
322  * Two getenv() substitute functions.  They differ in the type of arguments.
323  * BUGS: Both returns the pointer to an allocated space where the env var's
324  *	values is stored.  This space is freed automatically on the successive
325  *	call of	either function.  Therefore the caller must copy the contents
326  *	if it needs to access two env vars.  There is an arbitary limitation
327  *	on the number of chars of a env var name.
328  */
329 #define	LONGEST_ENVVARNAME	256		/* Too big? */
330 tchar *
331 getenv_(tchar *name_)
332 {
333 	char	name[LONGEST_ENVVARNAME * MB_LEN_MAX];
334 
335 	assert(strlen_(name_) < LONGEST_ENVVARNAME);
336 	return (getenvs_(tstostr(name, name_)));
337 }
338 
339 tchar *
340 getenvs_(char *name)
341 {
342 	static tchar	*pbuf = (tchar *)NULL;
343 	char	*val;
344 
345 	if (pbuf) {
346 		XFREE((void *)pbuf);
347 		pbuf = NOSTR;
348 	}
349 	val = getenv(name);
350 	if (val == (char *)NULL) {
351 		return (NOSTR);
352 	}
353 	return (pbuf = strtots(NOSTR, val));
354 }
355 
356 /* Followings are the system call interface for tchar strings. */
357 
358 /*
359  * creat() and open() replacement.
360  * BUGS: An unusually long file name could be dangerous.
361  */
362 int
363 creat_(tchar *name_, int mode)
364 {
365 	int fd;
366 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
367 
368 	tstostr(chbuf, name_);
369 	fd = creat((char *)chbuf, mode);
370 	if (fd != -1) {
371 		setfd(fd);
372 	}
373 	return (fd);
374 }
375 
376 /*VARARGS2*/
377 int
378 open_(path_, flags, mode)
379 	tchar 	*path_;
380 	int	flags;
381 	int	mode; /* May be omitted. */
382 {
383 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
384 	int fd;
385 
386 	tstostr(chbuf, path_);
387 	fd = open((char *)chbuf, flags, mode);
388 	if (fd != -1) {
389 		setfd(fd);
390 	}
391 	return (fd);
392 }
393 
394 /*
395  * mkstemp replacement
396  */
397 int
398 mkstemp_(tchar *name_)
399 {
400 	int fd;
401 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
402 
403 	tstostr(chbuf, name_);
404 	fd = mkstemp((char *)chbuf);
405 	if (fd != -1) {
406 		setfd(fd);
407 		strtots(name_, chbuf);
408 	}
409 	return (fd);
410 }
411 
412 /*
413  * read() and write() reaplacement.
414  *	int        d;
415  *	tchar      *buf;  - where the result be stored.  Not NULL terminated.
416  *	int        nchreq; - # of tchars requrested.
417  */
418 int
419 read_(int d, tchar *buf, int nchreq)
420 {
421 	unsigned char chbuf[BUFSIZ * MB_LEN_MAX]; /* General use buffer. */
422 #ifdef MBCHAR
423 	/*
424 	 * We would have to read more than tchar bytes
425 	 * when there are multibyte characters in the file.
426 	 */
427 	int	i, j, fflags;
428 	unsigned char	*s;	/* Byte being scanned for a multibyte char. */
429 	/* Points to the pos where next read() to read the data into. */
430 	unsigned char	*p;
431 	tchar	*t;
432 	wchar_t		wc;
433 	int		b_len;
434 	int		nchread = 0; /* Count how many bytes has been read. */
435 	int		nbytread = 0; /* Total # of bytes read. */
436 	/* # of bytes needed to complete the last char just read. */
437 	int		delta;
438 	unsigned char	*q;	/* q points to the first invalid byte. */
439 #ifdef DBG
440 	tprintf("Entering read_(d=%d, buf=0x%x, nchreq=%d);\n",
441 	    d, buf, nchreq);
442 #endif /* DBG */
443 	/*
444 	 *	Step 1: We collect the exact number of bytes that make
445 	 *	nchreq characters into chbuf.
446 	 *	We must be careful not to read too many bytes as we
447 	 *	cannot push back such over-read bytes.
448 	 *	The idea we use here is that n multibyte characters are stored
449 	 *	in no less than n but less than n*MB_CUR_MAX bytes.
450 	 */
451 	assert(nchreq <= BUFSIZ);
452 	delta = 0;
453 	p = s = chbuf;
454 	t = buf;
455 	while (nchread < nchreq) {
456 		int		m;  /* # of bytes to try to read this time. */
457 		int		k;  /* # of bytes successfully read. */
458 
459 retry:
460 		/*
461 		 * Let's say the (N+1)'th byte bN is actually the first
462 		 * byte of a three-byte character c.
463 		 * In that case, p, s, q look like this:
464 		 *
465 		 *		/-- already read--\ /-- not yet read --\
466 		 * chbuf[]:	b0 b1 ..... bN bN+1 bN+2 bN+2 ...
467 		 *		^		^	^
468 		 *		|		|	|
469 		 *		p		s	q
470 		 *				\----------/
471 		 *				c hasn't been completed
472 		 *
473 		 * Just after the next read(), p and q will be adavanced to:
474 		 *
475 		 *	/-- already read-----------------------\ /-- not yet -
476 		 * chbuf[]: b0 b1 ..... bN bN+1 bN+2 bN+2 ... bX bX+1 bX+2...
477 		 *			^	^		 ^
478 		 *			|	|		 |
479 		 *			s	p		 q
480 		 *			\----------/
481 		 *			 c has been completed
482 		 *			 but hasn't been scanned
483 		 */
484 		m = nchreq - nchread;
485 		assert(p + m < chbuf + sizeof (chbuf));
486 		k = read(d, p, m);
487 		/*
488 		 * when child sets O_NDELAY or O_NONBLOCK on stdin
489 		 * and exits and we are interactive then turn the modes off
490 		 * and retry
491 		 */
492 		if (k == 0) {
493 			if ((intty && !onelflg && !cflg) &&
494 			    ((fflags = fcntl(d, F_GETFL, 0)) & O_NDELAY)) {
495 				fflags &= ~O_NDELAY;
496 				fcntl(d, F_SETFL, fflags);
497 				goto retry;
498 			}
499 		} else if (k < 0) {
500 			if (errno == EAGAIN) {
501 				fflags = fcntl(d, F_GETFL, 0);
502 				fflags &= ~O_NONBLOCK;
503 				fcntl(d, F_SETFL, fflags);
504 				goto retry;
505 			}
506 			return (-1);
507 		}
508 		nbytread += k;
509 		q = p + k;
510 		delta = 0;
511 
512 		/* Try scaning characters in s..q-1 */
513 		while (s < q) {
514 			/* Convert the collected bytes into tchar array. */
515 			if (*s == 0) {
516 				/* NUL is treated as a normal char here. */
517 				*t++ = 0;
518 				s++;
519 				nchread++;
520 				continue;
521 			}
522 
523 			if ((b_len = q - s) > (int)MB_CUR_MAX) {
524 				b_len = MB_CUR_MAX;
525 			}
526 			if ((j = mbtowc(&wc, (char *)s, b_len)) <=  0) {
527 				if (b_len < (unsigned int)MB_CUR_MAX) {
528 					/*
529 					 * Needs more byte to complete this char
530 					 * In order to read() more than delta
531 					 * bytes.
532 					 */
533 					break;
534 				}
535 
536 				wc = (unsigned char)*s;
537 				j = 1;
538 			}
539 
540 			*t++ = wc;
541 			nchread++;
542 			s += j;
543 		}
544 
545 		if (k < m) {
546 			/* We've read as many bytes as possible. */
547 			while (s < q) {
548 				if ((b_len = q - s) > (int)MB_CUR_MAX) {
549 					b_len = MB_CUR_MAX;
550 				}
551 				if ((j = mbtowc(&wc, (char *)s, b_len)) <=  0) {
552 					wc = (unsigned char)*s;
553 					j = 1;
554 				}
555 				*t++ = wc;
556 				nchread++;
557 				s += j;
558 			}
559 			return (nchread);
560 		}
561 
562 		p = q;
563 	}
564 
565 	if ((delta = q - s) == 0) {
566 		return (nchread);
567 	}
568 
569 	if (*(s + delta - 1) == '\n') {
570 		while (s < q) {
571 			if ((b_len = q - s) > (int)MB_CUR_MAX) {
572 				b_len = MB_CUR_MAX;
573 			}
574 			if ((j = mbtowc(&wc, (char *)s, b_len)) <=  0) {
575 				wc = (unsigned char)*s;
576 				j = 1;
577 			}
578 			*t++ = wc;
579 			nchread++;
580 			s += j;
581 		}
582 		return (nchread);
583 	}
584 
585 	for (; delta < (int)MB_CUR_MAX; delta++, q++) {
586 		assert((q + 1) < (chbuf + sizeof (chbuf)));
587 		if (read(d, q, 1) != 1) {
588 			break;
589 		}
590 		if (*q == '\n') {
591 			break;
592 		}
593 		if (mbtowc(&wc, (char *)s, delta) > 0) {
594 			*t = wc;
595 			return (nchread + 1);
596 		}
597 	}
598 
599 	while (s < q) {
600 		if ((b_len = q - s) > (int)MB_CUR_MAX) {
601 			b_len = MB_CUR_MAX;
602 		}
603 		if ((j = mbtowc(&wc, (char *)s, b_len)) <=  0) {
604 			wc = (unsigned char)*s;
605 			j = 1;
606 		}
607 		*t++ = wc;
608 		nchread++;
609 		s += j;
610 	}
611 	return (nchread);
612 #else /* !MBCHAR */
613 	/* One byte always represents one tchar.  Easy! */
614 	int		i;
615 	unsigned char	*s;
616 	tchar		*t;
617 	int		nchread;
618 
619 #ifdef DBG
620 	tprintf("Entering read_(d=%d, buf=0x%x, nchreq=%d);\n",
621 	    d, buf, nchreq);
622 #endif /* DBG */
623 	assert(nchreq <= BUFSIZ);
624 retry:
625 	nchread = read(d, (char *)chbuf, nchreq);
626 	/*
627 	 * when child sets O_NDELAY or O_NONBLOCK on stdin
628 	 * and exits and we are interactive then turn the modes off
629 	 * and retry
630 	 */
631 	if (nchread == 0) {
632 		if ((intty && !onelflg && !cflg) &&
633 		    ((fflags = fcntl(d, F_GETFL, 0)) & O_NDELAY)) {
634 			fflags &= ~O_NDELAY;
635 			fcntl(d, F_SETFL, fflags);
636 			goto retry;
637 		}
638 	} else if (nchread < 0) {
639 		if (errno == EAGAIN) {
640 			fflags = fcntl(d, F_GETFL, 0);
641 			fflags &= ~O_NONBLOCK;
642 			fcntl(d, F_SETFL, fflags);
643 			goto retry;
644 		}
645 		len = 0;
646 	} else {
647 		for (i = 0, t = buf, s = chbuf; i < nchread; ++i) {
648 		    *t++ = ((tchar)*s++);
649 		}
650 	}
651 	return (nchread);
652 #endif
653 }
654 
655 /*
656  * BUG: write_() returns -1 on failure, or # of BYTEs it has written.
657  *	For consistency and symmetry, it should return the number of
658  *	characters it has actually written, but that is technically
659  *	difficult although not impossible.  Anyway, the return
660  *	value of write() has never been used by the original csh,
661  *	so this bug should be OK.
662  */
663 int
664 write_(int d, tchar *buf, int nch)
665 {
666 	unsigned char chbuf[BUFSIZ*MB_LEN_MAX]; /* General use buffer. */
667 #ifdef MBCHAR
668 	tchar		*pt;
669 	unsigned char	*pc;
670 	wchar_t		wc;
671 	int		i, j;
672 
673 #ifdef	DBG
674 	tprintf("Entering write_(d=%d, buf=0x%x, nch=%d);\n",
675 	    d, buf, nch); /* Hope printf() doesn't call write_() itself! */
676 #endif /* DBG */
677 	assert(nch * MB_CUR_MAX < sizeof (chbuf));
678 	i = nch;
679 	pt = buf;
680 	pc = chbuf;
681 	while (i--) {
682 		/*
683 		 * Convert to tchar string.
684 		 * NUL is treated as normal char here.
685 		 */
686 		wc = (wchar_t)((*pt++)&TRIM);
687 		if (wc == (wchar_t)0) {
688 			*pc++ = 0;
689 		} else {
690 			if ((j = wctomb((char *)pc, wc)) <= 0) {
691 				*pc = (unsigned char)wc;
692 				j = 1;
693 			}
694 			pc += j;
695 		}
696 	}
697 	return (write(d, chbuf, pc - chbuf));
698 #else /* !MBCHAR */
699 	/* One byte always represents one tchar.  Easy! */
700 	int	i;
701 	unsigned char	*s;
702 	tchar	*t;
703 
704 #ifdef	DBG
705 	tprintf("Entering write_(d=%d, buf=0x%x, nch=%d);\n",
706 	    d, buf, nch); /* Hope printf() doesn't call write_() itself! */
707 #endif /* DBG */
708 	assert(nch <= sizeof (chbuf));
709 	for (i = 0, t = buf, s = chbuf; i < nch; ++i) {
710 	    *s++ = (char)((*t++)&0xff);
711 	}
712 	return (write(d, (char *)chbuf, nch));
713 #endif
714 }
715 
716 #undef chbuf
717 
718 #include <sys/types.h>
719 #include <sys/stat.h>	/* satruct stat */
720 #include <dirent.h>	/* DIR */
721 
722 extern DIR *Dirp;
723 
724 int
725 stat_(tchar *path, struct stat *buf)
726 {
727 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
728 
729 	tstostr(chbuf, path);
730 	return (stat((char *)chbuf, buf));
731 }
732 
733 int
734 lstat_(tchar *path, struct stat *buf)
735 {
736 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
737 
738 	tstostr(chbuf, path);
739 	return (lstat((char *)chbuf, buf));
740 }
741 
742 int
743 chdir_(tchar *path)
744 {
745 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
746 
747 	tstostr(chbuf, path);
748 	return (chdir((char *)chbuf));
749 }
750 
751 tchar *
752 getwd_(tchar *path)
753 {
754 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
755 	int	rc;
756 
757 	rc = (int)getwd((char *)chbuf);
758 	if (rc == 0) {
759 		return (0);
760 	} else {
761 		return (strtots(path, chbuf));
762 	}
763 }
764 
765 int
766 unlink_(tchar *path)
767 {
768 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
769 
770 	tstostr(chbuf, path);
771 	return (unlink((char *)chbuf));
772 }
773 
774 DIR *
775 opendir_(tchar *dirname)
776 {
777 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
778 
779 	extern DIR *opendir();
780 	DIR	*dir;
781 
782 	dir = opendir(tstostr(chbuf, dirname));
783 	if (dir != NULL) {
784 		setfd(dir->dd_fd);
785 	}
786 	return (Dirp = dir);
787 }
788 
789 int
790 closedir_(DIR *dirp)
791 {
792 	int ret;
793 	extern int closedir();
794 
795 	ret = closedir(dirp);
796 	Dirp = NULL;
797 	return (ret);
798 }
799 
800 int
801 gethostname_(tchar *name, int namelen)
802 {
803 	char chbuf[BUFSIZ * MB_LEN_MAX]; /* General use buffer. */
804 
805 	assert(namelen < BUFSIZ);
806 	if (gethostname((char *)chbuf, sizeof (chbuf)) != 0) {
807 		return (-1);
808 	}
809 	if (mbstotcs(name, chbuf, namelen) < 0) {
810 		return (-1);
811 	}
812 	return (0); /* Succeeded. */
813 }
814 
815 int
816 readlink_(tchar *path, tchar *buf, int bufsiz)
817 {
818 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
819 	char	chpath[MAXPATHLEN + 1];
820 	int	i;
821 
822 	tstostr(chpath, path);
823 	i = readlink(chpath, (char *)chbuf, sizeof (chbuf));
824 	if (i < 0) {
825 		return (-1);
826 	}
827 	chbuf[i] = (char)0;	/* readlink() doesn't put NULL. */
828 	i = mbstotcs(buf, chbuf, bufsiz);
829 	if (i < 0) {
830 		return (-1);
831 	}
832 	return (i - 1); /* Return # of tchars EXCLUDING the terminating NULL. */
833 }
834 
835 int
836 atoi_(tchar *str)
837 {
838 	char chbuf[BUFSIZ * MB_LEN_MAX]; /* General use buffer. */
839 
840 	tstostr(chbuf, str);
841 	return (atoi((char *)chbuf));
842 }
843 
844 tchar *
845 simple(tchar *s)
846 {
847 	register tchar *sname = s;
848 
849 	while (1) {
850 		if (any('/', sname)) {
851 			while (*sname++ != '/')
852 				;
853 		} else {
854 			return (sname);
855 		}
856 	}
857 }
858