xref: /illumos-gate/usr/src/cmd/csh/sh.tchar.c (revision 032624d56c174c5c55126582b32e314a6af15522)
1 /*
2  * Copyright 2005 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 int
305 tswidth(tchar *ts)
306 {
307 #ifdef MBCHAR
308 	wchar_t	tc;
309 	int	w = 0;
310 	int	p_col;
311 
312 	while (tc = *ts++) {
313 		if ((p_col = wcwidth((wchar_t)tc)) > 0)
314 			w += p_col;
315 	}
316 	return (w);
317 #else /* !MBCHAR --- one char always occupies one column. */
318 	return (strlen_(ts));
319 #endif
320 }
321 
322 /*
323  * Two getenv() substitute functions.  They differ in the type of arguments.
324  * BUGS: Both returns the pointer to an allocated space where the env var's
325  *	values is stored.  This space is freed automatically on the successive
326  *	call of	either function.  Therefore the caller must copy the contents
327  *	if it needs to access two env vars.  There is an arbitary limitation
328  *	on the number of chars of a env var name.
329  */
330 #define	LONGEST_ENVVARNAME	256		/* Too big? */
331 tchar *
332 getenv_(tchar *name_)
333 {
334 	char	name[LONGEST_ENVVARNAME * MB_LEN_MAX];
335 
336 	assert(strlen_(name_) < LONGEST_ENVVARNAME);
337 	return (getenvs_(tstostr(name, name_)));
338 }
339 
340 tchar *
341 getenvs_(char *name)
342 {
343 	static tchar	*pbuf = (tchar *)NULL;
344 	char	*val;
345 
346 	if (pbuf) {
347 		XFREE((void *)pbuf);
348 		pbuf = NOSTR;
349 	}
350 	val = getenv(name);
351 	if (val == (char *)NULL) {
352 		return (NOSTR);
353 	}
354 	return (pbuf = strtots(NOSTR, val));
355 }
356 
357 /* Followings are the system call interface for tchar strings. */
358 
359 /*
360  * creat() and open() replacement.
361  * BUGS: An unusually long file name could be dangerous.
362  */
363 int
364 creat_(tchar *name_, int mode)
365 {
366 	int fd;
367 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
368 
369 	tstostr(chbuf, name_);
370 	fd = creat((char *)chbuf, mode);
371 	if (fd != -1) {
372 		setfd(fd);
373 	}
374 	return (fd);
375 }
376 
377 /*VARARGS2*/
378 int
379 open_(path_, flags, mode)
380 	tchar 	*path_;
381 	int	flags;
382 	int	mode; /* May be omitted. */
383 {
384 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
385 	int fd;
386 
387 	tstostr(chbuf, path_);
388 	fd = open((char *)chbuf, flags, mode);
389 	if (fd != -1) {
390 		setfd(fd);
391 	}
392 	return (fd);
393 }
394 
395 /*
396  * mkstemp replacement
397  */
398 int
399 mkstemp_(tchar *name_)
400 {
401 	int fd;
402 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
403 
404 	tstostr(chbuf, name_);
405 	fd = mkstemp((char *)chbuf);
406 	if (fd != -1) {
407 		setfd(fd);
408 		strtots(name_, chbuf);
409 	}
410 	return (fd);
411 }
412 
413 /*
414  * read() and write() reaplacement.
415  *	int        d;
416  *	tchar      *buf;  - where the result be stored.  Not NULL terminated.
417  *	int        nchreq; - # of tchars requrested.
418  */
419 int
420 read_(int d, tchar *buf, int nchreq)
421 {
422 	unsigned char chbuf[BUFSIZ * MB_LEN_MAX]; /* General use buffer. */
423 #ifdef MBCHAR
424 	/*
425 	 * We would have to read more than tchar bytes
426 	 * when there are multibyte characters in the file.
427 	 */
428 	int	i, j, fflags;
429 	unsigned char	*s;	/* Byte being scanned for a multibyte char. */
430 	/* Points to the pos where next read() to read the data into. */
431 	unsigned char	*p;
432 	tchar	*t;
433 	wchar_t		wc;
434 	int		b_len;
435 	int		nchread = 0; /* Count how many bytes has been read. */
436 	int		nbytread = 0; /* Total # of bytes read. */
437 	/* # of bytes needed to complete the last char just read. */
438 	int		delta;
439 	unsigned char	*q;	/* q points to the first invalid byte. */
440 #ifdef DBG
441 	tprintf("Entering read_(d=%d, buf=0x%x, nchreq=%d);\n",
442 	    d, buf, nchreq);
443 #endif /* DBG */
444 	/*
445 	 *	Step 1: We collect the exact number of bytes that make
446 	 *	nchreq characters into chbuf.
447 	 *	We must be careful not to read too many bytes as we
448 	 *	cannot push back such over-read bytes.
449 	 *	The idea we use here is that n multibyte characters are stored
450 	 *	in no less than n but less than n*MB_CUR_MAX bytes.
451 	 */
452 	assert(nchreq <= BUFSIZ);
453 	delta = 0;
454 	p = s = chbuf;
455 	t = buf;
456 	while (nchread < nchreq) {
457 		int		m;  /* # of bytes to try to read this time. */
458 		int		k;  /* # of bytes successfully read. */
459 
460 retry:
461 		/*
462 		 * Let's say the (N+1)'th byte bN is actually the first
463 		 * byte of a three-byte character c.
464 		 * In that case, p, s, q look like this:
465 		 *
466 		 *		/-- already read--\ /-- not yet read --\
467 		 * chbuf[]:	b0 b1 ..... bN bN+1 bN+2 bN+2 ...
468 		 *		^		^	^
469 		 *		|		|	|
470 		 *		p		s	q
471 		 *				\----------/
472 		 *				c hasn't been completed
473 		 *
474 		 * Just after the next read(), p and q will be adavanced to:
475 		 *
476 		 *	/-- already read-----------------------\ /-- not yet -
477 		 * chbuf[]: b0 b1 ..... bN bN+1 bN+2 bN+2 ... bX bX+1 bX+2...
478 		 *			^	^		 ^
479 		 *			|	|		 |
480 		 *			s	p		 q
481 		 *			\----------/
482 		 *			 c has been completed
483 		 *			 but hasn't been scanned
484 		 */
485 		m = nchreq - nchread;
486 		assert(p + m < chbuf + sizeof (chbuf));
487 		k = read(d, p, m);
488 		/*
489 		 * when child sets O_NDELAY or O_NONBLOCK on stdin
490 		 * and exits and we are interactive then turn the modes off
491 		 * and retry
492 		 */
493 		if (k == 0) {
494 			if ((intty && !onelflg && !cflg) &&
495 			    ((fflags = fcntl(d, F_GETFL, 0)) & O_NDELAY)) {
496 				fflags &= ~O_NDELAY;
497 				fcntl(d, F_SETFL, fflags);
498 				goto retry;
499 			}
500 		} else if (k < 0) {
501 			if (errno == EAGAIN) {
502 				fflags = fcntl(d, F_GETFL, 0);
503 				fflags &= ~O_NONBLOCK;
504 				fcntl(d, F_SETFL, fflags);
505 				goto retry;
506 			}
507 			return (-1);
508 		}
509 		nbytread += k;
510 		q = p + k;
511 		delta = 0;
512 
513 		/* Try scaning characters in s..q-1 */
514 		while (s < q) {
515 			/* Convert the collected bytes into tchar array. */
516 			if (*s == 0) {
517 				/* NUL is treated as a normal char here. */
518 				*t++ = 0;
519 				s++;
520 				nchread++;
521 				continue;
522 			}
523 
524 			if ((b_len = q - s) > (int)MB_CUR_MAX) {
525 				b_len = MB_CUR_MAX;
526 			}
527 			if ((j = mbtowc(&wc, (char *)s, b_len)) <=  0) {
528 				if (b_len < (unsigned int)MB_CUR_MAX) {
529 					/*
530 					 * Needs more byte to complete this char
531 					 * In order to read() more than delta
532 					 * bytes.
533 					 */
534 					break;
535 				}
536 
537 				wc = (unsigned char)*s;
538 				j = 1;
539 			}
540 
541 			*t++ = wc;
542 			nchread++;
543 			s += j;
544 		}
545 
546 		if (k < m) {
547 			/* We've read as many bytes as possible. */
548 			while (s < q) {
549 				if ((b_len = q - s) > (int)MB_CUR_MAX) {
550 					b_len = MB_CUR_MAX;
551 				}
552 				if ((j = mbtowc(&wc, (char *)s, b_len)) <=  0) {
553 					wc = (unsigned char)*s;
554 					j = 1;
555 				}
556 				*t++ = wc;
557 				nchread++;
558 				s += j;
559 			}
560 			return (nchread);
561 		}
562 
563 		p = q;
564 	}
565 
566 	if ((delta = q - s) == 0) {
567 		return (nchread);
568 	}
569 
570 	if (*(s + delta - 1) == '\n') {
571 		while (s < q) {
572 			if ((b_len = q - s) > (int)MB_CUR_MAX) {
573 				b_len = MB_CUR_MAX;
574 			}
575 			if ((j = mbtowc(&wc, (char *)s, b_len)) <=  0) {
576 				wc = (unsigned char)*s;
577 				j = 1;
578 			}
579 			*t++ = wc;
580 			nchread++;
581 			s += j;
582 		}
583 		return (nchread);
584 	}
585 
586 	for (; delta < (int)MB_CUR_MAX; delta++, q++) {
587 		assert((q + 1) < (chbuf + sizeof (chbuf)));
588 		if (read(d, q, 1) != 1) {
589 			break;
590 		}
591 		if (*q == '\n') {
592 			break;
593 		}
594 		if (mbtowc(&wc, (char *)s, delta) > 0) {
595 			*t = wc;
596 			return (nchread + 1);
597 		}
598 	}
599 
600 	while (s < q) {
601 		if ((b_len = q - s) > (int)MB_CUR_MAX) {
602 			b_len = MB_CUR_MAX;
603 		}
604 		if ((j = mbtowc(&wc, (char *)s, b_len)) <=  0) {
605 			wc = (unsigned char)*s;
606 			j = 1;
607 		}
608 		*t++ = wc;
609 		nchread++;
610 		s += j;
611 	}
612 	return (nchread);
613 #else /* !MBCHAR */
614 	/* One byte always represents one tchar.  Easy! */
615 	int		i;
616 	unsigned char	*s;
617 	tchar		*t;
618 	int		nchread;
619 
620 #ifdef DBG
621 	tprintf("Entering read_(d=%d, buf=0x%x, nchreq=%d);\n",
622 	    d, buf, nchreq);
623 #endif /* DBG */
624 	assert(nchreq <= BUFSIZ);
625 retry:
626 	nchread = read(d, (char *)chbuf, nchreq);
627 	/*
628 	 * when child sets O_NDELAY or O_NONBLOCK on stdin
629 	 * and exits and we are interactive then turn the modes off
630 	 * and retry
631 	 */
632 	if (nchread == 0) {
633 		if ((intty && !onelflg && !cflg) &&
634 		    ((fflags = fcntl(d, F_GETFL, 0)) & O_NDELAY)) {
635 			fflags &= ~O_NDELAY;
636 			fcntl(d, F_SETFL, fflags);
637 			goto retry;
638 		}
639 	} else if (nchread < 0) {
640 		if (errno == EAGAIN) {
641 			fflags = fcntl(d, F_GETFL, 0);
642 			fflags &= ~O_NONBLOCK;
643 			fcntl(d, F_SETFL, fflags);
644 			goto retry;
645 		}
646 		len = 0;
647 	} else {
648 		for (i = 0, t = buf, s = chbuf; i < nchread; ++i) {
649 		    *t++ = ((tchar)*s++);
650 		}
651 	}
652 	return (nchread);
653 #endif
654 }
655 
656 /*
657  * BUG: write_() returns -1 on failure, or # of BYTEs it has written.
658  *	For consistency and symmetry, it should return the number of
659  *	characters it has actually written, but that is technically
660  *	difficult although not impossible.  Anyway, the return
661  *	value of write() has never been used by the original csh,
662  *	so this bug should be OK.
663  */
664 int
665 write_(int d, tchar *buf, int nch)
666 {
667 	unsigned char chbuf[BUFSIZ*MB_LEN_MAX]; /* General use buffer. */
668 #ifdef MBCHAR
669 	tchar		*pt;
670 	unsigned char	*pc;
671 	wchar_t		wc;
672 	int		i, j;
673 
674 #ifdef	DBG
675 	tprintf("Entering write_(d=%d, buf=0x%x, nch=%d);\n",
676 	    d, buf, nch); /* Hope printf() doesn't call write_() itself! */
677 #endif /* DBG */
678 	assert(nch * MB_CUR_MAX < sizeof (chbuf));
679 	i = nch;
680 	pt = buf;
681 	pc = chbuf;
682 	while (i--) {
683 		/*
684 		 * Convert to tchar string.
685 		 * NUL is treated as normal char here.
686 		 */
687 		wc = (wchar_t)((*pt++)&TRIM);
688 		if (wc == (wchar_t)0) {
689 			*pc++ = 0;
690 		} else {
691 			if ((j = wctomb((char *)pc, wc)) <= 0) {
692 				*pc = (unsigned char)wc;
693 				j = 1;
694 			}
695 			pc += j;
696 		}
697 	}
698 	return (write(d, chbuf, pc - chbuf));
699 #else /* !MBCHAR */
700 	/* One byte always represents one tchar.  Easy! */
701 	int	i;
702 	unsigned char	*s;
703 	tchar	*t;
704 
705 #ifdef	DBG
706 	tprintf("Entering write_(d=%d, buf=0x%x, nch=%d);\n",
707 	    d, buf, nch); /* Hope printf() doesn't call write_() itself! */
708 #endif /* DBG */
709 	assert(nch <= sizeof (chbuf));
710 	for (i = 0, t = buf, s = chbuf; i < nch; ++i) {
711 	    *s++ = (char)((*t++)&0xff);
712 	}
713 	return (write(d, (char *)chbuf, nch));
714 #endif
715 }
716 
717 #undef chbuf
718 
719 #include <sys/types.h>
720 #include <sys/stat.h>	/* satruct stat */
721 #include <dirent.h>	/* DIR */
722 
723 extern DIR *Dirp;
724 
725 int
726 stat_(tchar *path, struct stat *buf)
727 {
728 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
729 
730 	tstostr(chbuf, path);
731 	return (stat((char *)chbuf, buf));
732 }
733 
734 int
735 lstat_(tchar *path, struct stat *buf)
736 {
737 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
738 
739 	tstostr(chbuf, path);
740 	return (lstat((char *)chbuf, buf));
741 }
742 
743 int
744 chdir_(tchar *path)
745 {
746 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
747 
748 	tstostr(chbuf, path);
749 	return (chdir((char *)chbuf));
750 }
751 
752 tchar *
753 getwd_(tchar *path)
754 {
755 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
756 	int	rc;
757 
758 	rc = (int)getwd((char *)chbuf);
759 	if (rc == 0) {
760 		return (0);
761 	} else {
762 		return (strtots(path, chbuf));
763 	}
764 }
765 
766 int
767 unlink_(tchar *path)
768 {
769 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
770 
771 	tstostr(chbuf, path);
772 	return (unlink((char *)chbuf));
773 }
774 
775 DIR *
776 opendir_(tchar *dirname)
777 {
778 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
779 
780 	extern DIR *opendir();
781 	DIR	*dir;
782 
783 	dir = opendir(tstostr(chbuf, dirname));
784 	if (dir != NULL) {
785 		setfd(dir->dd_fd);
786 	}
787 	return (Dirp = dir);
788 }
789 
790 int
791 closedir_(DIR *dirp)
792 {
793 	int ret;
794 	extern int closedir();
795 
796 	ret = closedir(dirp);
797 	Dirp = NULL;
798 	return (ret);
799 }
800 
801 int
802 gethostname_(tchar *name, int namelen)
803 {
804 	char chbuf[BUFSIZ * MB_LEN_MAX]; /* General use buffer. */
805 
806 	assert(namelen < BUFSIZ);
807 	if (gethostname((char *)chbuf, sizeof (chbuf)) != 0) {
808 		return (-1);
809 	}
810 	if (mbstotcs(name, chbuf, namelen) < 0) {
811 		return (-1);
812 	}
813 	return (0); /* Succeeded. */
814 }
815 
816 int
817 readlink_(tchar *path, tchar *buf, int bufsiz)
818 {
819 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
820 	char	chpath[MAXPATHLEN + 1];
821 	int	i;
822 
823 	tstostr(chpath, path);
824 	i = readlink(chpath, (char *)chbuf, sizeof (chbuf));
825 	if (i < 0) {
826 		return (-1);
827 	}
828 	chbuf[i] = (char)0;	/* readlink() doesn't put NULL. */
829 	i = mbstotcs(buf, chbuf, bufsiz);
830 	if (i < 0) {
831 		return (-1);
832 	}
833 	return (i - 1); /* Return # of tchars EXCLUDING the terminating NULL. */
834 }
835 
836 int
837 atoi_(tchar *str)
838 {
839 	char chbuf[BUFSIZ * MB_LEN_MAX]; /* General use buffer. */
840 
841 	tstostr(chbuf, str);
842 	return (atoi((char *)chbuf));
843 }
844 
845 tchar *
846 simple(tchar *s)
847 {
848 	tchar *sname = s;
849 
850 	while (1) {
851 		if (any('/', sname)) {
852 			while (*sname++ != '/')
853 				;
854 		} else {
855 			return (sname);
856 		}
857 	}
858 }
859