1 /***********************************************************************
3 * This software is part of the ast package *
4 * Copyright (c) 1982-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * David Korn <dgk@research.att.com> *
19 ***********************************************************************/
22 * string processing routines for Korn shell
27 #include <ast_wchar.h>
32 #include "lexstates.h"
36 #define mbchar(p) (*(unsigned char*)p++)
43 #if !_lib_iswprint && !defined(iswprint)
44 # define iswprint(c) (((c)&~0377) || isprint(c))
49 * Table lookup routine
50 * <table> is searched for string <sp> and corresponding value is returned
51 * This is only used for small tables and is used to save non-sharable memory
54 const Shtable_t
*sh_locate(register const char *sp
,const Shtable_t
*table
,int size
)
57 register const Shtable_t
*tp
;
59 static const Shtable_t empty
= {0,0};
60 if(sp
==0 || (first
= *sp
)==0)
63 while((c
= *tp
->sh_name
) && (CC_NATIVE
!=CC_ASCII
|| c
<= first
))
65 if(first
== c
&& strcmp(sp
,tp
->sh_name
)==0)
67 tp
= (Shtable_t
*)((char*)tp
+size
);
73 * shtab_options lookup routine
76 #define sep(c) ((c)=='-'||(c)=='_')
78 int sh_lookopt(register const char *sp
, int *invert
)
81 register const Shtable_t
*tp
;
83 register const char *s
, *t
, *sw
, *tw
;
90 if(*sp
=='n' && *(sp
+1)=='o' && (*(sp
+2)!='t' || *(sp
+3)!='i'))
104 if(no
= *t
=='n' && *(t
+1)=='o' && *(t
+2)!='t')
113 return(tp
->sh_number
);
121 if (*s
== '=' && !strtol(s
+1, NiL
, 0))
126 return(tp
->sh_number
);
151 else if(s
==sw
&& t
==tw
)
157 while(*t
&& !sep(*t
))
163 while (s
>sw
&& *s
!=*t
)
168 tp
= (Shtable_t
*)((char*)tp
+sizeof(*shtab_options
));
176 * look for the substring <oldsp> in <string> and replace with <newsp>
177 * The new string is put on top of the stack
179 char *sh_substitute(const char *string
,const char *oldsp
,char *newsp
)
181 assume string!=NULL && oldsp!=NULL && newsp!=NULL;
182 return x satisfying x==NULL ||
183 strlen(x)==(strlen(in string)+strlen(in newsp)-strlen(in oldsp));
186 register const char *sp
= string
;
187 register const char *cp
;
188 const char *savesp
= 0;
196 #endif /* SHOPT_MULTIBYTE */
199 /* skip to first character which matches start of oldsp */
200 while(*sp
&& (savesp
==sp
|| *sp
!= *cp
))
203 /* skip a whole character at a time */
208 #endif /* SHOPT_MULTIBYTE */
231 /* copy rest of string */
233 return(stakfreeze(1));
238 * Remove escape characters from characters in <sp> and eliminate quoted nulls.
241 void sh_trim(register char *sp
)
244 promise strlen(in sp) <= in strlen(sp);
256 if(mbwide() && (len
=mbsize(sp
))>1)
258 memmove(dp
, sp
, len
);
263 #endif /* SHOPT_MULTIBYTE */
275 * copy <str1> to <str2> changing upper case to lower case
276 * <str2> must be big enough to hold <str1>
277 * <str1> and <str2> may point to the same place.
280 void sh_utol(register char const *str1
,register char *str2
)
282 assume str1!=0 && str2!=0
283 return x satisfying strlen(in str1)==strlen(in str2);
287 for(; c
= *((unsigned char*)str1
); str1
++,str2
++)
298 * print <str> quoting chars so that it can be read by the shell
299 * puts null terminated result on stack, but doesn't freeze it
301 char *sh_fmtq(const char *string
)
303 register const char *cp
= string
, *op
;
304 register int c
, state
;
310 state
= ((c
= mbchar(cp
))==0);
312 state
= ((c
= *(unsigned char*)cp
++)==0);
317 while((c
=mbchar(cp
)),isaname(c
));
319 while((c
= *(unsigned char*)cp
++),isaname(c
));
322 return((char*)string
);
326 return((char*)string
);
333 c
= *(unsigned char*)cp
++;
337 if(c
==0 || c
=='#' || c
=='~')
340 for(;c
;c
= mbchar(cp
))
342 for(;c
; c
= *(unsigned char*)cp
++)
346 if(c
=='\'' || !iswprint(c
))
348 if(c
=='\'' || !isprint(c
))
349 #endif /* SHOPT_MULTIBYTE */
351 else if(c
==']' || (c
!=':' && c
<=0xff && (c
=sh_lexstates
[ST_NORM
][c
]) && c
!=S_EPAT
))
358 if(c
= --cp
- string
)
368 while(op
= cp
, c
= mbchar(cp
))
370 while(op
= cp
, c
= *(unsigned char*)cp
++)
376 case ('a'==97?'\033':39):
397 case '\\': case '\'':
404 sfprintf(staksp
,"\\%.3o",*(unsigned char*)op
++);
410 sfprintf(staksp
,"\\%.3o",c
);
423 stakwrite(op
, cp
-op
);
428 return(stakptr(offset
));
432 * print <str> quoting chars so that it can be read by the shell
433 * puts null terminated result on stack, but doesn't freeze it
434 * single!=0 limits quoting to '...'
435 * fold>0 prints raw newlines and inserts appropriately
436 * escaped newlines every (fold-x) chars
438 char *sh_fmtqf(const char *string
, int single
, int fold
)
440 register const char *cp
= string
;
441 register const char *bp
;
442 register const char *vp
;
451 if (!cp
|| !*cp
|| !single
&& !fold
|| fold
&& strlen(string
) < fold
)
454 single
= single
? 1 : 3;
456 a
= isaletter(c
) ? '=' : 0;
463 while ((!n
|| n
-- > 0) && (c
= mbchar(cp
)))
465 if (a
&& !isaname(c
))
470 if (c
== '\'' || !iswprint(c
))
472 if (c
== '\'' || !isprint(c
))
473 #endif /* SHOPT_MULTIBYTE */
482 stakwrite(bp
, cp
- bp
);
487 else if ((c
== '#' || c
== '~') && cp
== vp
|| c
== ']' || c
!= ':' && (c
= sh_lexstates
[ST_NORM
][c
]) && c
!= S_EPAT
)
497 while (c
= mbchar(cp
))
501 case ('a'==97?'\033':39):
542 stakwrite("'\\\n$'", 5);
545 sfprintf(staksp
, "\\%03o", c
);
551 if ((n
-= q
+ 1) <= 0)
559 stakwrite("'\\\n$'", 5);
576 n
= fold
? (fold
- 2) : 0;
577 while (c
= mbchar(cp
))
581 else if (n
&& --n
<= 0)
584 stakwrite(bp
, --cp
- bp
);
586 stakwrite("'\\\n'", 4);
588 else if (n
== 1 && *cp
== '\'')
591 stakwrite(bp
, --cp
- bp
);
593 stakwrite("'\\\n\\''", 6);
597 stakwrite(bp
, cp
- bp
- 1);
599 if (n
&& (n
-= 4) <= 0)
602 stakwrite("'\\\n\\''", 6);
605 stakwrite("'\\''", 4);
608 stakwrite(bp
, cp
- bp
- 1);
614 while (c
= mbchar(cp
))
619 stakwrite(bp
, --cp
- bp
);
621 stakwrite("\\\n", 2);
624 stakwrite(bp
, cp
- bp
- 1);
627 stakwrite(bp
, cp
- bp
);
635 return(stakptr(offset
));
639 int sh_strchr(const char *string
, register const char *dp
)
642 register const char *cp
=string
;
646 while(c
= mbchar(cp
))
655 #endif /* SHOPT_MULTIBYTE */
657 const char *_sh_translate(const char *message
)
659 #if ERROR_VERSION >= 20000317L
660 return(ERROR_translate(0,0,e_dict
,message
));
662 #if ERROR_VERSION >= 20000101L
663 return(ERROR_translate(e_dict
,message
));
665 return(ERROR_translate(message
,1));
671 * change '['identifier']' to identifier
672 * character before <str> must be a '['
673 * returns pointer to last character
675 char *sh_checkid(char *str
, char *last
)
677 register unsigned char *cp
= (unsigned char*)str
;
678 register unsigned char *v
= cp
;
680 if(c
= *cp
++,isaletter(c
))
681 while(c
= *cp
++,isaname(c
));
682 if(c
==']' && (!last
|| ((char*)cp
==last
)))
684 /* eliminate [ and ] */
706 #if _AST_VERSION <= 20000317L
707 char *fmtident(const char *string
)
709 return((char*)string
);