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