xref: /illumos-gate/usr/src/cmd/csh/sh.tchar.c (revision 6dde88b51419b99fe0aab8e56184c693945826b8)
1 /*
2  * Copyright 2006 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 /*
16  * This module provides with system/library function substitutes for tchar
17  * datatype. This also includes two conversion functions between tchar and
18  * char arrays.
19  *
20  * T. Kurosaka, Palo Alto, California, USA
21  * March 1989
22  *
23  * Implementation Notes:
24  *	Many functions defined here use a "char" buffer chbuf[].  In the
25  * first attempt, there used to be only one chbuf defined as static
26  * (private) variable and shared by these functions.  csh linked with that
27  * version of this file misbehaved in interpreting "eval `tset ....`".
28  * (in general, builtin function with back-quoted expression).
29  *	This bug seemed to be caused by sharing of chbuf
30  * by these functions simultanously (thru vfork() mechanism?).  We could not
31  * identify which two functions interfere each other so we decided to
32  * have each of these function its private instance of chbuf.
33  * The size of chbuf[] might be much bigger than necessary for some functions.
34  */
35 #ifdef DBG
36 #include <stdio.h>	/* For <assert.h> needs stderr defined. */
37 #else /* !DBG */
38 #define	NDEBUG		/* Disable assert(). */
39 #endif /* !DBG */
40 
41 #include <assert.h>
42 #include "sh.h"
43 
44 #ifdef MBCHAR
45 #include <widec.h>	/* For wcsetno() */
46 #endif
47 
48 #include <sys/param.h>	/* MAXPATHLEN */
49 #include <fcntl.h>
50 #include <unistd.h>
51 
52 bool	cflg;
53 
54 /*
55  * strtots(to, from): convert a char string 'from' into a tchar buffer 'to'.
56  *	'to' is assumed to have the enough size to hold the conversion result.
57  *	When 'to' is NOSTR(=(tchar *)0), strtots() attempts to allocate a space
58  *	automatically using xalloc().  It is caller's responsibility to
59  *	free the space allocated in this way, by calling xfree(ptr).
60  *	In either case, strtots() returns the pointer to the conversion
61  *	result (i.e. 'to', if 'to' wasn't NOSTR, or the allocated space.).
62  *	When a conversion or allocateion failed,  NOSTR is returned.
63  */
64 
65 tchar	*
66 strtots(tchar *to, char *from)
67 {
68 	int	i;
69 
70 	if (to == NOSTR) {	/* Need to xalloc(). */
71 		int	i;
72 
73 		i = mbstotcs(NOSTR, from, 0);
74 		if (i < 0) {
75 			return (NOSTR);
76 		}
77 
78 		/* Allocate space for the resulting tchar array. */
79 		to = (tchar *)xalloc(i * sizeof (tchar));
80 	}
81 	i = mbstotcs(to, from, INT_MAX);
82 	if (i < 0) {
83 		return (NOSTR);
84 	}
85 	return (to);
86 }
87 
88 char	*
89 tstostr(char *to, tchar *from)
90 {
91 	tchar	*ptc;
92 	wchar_t	wc;
93 	char	*pmb;
94 	int	len;
95 
96 	if (to == (char *)NULL) {	/* Need to xalloc(). */
97 		int	i;
98 		int	i1;
99 		char	junk[MB_LEN_MAX];
100 
101 		/* Get sum of byte counts for each char in from. */
102 		i = 0;
103 		ptc = from;
104 		while (wc = (wchar_t)((*ptc++)&TRIM)) {
105 			if ((i1 = wctomb(junk, wc)) <= 0) {
106 				i1 = 1;
107 			}
108 			i += i1;
109 		}
110 
111 		/* Allocate that much. */
112 		to = (char *)xalloc(i + 1);
113 	}
114 
115 	ptc = from;
116 	pmb = to;
117 	while (wc = (wchar_t)((*ptc++)&TRIM)) {
118 		if ((len = wctomb(pmb, wc)) <= 0) {
119 			*pmb = (unsigned char)wc;
120 			len = 1;
121 		}
122 		pmb += len;
123 	}
124 	*pmb = (char)0;
125 	return (to);
126 }
127 
128 /*
129  * mbstotcs(to, from, tosize) is similar to strtots() except that
130  * this returns # of tchars of the resulting tchar string.
131  * When NULL is give as the destination, no real conversion is carried out,
132  * and the function reports how many tchar characters would be made in
133  * the converted result including the terminating 0.
134  *	tchar	*to;	- Destination buffer, or NULL.
135  *	char	*from;	- Source string.
136  *	int	tosize; - Size of to, in terms of # of tchars.
137  */
138 int
139 mbstotcs(tchar *to, char *from, int tosize)
140 {
141 	tchar	*ptc = to;
142 	char	*pmb = from;
143 	wchar_t	wc;
144 	int	chcnt = 0;
145 	int	j;
146 
147 
148 	/* Just count how many tchar would be in the result. */
149 	if (to == (tchar *)NULL) {
150 		while (*pmb) {
151 			if ((j = mbtowc(&wc, pmb, MB_CUR_MAX)) <= 0) {
152 				j = 1;
153 			}
154 			pmb += j;
155 			chcnt++;
156 		}
157 		chcnt++;	/* For terminator. */
158 		return (chcnt);	/* # of chars including terminating zero. */
159 	} else {	/* Do the real conversion. */
160 		while (*pmb) {
161 			if ((j = mbtowc(&wc, pmb, MB_CUR_MAX)) <= 0) {
162 				wc = (unsigned char)*pmb;
163 				j = 1;
164 			}
165 			pmb += j;
166 			*(ptc++) = (tchar)wc;
167 			if (++chcnt >= tosize) {
168 				break;
169 			}
170 		}
171 		/* Terminate with zero only when space is left. */
172 		if (chcnt < tosize) {
173 			*ptc = (tchar)0;
174 			++chcnt;
175 		}
176 		return (chcnt); /* # of chars including terminating zero. */
177 	}
178 }
179 
180 
181 /* tchar version of STRING functions. */
182 
183 /*
184  * Returns the number of
185  * non-NULL tchar elements in tchar string argument.
186  */
187 int
188 strlen_(tchar *s)
189 {
190 	int n;
191 
192 	n = 0;
193 	while (*s++) {
194 		n++;
195 	}
196 	return (n);
197 }
198 
199 /*
200  * Concatenate tchar string s2 on the end of s1.  S1's space must be large
201  * enough.  Return s1.
202  */
203 tchar *
204 strcat_(tchar *s1, tchar *s2)
205 {
206 	tchar *os1;
207 
208 	os1 = s1;
209 	while (*s1++)
210 		;
211 	--s1;
212 	while (*s1++ = *s2++)
213 		;
214 	return (os1);
215 }
216 
217 /*
218  * Compare tchar strings:  s1>s2: >0  s1==s2: 0  s1<s2: <0
219  * BUGS: Comparison between two characters are done by subtracting two chars
220  *	after converting each to an unsigned long int value.  It might not make
221  *	a whole lot of sense to do that if the characters are in represented
222  *	as wide characters and the two characters belong to different codesets.
223  *	Therefore, this function should be used only to test the equallness.
224  */
225 int
226 strcmp_(tchar *s1, tchar *s2)
227 {
228 	while (*s1 == *s2++) {
229 		if (*s1++ == (tchar)0) {
230 			return (0);
231 		}
232 	}
233 	return (((unsigned long)*s1) - ((unsigned long)*(--s2)));
234 }
235 
236 /*
237  * This is only used in sh.glob.c for sorting purpose.
238  */
239 int
240 strcoll_(tchar *s1, tchar *s2)
241 {
242 	char buf1[BUFSIZ];
243 	char buf2[BUFSIZ];
244 
245 	tstostr(buf1, s1);
246 	tstostr(buf2, s2);
247 	return (strcoll(buf1, buf2));
248 }
249 
250 /*
251  * Copy tchar string s2 to s1.  s1 must be large enough.
252  * return s1
253  */
254 tchar *
255 strcpy_(tchar *s1, tchar *s2)
256 {
257 	tchar *os1;
258 
259 	os1 = s1;
260 	while (*s1++ = *s2++)
261 		;
262 	return (os1);
263 }
264 
265 /*
266  * Return the ptr in sp at which the character c appears;
267  * NULL if not found
268  */
269 tchar *
270 index_(tchar *sp, tchar c)
271 {
272 
273 	do {
274 		if (*sp == c) {
275 			return (sp);
276 		}
277 	} while (*sp++);
278 	return (NULL);
279 }
280 
281 /*
282  * Return the ptr in sp at which the character c last
283  * appears; NOSTR if not found
284  */
285 
286 tchar *
287 rindex_(tchar *sp, tchar c)
288 {
289 	tchar *r;
290 
291 	r = NOSTR;
292 	do {
293 		if (*sp == c) {
294 			r = sp;
295 		}
296 	} while (*sp++);
297 	return (r);
298 }
299 
300 /* Additional misc functions. */
301 
302 /* Calculate the display width of a string.  */
303 int
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(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 	int		mb_cur_max = MB_CUR_MAX;
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) > mb_cur_max) {
525 				b_len = mb_cur_max;
526 			}
527 			if ((j = mbtowc(&wc, (char *)s, b_len)) <=  0) {
528 				if (mb_cur_max > 1 && b_len < 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 				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) > 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 (mb_cur_max == 1 || (delta = q - s) == 0) {
566 		return (nchread);
567 	}
568 
569 	/*
570 	 * We may have (MB_CUR_MAX - 1) unread data in the buffer.
571 	 * Here, the last converted data was an illegal character which was
572 	 * treated as one byte character. We don't know at this point
573 	 * whether or not the remaining data is in legal sequence.
574 	 * We first attempt to convert the remaining data.
575 	 */
576 	do {
577 		if ((j = mbtowc(&wc, (char *)s, delta)) <= 0)
578 			break;
579 		*t++ = wc;
580 		nchread++;
581 		s += j;
582 		delta -= j;
583 	} while (delta > 0);
584 
585 	if (delta == 0)
586 		return (nchread);
587 
588 	/*
589 	 * There seem to be ugly sequence in the buffer. Fill up till
590 	 * mb_cur_max and see if we can get a right sequence.
591 	 */
592 	while (delta < mb_cur_max) {
593 		assert((q + 1) < (chbuf + sizeof (chbuf)));
594 		if (read(d, q, 1) != 1)
595 			break;
596 		delta++;
597 		q++;
598 		if (mbtowc(&wc, (char *)s, delta) > 0) {
599 			*t = wc;
600 			return (nchread + 1);
601 		}
602 	}
603 
604 	/*
605 	 * no luck. we have filled MB_CUR_MAX bytes in the buffer.
606 	 * Ideally we should return with leaving such data off and
607 	 * put them into a local buffer for next read, but we don't
608 	 * have such.
609 	 * So, stop reading further, and treat them as all single
610 	 * byte characters.
611 	 */
612 	while (s < q) {
613 		b_len = q - s;
614 		if ((j = mbtowc(&wc, (char *)s, b_len)) <=  0) {
615 			wc = (unsigned char)*s;
616 			j = 1;
617 		}
618 		*t++ = wc;
619 		nchread++;
620 		s += j;
621 	}
622 	return (nchread);
623 
624 #else /* !MBCHAR */
625 	/* One byte always represents one tchar.  Easy! */
626 	int		i;
627 	unsigned char	*s;
628 	tchar		*t;
629 	int		nchread;
630 
631 #ifdef DBG
632 	tprintf("Entering read_(d=%d, buf=0x%x, nchreq=%d);\n",
633 	    d, buf, nchreq);
634 #endif /* DBG */
635 	assert(nchreq <= BUFSIZ);
636 retry:
637 	nchread = read(d, (char *)chbuf, nchreq);
638 	/*
639 	 * when child sets O_NDELAY or O_NONBLOCK on stdin
640 	 * and exits and we are interactive then turn the modes off
641 	 * and retry
642 	 */
643 	if (nchread == 0) {
644 		if ((intty && !onelflg && !cflg) &&
645 		    ((fflags = fcntl(d, F_GETFL, 0)) & O_NDELAY)) {
646 			fflags &= ~O_NDELAY;
647 			fcntl(d, F_SETFL, fflags);
648 			goto retry;
649 		}
650 	} else if (nchread < 0) {
651 		if (errno == EAGAIN) {
652 			fflags = fcntl(d, F_GETFL, 0);
653 			fflags &= ~O_NONBLOCK;
654 			fcntl(d, F_SETFL, fflags);
655 			goto retry;
656 		}
657 		len = 0;
658 	} else {
659 		for (i = 0, t = buf, s = chbuf; i < nchread; ++i) {
660 		    *t++ = ((tchar)*s++);
661 		}
662 	}
663 	return (nchread);
664 #endif
665 }
666 
667 /*
668  * BUG: write_() returns -1 on failure, or # of BYTEs it has written.
669  *	For consistency and symmetry, it should return the number of
670  *	characters it has actually written, but that is technically
671  *	difficult although not impossible.  Anyway, the return
672  *	value of write() has never been used by the original csh,
673  *	so this bug should be OK.
674  */
675 int
676 write_(int d, tchar *buf, int nch)
677 {
678 	unsigned char chbuf[BUFSIZ*MB_LEN_MAX]; /* General use buffer. */
679 #ifdef MBCHAR
680 	tchar		*pt;
681 	unsigned char	*pc;
682 	wchar_t		wc;
683 	int		i, j;
684 
685 #ifdef	DBG
686 	tprintf("Entering write_(d=%d, buf=0x%x, nch=%d);\n",
687 	    d, buf, nch); /* Hope printf() doesn't call write_() itself! */
688 #endif /* DBG */
689 	assert(nch * MB_CUR_MAX < sizeof (chbuf));
690 	i = nch;
691 	pt = buf;
692 	pc = chbuf;
693 	while (i--) {
694 		/*
695 		 * Convert to tchar string.
696 		 * NUL is treated as normal char here.
697 		 */
698 		wc = (wchar_t)((*pt++)&TRIM);
699 		if (wc == (wchar_t)0) {
700 			*pc++ = 0;
701 		} else {
702 			if ((j = wctomb((char *)pc, wc)) <= 0) {
703 				*pc = (unsigned char)wc;
704 				j = 1;
705 			}
706 			pc += j;
707 		}
708 	}
709 	return (write(d, chbuf, pc - chbuf));
710 #else /* !MBCHAR */
711 	/* One byte always represents one tchar.  Easy! */
712 	int	i;
713 	unsigned char	*s;
714 	tchar	*t;
715 
716 #ifdef	DBG
717 	tprintf("Entering write_(d=%d, buf=0x%x, nch=%d);\n",
718 	    d, buf, nch); /* Hope printf() doesn't call write_() itself! */
719 #endif /* DBG */
720 	assert(nch <= sizeof (chbuf));
721 	for (i = 0, t = buf, s = chbuf; i < nch; ++i) {
722 	    *s++ = (char)((*t++)&0xff);
723 	}
724 	return (write(d, (char *)chbuf, nch));
725 #endif
726 }
727 
728 #undef chbuf
729 
730 #include <sys/types.h>
731 #include <sys/stat.h>	/* satruct stat */
732 #include <dirent.h>	/* DIR */
733 
734 extern DIR *Dirp;
735 
736 int
737 stat_(tchar *path, struct stat *buf)
738 {
739 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
740 
741 	tstostr(chbuf, path);
742 	return (stat((char *)chbuf, buf));
743 }
744 
745 int
746 lstat_(tchar *path, struct stat *buf)
747 {
748 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
749 
750 	tstostr(chbuf, path);
751 	return (lstat((char *)chbuf, buf));
752 }
753 
754 int
755 chdir_(tchar *path)
756 {
757 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
758 
759 	tstostr(chbuf, path);
760 	return (chdir((char *)chbuf));
761 }
762 
763 tchar *
764 getwd_(tchar *path)
765 {
766 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
767 	int	rc;
768 
769 	rc = (int)getwd((char *)chbuf);
770 	if (rc == 0) {
771 		return (0);
772 	} else {
773 		return (strtots(path, chbuf));
774 	}
775 }
776 
777 int
778 unlink_(tchar *path)
779 {
780 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
781 
782 	tstostr(chbuf, path);
783 	return (unlink((char *)chbuf));
784 }
785 
786 DIR *
787 opendir_(tchar *dirname)
788 {
789 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
790 
791 	extern DIR *opendir();
792 	DIR	*dir;
793 
794 	dir = opendir(tstostr(chbuf, dirname));
795 	if (dir != NULL) {
796 		setfd(dir->dd_fd);
797 	}
798 	return (Dirp = dir);
799 }
800 
801 int
802 closedir_(DIR *dirp)
803 {
804 	int ret;
805 	extern int closedir();
806 
807 	ret = closedir(dirp);
808 	Dirp = NULL;
809 	return (ret);
810 }
811 
812 int
813 gethostname_(tchar *name, int namelen)
814 {
815 	char chbuf[BUFSIZ * MB_LEN_MAX]; /* General use buffer. */
816 
817 	assert(namelen < BUFSIZ);
818 	if (gethostname((char *)chbuf, sizeof (chbuf)) != 0) {
819 		return (-1);
820 	}
821 	if (mbstotcs(name, chbuf, namelen) < 0) {
822 		return (-1);
823 	}
824 	return (0); /* Succeeded. */
825 }
826 
827 int
828 readlink_(tchar *path, tchar *buf, int bufsiz)
829 {
830 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
831 	char	chpath[MAXPATHLEN + 1];
832 	int	i;
833 
834 	tstostr(chpath, path);
835 	i = readlink(chpath, (char *)chbuf, sizeof (chbuf));
836 	if (i < 0) {
837 		return (-1);
838 	}
839 	chbuf[i] = (char)0;	/* readlink() doesn't put NULL. */
840 	i = mbstotcs(buf, chbuf, bufsiz);
841 	if (i < 0) {
842 		return (-1);
843 	}
844 	return (i - 1); /* Return # of tchars EXCLUDING the terminating NULL. */
845 }
846 
847 /* checks that it's a number */
848 
849 int
850 chkalldigit_(tchar *str)
851 {
852 	char chbuf[BUFSIZ * MB_LEN_MAX]; /* General use buffer. */
853 	char *c = chbuf;
854 
855 	(void) tstostr(chbuf, str);
856 
857 	while (*c)
858 		if (!isdigit(*(c++)))
859 			return (-1);
860 
861 	return (0);
862 }
863 
864 int
865 atoi_(tchar *str)
866 {
867 	char chbuf[BUFSIZ * MB_LEN_MAX]; /* General use buffer. */
868 
869 	tstostr(chbuf, str);
870 	return (atoi((char *)chbuf));
871 }
872 
873 tchar *
874 simple(tchar *s)
875 {
876 	tchar *sname = s;
877 
878 	while (1) {
879 		if (any('/', sname)) {
880 			while (*sname++ != '/')
881 				;
882 		} else {
883 			return (sname);
884 		}
885 	}
886 }
887