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