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