14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*8462SApril.Chin@Sun.COM *          Copyright (c) 1982-2008 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
7*8462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                  David Korn <dgk@research.att.com>                   *
184887Schin *                                                                      *
194887Schin ***********************************************************************/
204887Schin #pragma prototyped
214887Schin /*
224887Schin  * string processing routines for Korn shell
234887Schin  *
244887Schin  */
254887Schin 
264887Schin #include	<ast.h>
274887Schin #include	<ast_wchar.h>
284887Schin #include	"defs.h"
294887Schin #include	<stak.h>
304887Schin #include	<ctype.h>
314887Schin #include	<ccode.h>
324887Schin #include	"shtable.h"
334887Schin #include	"lexstates.h"
344887Schin #include	"national.h"
354887Schin 
364887Schin #if !SHOPT_MULTIBYTE
374887Schin #define mbchar(p)	(*(unsigned char*)p++)
384887Schin #endif
394887Schin 
404887Schin #if _hdr_wctype
414887Schin #   include <wctype.h>
424887Schin #endif
434887Schin 
444887Schin #if !_lib_iswprint && !defined(iswprint)
454887Schin #   define iswprint(c)		(((c)&~0377) || isprint(c))
464887Schin #endif
474887Schin 
484887Schin 
494887Schin /*
504887Schin  *  Table lookup routine
514887Schin  *  <table> is searched for string <sp> and corresponding value is returned
524887Schin  *  This is only used for small tables and is used to save non-sharable memory
534887Schin  */
544887Schin 
554887Schin const Shtable_t *sh_locate(register const char *sp,const Shtable_t *table,int size)
564887Schin {
574887Schin 	register int			first;
584887Schin 	register const Shtable_t	*tp;
594887Schin 	register int			c;
604887Schin 	static const Shtable_t		empty = {0,0};
614887Schin 	if(sp==0 || (first= *sp)==0)
624887Schin 		return(&empty);
634887Schin 	tp=table;
644887Schin 	while((c= *tp->sh_name) && (CC_NATIVE!=CC_ASCII || c <= first))
654887Schin 	{
664887Schin 		if(first == c && strcmp(sp,tp->sh_name)==0)
674887Schin 			return(tp);
684887Schin 		tp = (Shtable_t*)((char*)tp+size);
694887Schin 	}
704887Schin 	return(&empty);
714887Schin }
724887Schin 
734887Schin /*
744887Schin  *  shtab_options lookup routine
754887Schin  */
764887Schin 
774887Schin #define sep(c)		((c)=='-'||(c)=='_')
784887Schin 
794887Schin int sh_lookopt(register const char *sp, int *invert)
804887Schin {
814887Schin 	register int			first;
824887Schin 	register const Shtable_t	*tp;
834887Schin 	register int			c;
844887Schin 	register const char		*s, *t, *sw, *tw;
854887Schin 	int				amb;
864887Schin 	int				hit;
874887Schin 	int				inv;
884887Schin 	int				no;
894887Schin 	if(sp==0)
904887Schin 		return(0);
914887Schin 	if(*sp=='n' && *(sp+1)=='o' && (*(sp+2)!='t' || *(sp+3)!='i'))
924887Schin 	{
934887Schin 		sp+=2;
944887Schin 		if(sep(*sp))
954887Schin 			sp++;
964887Schin 		*invert = !*invert;
974887Schin 	}
984887Schin 	if((first= *sp)==0)
994887Schin 		return(0);
1004887Schin 	tp=shtab_options;
1014887Schin 	amb=hit=0;
1024887Schin 	for(;;)
1034887Schin 	{
1044887Schin 		t=tp->sh_name;
1054887Schin 		if(no = *t=='n' && *(t+1)=='o' && *(t+2)!='t')
1064887Schin 			t+=2;
1074887Schin 		if(!(c= *t))
1084887Schin 			break;
1094887Schin 		if(first == c)
1104887Schin 		{
1114887Schin 			if(strcmp(sp,t)==0)
1124887Schin 			{
1134887Schin 				*invert ^= no;
1144887Schin 				return(tp->sh_number);
1154887Schin 			}
1164887Schin 			s=sw=sp;
1174887Schin 			tw=t;
1184887Schin 			for(;;)
1194887Schin 			{
1204887Schin 				if(!*s || *s=='=')
1214887Schin 				{
1224887Schin 					if (*s == '=' && !strtol(s+1, NiL, 0))
1234887Schin 						no = !no;
1244887Schin 					if (!*t)
1254887Schin 					{
1264887Schin 						*invert ^= no;
1274887Schin 						return(tp->sh_number);
1284887Schin 					}
1294887Schin 					if (hit || amb)
1304887Schin 					{
1314887Schin 						hit = 0;
1324887Schin 						amb = 1;
1334887Schin 					}
1344887Schin 					else
1354887Schin 					{
1364887Schin 						hit = tp->sh_number;
1374887Schin 						inv = no;
1384887Schin 					}
1394887Schin 					break;
1404887Schin 				}
1414887Schin 				else if(!*t)
1424887Schin 					break;
1434887Schin 				else if(sep(*s))
1444887Schin 					sw = ++s;
1454887Schin 				else if(sep(*t))
1464887Schin 					tw = ++t;
1474887Schin 				else if(*s==*t)
1484887Schin 				{
1494887Schin 					s++;
1504887Schin 					t++;
1514887Schin 				}
1524887Schin 				else if(s==sw && t==tw)
1534887Schin 					break;
1544887Schin 				else
1554887Schin 				{
1564887Schin 					if(t!=tw)
1574887Schin 					{
1584887Schin 						while(*t && !sep(*t))
1594887Schin 							t++;
1604887Schin 						if(!*t)
1614887Schin 							break;
1624887Schin 						tw = ++t;
1634887Schin 					}
1644887Schin 					while (s>sw && *s!=*t)
1654887Schin 						s--;
1664887Schin 				}
1674887Schin 			}
1684887Schin 		}
1694887Schin 		tp = (Shtable_t*)((char*)tp+sizeof(*shtab_options));
1704887Schin 	}
1714887Schin 	if(hit)
1724887Schin 		*invert ^= inv;
1734887Schin 	return(hit);
1744887Schin }
1754887Schin 
1764887Schin /*
1774887Schin  * look for the substring <oldsp> in <string> and replace with <newsp>
1784887Schin  * The new string is put on top of the stack
1794887Schin  */
1804887Schin char *sh_substitute(const char *string,const char *oldsp,char *newsp)
1814887Schin /*@
1824887Schin 	assume string!=NULL && oldsp!=NULL && newsp!=NULL;
1834887Schin 	return x satisfying x==NULL ||
1844887Schin 		strlen(x)==(strlen(in string)+strlen(in newsp)-strlen(in oldsp));
1854887Schin @*/
1864887Schin {
1874887Schin 	register const char *sp = string;
1884887Schin 	register const char *cp;
1894887Schin 	const char *savesp = 0;
1904887Schin 	stakseek(0);
1914887Schin 	if(*sp==0)
1924887Schin 		return((char*)0);
1934887Schin 	if(*(cp=oldsp) == 0)
1944887Schin 		goto found;
1954887Schin #if SHOPT_MULTIBYTE
1964887Schin 	mbinit();
1974887Schin #endif /* SHOPT_MULTIBYTE */
1984887Schin 	do
1994887Schin 	{
2004887Schin 	/* skip to first character which matches start of oldsp */
2014887Schin 		while(*sp && (savesp==sp || *sp != *cp))
2024887Schin 		{
2034887Schin #if SHOPT_MULTIBYTE
2044887Schin 			/* skip a whole character at a time */
2054887Schin 			int c = mbsize(sp);
2064887Schin 			if(c < 0)
2074887Schin 				sp++;
2084887Schin 			while(c-- > 0)
2094887Schin #endif /* SHOPT_MULTIBYTE */
2104887Schin 			stakputc(*sp++);
2114887Schin 		}
2124887Schin 		if(*sp == 0)
2134887Schin 			return((char*)0);
2144887Schin 		savesp = sp;
2154887Schin 	        for(;*cp;cp++)
2164887Schin 		{
2174887Schin 			if(*cp != *sp++)
2184887Schin 				break;
2194887Schin 		}
2204887Schin 		if(*cp==0)
2214887Schin 		/* match found */
2224887Schin 			goto found;
2234887Schin 		sp = savesp;
2244887Schin 		cp = oldsp;
2254887Schin 	}
2264887Schin 	while(*sp);
2274887Schin 	return((char*)0);
2284887Schin 
2294887Schin found:
2304887Schin 	/* copy new */
2314887Schin 	stakputs(newsp);
2324887Schin 	/* copy rest of string */
2334887Schin 	stakputs(sp);
2344887Schin 	return(stakfreeze(1));
2354887Schin }
2364887Schin 
2374887Schin /*
2384887Schin  * TRIM(sp)
2394887Schin  * Remove escape characters from characters in <sp> and eliminate quoted nulls.
2404887Schin  */
2414887Schin 
2424887Schin void	sh_trim(register char *sp)
2434887Schin /*@
2444887Schin 	assume sp!=NULL;
2454887Schin 	promise  strlen(in sp) <= in strlen(sp);
2464887Schin @*/
2474887Schin {
2484887Schin 	register char *dp;
2494887Schin 	register int c;
2504887Schin 	if(sp)
2514887Schin 	{
2524887Schin 		dp = sp;
2534887Schin 		while(c= *sp)
2544887Schin 		{
2554887Schin #if SHOPT_MULTIBYTE
2564887Schin 			int len;
2574887Schin 			if(mbwide() && (len=mbsize(sp))>1)
2584887Schin 			{
259*8462SApril.Chin@Sun.COM 				memmove(dp, sp, len);
2604887Schin 				dp += len;
2614887Schin 				sp += len;
2624887Schin 				continue;
2634887Schin 			}
2644887Schin #endif /* SHOPT_MULTIBYTE */
2654887Schin 			sp++;
2664887Schin 			if(c == '\\')
2674887Schin 				c = *sp++;
2684887Schin 			if(c)
2694887Schin 				*dp++ = c;
2704887Schin 		}
2714887Schin 		*dp = 0;
2724887Schin 	}
2734887Schin }
2744887Schin 
2754887Schin /*
2764887Schin  * copy <str1> to <str2> changing upper case to lower case
2774887Schin  * <str2> must be big enough to hold <str1>
2784887Schin  * <str1> and <str2> may point to the same place.
2794887Schin  */
2804887Schin 
2814887Schin void sh_utol(register char const *str1,register char *str2)
2824887Schin /*@
2834887Schin 	assume str1!=0 && str2!=0
2844887Schin 	return x satisfying strlen(in str1)==strlen(in str2);
2854887Schin @*/
2864887Schin {
2874887Schin 	register int c;
2884887Schin 	for(; c= *((unsigned char*)str1); str1++,str2++)
2894887Schin 	{
2904887Schin 		if(isupper(c))
2914887Schin 			*str2 = tolower(c);
2924887Schin 		else
2934887Schin 			*str2 = c;
2944887Schin 	}
2954887Schin 	*str2 = 0;
2964887Schin }
2974887Schin 
2984887Schin /*
2994887Schin  * print <str> quoting chars so that it can be read by the shell
3004887Schin  * puts null terminated result on stack, but doesn't freeze it
3014887Schin  */
3024887Schin char	*sh_fmtq(const char *string)
3034887Schin {
304*8462SApril.Chin@Sun.COM 	register const char *cp = string, *op;
3054887Schin 	register int c, state;
3064887Schin 	int offset;
3074887Schin 	if(!cp)
3084887Schin 		return((char*)0);
3094887Schin 	offset = staktell();
3104887Schin #if SHOPT_MULTIBYTE
3114887Schin 	state = ((c= mbchar(cp))==0);
3124887Schin #else
3134887Schin 	state = ((c= *(unsigned char*)cp++)==0);
3144887Schin #endif
3154887Schin 	if(isaletter(c))
3164887Schin 	{
3174887Schin #if SHOPT_MULTIBYTE
3184887Schin 		while((c=mbchar(cp)),isaname(c));
3194887Schin #else
3204887Schin 		while((c = *(unsigned char*)cp++),isaname(c));
3214887Schin #endif
3224887Schin 		if(c==0)
3234887Schin 			return((char*)string);
3244887Schin 		if(c=='=')
3254887Schin 		{
3264887Schin 			if(*cp==0)
3274887Schin 				return((char*)string);
3284887Schin 			c = cp - string;
3294887Schin 			stakwrite(string,c);
3304887Schin 			string = cp;
3314887Schin #if SHOPT_MULTIBYTE
3324887Schin 			c = mbchar(cp);
3334887Schin #else
3344887Schin 			c = *(unsigned char*)cp++;
3354887Schin #endif
3364887Schin 		}
3374887Schin 	}
3384887Schin 	if(c==0 || c=='#' || c=='~')
3394887Schin 		state = 1;
3404887Schin #if SHOPT_MULTIBYTE
3414887Schin 	for(;c;c= mbchar(cp))
3424887Schin #else
3434887Schin 	for(;c; c= *(unsigned char*)cp++)
3444887Schin #endif
3454887Schin 	{
3464887Schin #if SHOPT_MULTIBYTE
3474887Schin 		if(c=='\'' || !iswprint(c))
3484887Schin #else
3494887Schin 		if(c=='\'' || !isprint(c))
3504887Schin #endif /* SHOPT_MULTIBYTE */
3514887Schin 			state = 2;
352*8462SApril.Chin@Sun.COM 		else if(c==']' || (c!=':' && c<=0xff && (c=sh_lexstates[ST_NORM][c]) && c!=S_EPAT))
3534887Schin 			state |=1;
3544887Schin 	}
3554887Schin 	if(state<2)
3564887Schin 	{
3574887Schin 		if(state==1)
3584887Schin 			stakputc('\'');
3594887Schin 		if(c = --cp - string)
3604887Schin 			stakwrite(string,c);
3614887Schin 		if(state==1)
3624887Schin 			stakputc('\'');
3634887Schin 	}
3644887Schin 	else
3654887Schin 	{
3664887Schin 		stakwrite("$'",2);
3674887Schin 		cp = string;
3684887Schin #if SHOPT_MULTIBYTE
369*8462SApril.Chin@Sun.COM 		while(op = cp, c= mbchar(cp))
3704887Schin #else
371*8462SApril.Chin@Sun.COM 		while(op = cp, c= *(unsigned char*)cp++)
3724887Schin #endif
3734887Schin 		{
3744887Schin 			state=1;
3754887Schin 			switch(c)
3764887Schin 			{
3774887Schin 			    case ('a'==97?'\033':39):
3784887Schin 				c = 'E';
3794887Schin 				break;
3804887Schin 			    case '\n':
3814887Schin 				c = 'n';
3824887Schin 				break;
3834887Schin 			    case '\r':
3844887Schin 				c = 'r';
3854887Schin 				break;
3864887Schin 			    case '\t':
3874887Schin 				c = 't';
3884887Schin 				break;
3894887Schin 			    case '\f':
3904887Schin 				c = 'f';
3914887Schin 				break;
3924887Schin 			    case '\b':
3934887Schin 				c = 'b';
3944887Schin 				break;
3954887Schin 			    case '\a':
3964887Schin 				c = 'a';
3974887Schin 				break;
3984887Schin 			    case '\\':	case '\'':
3994887Schin 				break;
4004887Schin 			    default:
4014887Schin #if SHOPT_MULTIBYTE
4024887Schin 				if(!iswprint(c))
403*8462SApril.Chin@Sun.COM 				{
404*8462SApril.Chin@Sun.COM 					while(op<cp)
405*8462SApril.Chin@Sun.COM 						sfprintf(staksp,"\\%.3o",*(unsigned char*)op++);
406*8462SApril.Chin@Sun.COM 					continue;
407*8462SApril.Chin@Sun.COM 				}
4084887Schin #else
4094887Schin 				if(!isprint(c))
4104887Schin 				{
4114887Schin 					sfprintf(staksp,"\\%.3o",c);
4124887Schin 					continue;
4134887Schin 				}
414*8462SApril.Chin@Sun.COM #endif
4154887Schin 				state=0;
4164887Schin 				break;
4174887Schin 			}
4184887Schin 			if(state)
419*8462SApril.Chin@Sun.COM 			{
4204887Schin 				stakputc('\\');
421*8462SApril.Chin@Sun.COM 				stakputc(c);
422*8462SApril.Chin@Sun.COM 			}
423*8462SApril.Chin@Sun.COM 			else
424*8462SApril.Chin@Sun.COM 				stakwrite(op, cp-op);
4254887Schin 		}
4264887Schin 		stakputc('\'');
4274887Schin 	}
4284887Schin 	stakputc(0);
4294887Schin 	return(stakptr(offset));
4304887Schin }
4314887Schin 
4324887Schin /*
4334887Schin  * print <str> quoting chars so that it can be read by the shell
4344887Schin  * puts null terminated result on stack, but doesn't freeze it
4354887Schin  * single!=0 limits quoting to '...'
4364887Schin  * fold>0 prints raw newlines and inserts appropriately
4374887Schin  * escaped newlines every (fold-x) chars
4384887Schin  */
4394887Schin char	*sh_fmtqf(const char *string, int single, int fold)
4404887Schin {
4414887Schin 	register const char *cp = string;
4424887Schin 	register const char *bp;
4434887Schin 	register const char *vp;
4444887Schin 	register int c;
4454887Schin 	register int n;
4464887Schin 	register int q;
4474887Schin 	register int a;
4484887Schin 	int offset;
4494887Schin 
4504887Schin 	if (--fold < 8)
4514887Schin 		fold = 0;
4524887Schin 	if (!cp || !*cp || !single && !fold || fold && strlen(string) < fold)
4534887Schin 		return sh_fmtq(cp);
4544887Schin 	offset = staktell();
4554887Schin 	single = single ? 1 : 3;
4564887Schin 	c = mbchar(string);
4574887Schin 	a = isaletter(c) ? '=' : 0;
4584887Schin 	vp = cp + 1;
4594887Schin 	do
4604887Schin 	{
4614887Schin 		q = 0;
4624887Schin 		n = fold;
4634887Schin 		bp = cp;
4644887Schin 		while ((!n || n-- > 0) && (c = mbchar(cp)))
4654887Schin 		{
4664887Schin 			if (a && !isaname(c))
4674887Schin 				a = 0;
4684887Schin #if SHOPT_MULTIBYTE
4694887Schin 			if (c >= 0x200)
4704887Schin 				continue;
4714887Schin 			if (c == '\'' || !iswprint(c))
4724887Schin #else
4734887Schin 			if (c == '\'' || !isprint(c))
4744887Schin #endif /* SHOPT_MULTIBYTE */
4754887Schin 			{
4764887Schin 				q = single;
4774887Schin 				break;
4784887Schin 			}
4794887Schin 			if (c == '\n')
4804887Schin 				q = 1;
4814887Schin 			else if (c == a)
4824887Schin 			{
4834887Schin 				stakwrite(bp, cp - bp);
4844887Schin 				bp = cp;
4854887Schin 				vp = cp + 1;
4864887Schin 				a = 0;
4874887Schin 			}
4884887Schin 			else if ((c == '#' || c == '~') && cp == vp || c == ']' || c != ':' && (c = sh_lexstates[ST_NORM][c]) && c != S_EPAT)
4894887Schin 				q = 1;
4904887Schin 		}
4914887Schin 		if (q & 2)
4924887Schin 		{
4934887Schin 			stakputc('$');
4944887Schin 			stakputc('\'');
4954887Schin 			cp = bp;
4964887Schin 			n = fold - 3;
4974887Schin 			q = 1;
4984887Schin 			while (c = mbchar(cp))
4994887Schin 			{
5004887Schin 				switch (c)
5014887Schin 				{
5024887Schin 		    		case ('a'==97?'\033':39):
5034887Schin 					c = 'E';
5044887Schin 					break;
5054887Schin 		    		case '\n':
5064887Schin 					q = 0;
5074887Schin 					n = fold - 1;
5084887Schin 					break;
5094887Schin 		    		case '\r':
5104887Schin 					c = 'r';
5114887Schin 					break;
5124887Schin 		    		case '\t':
5134887Schin 					c = 't';
5144887Schin 					break;
5154887Schin 		    		case '\f':
5164887Schin 					c = 'f';
5174887Schin 					break;
5184887Schin 		    		case '\b':
5194887Schin 					c = 'b';
5204887Schin 					break;
5214887Schin 		    		case '\a':
5224887Schin 					c = 'a';
5234887Schin 					break;
5244887Schin 		    		case '\\':
5254887Schin 					if (*cp == 'n')
5264887Schin 					{
5274887Schin 						c = '\n';
5284887Schin 						q = 0;
5294887Schin 						n = fold - 1;
5304887Schin 						break;
5314887Schin 					}
5324887Schin 				case '\'':
5334887Schin 					break;
5344887Schin 		    		default:
5354887Schin #if SHOPT_MULTIBYTE
5364887Schin 					if(!iswprint(c))
5374887Schin #else
5384887Schin 					if(!isprint(c))
5394887Schin #endif
5404887Schin 					{
5414887Schin 						if ((n -= 4) <= 0)
5424887Schin 						{
5434887Schin 							stakwrite("'\\\n$'", 5);
5444887Schin 							n = fold - 7;
5454887Schin 						}
5464887Schin 						sfprintf(staksp, "\\%03o", c);
5474887Schin 						continue;
5484887Schin 					}
5494887Schin 					q = 0;
5504887Schin 					break;
5514887Schin 				}
5524887Schin 				if ((n -= q + 1) <= 0)
5534887Schin 				{
5544887Schin 					if (!q)
5554887Schin 					{
5564887Schin 						stakputc('\'');
5574887Schin 						cp = bp;
5584887Schin 						break;
5594887Schin 					}
5604887Schin 					stakwrite("'\\\n$'", 5);
5614887Schin 					n = fold - 5;
5624887Schin 				}
5634887Schin 				if (q)
5644887Schin 					stakputc('\\');
5654887Schin 				else
5664887Schin 					q = 1;
5674887Schin 				stakputc(c);
5684887Schin 				bp = cp;
5694887Schin 			}
5704887Schin 			if (!c)
5714887Schin 				stakputc('\'');
5724887Schin 		}
5734887Schin 		else if (q & 1)
5744887Schin 		{
5754887Schin 			stakputc('\'');
5764887Schin 			cp = bp;
5774887Schin 			n = fold ? (fold - 2) : 0;
5784887Schin 			while (c = mbchar(cp))
5794887Schin 			{
5804887Schin 				if (c == '\n')
5814887Schin 					n = fold - 1;
5824887Schin 				else if (n && --n <= 0)
5834887Schin 				{
5844887Schin 					n = fold - 2;
5854887Schin 					stakwrite(bp, --cp - bp);
5864887Schin 					bp = cp;
5874887Schin 					stakwrite("'\\\n'", 4);
5884887Schin 				}
5894887Schin 				else if (n == 1 && *cp == '\'')
5904887Schin 				{
5914887Schin 					n = fold - 5;
5924887Schin 					stakwrite(bp, --cp - bp);
5934887Schin 					bp = cp;
5944887Schin 					stakwrite("'\\\n\\''", 6);
5954887Schin 				}
5964887Schin 				else if (c == '\'')
5974887Schin 				{
5984887Schin 					stakwrite(bp, cp - bp - 1);
5994887Schin 					bp = cp;
6004887Schin 					if (n && (n -= 4) <= 0)
6014887Schin 					{
6024887Schin 						n = fold - 5;
6034887Schin 						stakwrite("'\\\n\\''", 6);
6044887Schin 					}
6054887Schin 					else
6064887Schin 						stakwrite("'\\''", 4);
6074887Schin 				}
6084887Schin 			}
6094887Schin 			stakwrite(bp, cp - bp - 1);
6104887Schin 			stakputc('\'');
6114887Schin 		}
6124887Schin 		else if (n = fold)
6134887Schin 		{
6144887Schin 			cp = bp;
6154887Schin 			while (c = mbchar(cp))
6164887Schin 			{
6174887Schin 				if (--n <= 0)
6184887Schin 				{
6194887Schin 					n = fold;
6204887Schin 					stakwrite(bp, --cp - bp);
6214887Schin 					bp = cp;
6224887Schin 					stakwrite("\\\n", 2);
6234887Schin 				}
6244887Schin 			}
6254887Schin 			stakwrite(bp, cp - bp - 1);
6264887Schin 		}
6274887Schin 		else
6284887Schin 			stakwrite(bp, cp - bp);
6294887Schin 		if (c)
6304887Schin 		{
6314887Schin 			stakputc('\\');
6324887Schin 			stakputc('\n');
6334887Schin 		}
6344887Schin 	} while (c);
6354887Schin 	stakputc(0);
6364887Schin 	return(stakptr(offset));
6374887Schin }
6384887Schin 
6394887Schin #if SHOPT_MULTIBYTE
6404887Schin 	int sh_strchr(const char *string, register const char *dp)
6414887Schin 	{
6424887Schin 		wchar_t c, d;
6434887Schin 		register const char *cp=string;
6444887Schin 		mbinit();
6454887Schin 		d = mbchar(dp);
6464887Schin 		mbinit();
6474887Schin 		while(c = mbchar(cp))
6484887Schin 		{
6494887Schin 			if(c==d)
6504887Schin 				return(cp-string);
6514887Schin 		}
6524887Schin 		if(d==0)
6534887Schin 			return(cp-string);
6544887Schin 		return(-1);
6554887Schin 	}
6564887Schin #endif /* SHOPT_MULTIBYTE */
6574887Schin 
6584887Schin const char *_sh_translate(const char *message)
6594887Schin {
6604887Schin #if ERROR_VERSION >= 20000317L
6614887Schin 	return(ERROR_translate(0,0,e_dict,message));
6624887Schin #else
6634887Schin #if ERROR_VERSION >= 20000101L
6644887Schin 	return(ERROR_translate(e_dict,message));
6654887Schin #else
6664887Schin 	return(ERROR_translate(message,1));
6674887Schin #endif
6684887Schin #endif
6694887Schin }
6704887Schin 
6714887Schin /*
6724887Schin  * change '['identifier']' to identifier
6734887Schin  * character before <str> must be a '['
6744887Schin  * returns pointer to last character
6754887Schin  */
6764887Schin char *sh_checkid(char *str, char *last)
6774887Schin {
6784887Schin 	register unsigned char *cp = (unsigned char*)str;
6794887Schin 	register unsigned char *v = cp;
6804887Schin 	register int c;
6814887Schin 	if(c= *cp++,isaletter(c))
6824887Schin 		while(c= *cp++,isaname(c));
6834887Schin 	if(c==']' && (!last || ((char*)cp==last)))
6844887Schin 	{
6854887Schin 		/* eliminate [ and ] */
6864887Schin 		while(v < cp)
6874887Schin 		{
6884887Schin 			v[-1] = *v;
6894887Schin 			v++;
6904887Schin 		}
6914887Schin 		if(last)
6924887Schin 			last -=2;
6934887Schin 		else
6944887Schin 		{
6954887Schin 			while(*v)
6964887Schin 			{
6974887Schin 				v[-2] = *v;
6984887Schin 				v++;
6994887Schin 			}
7004887Schin 			v[-2] = 0;
7014887Schin 			last = (char*)v;
7024887Schin 		}
7034887Schin 	}
7044887Schin 	return(last);
7054887Schin }
7064887Schin 
7074887Schin #if	_AST_VERSION  <= 20000317L
7084887Schin char *fmtident(const char *string)
7094887Schin {
7104887Schin 	return((char*)string);
7114887Schin }
7124887Schin #endif
713