1*4887Schin /***********************************************************************
2*4887Schin *                                                                      *
3*4887Schin *               This software is part of the ast package               *
4*4887Schin *           Copyright (c) 1982-2007 AT&T Knowledge Ventures            *
5*4887Schin *                      and is licensed under the                       *
6*4887Schin *                  Common Public License, Version 1.0                  *
7*4887Schin *                      by AT&T Knowledge Ventures                      *
8*4887Schin *                                                                      *
9*4887Schin *                A copy of the License is available at                 *
10*4887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
11*4887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
12*4887Schin *                                                                      *
13*4887Schin *              Information and Software Systems Research               *
14*4887Schin *                            AT&T Research                             *
15*4887Schin *                           Florham Park NJ                            *
16*4887Schin *                                                                      *
17*4887Schin *                  David Korn <dgk@research.att.com>                   *
18*4887Schin *                                                                      *
19*4887Schin ***********************************************************************/
20*4887Schin #pragma prototyped
21*4887Schin /*
22*4887Schin  * string processing routines for Korn shell
23*4887Schin  *
24*4887Schin  */
25*4887Schin 
26*4887Schin #include	<ast.h>
27*4887Schin #include	<ast_wchar.h>
28*4887Schin #include	"defs.h"
29*4887Schin #include	<stak.h>
30*4887Schin #include	<ctype.h>
31*4887Schin #include	<ccode.h>
32*4887Schin #include	"shtable.h"
33*4887Schin #include	"lexstates.h"
34*4887Schin #include	"national.h"
35*4887Schin 
36*4887Schin #if !SHOPT_MULTIBYTE
37*4887Schin #define mbchar(p)	(*(unsigned char*)p++)
38*4887Schin #endif
39*4887Schin 
40*4887Schin #if _hdr_wctype
41*4887Schin #   include <wctype.h>
42*4887Schin #endif
43*4887Schin 
44*4887Schin #if !_lib_iswprint && !defined(iswprint)
45*4887Schin #   define iswprint(c)		(((c)&~0377) || isprint(c))
46*4887Schin #endif
47*4887Schin 
48*4887Schin 
49*4887Schin /*
50*4887Schin  *  Table lookup routine
51*4887Schin  *  <table> is searched for string <sp> and corresponding value is returned
52*4887Schin  *  This is only used for small tables and is used to save non-sharable memory
53*4887Schin  */
54*4887Schin 
55*4887Schin const Shtable_t *sh_locate(register const char *sp,const Shtable_t *table,int size)
56*4887Schin {
57*4887Schin 	register int			first;
58*4887Schin 	register const Shtable_t	*tp;
59*4887Schin 	register int			c;
60*4887Schin 	static const Shtable_t		empty = {0,0};
61*4887Schin 	if(sp==0 || (first= *sp)==0)
62*4887Schin 		return(&empty);
63*4887Schin 	tp=table;
64*4887Schin 	while((c= *tp->sh_name) && (CC_NATIVE!=CC_ASCII || c <= first))
65*4887Schin 	{
66*4887Schin 		if(first == c && strcmp(sp,tp->sh_name)==0)
67*4887Schin 			return(tp);
68*4887Schin 		tp = (Shtable_t*)((char*)tp+size);
69*4887Schin 	}
70*4887Schin 	return(&empty);
71*4887Schin }
72*4887Schin 
73*4887Schin /*
74*4887Schin  *  shtab_options lookup routine
75*4887Schin  */
76*4887Schin 
77*4887Schin #define sep(c)		((c)=='-'||(c)=='_')
78*4887Schin 
79*4887Schin int sh_lookopt(register const char *sp, int *invert)
80*4887Schin {
81*4887Schin 	register int			first;
82*4887Schin 	register const Shtable_t	*tp;
83*4887Schin 	register int			c;
84*4887Schin 	register const char		*s, *t, *sw, *tw;
85*4887Schin 	int				amb;
86*4887Schin 	int				hit;
87*4887Schin 	int				inv;
88*4887Schin 	int				no;
89*4887Schin 	if(sp==0)
90*4887Schin 		return(0);
91*4887Schin 	if(*sp=='n' && *(sp+1)=='o' && (*(sp+2)!='t' || *(sp+3)!='i'))
92*4887Schin 	{
93*4887Schin 		sp+=2;
94*4887Schin 		if(sep(*sp))
95*4887Schin 			sp++;
96*4887Schin 		*invert = !*invert;
97*4887Schin 	}
98*4887Schin 	if((first= *sp)==0)
99*4887Schin 		return(0);
100*4887Schin 	tp=shtab_options;
101*4887Schin 	amb=hit=0;
102*4887Schin 	for(;;)
103*4887Schin 	{
104*4887Schin 		t=tp->sh_name;
105*4887Schin 		if(no = *t=='n' && *(t+1)=='o' && *(t+2)!='t')
106*4887Schin 			t+=2;
107*4887Schin 		if(!(c= *t))
108*4887Schin 			break;
109*4887Schin 		if(first == c)
110*4887Schin 		{
111*4887Schin 			if(strcmp(sp,t)==0)
112*4887Schin 			{
113*4887Schin 				*invert ^= no;
114*4887Schin 				return(tp->sh_number);
115*4887Schin 			}
116*4887Schin 			s=sw=sp;
117*4887Schin 			tw=t;
118*4887Schin 			for(;;)
119*4887Schin 			{
120*4887Schin 				if(!*s || *s=='=')
121*4887Schin 				{
122*4887Schin 					if (*s == '=' && !strtol(s+1, NiL, 0))
123*4887Schin 						no = !no;
124*4887Schin 					if (!*t)
125*4887Schin 					{
126*4887Schin 						*invert ^= no;
127*4887Schin 						return(tp->sh_number);
128*4887Schin 					}
129*4887Schin 					if (hit || amb)
130*4887Schin 					{
131*4887Schin 						hit = 0;
132*4887Schin 						amb = 1;
133*4887Schin 					}
134*4887Schin 					else
135*4887Schin 					{
136*4887Schin 						hit = tp->sh_number;
137*4887Schin 						inv = no;
138*4887Schin 					}
139*4887Schin 					break;
140*4887Schin 				}
141*4887Schin 				else if(!*t)
142*4887Schin 					break;
143*4887Schin 				else if(sep(*s))
144*4887Schin 					sw = ++s;
145*4887Schin 				else if(sep(*t))
146*4887Schin 					tw = ++t;
147*4887Schin 				else if(*s==*t)
148*4887Schin 				{
149*4887Schin 					s++;
150*4887Schin 					t++;
151*4887Schin 				}
152*4887Schin 				else if(s==sw && t==tw)
153*4887Schin 					break;
154*4887Schin 				else
155*4887Schin 				{
156*4887Schin 					if(t!=tw)
157*4887Schin 					{
158*4887Schin 						while(*t && !sep(*t))
159*4887Schin 							t++;
160*4887Schin 						if(!*t)
161*4887Schin 							break;
162*4887Schin 						tw = ++t;
163*4887Schin 					}
164*4887Schin 					while (s>sw && *s!=*t)
165*4887Schin 						s--;
166*4887Schin 				}
167*4887Schin 			}
168*4887Schin 		}
169*4887Schin 		tp = (Shtable_t*)((char*)tp+sizeof(*shtab_options));
170*4887Schin 	}
171*4887Schin 	if(hit)
172*4887Schin 		*invert ^= inv;
173*4887Schin 	return(hit);
174*4887Schin }
175*4887Schin 
176*4887Schin /*
177*4887Schin  * look for the substring <oldsp> in <string> and replace with <newsp>
178*4887Schin  * The new string is put on top of the stack
179*4887Schin  */
180*4887Schin char *sh_substitute(const char *string,const char *oldsp,char *newsp)
181*4887Schin /*@
182*4887Schin 	assume string!=NULL && oldsp!=NULL && newsp!=NULL;
183*4887Schin 	return x satisfying x==NULL ||
184*4887Schin 		strlen(x)==(strlen(in string)+strlen(in newsp)-strlen(in oldsp));
185*4887Schin @*/
186*4887Schin {
187*4887Schin 	register const char *sp = string;
188*4887Schin 	register const char *cp;
189*4887Schin 	const char *savesp = 0;
190*4887Schin 	stakseek(0);
191*4887Schin 	if(*sp==0)
192*4887Schin 		return((char*)0);
193*4887Schin 	if(*(cp=oldsp) == 0)
194*4887Schin 		goto found;
195*4887Schin #if SHOPT_MULTIBYTE
196*4887Schin 	mbinit();
197*4887Schin #endif /* SHOPT_MULTIBYTE */
198*4887Schin 	do
199*4887Schin 	{
200*4887Schin 	/* skip to first character which matches start of oldsp */
201*4887Schin 		while(*sp && (savesp==sp || *sp != *cp))
202*4887Schin 		{
203*4887Schin #if SHOPT_MULTIBYTE
204*4887Schin 			/* skip a whole character at a time */
205*4887Schin 			int c = mbsize(sp);
206*4887Schin 			if(c < 0)
207*4887Schin 				sp++;
208*4887Schin 			while(c-- > 0)
209*4887Schin #endif /* SHOPT_MULTIBYTE */
210*4887Schin 			stakputc(*sp++);
211*4887Schin 		}
212*4887Schin 		if(*sp == 0)
213*4887Schin 			return((char*)0);
214*4887Schin 		savesp = sp;
215*4887Schin 	        for(;*cp;cp++)
216*4887Schin 		{
217*4887Schin 			if(*cp != *sp++)
218*4887Schin 				break;
219*4887Schin 		}
220*4887Schin 		if(*cp==0)
221*4887Schin 		/* match found */
222*4887Schin 			goto found;
223*4887Schin 		sp = savesp;
224*4887Schin 		cp = oldsp;
225*4887Schin 	}
226*4887Schin 	while(*sp);
227*4887Schin 	return((char*)0);
228*4887Schin 
229*4887Schin found:
230*4887Schin 	/* copy new */
231*4887Schin 	stakputs(newsp);
232*4887Schin 	/* copy rest of string */
233*4887Schin 	stakputs(sp);
234*4887Schin 	return(stakfreeze(1));
235*4887Schin }
236*4887Schin 
237*4887Schin /*
238*4887Schin  * TRIM(sp)
239*4887Schin  * Remove escape characters from characters in <sp> and eliminate quoted nulls.
240*4887Schin  */
241*4887Schin 
242*4887Schin void	sh_trim(register char *sp)
243*4887Schin /*@
244*4887Schin 	assume sp!=NULL;
245*4887Schin 	promise  strlen(in sp) <= in strlen(sp);
246*4887Schin @*/
247*4887Schin {
248*4887Schin 	register char *dp;
249*4887Schin 	register int c;
250*4887Schin 	if(sp)
251*4887Schin 	{
252*4887Schin 		dp = sp;
253*4887Schin 		while(c= *sp)
254*4887Schin 		{
255*4887Schin #if SHOPT_MULTIBYTE
256*4887Schin 			int len;
257*4887Schin 			if(mbwide() && (len=mbsize(sp))>1)
258*4887Schin 			{
259*4887Schin 				dp += len;
260*4887Schin 				sp += len;
261*4887Schin 				continue;
262*4887Schin 			}
263*4887Schin #endif /* SHOPT_MULTIBYTE */
264*4887Schin 			sp++;
265*4887Schin 			if(c == '\\')
266*4887Schin 				c = *sp++;
267*4887Schin 			if(c)
268*4887Schin 				*dp++ = c;
269*4887Schin 		}
270*4887Schin 		*dp = 0;
271*4887Schin 	}
272*4887Schin }
273*4887Schin 
274*4887Schin /*
275*4887Schin  * copy <str1> to <str2> changing upper case to lower case
276*4887Schin  * <str2> must be big enough to hold <str1>
277*4887Schin  * <str1> and <str2> may point to the same place.
278*4887Schin  */
279*4887Schin 
280*4887Schin void sh_utol(register char const *str1,register char *str2)
281*4887Schin /*@
282*4887Schin 	assume str1!=0 && str2!=0
283*4887Schin 	return x satisfying strlen(in str1)==strlen(in str2);
284*4887Schin @*/
285*4887Schin {
286*4887Schin 	register int c;
287*4887Schin 	for(; c= *((unsigned char*)str1); str1++,str2++)
288*4887Schin 	{
289*4887Schin 		if(isupper(c))
290*4887Schin 			*str2 = tolower(c);
291*4887Schin 		else
292*4887Schin 			*str2 = c;
293*4887Schin 	}
294*4887Schin 	*str2 = 0;
295*4887Schin }
296*4887Schin 
297*4887Schin /*
298*4887Schin  * print <str> quoting chars so that it can be read by the shell
299*4887Schin  * puts null terminated result on stack, but doesn't freeze it
300*4887Schin  */
301*4887Schin char	*sh_fmtq(const char *string)
302*4887Schin {
303*4887Schin 	register const char *cp = string;
304*4887Schin 	register int c, state;
305*4887Schin 	int offset;
306*4887Schin 	if(!cp)
307*4887Schin 		return((char*)0);
308*4887Schin 	offset = staktell();
309*4887Schin #if SHOPT_MULTIBYTE
310*4887Schin 	state = ((c= mbchar(cp))==0);
311*4887Schin #else
312*4887Schin 	state = ((c= *(unsigned char*)cp++)==0);
313*4887Schin #endif
314*4887Schin 	if(isaletter(c))
315*4887Schin 	{
316*4887Schin #if SHOPT_MULTIBYTE
317*4887Schin 		while((c=mbchar(cp)),isaname(c));
318*4887Schin #else
319*4887Schin 		while((c = *(unsigned char*)cp++),isaname(c));
320*4887Schin #endif
321*4887Schin 		if(c==0)
322*4887Schin 			return((char*)string);
323*4887Schin 		if(c=='=')
324*4887Schin 		{
325*4887Schin 			if(*cp==0)
326*4887Schin 				return((char*)string);
327*4887Schin 			c = cp - string;
328*4887Schin 			stakwrite(string,c);
329*4887Schin 			string = cp;
330*4887Schin #if SHOPT_MULTIBYTE
331*4887Schin 			c = mbchar(cp);
332*4887Schin #else
333*4887Schin 			c = *(unsigned char*)cp++;
334*4887Schin #endif
335*4887Schin 		}
336*4887Schin 	}
337*4887Schin 	if(c==0 || c=='#' || c=='~')
338*4887Schin 		state = 1;
339*4887Schin #if SHOPT_MULTIBYTE
340*4887Schin 	for(;c;c= mbchar(cp))
341*4887Schin #else
342*4887Schin 	for(;c; c= *(unsigned char*)cp++)
343*4887Schin #endif
344*4887Schin 	{
345*4887Schin #if SHOPT_MULTIBYTE
346*4887Schin 		if(c>=0x200)
347*4887Schin 			continue;
348*4887Schin 		if(c=='\'' || !iswprint(c))
349*4887Schin #else
350*4887Schin 		if(c=='\'' || !isprint(c))
351*4887Schin #endif /* SHOPT_MULTIBYTE */
352*4887Schin 			state = 2;
353*4887Schin 		else if(c==']' || (c!=':' && (c=sh_lexstates[ST_NORM][c]) && c!=S_EPAT))
354*4887Schin 			state |=1;
355*4887Schin 	}
356*4887Schin 	if(state<2)
357*4887Schin 	{
358*4887Schin 		if(state==1)
359*4887Schin 			stakputc('\'');
360*4887Schin 		if(c = --cp - string)
361*4887Schin 			stakwrite(string,c);
362*4887Schin 		if(state==1)
363*4887Schin 			stakputc('\'');
364*4887Schin 	}
365*4887Schin 	else
366*4887Schin 	{
367*4887Schin 		stakwrite("$'",2);
368*4887Schin 		cp = string;
369*4887Schin #if SHOPT_MULTIBYTE
370*4887Schin 		while(c= mbchar(cp))
371*4887Schin #else
372*4887Schin 		while(c= *(unsigned char*)cp++)
373*4887Schin #endif
374*4887Schin 		{
375*4887Schin 			state=1;
376*4887Schin 			switch(c)
377*4887Schin 			{
378*4887Schin 			    case ('a'==97?'\033':39):
379*4887Schin 				c = 'E';
380*4887Schin 				break;
381*4887Schin 			    case '\n':
382*4887Schin 				c = 'n';
383*4887Schin 				break;
384*4887Schin 			    case '\r':
385*4887Schin 				c = 'r';
386*4887Schin 				break;
387*4887Schin 			    case '\t':
388*4887Schin 				c = 't';
389*4887Schin 				break;
390*4887Schin 			    case '\f':
391*4887Schin 				c = 'f';
392*4887Schin 				break;
393*4887Schin 			    case '\b':
394*4887Schin 				c = 'b';
395*4887Schin 				break;
396*4887Schin 			    case '\a':
397*4887Schin 				c = 'a';
398*4887Schin 				break;
399*4887Schin 			    case '\\':	case '\'':
400*4887Schin 				break;
401*4887Schin 			    default:
402*4887Schin #if SHOPT_MULTIBYTE
403*4887Schin 				if(!iswprint(c))
404*4887Schin #else
405*4887Schin 				if(!isprint(c))
406*4887Schin #endif
407*4887Schin 				{
408*4887Schin 					sfprintf(staksp,"\\%.3o",c);
409*4887Schin 					continue;
410*4887Schin 				}
411*4887Schin 				state=0;
412*4887Schin 				break;
413*4887Schin 			}
414*4887Schin 			if(state)
415*4887Schin 				stakputc('\\');
416*4887Schin 			stakputc(c);
417*4887Schin 		}
418*4887Schin 		stakputc('\'');
419*4887Schin 	}
420*4887Schin 	stakputc(0);
421*4887Schin 	return(stakptr(offset));
422*4887Schin }
423*4887Schin 
424*4887Schin /*
425*4887Schin  * print <str> quoting chars so that it can be read by the shell
426*4887Schin  * puts null terminated result on stack, but doesn't freeze it
427*4887Schin  * single!=0 limits quoting to '...'
428*4887Schin  * fold>0 prints raw newlines and inserts appropriately
429*4887Schin  * escaped newlines every (fold-x) chars
430*4887Schin  */
431*4887Schin char	*sh_fmtqf(const char *string, int single, int fold)
432*4887Schin {
433*4887Schin 	register const char *cp = string;
434*4887Schin 	register const char *bp;
435*4887Schin 	register const char *vp;
436*4887Schin 	register int c;
437*4887Schin 	register int n;
438*4887Schin 	register int q;
439*4887Schin 	register int a;
440*4887Schin 	int offset;
441*4887Schin 
442*4887Schin 	if (--fold < 8)
443*4887Schin 		fold = 0;
444*4887Schin 	if (!cp || !*cp || !single && !fold || fold && strlen(string) < fold)
445*4887Schin 		return sh_fmtq(cp);
446*4887Schin 	offset = staktell();
447*4887Schin 	single = single ? 1 : 3;
448*4887Schin 	c = mbchar(string);
449*4887Schin 	a = isaletter(c) ? '=' : 0;
450*4887Schin 	vp = cp + 1;
451*4887Schin 	do
452*4887Schin 	{
453*4887Schin 		q = 0;
454*4887Schin 		n = fold;
455*4887Schin 		bp = cp;
456*4887Schin 		while ((!n || n-- > 0) && (c = mbchar(cp)))
457*4887Schin 		{
458*4887Schin 			if (a && !isaname(c))
459*4887Schin 				a = 0;
460*4887Schin #if SHOPT_MULTIBYTE
461*4887Schin 			if (c >= 0x200)
462*4887Schin 				continue;
463*4887Schin 			if (c == '\'' || !iswprint(c))
464*4887Schin #else
465*4887Schin 			if (c == '\'' || !isprint(c))
466*4887Schin #endif /* SHOPT_MULTIBYTE */
467*4887Schin 			{
468*4887Schin 				q = single;
469*4887Schin 				break;
470*4887Schin 			}
471*4887Schin 			if (c == '\n')
472*4887Schin 				q = 1;
473*4887Schin 			else if (c == a)
474*4887Schin 			{
475*4887Schin 				stakwrite(bp, cp - bp);
476*4887Schin 				bp = cp;
477*4887Schin 				vp = cp + 1;
478*4887Schin 				a = 0;
479*4887Schin 			}
480*4887Schin 			else if ((c == '#' || c == '~') && cp == vp || c == ']' || c != ':' && (c = sh_lexstates[ST_NORM][c]) && c != S_EPAT)
481*4887Schin 				q = 1;
482*4887Schin 		}
483*4887Schin 		if (q & 2)
484*4887Schin 		{
485*4887Schin 			stakputc('$');
486*4887Schin 			stakputc('\'');
487*4887Schin 			cp = bp;
488*4887Schin 			n = fold - 3;
489*4887Schin 			q = 1;
490*4887Schin 			while (c = mbchar(cp))
491*4887Schin 			{
492*4887Schin 				switch (c)
493*4887Schin 				{
494*4887Schin 		    		case ('a'==97?'\033':39):
495*4887Schin 					c = 'E';
496*4887Schin 					break;
497*4887Schin 		    		case '\n':
498*4887Schin 					q = 0;
499*4887Schin 					n = fold - 1;
500*4887Schin 					break;
501*4887Schin 		    		case '\r':
502*4887Schin 					c = 'r';
503*4887Schin 					break;
504*4887Schin 		    		case '\t':
505*4887Schin 					c = 't';
506*4887Schin 					break;
507*4887Schin 		    		case '\f':
508*4887Schin 					c = 'f';
509*4887Schin 					break;
510*4887Schin 		    		case '\b':
511*4887Schin 					c = 'b';
512*4887Schin 					break;
513*4887Schin 		    		case '\a':
514*4887Schin 					c = 'a';
515*4887Schin 					break;
516*4887Schin 		    		case '\\':
517*4887Schin 					if (*cp == 'n')
518*4887Schin 					{
519*4887Schin 						c = '\n';
520*4887Schin 						q = 0;
521*4887Schin 						n = fold - 1;
522*4887Schin 						break;
523*4887Schin 					}
524*4887Schin 				case '\'':
525*4887Schin 					break;
526*4887Schin 		    		default:
527*4887Schin #if SHOPT_MULTIBYTE
528*4887Schin 					if(!iswprint(c))
529*4887Schin #else
530*4887Schin 					if(!isprint(c))
531*4887Schin #endif
532*4887Schin 					{
533*4887Schin 						if ((n -= 4) <= 0)
534*4887Schin 						{
535*4887Schin 							stakwrite("'\\\n$'", 5);
536*4887Schin 							n = fold - 7;
537*4887Schin 						}
538*4887Schin 						sfprintf(staksp, "\\%03o", c);
539*4887Schin 						continue;
540*4887Schin 					}
541*4887Schin 					q = 0;
542*4887Schin 					break;
543*4887Schin 				}
544*4887Schin 				if ((n -= q + 1) <= 0)
545*4887Schin 				{
546*4887Schin 					if (!q)
547*4887Schin 					{
548*4887Schin 						stakputc('\'');
549*4887Schin 						cp = bp;
550*4887Schin 						break;
551*4887Schin 					}
552*4887Schin 					stakwrite("'\\\n$'", 5);
553*4887Schin 					n = fold - 5;
554*4887Schin 				}
555*4887Schin 				if (q)
556*4887Schin 					stakputc('\\');
557*4887Schin 				else
558*4887Schin 					q = 1;
559*4887Schin 				stakputc(c);
560*4887Schin 				bp = cp;
561*4887Schin 			}
562*4887Schin 			if (!c)
563*4887Schin 				stakputc('\'');
564*4887Schin 		}
565*4887Schin 		else if (q & 1)
566*4887Schin 		{
567*4887Schin 			stakputc('\'');
568*4887Schin 			cp = bp;
569*4887Schin 			n = fold ? (fold - 2) : 0;
570*4887Schin 			while (c = mbchar(cp))
571*4887Schin 			{
572*4887Schin 				if (c == '\n')
573*4887Schin 					n = fold - 1;
574*4887Schin 				else if (n && --n <= 0)
575*4887Schin 				{
576*4887Schin 					n = fold - 2;
577*4887Schin 					stakwrite(bp, --cp - bp);
578*4887Schin 					bp = cp;
579*4887Schin 					stakwrite("'\\\n'", 4);
580*4887Schin 				}
581*4887Schin 				else if (n == 1 && *cp == '\'')
582*4887Schin 				{
583*4887Schin 					n = fold - 5;
584*4887Schin 					stakwrite(bp, --cp - bp);
585*4887Schin 					bp = cp;
586*4887Schin 					stakwrite("'\\\n\\''", 6);
587*4887Schin 				}
588*4887Schin 				else if (c == '\'')
589*4887Schin 				{
590*4887Schin 					stakwrite(bp, cp - bp - 1);
591*4887Schin 					bp = cp;
592*4887Schin 					if (n && (n -= 4) <= 0)
593*4887Schin 					{
594*4887Schin 						n = fold - 5;
595*4887Schin 						stakwrite("'\\\n\\''", 6);
596*4887Schin 					}
597*4887Schin 					else
598*4887Schin 						stakwrite("'\\''", 4);
599*4887Schin 				}
600*4887Schin 			}
601*4887Schin 			stakwrite(bp, cp - bp - 1);
602*4887Schin 			stakputc('\'');
603*4887Schin 		}
604*4887Schin 		else if (n = fold)
605*4887Schin 		{
606*4887Schin 			cp = bp;
607*4887Schin 			while (c = mbchar(cp))
608*4887Schin 			{
609*4887Schin 				if (--n <= 0)
610*4887Schin 				{
611*4887Schin 					n = fold;
612*4887Schin 					stakwrite(bp, --cp - bp);
613*4887Schin 					bp = cp;
614*4887Schin 					stakwrite("\\\n", 2);
615*4887Schin 				}
616*4887Schin 			}
617*4887Schin 			stakwrite(bp, cp - bp - 1);
618*4887Schin 		}
619*4887Schin 		else
620*4887Schin 			stakwrite(bp, cp - bp);
621*4887Schin 		if (c)
622*4887Schin 		{
623*4887Schin 			stakputc('\\');
624*4887Schin 			stakputc('\n');
625*4887Schin 		}
626*4887Schin 	} while (c);
627*4887Schin 	stakputc(0);
628*4887Schin 	return(stakptr(offset));
629*4887Schin }
630*4887Schin 
631*4887Schin #if SHOPT_MULTIBYTE
632*4887Schin 	int sh_strchr(const char *string, register const char *dp)
633*4887Schin 	{
634*4887Schin 		wchar_t c, d;
635*4887Schin 		register const char *cp=string;
636*4887Schin 		mbinit();
637*4887Schin 		d = mbchar(dp);
638*4887Schin 		mbinit();
639*4887Schin 		while(c = mbchar(cp))
640*4887Schin 		{
641*4887Schin 			if(c==d)
642*4887Schin 				return(cp-string);
643*4887Schin 		}
644*4887Schin 		if(d==0)
645*4887Schin 			return(cp-string);
646*4887Schin 		return(-1);
647*4887Schin 	}
648*4887Schin #endif /* SHOPT_MULTIBYTE */
649*4887Schin 
650*4887Schin const char *_sh_translate(const char *message)
651*4887Schin {
652*4887Schin #if ERROR_VERSION >= 20000317L
653*4887Schin 	return(ERROR_translate(0,0,e_dict,message));
654*4887Schin #else
655*4887Schin #if ERROR_VERSION >= 20000101L
656*4887Schin 	return(ERROR_translate(e_dict,message));
657*4887Schin #else
658*4887Schin 	return(ERROR_translate(message,1));
659*4887Schin #endif
660*4887Schin #endif
661*4887Schin }
662*4887Schin 
663*4887Schin /*
664*4887Schin  * change '['identifier']' to identifier
665*4887Schin  * character before <str> must be a '['
666*4887Schin  * returns pointer to last character
667*4887Schin  */
668*4887Schin char *sh_checkid(char *str, char *last)
669*4887Schin {
670*4887Schin 	register unsigned char *cp = (unsigned char*)str;
671*4887Schin 	register unsigned char *v = cp;
672*4887Schin 	register int c;
673*4887Schin 	if(c= *cp++,isaletter(c))
674*4887Schin 		while(c= *cp++,isaname(c));
675*4887Schin 	if(c==']' && (!last || ((char*)cp==last)))
676*4887Schin 	{
677*4887Schin 		/* eliminate [ and ] */
678*4887Schin 		while(v < cp)
679*4887Schin 		{
680*4887Schin 			v[-1] = *v;
681*4887Schin 			v++;
682*4887Schin 		}
683*4887Schin 		if(last)
684*4887Schin 			last -=2;
685*4887Schin 		else
686*4887Schin 		{
687*4887Schin 			while(*v)
688*4887Schin 			{
689*4887Schin 				v[-2] = *v;
690*4887Schin 				v++;
691*4887Schin 			}
692*4887Schin 			v[-2] = 0;
693*4887Schin 			last = (char*)v;
694*4887Schin 		}
695*4887Schin 	}
696*4887Schin 	return(last);
697*4887Schin }
698*4887Schin 
699*4887Schin #if	_AST_VERSION  <= 20000317L
700*4887Schin char *fmtident(const char *string)
701*4887Schin {
702*4887Schin 	return((char*)string);
703*4887Schin }
704*4887Schin #endif
705