xref: /illumos-gate/usr/src/cmd/csh/sh.tchar.c (revision 70a587dd)
17c478bd9Sstevel@tonic-gate /*
2*70a587ddSchin  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
37c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
47c478bd9Sstevel@tonic-gate  */
57c478bd9Sstevel@tonic-gate 
67c478bd9Sstevel@tonic-gate /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
77c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
87c478bd9Sstevel@tonic-gate 
97c478bd9Sstevel@tonic-gate /*
107c478bd9Sstevel@tonic-gate  * Copyright (c) 1980 Regents of the University of California.
117c478bd9Sstevel@tonic-gate  * All rights reserved. The Berkeley Software License Agreement
127c478bd9Sstevel@tonic-gate  * specifies the terms and conditions for redistribution.
137c478bd9Sstevel@tonic-gate  */
147c478bd9Sstevel@tonic-gate 
157c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
167c478bd9Sstevel@tonic-gate 
177c478bd9Sstevel@tonic-gate /*
187c478bd9Sstevel@tonic-gate  * This module provides with system/library function substitutes for tchar
197c478bd9Sstevel@tonic-gate  * datatype. This also includes two conversion functions between tchar and
207c478bd9Sstevel@tonic-gate  * char arrays.
217c478bd9Sstevel@tonic-gate  *
227c478bd9Sstevel@tonic-gate  * T. Kurosaka, Palo Alto, California, USA
237c478bd9Sstevel@tonic-gate  * March 1989
247c478bd9Sstevel@tonic-gate  *
257c478bd9Sstevel@tonic-gate  * Implementation Notes:
267c478bd9Sstevel@tonic-gate  *	Many functions defined here use a "char" buffer chbuf[].  In the
277c478bd9Sstevel@tonic-gate  * first attempt, there used to be only one chbuf defined as static
287c478bd9Sstevel@tonic-gate  * (private) variable and shared by these functions.  csh linked with that
297c478bd9Sstevel@tonic-gate  * version of this file misbehaved in interpreting "eval `tset ....`".
307c478bd9Sstevel@tonic-gate  * (in general, builtin function with back-quoted expression).
317c478bd9Sstevel@tonic-gate  *	This bug seemed to be caused by sharing of chbuf
327c478bd9Sstevel@tonic-gate  * by these functions simultanously (thru vfork() mechanism?).  We could not
337c478bd9Sstevel@tonic-gate  * identify which two functions interfere each other so we decided to
347c478bd9Sstevel@tonic-gate  * have each of these function its private instance of chbuf.
357c478bd9Sstevel@tonic-gate  * The size of chbuf[] might be much bigger than necessary for some functions.
367c478bd9Sstevel@tonic-gate  */
377c478bd9Sstevel@tonic-gate #ifdef DBG
387c478bd9Sstevel@tonic-gate #include <stdio.h>	/* For <assert.h> needs stderr defined. */
397c478bd9Sstevel@tonic-gate #else /* !DBG */
407c478bd9Sstevel@tonic-gate #define	NDEBUG		/* Disable assert(). */
417c478bd9Sstevel@tonic-gate #endif /* !DBG */
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate #include <assert.h>
447c478bd9Sstevel@tonic-gate #include "sh.h"
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #ifdef MBCHAR
477c478bd9Sstevel@tonic-gate #include <widec.h>	/* For wcsetno() */
487c478bd9Sstevel@tonic-gate #endif
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate #include <sys/param.h>	/* MAXPATHLEN */
517c478bd9Sstevel@tonic-gate #include <fcntl.h>
527c478bd9Sstevel@tonic-gate #include <unistd.h>
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate 
557c478bd9Sstevel@tonic-gate /*
567c478bd9Sstevel@tonic-gate  * strtots(to, from): convert a char string 'from' into a tchar buffer 'to'.
577c478bd9Sstevel@tonic-gate  *	'to' is assumed to have the enough size to hold the conversion result.
587c478bd9Sstevel@tonic-gate  *	When 'to' is NOSTR(=(tchar *)0), strtots() attempts to allocate a space
597c478bd9Sstevel@tonic-gate  *	automatically using xalloc().  It is caller's responsibility to
6065b0c20eSnakanon  *	free the space allocated in this way, by calling xfree(ptr).
617c478bd9Sstevel@tonic-gate  *	In either case, strtots() returns the pointer to the conversion
627c478bd9Sstevel@tonic-gate  *	result (i.e. 'to', if 'to' wasn't NOSTR, or the allocated space.).
637c478bd9Sstevel@tonic-gate  *	When a conversion or allocateion failed,  NOSTR is returned.
647c478bd9Sstevel@tonic-gate  */
657c478bd9Sstevel@tonic-gate 
667c478bd9Sstevel@tonic-gate tchar	*
677c478bd9Sstevel@tonic-gate strtots(tchar *to, char *from)
687c478bd9Sstevel@tonic-gate {
697c478bd9Sstevel@tonic-gate 	int	i;
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate 	if (to == NOSTR) {	/* Need to xalloc(). */
727c478bd9Sstevel@tonic-gate 		int	i;
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate 		i = mbstotcs(NOSTR, from, 0);
757c478bd9Sstevel@tonic-gate 		if (i < 0) {
767c478bd9Sstevel@tonic-gate 			return (NOSTR);
777c478bd9Sstevel@tonic-gate 		}
787c478bd9Sstevel@tonic-gate 
797c478bd9Sstevel@tonic-gate 		/* Allocate space for the resulting tchar array. */
807c478bd9Sstevel@tonic-gate 		to = (tchar *)xalloc(i * sizeof (tchar));
817c478bd9Sstevel@tonic-gate 	}
827c478bd9Sstevel@tonic-gate 	i = mbstotcs(to, from, INT_MAX);
837c478bd9Sstevel@tonic-gate 	if (i < 0) {
847c478bd9Sstevel@tonic-gate 		return (NOSTR);
857c478bd9Sstevel@tonic-gate 	}
867c478bd9Sstevel@tonic-gate 	return (to);
877c478bd9Sstevel@tonic-gate }
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate char	*
907c478bd9Sstevel@tonic-gate tstostr(char *to, tchar *from)
917c478bd9Sstevel@tonic-gate {
927c478bd9Sstevel@tonic-gate 	tchar	*ptc;
937c478bd9Sstevel@tonic-gate 	wchar_t	wc;
947c478bd9Sstevel@tonic-gate 	char	*pmb;
957c478bd9Sstevel@tonic-gate 	int	len;
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 	if (to == (char *)NULL) {	/* Need to xalloc(). */
987c478bd9Sstevel@tonic-gate 		int	i;
997c478bd9Sstevel@tonic-gate 		int	i1;
1007c478bd9Sstevel@tonic-gate 		char	junk[MB_LEN_MAX];
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate 		/* Get sum of byte counts for each char in from. */
1037c478bd9Sstevel@tonic-gate 		i = 0;
1047c478bd9Sstevel@tonic-gate 		ptc = from;
1057c478bd9Sstevel@tonic-gate 		while (wc = (wchar_t)((*ptc++)&TRIM)) {
1067c478bd9Sstevel@tonic-gate 			if ((i1 = wctomb(junk, wc)) <= 0) {
1077c478bd9Sstevel@tonic-gate 				i1 = 1;
1087c478bd9Sstevel@tonic-gate 			}
1097c478bd9Sstevel@tonic-gate 			i += i1;
1107c478bd9Sstevel@tonic-gate 		}
1117c478bd9Sstevel@tonic-gate 
1127c478bd9Sstevel@tonic-gate 		/* Allocate that much. */
1137c478bd9Sstevel@tonic-gate 		to = (char *)xalloc(i + 1);
1147c478bd9Sstevel@tonic-gate 	}
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate 	ptc = from;
1177c478bd9Sstevel@tonic-gate 	pmb = to;
1187c478bd9Sstevel@tonic-gate 	while (wc = (wchar_t)((*ptc++)&TRIM)) {
1197c478bd9Sstevel@tonic-gate 		if ((len = wctomb(pmb, wc)) <= 0) {
1207c478bd9Sstevel@tonic-gate 			*pmb = (unsigned char)wc;
1217c478bd9Sstevel@tonic-gate 			len = 1;
1227c478bd9Sstevel@tonic-gate 		}
1237c478bd9Sstevel@tonic-gate 		pmb += len;
1247c478bd9Sstevel@tonic-gate 	}
1257c478bd9Sstevel@tonic-gate 	*pmb = (char)0;
1267c478bd9Sstevel@tonic-gate 	return (to);
1277c478bd9Sstevel@tonic-gate }
1287c478bd9Sstevel@tonic-gate 
1297c478bd9Sstevel@tonic-gate /*
1307c478bd9Sstevel@tonic-gate  * mbstotcs(to, from, tosize) is similar to strtots() except that
1317c478bd9Sstevel@tonic-gate  * this returns # of tchars of the resulting tchar string.
1327c478bd9Sstevel@tonic-gate  * When NULL is give as the destination, no real conversion is carried out,
1337c478bd9Sstevel@tonic-gate  * and the function reports how many tchar characters would be made in
1347c478bd9Sstevel@tonic-gate  * the converted result including the terminating 0.
1357c478bd9Sstevel@tonic-gate  *	tchar	*to;	- Destination buffer, or NULL.
1367c478bd9Sstevel@tonic-gate  *	char	*from;	- Source string.
1377c478bd9Sstevel@tonic-gate  *	int	tosize; - Size of to, in terms of # of tchars.
1387c478bd9Sstevel@tonic-gate  */
1397c478bd9Sstevel@tonic-gate int
1407c478bd9Sstevel@tonic-gate mbstotcs(tchar *to, char *from, int tosize)
1417c478bd9Sstevel@tonic-gate {
1427c478bd9Sstevel@tonic-gate 	tchar	*ptc = to;
1437c478bd9Sstevel@tonic-gate 	char	*pmb = from;
1447c478bd9Sstevel@tonic-gate 	wchar_t	wc;
1457c478bd9Sstevel@tonic-gate 	int	chcnt = 0;
1467c478bd9Sstevel@tonic-gate 	int	j;
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate 	/* Just count how many tchar would be in the result. */
1507c478bd9Sstevel@tonic-gate 	if (to == (tchar *)NULL) {
1517c478bd9Sstevel@tonic-gate 		while (*pmb) {
1527c478bd9Sstevel@tonic-gate 			if ((j = mbtowc(&wc, pmb, MB_CUR_MAX)) <= 0) {
1537c478bd9Sstevel@tonic-gate 				j = 1;
1547c478bd9Sstevel@tonic-gate 			}
1557c478bd9Sstevel@tonic-gate 			pmb += j;
1567c478bd9Sstevel@tonic-gate 			chcnt++;
1577c478bd9Sstevel@tonic-gate 		}
1587c478bd9Sstevel@tonic-gate 		chcnt++;	/* For terminator. */
1597c478bd9Sstevel@tonic-gate 		return (chcnt);	/* # of chars including terminating zero. */
1607c478bd9Sstevel@tonic-gate 	} else {	/* Do the real conversion. */
1617c478bd9Sstevel@tonic-gate 		while (*pmb) {
1627c478bd9Sstevel@tonic-gate 			if ((j = mbtowc(&wc, pmb, MB_CUR_MAX)) <= 0) {
1637c478bd9Sstevel@tonic-gate 				wc = (unsigned char)*pmb;
1647c478bd9Sstevel@tonic-gate 				j = 1;
1657c478bd9Sstevel@tonic-gate 			}
1667c478bd9Sstevel@tonic-gate 			pmb += j;
1677c478bd9Sstevel@tonic-gate 			*(ptc++) = (tchar)wc;
1687c478bd9Sstevel@tonic-gate 			if (++chcnt >= tosize) {
1697c478bd9Sstevel@tonic-gate 				break;
1707c478bd9Sstevel@tonic-gate 			}
1717c478bd9Sstevel@tonic-gate 		}
1727c478bd9Sstevel@tonic-gate 		/* Terminate with zero only when space is left. */
1737c478bd9Sstevel@tonic-gate 		if (chcnt < tosize) {
1747c478bd9Sstevel@tonic-gate 			*ptc = (tchar)0;
1757c478bd9Sstevel@tonic-gate 			++chcnt;
1767c478bd9Sstevel@tonic-gate 		}
1777c478bd9Sstevel@tonic-gate 		return (chcnt); /* # of chars including terminating zero. */
1787c478bd9Sstevel@tonic-gate 	}
1797c478bd9Sstevel@tonic-gate }
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 
1827c478bd9Sstevel@tonic-gate /* tchar version of STRING functions. */
1837c478bd9Sstevel@tonic-gate 
1847c478bd9Sstevel@tonic-gate /*
1857c478bd9Sstevel@tonic-gate  * Returns the number of
1867c478bd9Sstevel@tonic-gate  * non-NULL tchar elements in tchar string argument.
1877c478bd9Sstevel@tonic-gate  */
1887c478bd9Sstevel@tonic-gate int
1897c478bd9Sstevel@tonic-gate strlen_(tchar *s)
1907c478bd9Sstevel@tonic-gate {
1917c478bd9Sstevel@tonic-gate 	int n;
1927c478bd9Sstevel@tonic-gate 
1937c478bd9Sstevel@tonic-gate 	n = 0;
1947c478bd9Sstevel@tonic-gate 	while (*s++) {
1957c478bd9Sstevel@tonic-gate 		n++;
1967c478bd9Sstevel@tonic-gate 	}
1977c478bd9Sstevel@tonic-gate 	return (n);
1987c478bd9Sstevel@tonic-gate }
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate /*
2017c478bd9Sstevel@tonic-gate  * Concatenate tchar string s2 on the end of s1.  S1's space must be large
2027c478bd9Sstevel@tonic-gate  * enough.  Return s1.
2037c478bd9Sstevel@tonic-gate  */
2047c478bd9Sstevel@tonic-gate tchar *
2057c478bd9Sstevel@tonic-gate strcat_(tchar *s1, tchar *s2)
2067c478bd9Sstevel@tonic-gate {
2077c478bd9Sstevel@tonic-gate 	tchar *os1;
2087c478bd9Sstevel@tonic-gate 
2097c478bd9Sstevel@tonic-gate 	os1 = s1;
2107c478bd9Sstevel@tonic-gate 	while (*s1++)
2117c478bd9Sstevel@tonic-gate 		;
2127c478bd9Sstevel@tonic-gate 	--s1;
2137c478bd9Sstevel@tonic-gate 	while (*s1++ = *s2++)
2147c478bd9Sstevel@tonic-gate 		;
2157c478bd9Sstevel@tonic-gate 	return (os1);
2167c478bd9Sstevel@tonic-gate }
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate /*
2197c478bd9Sstevel@tonic-gate  * Compare tchar strings:  s1>s2: >0  s1==s2: 0  s1<s2: <0
2207c478bd9Sstevel@tonic-gate  * BUGS: Comparison between two characters are done by subtracting two chars
2217c478bd9Sstevel@tonic-gate  *	after converting each to an unsigned long int value.  It might not make
2227c478bd9Sstevel@tonic-gate  *	a whole lot of sense to do that if the characters are in represented
2237c478bd9Sstevel@tonic-gate  *	as wide characters and the two characters belong to different codesets.
2247c478bd9Sstevel@tonic-gate  *	Therefore, this function should be used only to test the equallness.
2257c478bd9Sstevel@tonic-gate  */
2267c478bd9Sstevel@tonic-gate int
2277c478bd9Sstevel@tonic-gate strcmp_(tchar *s1, tchar *s2)
2287c478bd9Sstevel@tonic-gate {
2297c478bd9Sstevel@tonic-gate 	while (*s1 == *s2++) {
2307c478bd9Sstevel@tonic-gate 		if (*s1++ == (tchar)0) {
2317c478bd9Sstevel@tonic-gate 			return (0);
2327c478bd9Sstevel@tonic-gate 		}
2337c478bd9Sstevel@tonic-gate 	}
2347c478bd9Sstevel@tonic-gate 	return (((unsigned long)*s1) - ((unsigned long)*(--s2)));
2357c478bd9Sstevel@tonic-gate }
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate /*
2387c478bd9Sstevel@tonic-gate  * This is only used in sh.glob.c for sorting purpose.
2397c478bd9Sstevel@tonic-gate  */
2407c478bd9Sstevel@tonic-gate int
2417c478bd9Sstevel@tonic-gate strcoll_(tchar *s1, tchar *s2)
2427c478bd9Sstevel@tonic-gate {
2437c478bd9Sstevel@tonic-gate 	char buf1[BUFSIZ];
2447c478bd9Sstevel@tonic-gate 	char buf2[BUFSIZ];
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate 	tstostr(buf1, s1);
2477c478bd9Sstevel@tonic-gate 	tstostr(buf2, s2);
2487c478bd9Sstevel@tonic-gate 	return (strcoll(buf1, buf2));
2497c478bd9Sstevel@tonic-gate }
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate /*
2527c478bd9Sstevel@tonic-gate  * Copy tchar string s2 to s1.  s1 must be large enough.
2537c478bd9Sstevel@tonic-gate  * return s1
2547c478bd9Sstevel@tonic-gate  */
2557c478bd9Sstevel@tonic-gate tchar *
2567c478bd9Sstevel@tonic-gate strcpy_(tchar *s1, tchar *s2)
2577c478bd9Sstevel@tonic-gate {
2587c478bd9Sstevel@tonic-gate 	tchar *os1;
2597c478bd9Sstevel@tonic-gate 
2607c478bd9Sstevel@tonic-gate 	os1 = s1;
2617c478bd9Sstevel@tonic-gate 	while (*s1++ = *s2++)
2627c478bd9Sstevel@tonic-gate 		;
2637c478bd9Sstevel@tonic-gate 	return (os1);
2647c478bd9Sstevel@tonic-gate }
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate /*
2677c478bd9Sstevel@tonic-gate  * Return the ptr in sp at which the character c appears;
2687c478bd9Sstevel@tonic-gate  * NULL if not found
2697c478bd9Sstevel@tonic-gate  */
2707c478bd9Sstevel@tonic-gate tchar *
2717c478bd9Sstevel@tonic-gate index_(tchar *sp, tchar c)
2727c478bd9Sstevel@tonic-gate {
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate 	do {
2757c478bd9Sstevel@tonic-gate 		if (*sp == c) {
2767c478bd9Sstevel@tonic-gate 			return (sp);
2777c478bd9Sstevel@tonic-gate 		}
2787c478bd9Sstevel@tonic-gate 	} while (*sp++);
2797c478bd9Sstevel@tonic-gate 	return (NULL);
2807c478bd9Sstevel@tonic-gate }
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate /*
2837c478bd9Sstevel@tonic-gate  * Return the ptr in sp at which the character c last
2847c478bd9Sstevel@tonic-gate  * appears; NOSTR if not found
2857c478bd9Sstevel@tonic-gate  */
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate tchar *
2887c478bd9Sstevel@tonic-gate rindex_(tchar *sp, tchar c)
2897c478bd9Sstevel@tonic-gate {
2907c478bd9Sstevel@tonic-gate 	tchar *r;
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate 	r = NOSTR;
2937c478bd9Sstevel@tonic-gate 	do {
2947c478bd9Sstevel@tonic-gate 		if (*sp == c) {
2957c478bd9Sstevel@tonic-gate 			r = sp;
2967c478bd9Sstevel@tonic-gate 		}
2977c478bd9Sstevel@tonic-gate 	} while (*sp++);
2987c478bd9Sstevel@tonic-gate 	return (r);
2997c478bd9Sstevel@tonic-gate }
3007c478bd9Sstevel@tonic-gate 
3017c478bd9Sstevel@tonic-gate /* Additional misc functions. */
3027c478bd9Sstevel@tonic-gate 
3037c478bd9Sstevel@tonic-gate /* Calculate the display width of a string.  */
3046c02b4a4Smuffin int
3057c478bd9Sstevel@tonic-gate tswidth(tchar *ts)
3067c478bd9Sstevel@tonic-gate {
3077c478bd9Sstevel@tonic-gate #ifdef MBCHAR
3087c478bd9Sstevel@tonic-gate 	wchar_t	tc;
3097c478bd9Sstevel@tonic-gate 	int	w = 0;
3107c478bd9Sstevel@tonic-gate 	int	p_col;
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	while (tc = *ts++) {
3137c478bd9Sstevel@tonic-gate 		if ((p_col = wcwidth((wchar_t)tc)) > 0)
3147c478bd9Sstevel@tonic-gate 			w += p_col;
3157c478bd9Sstevel@tonic-gate 	}
3167c478bd9Sstevel@tonic-gate 	return (w);
3177c478bd9Sstevel@tonic-gate #else /* !MBCHAR --- one char always occupies one column. */
3187c478bd9Sstevel@tonic-gate 	return (strlen_(ts));
3197c478bd9Sstevel@tonic-gate #endif
3207c478bd9Sstevel@tonic-gate }
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate /*
3237c478bd9Sstevel@tonic-gate  * Two getenv() substitute functions.  They differ in the type of arguments.
3247c478bd9Sstevel@tonic-gate  * BUGS: Both returns the pointer to an allocated space where the env var's
3257c478bd9Sstevel@tonic-gate  *	values is stored.  This space is freed automatically on the successive
3267c478bd9Sstevel@tonic-gate  *	call of	either function.  Therefore the caller must copy the contents
3277c478bd9Sstevel@tonic-gate  *	if it needs to access two env vars.  There is an arbitary limitation
3287c478bd9Sstevel@tonic-gate  *	on the number of chars of a env var name.
3297c478bd9Sstevel@tonic-gate  */
3307c478bd9Sstevel@tonic-gate #define	LONGEST_ENVVARNAME	256		/* Too big? */
3317c478bd9Sstevel@tonic-gate tchar *
3327c478bd9Sstevel@tonic-gate getenv_(tchar *name_)
3337c478bd9Sstevel@tonic-gate {
3347c478bd9Sstevel@tonic-gate 	char	name[LONGEST_ENVVARNAME * MB_LEN_MAX];
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	assert(strlen_(name_) < LONGEST_ENVVARNAME);
3377c478bd9Sstevel@tonic-gate 	return (getenvs_(tstostr(name, name_)));
3387c478bd9Sstevel@tonic-gate }
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate tchar *
3417c478bd9Sstevel@tonic-gate getenvs_(char *name)
3427c478bd9Sstevel@tonic-gate {
3437c478bd9Sstevel@tonic-gate 	static tchar	*pbuf = (tchar *)NULL;
3447c478bd9Sstevel@tonic-gate 	char	*val;
3457c478bd9Sstevel@tonic-gate 
3467c478bd9Sstevel@tonic-gate 	if (pbuf) {
34765b0c20eSnakanon 		xfree(pbuf);
3487c478bd9Sstevel@tonic-gate 		pbuf = NOSTR;
3497c478bd9Sstevel@tonic-gate 	}
3507c478bd9Sstevel@tonic-gate 	val = getenv(name);
3517c478bd9Sstevel@tonic-gate 	if (val == (char *)NULL) {
3527c478bd9Sstevel@tonic-gate 		return (NOSTR);
3537c478bd9Sstevel@tonic-gate 	}
3547c478bd9Sstevel@tonic-gate 	return (pbuf = strtots(NOSTR, val));
3557c478bd9Sstevel@tonic-gate }
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate /* Followings are the system call interface for tchar strings. */
3587c478bd9Sstevel@tonic-gate 
3597c478bd9Sstevel@tonic-gate /*
3607c478bd9Sstevel@tonic-gate  * creat() and open() replacement.
3617c478bd9Sstevel@tonic-gate  * BUGS: An unusually long file name could be dangerous.
3627c478bd9Sstevel@tonic-gate  */
3637c478bd9Sstevel@tonic-gate int
3647c478bd9Sstevel@tonic-gate creat_(tchar *name_, int mode)
3657c478bd9Sstevel@tonic-gate {
3667c478bd9Sstevel@tonic-gate 	int fd;
3677c478bd9Sstevel@tonic-gate 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
3687c478bd9Sstevel@tonic-gate 
3697c478bd9Sstevel@tonic-gate 	tstostr(chbuf, name_);
3707c478bd9Sstevel@tonic-gate 	fd = creat((char *)chbuf, mode);
3717c478bd9Sstevel@tonic-gate 	if (fd != -1) {
3727c478bd9Sstevel@tonic-gate 		setfd(fd);
3737c478bd9Sstevel@tonic-gate 	}
3747c478bd9Sstevel@tonic-gate 	return (fd);
3757c478bd9Sstevel@tonic-gate }
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate /*VARARGS2*/
3787c478bd9Sstevel@tonic-gate int
3797c478bd9Sstevel@tonic-gate open_(path_, flags, mode)
3807c478bd9Sstevel@tonic-gate 	tchar 	*path_;
3817c478bd9Sstevel@tonic-gate 	int	flags;
3827c478bd9Sstevel@tonic-gate 	int	mode; /* May be omitted. */
3837c478bd9Sstevel@tonic-gate {
3847c478bd9Sstevel@tonic-gate 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
3857c478bd9Sstevel@tonic-gate 	int fd;
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	tstostr(chbuf, path_);
3887c478bd9Sstevel@tonic-gate 	fd = open((char *)chbuf, flags, mode);
3897c478bd9Sstevel@tonic-gate 	if (fd != -1) {
3907c478bd9Sstevel@tonic-gate 		setfd(fd);
3917c478bd9Sstevel@tonic-gate 	}
3927c478bd9Sstevel@tonic-gate 	return (fd);
3937c478bd9Sstevel@tonic-gate }
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate /*
3967c478bd9Sstevel@tonic-gate  * mkstemp replacement
3977c478bd9Sstevel@tonic-gate  */
3987c478bd9Sstevel@tonic-gate int
3997c478bd9Sstevel@tonic-gate mkstemp_(tchar *name_)
4007c478bd9Sstevel@tonic-gate {
4017c478bd9Sstevel@tonic-gate 	int fd;
4027c478bd9Sstevel@tonic-gate 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
4037c478bd9Sstevel@tonic-gate 
4047c478bd9Sstevel@tonic-gate 	tstostr(chbuf, name_);
4057c478bd9Sstevel@tonic-gate 	fd = mkstemp((char *)chbuf);
4067c478bd9Sstevel@tonic-gate 	if (fd != -1) {
4077c478bd9Sstevel@tonic-gate 		setfd(fd);
4087c478bd9Sstevel@tonic-gate 		strtots(name_, chbuf);
4097c478bd9Sstevel@tonic-gate 	}
4107c478bd9Sstevel@tonic-gate 	return (fd);
4117c478bd9Sstevel@tonic-gate }
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate /*
4147c478bd9Sstevel@tonic-gate  * read() and write() reaplacement.
4157c478bd9Sstevel@tonic-gate  *	int        d;
4167c478bd9Sstevel@tonic-gate  *	tchar      *buf;  - where the result be stored.  Not NULL terminated.
4177c478bd9Sstevel@tonic-gate  *	int        nchreq; - # of tchars requrested.
4187c478bd9Sstevel@tonic-gate  */
4197c478bd9Sstevel@tonic-gate int
4207c478bd9Sstevel@tonic-gate read_(int d, tchar *buf, int nchreq)
4217c478bd9Sstevel@tonic-gate {
4227c478bd9Sstevel@tonic-gate 	unsigned char chbuf[BUFSIZ * MB_LEN_MAX]; /* General use buffer. */
4237c478bd9Sstevel@tonic-gate #ifdef MBCHAR
4247c478bd9Sstevel@tonic-gate 	/*
4257c478bd9Sstevel@tonic-gate 	 * We would have to read more than tchar bytes
4267c478bd9Sstevel@tonic-gate 	 * when there are multibyte characters in the file.
4277c478bd9Sstevel@tonic-gate 	 */
4287c478bd9Sstevel@tonic-gate 	int	i, j, fflags;
4297c478bd9Sstevel@tonic-gate 	unsigned char	*s;	/* Byte being scanned for a multibyte char. */
4307c478bd9Sstevel@tonic-gate 	/* Points to the pos where next read() to read the data into. */
4317c478bd9Sstevel@tonic-gate 	unsigned char	*p;
4327c478bd9Sstevel@tonic-gate 	tchar	*t;
4337c478bd9Sstevel@tonic-gate 	wchar_t		wc;
4347c478bd9Sstevel@tonic-gate 	int		b_len;
4357c478bd9Sstevel@tonic-gate 	int		nchread = 0; /* Count how many bytes has been read. */
4367c478bd9Sstevel@tonic-gate 	int		nbytread = 0; /* Total # of bytes read. */
4377c478bd9Sstevel@tonic-gate 	/* # of bytes needed to complete the last char just read. */
4387c478bd9Sstevel@tonic-gate 	int		delta;
4397c478bd9Sstevel@tonic-gate 	unsigned char	*q;	/* q points to the first invalid byte. */
44065b0c20eSnakanon 	int		mb_cur_max = MB_CUR_MAX;
4417c478bd9Sstevel@tonic-gate #ifdef DBG
4427c478bd9Sstevel@tonic-gate 	tprintf("Entering read_(d=%d, buf=0x%x, nchreq=%d);\n",
4437c478bd9Sstevel@tonic-gate 	    d, buf, nchreq);
4447c478bd9Sstevel@tonic-gate #endif /* DBG */
4457c478bd9Sstevel@tonic-gate 	/*
4467c478bd9Sstevel@tonic-gate 	 *	Step 1: We collect the exact number of bytes that make
4477c478bd9Sstevel@tonic-gate 	 *	nchreq characters into chbuf.
4487c478bd9Sstevel@tonic-gate 	 *	We must be careful not to read too many bytes as we
4497c478bd9Sstevel@tonic-gate 	 *	cannot push back such over-read bytes.
4507c478bd9Sstevel@tonic-gate 	 *	The idea we use here is that n multibyte characters are stored
4517c478bd9Sstevel@tonic-gate 	 *	in no less than n but less than n*MB_CUR_MAX bytes.
4527c478bd9Sstevel@tonic-gate 	 */
4537c478bd9Sstevel@tonic-gate 	assert(nchreq <= BUFSIZ);
4547c478bd9Sstevel@tonic-gate 	delta = 0;
4557c478bd9Sstevel@tonic-gate 	p = s = chbuf;
4567c478bd9Sstevel@tonic-gate 	t = buf;
4577c478bd9Sstevel@tonic-gate 	while (nchread < nchreq) {
4587c478bd9Sstevel@tonic-gate 		int		m;  /* # of bytes to try to read this time. */
4597c478bd9Sstevel@tonic-gate 		int		k;  /* # of bytes successfully read. */
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate retry:
4627c478bd9Sstevel@tonic-gate 		/*
4637c478bd9Sstevel@tonic-gate 		 * Let's say the (N+1)'th byte bN is actually the first
4647c478bd9Sstevel@tonic-gate 		 * byte of a three-byte character c.
4657c478bd9Sstevel@tonic-gate 		 * In that case, p, s, q look like this:
4667c478bd9Sstevel@tonic-gate 		 *
4677c478bd9Sstevel@tonic-gate 		 *		/-- already read--\ /-- not yet read --\
4687c478bd9Sstevel@tonic-gate 		 * chbuf[]:	b0 b1 ..... bN bN+1 bN+2 bN+2 ...
4697c478bd9Sstevel@tonic-gate 		 *		^		^	^
4707c478bd9Sstevel@tonic-gate 		 *		|		|	|
4717c478bd9Sstevel@tonic-gate 		 *		p		s	q
4727c478bd9Sstevel@tonic-gate 		 *				\----------/
4737c478bd9Sstevel@tonic-gate 		 *				c hasn't been completed
4747c478bd9Sstevel@tonic-gate 		 *
4757c478bd9Sstevel@tonic-gate 		 * Just after the next read(), p and q will be adavanced to:
4767c478bd9Sstevel@tonic-gate 		 *
4777c478bd9Sstevel@tonic-gate 		 *	/-- already read-----------------------\ /-- not yet -
4787c478bd9Sstevel@tonic-gate 		 * chbuf[]: b0 b1 ..... bN bN+1 bN+2 bN+2 ... bX bX+1 bX+2...
4797c478bd9Sstevel@tonic-gate 		 *			^	^		 ^
4807c478bd9Sstevel@tonic-gate 		 *			|	|		 |
4817c478bd9Sstevel@tonic-gate 		 *			s	p		 q
4827c478bd9Sstevel@tonic-gate 		 *			\----------/
4837c478bd9Sstevel@tonic-gate 		 *			 c has been completed
4847c478bd9Sstevel@tonic-gate 		 *			 but hasn't been scanned
4857c478bd9Sstevel@tonic-gate 		 */
4867c478bd9Sstevel@tonic-gate 		m = nchreq - nchread;
4877c478bd9Sstevel@tonic-gate 		assert(p + m < chbuf + sizeof (chbuf));
4887c478bd9Sstevel@tonic-gate 		k = read(d, p, m);
4897c478bd9Sstevel@tonic-gate 		/*
4907c478bd9Sstevel@tonic-gate 		 * when child sets O_NDELAY or O_NONBLOCK on stdin
4917c478bd9Sstevel@tonic-gate 		 * and exits and we are interactive then turn the modes off
4927c478bd9Sstevel@tonic-gate 		 * and retry
4937c478bd9Sstevel@tonic-gate 		 */
4947c478bd9Sstevel@tonic-gate 		if (k == 0) {
4957c478bd9Sstevel@tonic-gate 			if ((intty && !onelflg && !cflg) &&
4967c478bd9Sstevel@tonic-gate 			    ((fflags = fcntl(d, F_GETFL, 0)) & O_NDELAY)) {
4977c478bd9Sstevel@tonic-gate 				fflags &= ~O_NDELAY;
4987c478bd9Sstevel@tonic-gate 				fcntl(d, F_SETFL, fflags);
4997c478bd9Sstevel@tonic-gate 				goto retry;
5007c478bd9Sstevel@tonic-gate 			}
5017c478bd9Sstevel@tonic-gate 		} else if (k < 0) {
5027c478bd9Sstevel@tonic-gate 			if (errno == EAGAIN) {
5037c478bd9Sstevel@tonic-gate 				fflags = fcntl(d, F_GETFL, 0);
5047c478bd9Sstevel@tonic-gate 				fflags &= ~O_NONBLOCK;
5057c478bd9Sstevel@tonic-gate 				fcntl(d, F_SETFL, fflags);
5067c478bd9Sstevel@tonic-gate 				goto retry;
5077c478bd9Sstevel@tonic-gate 			}
5087c478bd9Sstevel@tonic-gate 			return (-1);
5097c478bd9Sstevel@tonic-gate 		}
5107c478bd9Sstevel@tonic-gate 		nbytread += k;
5117c478bd9Sstevel@tonic-gate 		q = p + k;
5127c478bd9Sstevel@tonic-gate 		delta = 0;
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 		/* Try scaning characters in s..q-1 */
5157c478bd9Sstevel@tonic-gate 		while (s < q) {
5167c478bd9Sstevel@tonic-gate 			/* Convert the collected bytes into tchar array. */
5177c478bd9Sstevel@tonic-gate 			if (*s == 0) {
5187c478bd9Sstevel@tonic-gate 				/* NUL is treated as a normal char here. */
5197c478bd9Sstevel@tonic-gate 				*t++ = 0;
5207c478bd9Sstevel@tonic-gate 				s++;
5217c478bd9Sstevel@tonic-gate 				nchread++;
5227c478bd9Sstevel@tonic-gate 				continue;
5237c478bd9Sstevel@tonic-gate 			}
5247c478bd9Sstevel@tonic-gate 
52565b0c20eSnakanon 			if ((b_len = q - s) > mb_cur_max) {
52665b0c20eSnakanon 				b_len = mb_cur_max;
5277c478bd9Sstevel@tonic-gate 			}
5287c478bd9Sstevel@tonic-gate 			if ((j = mbtowc(&wc, (char *)s, b_len)) <=  0) {
52965b0c20eSnakanon 				if (mb_cur_max > 1 && b_len < mb_cur_max) {
5307c478bd9Sstevel@tonic-gate 					/*
5317c478bd9Sstevel@tonic-gate 					 * Needs more byte to complete this char
5327c478bd9Sstevel@tonic-gate 					 * In order to read() more than delta
5337c478bd9Sstevel@tonic-gate 					 * bytes.
5347c478bd9Sstevel@tonic-gate 					 */
5357c478bd9Sstevel@tonic-gate 					break;
5367c478bd9Sstevel@tonic-gate 				}
5377c478bd9Sstevel@tonic-gate 				wc = (unsigned char)*s;
5387c478bd9Sstevel@tonic-gate 				j = 1;
5397c478bd9Sstevel@tonic-gate 			}
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 			*t++ = wc;
5427c478bd9Sstevel@tonic-gate 			nchread++;
5437c478bd9Sstevel@tonic-gate 			s += j;
5447c478bd9Sstevel@tonic-gate 		}
5457c478bd9Sstevel@tonic-gate 
5467c478bd9Sstevel@tonic-gate 		if (k < m) {
5477c478bd9Sstevel@tonic-gate 			/* We've read as many bytes as possible. */
5487c478bd9Sstevel@tonic-gate 			while (s < q) {
54965b0c20eSnakanon 				if ((b_len = q - s) > mb_cur_max) {
55065b0c20eSnakanon 					b_len = mb_cur_max;
5517c478bd9Sstevel@tonic-gate 				}
5527c478bd9Sstevel@tonic-gate 				if ((j = mbtowc(&wc, (char *)s, b_len)) <=  0) {
5537c478bd9Sstevel@tonic-gate 					wc = (unsigned char)*s;
5547c478bd9Sstevel@tonic-gate 					j = 1;
5557c478bd9Sstevel@tonic-gate 				}
5567c478bd9Sstevel@tonic-gate 				*t++ = wc;
5577c478bd9Sstevel@tonic-gate 				nchread++;
5587c478bd9Sstevel@tonic-gate 				s += j;
5597c478bd9Sstevel@tonic-gate 			}
5607c478bd9Sstevel@tonic-gate 			return (nchread);
5617c478bd9Sstevel@tonic-gate 		}
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 		p = q;
5647c478bd9Sstevel@tonic-gate 	}
5657c478bd9Sstevel@tonic-gate 
56665b0c20eSnakanon 	if (mb_cur_max == 1 || (delta = q - s) == 0) {
5677c478bd9Sstevel@tonic-gate 		return (nchread);
5687c478bd9Sstevel@tonic-gate 	}
5697c478bd9Sstevel@tonic-gate 
57065b0c20eSnakanon 	/*
57165b0c20eSnakanon 	 * We may have (MB_CUR_MAX - 1) unread data in the buffer.
57265b0c20eSnakanon 	 * Here, the last converted data was an illegal character which was
57365b0c20eSnakanon 	 * treated as one byte character. We don't know at this point
57465b0c20eSnakanon 	 * whether or not the remaining data is in legal sequence.
57565b0c20eSnakanon 	 * We first attempt to convert the remaining data.
57665b0c20eSnakanon 	 */
57765b0c20eSnakanon 	do {
57865b0c20eSnakanon 		if ((j = mbtowc(&wc, (char *)s, delta)) <= 0)
57965b0c20eSnakanon 			break;
58065b0c20eSnakanon 		*t++ = wc;
58165b0c20eSnakanon 		nchread++;
58265b0c20eSnakanon 		s += j;
58365b0c20eSnakanon 		delta -= j;
58465b0c20eSnakanon 	} while (delta > 0);
58565b0c20eSnakanon 
58665b0c20eSnakanon 	if (delta == 0)
5877c478bd9Sstevel@tonic-gate 		return (nchread);
5887c478bd9Sstevel@tonic-gate 
58965b0c20eSnakanon 	/*
59065b0c20eSnakanon 	 * There seem to be ugly sequence in the buffer. Fill up till
59165b0c20eSnakanon 	 * mb_cur_max and see if we can get a right sequence.
59265b0c20eSnakanon 	 */
59365b0c20eSnakanon 	while (delta < mb_cur_max) {
5947c478bd9Sstevel@tonic-gate 		assert((q + 1) < (chbuf + sizeof (chbuf)));
59565b0c20eSnakanon 		if (read(d, q, 1) != 1)
5967c478bd9Sstevel@tonic-gate 			break;
59765b0c20eSnakanon 		delta++;
59865b0c20eSnakanon 		q++;
5997c478bd9Sstevel@tonic-gate 		if (mbtowc(&wc, (char *)s, delta) > 0) {
6007c478bd9Sstevel@tonic-gate 			*t = wc;
6017c478bd9Sstevel@tonic-gate 			return (nchread + 1);
6027c478bd9Sstevel@tonic-gate 		}
6037c478bd9Sstevel@tonic-gate 	}
6047c478bd9Sstevel@tonic-gate 
60565b0c20eSnakanon 	/*
60665b0c20eSnakanon 	 * no luck. we have filled MB_CUR_MAX bytes in the buffer.
60765b0c20eSnakanon 	 * Ideally we should return with leaving such data off and
60865b0c20eSnakanon 	 * put them into a local buffer for next read, but we don't
60965b0c20eSnakanon 	 * have such.
61065b0c20eSnakanon 	 * So, stop reading further, and treat them as all single
61165b0c20eSnakanon 	 * byte characters.
61265b0c20eSnakanon 	 */
6137c478bd9Sstevel@tonic-gate 	while (s < q) {
61465b0c20eSnakanon 		b_len = q - s;
6157c478bd9Sstevel@tonic-gate 		if ((j = mbtowc(&wc, (char *)s, b_len)) <=  0) {
6167c478bd9Sstevel@tonic-gate 			wc = (unsigned char)*s;
6177c478bd9Sstevel@tonic-gate 			j = 1;
6187c478bd9Sstevel@tonic-gate 		}
6197c478bd9Sstevel@tonic-gate 		*t++ = wc;
6207c478bd9Sstevel@tonic-gate 		nchread++;
6217c478bd9Sstevel@tonic-gate 		s += j;
6227c478bd9Sstevel@tonic-gate 	}
6237c478bd9Sstevel@tonic-gate 	return (nchread);
62465b0c20eSnakanon 
6257c478bd9Sstevel@tonic-gate #else /* !MBCHAR */
6267c478bd9Sstevel@tonic-gate 	/* One byte always represents one tchar.  Easy! */
6277c478bd9Sstevel@tonic-gate 	int		i;
6287c478bd9Sstevel@tonic-gate 	unsigned char	*s;
6297c478bd9Sstevel@tonic-gate 	tchar		*t;
6307c478bd9Sstevel@tonic-gate 	int		nchread;
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate #ifdef DBG
6337c478bd9Sstevel@tonic-gate 	tprintf("Entering read_(d=%d, buf=0x%x, nchreq=%d);\n",
6347c478bd9Sstevel@tonic-gate 	    d, buf, nchreq);
6357c478bd9Sstevel@tonic-gate #endif /* DBG */
6367c478bd9Sstevel@tonic-gate 	assert(nchreq <= BUFSIZ);
6377c478bd9Sstevel@tonic-gate retry:
6387c478bd9Sstevel@tonic-gate 	nchread = read(d, (char *)chbuf, nchreq);
6397c478bd9Sstevel@tonic-gate 	/*
6407c478bd9Sstevel@tonic-gate 	 * when child sets O_NDELAY or O_NONBLOCK on stdin
6417c478bd9Sstevel@tonic-gate 	 * and exits and we are interactive then turn the modes off
6427c478bd9Sstevel@tonic-gate 	 * and retry
6437c478bd9Sstevel@tonic-gate 	 */
6447c478bd9Sstevel@tonic-gate 	if (nchread == 0) {
6457c478bd9Sstevel@tonic-gate 		if ((intty && !onelflg && !cflg) &&
6467c478bd9Sstevel@tonic-gate 		    ((fflags = fcntl(d, F_GETFL, 0)) & O_NDELAY)) {
6477c478bd9Sstevel@tonic-gate 			fflags &= ~O_NDELAY;
6487c478bd9Sstevel@tonic-gate 			fcntl(d, F_SETFL, fflags);
6497c478bd9Sstevel@tonic-gate 			goto retry;
6507c478bd9Sstevel@tonic-gate 		}
6517c478bd9Sstevel@tonic-gate 	} else if (nchread < 0) {
6527c478bd9Sstevel@tonic-gate 		if (errno == EAGAIN) {
6537c478bd9Sstevel@tonic-gate 			fflags = fcntl(d, F_GETFL, 0);
6547c478bd9Sstevel@tonic-gate 			fflags &= ~O_NONBLOCK;
6557c478bd9Sstevel@tonic-gate 			fcntl(d, F_SETFL, fflags);
6567c478bd9Sstevel@tonic-gate 			goto retry;
6577c478bd9Sstevel@tonic-gate 		}
6587c478bd9Sstevel@tonic-gate 		len = 0;
6597c478bd9Sstevel@tonic-gate 	} else {
6607c478bd9Sstevel@tonic-gate 		for (i = 0, t = buf, s = chbuf; i < nchread; ++i) {
6617c478bd9Sstevel@tonic-gate 		    *t++ = ((tchar)*s++);
6627c478bd9Sstevel@tonic-gate 		}
6637c478bd9Sstevel@tonic-gate 	}
6647c478bd9Sstevel@tonic-gate 	return (nchread);
6657c478bd9Sstevel@tonic-gate #endif
6667c478bd9Sstevel@tonic-gate }
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate /*
6697c478bd9Sstevel@tonic-gate  * BUG: write_() returns -1 on failure, or # of BYTEs it has written.
6707c478bd9Sstevel@tonic-gate  *	For consistency and symmetry, it should return the number of
6717c478bd9Sstevel@tonic-gate  *	characters it has actually written, but that is technically
6727c478bd9Sstevel@tonic-gate  *	difficult although not impossible.  Anyway, the return
6737c478bd9Sstevel@tonic-gate  *	value of write() has never been used by the original csh,
6747c478bd9Sstevel@tonic-gate  *	so this bug should be OK.
6757c478bd9Sstevel@tonic-gate  */
6767c478bd9Sstevel@tonic-gate int
6777c478bd9Sstevel@tonic-gate write_(int d, tchar *buf, int nch)
6787c478bd9Sstevel@tonic-gate {
6797c478bd9Sstevel@tonic-gate 	unsigned char chbuf[BUFSIZ*MB_LEN_MAX]; /* General use buffer. */
6807c478bd9Sstevel@tonic-gate #ifdef MBCHAR
6817c478bd9Sstevel@tonic-gate 	tchar		*pt;
6827c478bd9Sstevel@tonic-gate 	unsigned char	*pc;
6837c478bd9Sstevel@tonic-gate 	wchar_t		wc;
6847c478bd9Sstevel@tonic-gate 	int		i, j;
6857c478bd9Sstevel@tonic-gate 
6867c478bd9Sstevel@tonic-gate #ifdef	DBG
6877c478bd9Sstevel@tonic-gate 	tprintf("Entering write_(d=%d, buf=0x%x, nch=%d);\n",
6887c478bd9Sstevel@tonic-gate 	    d, buf, nch); /* Hope printf() doesn't call write_() itself! */
6897c478bd9Sstevel@tonic-gate #endif /* DBG */
6907c478bd9Sstevel@tonic-gate 	assert(nch * MB_CUR_MAX < sizeof (chbuf));
6917c478bd9Sstevel@tonic-gate 	i = nch;
6927c478bd9Sstevel@tonic-gate 	pt = buf;
6937c478bd9Sstevel@tonic-gate 	pc = chbuf;
6947c478bd9Sstevel@tonic-gate 	while (i--) {
6957c478bd9Sstevel@tonic-gate 		/*
6967c478bd9Sstevel@tonic-gate 		 * Convert to tchar string.
6977c478bd9Sstevel@tonic-gate 		 * NUL is treated as normal char here.
6987c478bd9Sstevel@tonic-gate 		 */
6997c478bd9Sstevel@tonic-gate 		wc = (wchar_t)((*pt++)&TRIM);
7007c478bd9Sstevel@tonic-gate 		if (wc == (wchar_t)0) {
7017c478bd9Sstevel@tonic-gate 			*pc++ = 0;
7027c478bd9Sstevel@tonic-gate 		} else {
7037c478bd9Sstevel@tonic-gate 			if ((j = wctomb((char *)pc, wc)) <= 0) {
7047c478bd9Sstevel@tonic-gate 				*pc = (unsigned char)wc;
7057c478bd9Sstevel@tonic-gate 				j = 1;
7067c478bd9Sstevel@tonic-gate 			}
7077c478bd9Sstevel@tonic-gate 			pc += j;
7087c478bd9Sstevel@tonic-gate 		}
7097c478bd9Sstevel@tonic-gate 	}
7107c478bd9Sstevel@tonic-gate 	return (write(d, chbuf, pc - chbuf));
7117c478bd9Sstevel@tonic-gate #else /* !MBCHAR */
7127c478bd9Sstevel@tonic-gate 	/* One byte always represents one tchar.  Easy! */
7137c478bd9Sstevel@tonic-gate 	int	i;
7147c478bd9Sstevel@tonic-gate 	unsigned char	*s;
7157c478bd9Sstevel@tonic-gate 	tchar	*t;
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate #ifdef	DBG
7187c478bd9Sstevel@tonic-gate 	tprintf("Entering write_(d=%d, buf=0x%x, nch=%d);\n",
7197c478bd9Sstevel@tonic-gate 	    d, buf, nch); /* Hope printf() doesn't call write_() itself! */
7207c478bd9Sstevel@tonic-gate #endif /* DBG */
7217c478bd9Sstevel@tonic-gate 	assert(nch <= sizeof (chbuf));
7227c478bd9Sstevel@tonic-gate 	for (i = 0, t = buf, s = chbuf; i < nch; ++i) {
7237c478bd9Sstevel@tonic-gate 	    *s++ = (char)((*t++)&0xff);
7247c478bd9Sstevel@tonic-gate 	}
7257c478bd9Sstevel@tonic-gate 	return (write(d, (char *)chbuf, nch));
7267c478bd9Sstevel@tonic-gate #endif
7277c478bd9Sstevel@tonic-gate }
7287c478bd9Sstevel@tonic-gate 
7297c478bd9Sstevel@tonic-gate #undef chbuf
7307c478bd9Sstevel@tonic-gate 
7317c478bd9Sstevel@tonic-gate #include <sys/types.h>
7327c478bd9Sstevel@tonic-gate #include <sys/stat.h>	/* satruct stat */
7337c478bd9Sstevel@tonic-gate #include <dirent.h>	/* DIR */
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate extern DIR *Dirp;
7367c478bd9Sstevel@tonic-gate 
7377c478bd9Sstevel@tonic-gate int
7387c478bd9Sstevel@tonic-gate stat_(tchar *path, struct stat *buf)
7397c478bd9Sstevel@tonic-gate {
7407c478bd9Sstevel@tonic-gate 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
7417c478bd9Sstevel@tonic-gate 
7427c478bd9Sstevel@tonic-gate 	tstostr(chbuf, path);
7437c478bd9Sstevel@tonic-gate 	return (stat((char *)chbuf, buf));
7447c478bd9Sstevel@tonic-gate }
7457c478bd9Sstevel@tonic-gate 
7467c478bd9Sstevel@tonic-gate int
7477c478bd9Sstevel@tonic-gate lstat_(tchar *path, struct stat *buf)
7487c478bd9Sstevel@tonic-gate {
7497c478bd9Sstevel@tonic-gate 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
7507c478bd9Sstevel@tonic-gate 
7517c478bd9Sstevel@tonic-gate 	tstostr(chbuf, path);
7527c478bd9Sstevel@tonic-gate 	return (lstat((char *)chbuf, buf));
7537c478bd9Sstevel@tonic-gate }
7547c478bd9Sstevel@tonic-gate 
7557c478bd9Sstevel@tonic-gate int
7567c478bd9Sstevel@tonic-gate chdir_(tchar *path)
7577c478bd9Sstevel@tonic-gate {
7587c478bd9Sstevel@tonic-gate 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 	tstostr(chbuf, path);
7617c478bd9Sstevel@tonic-gate 	return (chdir((char *)chbuf));
7627c478bd9Sstevel@tonic-gate }
7637c478bd9Sstevel@tonic-gate 
7647c478bd9Sstevel@tonic-gate tchar *
7657c478bd9Sstevel@tonic-gate getwd_(tchar *path)
7667c478bd9Sstevel@tonic-gate {
7677c478bd9Sstevel@tonic-gate 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
7687c478bd9Sstevel@tonic-gate 	int	rc;
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 	rc = (int)getwd((char *)chbuf);
7717c478bd9Sstevel@tonic-gate 	if (rc == 0) {
7727c478bd9Sstevel@tonic-gate 		return (0);
7737c478bd9Sstevel@tonic-gate 	} else {
7747c478bd9Sstevel@tonic-gate 		return (strtots(path, chbuf));
7757c478bd9Sstevel@tonic-gate 	}
7767c478bd9Sstevel@tonic-gate }
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate int
7797c478bd9Sstevel@tonic-gate unlink_(tchar *path)
7807c478bd9Sstevel@tonic-gate {
7817c478bd9Sstevel@tonic-gate 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
7827c478bd9Sstevel@tonic-gate 
7837c478bd9Sstevel@tonic-gate 	tstostr(chbuf, path);
7847c478bd9Sstevel@tonic-gate 	return (unlink((char *)chbuf));
7857c478bd9Sstevel@tonic-gate }
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate DIR *
7887c478bd9Sstevel@tonic-gate opendir_(tchar *dirname)
7897c478bd9Sstevel@tonic-gate {
7907c478bd9Sstevel@tonic-gate 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate 	extern DIR *opendir();
7937c478bd9Sstevel@tonic-gate 	DIR	*dir;
7947c478bd9Sstevel@tonic-gate 
7957c478bd9Sstevel@tonic-gate 	dir = opendir(tstostr(chbuf, dirname));
7967c478bd9Sstevel@tonic-gate 	if (dir != NULL) {
7977c478bd9Sstevel@tonic-gate 		setfd(dir->dd_fd);
7987c478bd9Sstevel@tonic-gate 	}
7997c478bd9Sstevel@tonic-gate 	return (Dirp = dir);
8007c478bd9Sstevel@tonic-gate }
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate int
8037c478bd9Sstevel@tonic-gate closedir_(DIR *dirp)
8047c478bd9Sstevel@tonic-gate {
8057c478bd9Sstevel@tonic-gate 	int ret;
8067c478bd9Sstevel@tonic-gate 	extern int closedir();
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 	ret = closedir(dirp);
8097c478bd9Sstevel@tonic-gate 	Dirp = NULL;
8107c478bd9Sstevel@tonic-gate 	return (ret);
8117c478bd9Sstevel@tonic-gate }
8127c478bd9Sstevel@tonic-gate 
8137c478bd9Sstevel@tonic-gate int
8147c478bd9Sstevel@tonic-gate gethostname_(tchar *name, int namelen)
8157c478bd9Sstevel@tonic-gate {
8167c478bd9Sstevel@tonic-gate 	char chbuf[BUFSIZ * MB_LEN_MAX]; /* General use buffer. */
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate 	assert(namelen < BUFSIZ);
8197c478bd9Sstevel@tonic-gate 	if (gethostname((char *)chbuf, sizeof (chbuf)) != 0) {
8207c478bd9Sstevel@tonic-gate 		return (-1);
8217c478bd9Sstevel@tonic-gate 	}
8227c478bd9Sstevel@tonic-gate 	if (mbstotcs(name, chbuf, namelen) < 0) {
8237c478bd9Sstevel@tonic-gate 		return (-1);
8247c478bd9Sstevel@tonic-gate 	}
8257c478bd9Sstevel@tonic-gate 	return (0); /* Succeeded. */
8267c478bd9Sstevel@tonic-gate }
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate int
8297c478bd9Sstevel@tonic-gate readlink_(tchar *path, tchar *buf, int bufsiz)
8307c478bd9Sstevel@tonic-gate {
8317c478bd9Sstevel@tonic-gate 	char chbuf[MAXPATHLEN * MB_LEN_MAX]; /* General use buffer. */
8327c478bd9Sstevel@tonic-gate 	char	chpath[MAXPATHLEN + 1];
8337c478bd9Sstevel@tonic-gate 	int	i;
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate 	tstostr(chpath, path);
8367c478bd9Sstevel@tonic-gate 	i = readlink(chpath, (char *)chbuf, sizeof (chbuf));
8377c478bd9Sstevel@tonic-gate 	if (i < 0) {
8387c478bd9Sstevel@tonic-gate 		return (-1);
8397c478bd9Sstevel@tonic-gate 	}
8407c478bd9Sstevel@tonic-gate 	chbuf[i] = (char)0;	/* readlink() doesn't put NULL. */
8417c478bd9Sstevel@tonic-gate 	i = mbstotcs(buf, chbuf, bufsiz);
8427c478bd9Sstevel@tonic-gate 	if (i < 0) {
8437c478bd9Sstevel@tonic-gate 		return (-1);
8447c478bd9Sstevel@tonic-gate 	}
8457c478bd9Sstevel@tonic-gate 	return (i - 1); /* Return # of tchars EXCLUDING the terminating NULL. */
8467c478bd9Sstevel@tonic-gate }
8477c478bd9Sstevel@tonic-gate 
848*70a587ddSchin /* checks that it's a number */
849*70a587ddSchin 
850*70a587ddSchin int
851*70a587ddSchin chkalldigit_(tchar *str)
852*70a587ddSchin {
853*70a587ddSchin 	char chbuf[BUFSIZ * MB_LEN_MAX]; /* General use buffer. */
854*70a587ddSchin 	char *c = chbuf;
855*70a587ddSchin 
856*70a587ddSchin 	(void) tstostr(chbuf, str);
857*70a587ddSchin 
858*70a587ddSchin 	while (*c)
859*70a587ddSchin 		if (!isdigit(*(c++)))
860*70a587ddSchin 			return (-1);
861*70a587ddSchin 
862*70a587ddSchin 	return (0);
863*70a587ddSchin }
864*70a587ddSchin 
8657c478bd9Sstevel@tonic-gate int
8667c478bd9Sstevel@tonic-gate atoi_(tchar *str)
8677c478bd9Sstevel@tonic-gate {
8687c478bd9Sstevel@tonic-gate 	char chbuf[BUFSIZ * MB_LEN_MAX]; /* General use buffer. */
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 	tstostr(chbuf, str);
8717c478bd9Sstevel@tonic-gate 	return (atoi((char *)chbuf));
8727c478bd9Sstevel@tonic-gate }
8737c478bd9Sstevel@tonic-gate 
8747c478bd9Sstevel@tonic-gate tchar *
8757c478bd9Sstevel@tonic-gate simple(tchar *s)
8767c478bd9Sstevel@tonic-gate {
8776c02b4a4Smuffin 	tchar *sname = s;
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 	while (1) {
8807c478bd9Sstevel@tonic-gate 		if (any('/', sname)) {
8817c478bd9Sstevel@tonic-gate 			while (*sname++ != '/')
8827c478bd9Sstevel@tonic-gate 				;
8837c478bd9Sstevel@tonic-gate 		} else {
8847c478bd9Sstevel@tonic-gate 			return (sname);
8857c478bd9Sstevel@tonic-gate 		}
8867c478bd9Sstevel@tonic-gate 	}
8877c478bd9Sstevel@tonic-gate }
888