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