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