/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1982-2010 AT&T Intellectual Property *
* and is licensed under the *
* Common Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* David Korn <dgk@research.att.com> *
* *
***********************************************************************/
#pragma prototyped
/*
* string processing routines for Korn shell
*
*/
#include <ast.h>
#include <ast_wchar.h>
#include "defs.h"
#include <stak.h>
#include <ccode.h>
#include "shtable.h"
#include "lexstates.h"
#include "national.h"
#if !SHOPT_MULTIBYTE
#define mbchar(p) (*(unsigned char*)p++)
#endif
#if _hdr_wctype
# include <wctype.h>
#endif
#if !_lib_iswprint && !defined(iswprint)
#endif
/*
* Table lookup routine
* <table> is searched for string <sp> and corresponding value is returned
* This is only used for small tables and is used to save non-sharable memory
*/
{
register int first;
register int c;
return(&empty);
{
return(tp);
}
return(&empty);
}
/*
* shtab_options lookup routine
*/
{
register int first;
register int c;
int amb;
int hit;
int inv;
int no;
if(sp==0)
return(0);
{
sp+=2;
sp++;
}
return(0);
for(;;)
{
t+=2;
if(!(c= *t))
break;
if(first == c)
{
{
}
tw=t;
for(;;)
{
if(!*s || *s=='=')
{
if (!*t)
{
}
{
hit = 0;
amb = 1;
}
else
{
}
break;
}
else if(!*t)
break;
else if(sep(*s))
sw = ++s;
else if(sep(*t))
tw = ++t;
else if(*s==*t)
{
s++;
t++;
}
break;
else
{
if(t!=tw)
{
while(*t && !sep(*t))
t++;
if(!*t)
break;
tw = ++t;
}
while (s>sw && *s!=*t)
s--;
}
}
}
}
if(hit)
return(hit);
}
/*
* look for the substring <oldsp> in <string> and replace with <newsp>
* The new string is put on top of the stack
*/
/*@
assume string!=NULL && oldsp!=NULL && newsp!=NULL;
return x satisfying x==NULL ||
strlen(x)==(strlen(in string)+strlen(in newsp)-strlen(in oldsp));
@*/
{
register const char *cp;
const char *savesp = 0;
stakseek(0);
if(*sp==0)
return((char*)0);
goto found;
#if SHOPT_MULTIBYTE
mbinit();
#endif /* SHOPT_MULTIBYTE */
do
{
/* skip to first character which matches start of oldsp */
{
#if SHOPT_MULTIBYTE
/* skip a whole character at a time */
if(c < 0)
sp++;
while(c-- > 0)
#endif /* SHOPT_MULTIBYTE */
}
if(*sp == 0)
return((char*)0);
{
break;
}
if(*cp==0)
/* match found */
goto found;
}
while(*sp);
return((char*)0);
/* copy new */
/* copy rest of string */
return(stakfreeze(1));
}
/*
* TRIM(sp)
* Remove escape characters from characters in <sp> and eliminate quoted nulls.
*/
/*@
assume sp!=NULL;
promise strlen(in sp) <= in strlen(sp);
@*/
{
register char *dp;
register int c;
if(sp)
{
while(c= *sp)
{
#if SHOPT_MULTIBYTE
int len;
{
continue;
}
#endif /* SHOPT_MULTIBYTE */
sp++;
if(c == '\\')
c = *sp++;
if(c)
*dp++ = c;
}
*dp = 0;
}
}
/*
* copy <str1> to <str2> changing upper case to lower case
* <str2> must be big enough to hold <str1>
* <str1> and <str2> may point to the same place.
*/
/*@
assume str1!=0 && str2!=0
return x satisfying strlen(in str1)==strlen(in str2);
@*/
{
register int c;
{
if(isupper(c))
else
*str2 = c;
}
*str2 = 0;
}
/*
* print <str> quoting chars so that it can be read by the shell
* puts null terminated result on stack, but doesn't freeze it
*/
{
register int c, state;
int offset;
if(!cp)
return((char*)0);
#if SHOPT_MULTIBYTE
#else
#endif
if(isaletter(c))
{
#if SHOPT_MULTIBYTE
#else
#endif
if(c==0)
return((char*)string);
if(c=='=')
{
if(*cp==0)
return((char*)string);
#if SHOPT_MULTIBYTE
#else
c = *(unsigned char*)cp++;
#endif
}
}
if(c==0 || c=='#' || c=='~')
state = 1;
#if SHOPT_MULTIBYTE
#else
for(;c; c= *(unsigned char*)cp++)
#endif
{
#if SHOPT_MULTIBYTE
if(c=='\'' || !iswprint(c))
#else
if(c=='\'' || !isprint(c))
#endif /* SHOPT_MULTIBYTE */
state = 2;
state |=1;
}
if(state<2)
{
if(state==1)
stakputc('\'');
if(state==1)
stakputc('\'');
}
else
{
#if SHOPT_MULTIBYTE
#else
#endif
{
state=1;
switch(c)
{
case ('a'==97?'\033':39):
c = 'E';
break;
case '\n':
c = 'n';
break;
case '\r':
c = 'r';
break;
case '\t':
c = 't';
break;
case '\f':
c = 'f';
break;
case '\b':
c = 'b';
break;
case '\a':
c = 'a';
break;
case '\\': case '\'':
break;
default:
#if SHOPT_MULTIBYTE
if(!iswprint(c))
{
continue;
}
#else
if(!isprint(c))
{
continue;
}
#endif
state=0;
break;
}
if(state)
{
stakputc('\\');
stakputc(c);
}
else
}
stakputc('\'');
}
stakputc(0);
}
/*
* print <str> quoting chars so that it can be read by the shell
* puts null terminated result on stack, but doesn't freeze it
* single!=0 limits quoting to '...'
* fold>0 prints raw newlines and inserts appropriately
* escaped newlines every (fold-x) chars
*/
{
register const char *bp;
register const char *vp;
register int c;
register int n;
register int q;
register int a;
int offset;
if (--fold < 8)
fold = 0;
a = isaletter(c) ? '=' : 0;
do
{
q = 0;
n = fold;
{
if (a && !isaname(c))
a = 0;
#if SHOPT_MULTIBYTE
if (c >= 0x200)
continue;
if (c == '\'' || !iswprint(c))
#else
if (c == '\'' || !isprint(c))
#endif /* SHOPT_MULTIBYTE */
{
q = single;
break;
}
if (c == '\n')
q = 1;
else if (c == a)
{
a = 0;
}
else if ((c == '#' || c == '~') && cp == vp || c == ']' || c != ':' && (c = sh_lexstates[ST_NORM][c]) && c != S_EPAT)
q = 1;
}
if (q & 2)
{
stakputc('$');
stakputc('\'');
n = fold - 3;
q = 1;
{
switch (c)
{
case ('a'==97?'\033':39):
c = 'E';
break;
case '\n':
q = 0;
n = fold - 1;
break;
case '\r':
c = 'r';
break;
case '\t':
c = 't';
break;
case '\f':
c = 'f';
break;
case '\b':
c = 'b';
break;
case '\a':
c = 'a';
break;
case '\\':
if (*cp == 'n')
{
c = '\n';
q = 0;
n = fold - 1;
break;
}
case '\'':
break;
default:
#if SHOPT_MULTIBYTE
if(!iswprint(c))
#else
if(!isprint(c))
#endif
{
if ((n -= 4) <= 0)
{
n = fold - 7;
}
continue;
}
q = 0;
break;
}
if ((n -= q + 1) <= 0)
{
if (!q)
{
stakputc('\'');
break;
}
n = fold - 5;
}
if (q)
stakputc('\\');
else
q = 1;
stakputc(c);
}
if (!c)
stakputc('\'');
}
else if (q & 1)
{
stakputc('\'');
{
if (c == '\n')
n = fold - 1;
else if (n && --n <= 0)
{
n = fold - 2;
}
{
n = fold - 5;
}
else if (c == '\'')
{
if (n && (n -= 4) <= 0)
{
n = fold - 5;
}
else
}
}
stakputc('\'');
}
else if (n = fold)
{
{
if (--n <= 0)
{
n = fold;
}
}
}
else
if (c)
{
stakputc('\\');
stakputc('\n');
}
} while (c);
stakputc(0);
}
#if SHOPT_MULTIBYTE
{
wchar_t c, d;
mbinit();
mbinit();
{
if(c==d)
}
if(d==0)
return(-1);
}
#endif /* SHOPT_MULTIBYTE */
{
#if ERROR_VERSION >= 20000317L
#else
#if ERROR_VERSION >= 20000101L
#else
#endif
#endif
}
/*
* change '['identifier']' to identifier
* character before <str> must be a '['
* returns pointer to last character
*/
{
register unsigned char *v = cp;
register int c;
{
/* eliminate [ and ] */
while(v < cp)
{
v[-1] = *v;
v++;
}
if(last)
last -=2;
else
{
while(*v)
{
v[-2] = *v;
v++;
}
v[-2] = 0;
last = (char*)v;
}
}
return(last);
}
#if _AST_VERSION <= 20000317L
{
return((char*)string);
}
#endif