#include "sh.h"
-__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.201 2017/04/06 01:59:54 tg Exp $");
+__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.215 2017/08/28 23:27:51 tg Exp $");
/*
* string expansion
#define IFS_IWS 3 /* beginning of word, ignore IFS WS */
#define IFS_QUOTE 4 /* beg.w/quote, become IFS_WORD unless "$@" */
+#define STYPE_CHAR 0xFF
+#define STYPE_DBL 0x100
+#define STYPE_AT 0x200
+#define STYPE_SINGLE 0x2FF
+#define STYPE_MASK 0x300
+
static int varsub(Expand *, const char *, const char *, int *, int *);
static int comsub(Expand *, const char *, int);
static char *valsub(struct op *, Area *);
switch (type) {
case XBASE:
/* original prefixed string */
- c = *sp++;
+ c = ord(*sp++);
switch (c) {
case EOS:
c = 0;
break;
case CHAR:
- c = *sp++;
+ c = ord(*sp++);
break;
case QCHAR:
/* temporary quote */
quote |= 2;
- c = *sp++;
+ c = ord(*sp++);
break;
case OQUOTE:
if (word != IFS_WORD)
case COMASUB:
case COMSUB:
*dp++ = '(';
- c = ')';
+ c = ord(')');
break;
case FUNASUB:
case FUNSUB:
case VALSUB:
*dp++ = '{';
*dp++ = c == VALSUB ? '|' : ' ';
- c = '}';
+ c = ord('}');
break;
}
while (*sp != '\0') {
Xcheck(ds, dp);
*dp++ = *sp++;
}
- if (c == '}')
+ if (c == ord('}'))
*dp++ = ';';
*dp++ = c;
} else {
/* skip qualifier(s) */
if (stype)
sp += slen;
- switch (stype & 0x17F) {
- case 0x100 | '#':
+ switch (stype & STYPE_SINGLE) {
+ case ord('#') | STYPE_AT:
x.str = shf_smprintf("%08X",
(unsigned int)hash(str_val(st->var)));
break;
- case 0x100 | 'Q': {
+ case ord('Q') | STYPE_AT: {
struct shf shf;
shf_sopen(NULL, 0, SHF_WR|SHF_DYNAMIC, &shf);
x.str = shf_sclose(&shf);
break;
}
- case '0': {
+ case ord('0'): {
char *beg, *mid, *end, *stg;
mksh_ari_t from = 0, num = -1, flen, finc = 0;
mid = beg + (wdscan(sp, ADELIM) - sp);
stg = beg + (wdscan(sp, CSUBST) - sp);
mid[-2] = EOS;
- if (mid[-1] == /*{*/'}') {
+ if (ord(mid[-1]) == ord(/*{*/ '}')) {
sp += mid - beg - 1;
end = NULL;
} else {
end = mid +
(wdscan(mid, ADELIM) - mid);
- if (end[-1] != /*{*/ '}')
+ if (ord(end[-1]) != ord(/*{*/ '}'))
/* more than max delimiters */
goto unwind_substsyn;
end[-2] = EOS;
strndupx(x.str, beg, num, ATEMP);
goto do_CSUBST;
}
- case 0x100 | '/':
- case '/': {
+ case ord('/') | STYPE_AT:
+ case ord('/'): {
char *s, *p, *d, *sbeg, *end;
char *pat = NULL, *rrep = null;
char fpat = 0, *tpat1, *tpat2;
p = s + (wdscan(sp, ADELIM) - sp);
d = s + (wdscan(sp, CSUBST) - sp);
p[-2] = EOS;
- if (p[-1] == /*{*/'}')
+ if (ord(p[-1]) == ord(/*{*/ '}'))
d = NULL;
else
d[-2] = EOS;
sp += (d ? d : p) - s - 1;
- if (!(stype & 0x180) &&
+ if (!(stype & STYPE_MASK) &&
s[0] == CHAR &&
- (s[1] == '#' || s[1] == '%'))
+ ctype(s[1], C_SUB2))
fpat = s[1];
wpat = s + (fpat ? 2 : 0);
wrep = d ? p : NULL;
- if (!(stype & 0x100)) {
+ if (!(stype & STYPE_AT)) {
rrep = wrep ? evalstr(wrep,
DOTILDE | DOSCALAR) :
null;
*/
goto no_repl;
}
- if ((stype & 0x180) &&
+ if ((stype & STYPE_MASK) &&
gmatchx(null, pat, false)) {
/*
* pattern matches empty
* string => don't loop
*/
- stype &= ~0x180;
+ stype &= ~STYPE_MASK;
}
/* first see if we have any match at all */
- if (fpat == '#') {
+ if (ord(fpat) == ord('#')) {
/* anchor at the beginning */
tpat1 = shf_smprintf("%s%c*", pat, MAGIC);
tpat2 = tpat1;
- } else if (fpat == '%') {
+ } else if (ord(fpat) == ord('%')) {
/* anchor at the end */
tpat1 = shf_smprintf("%c*%s", MAGIC, pat);
tpat2 = pat;
goto end_repl;
end = strnul(s);
/* now anchor the beginning of the match */
- if (fpat != '#')
+ if (ord(fpat) != ord('#'))
while (sbeg <= end) {
if (gmatchx(sbeg, tpat2, false))
break;
}
/* now anchor the end of the match */
p = end;
- if (fpat != '%')
+ if (ord(fpat) != ord('%'))
while (p >= sbeg) {
bool gotmatch;
strndupx(end, sbeg, p - sbeg, ATEMP);
record_match(end);
afree(end, ATEMP);
- if (stype & 0x100) {
+ if (stype & STYPE_AT) {
if (rrep != null)
afree(rrep, ATEMP);
rrep = wrep ? evalstr(wrep,
sbeg = d + (sbeg - s) + strlen(rrep);
afree(s, ATEMP);
s = d;
- if (stype & 0x100) {
+ if (stype & STYPE_AT) {
afree(tpat1, ATEMP);
afree(pat, ATEMP);
goto again_search;
- } else if (stype & 0x80)
+ } else if (stype & STYPE_DBL)
goto again_repl;
end_repl:
afree(tpat1, ATEMP);
afree(ws, ATEMP);
goto do_CSUBST;
}
- case '#':
- case '%':
+ case ord('#'):
+ case ord('%'):
/* ! DOBLANK,DOBRACE */
f = (f & DONTRUNCOMMAND) |
DOPAT | DOTILDE |
*/
if (!Flag(FSH)) {
*dp++ = MAGIC;
- *dp++ = 0x80 | '@';
+ *dp++ = ord(0x80 | '@');
}
break;
- case '=':
+ case ord('='):
/*
* Tilde expansion for string
* variables in POSIX mode is
f &= ~(DOBLANK|DOGLOB|DOBRACE);
tilde_ok = 1;
break;
- case '?':
+ case ord('?'):
if (*sp == CSUBST)
errorf("%s: parameter null or not set",
st->var->name);
f = st->f;
if (f & DOBLANK)
doblank--;
- switch (st->stype & 0x17F) {
- case '#':
- case '%':
+ switch (st->stype & STYPE_SINGLE) {
+ case ord('#'):
+ case ord('%'):
if (!Flag(FSH)) {
/* Append end-pattern */
*dp++ = MAGIC;
doblank++;
st = st->prev;
continue;
- case '=':
+ case ord('='):
/*
* Restore our position and substitute
* the value of st->var (may not be
st = st->prev;
word = quote || (!*x.str && (f & DOSCALAR)) ? IFS_WORD : IFS_IWS;
continue;
- case '?':
+ case ord('?'):
dp = Xrestpos(ds, dp, st->base);
errorf(Tf_sD_s, st->var->name,
debunk(dp, dp, strlen(dp) + 1));
break;
- case '0':
- case 0x100 | '/':
- case '/':
- case 0x100 | '#':
- case 0x100 | 'Q':
+ case ord('0'):
+ case ord('/') | STYPE_AT:
+ case ord('/'):
+ case ord('#') | STYPE_AT:
+ case ord('Q') | STYPE_AT:
dp = Xrestpos(ds, dp, st->base);
type = XSUB;
word = quote || (!*x.str && (f & DOSCALAR)) ? IFS_WORD : IFS_IWS;
doblank--;
continue;
}
- c = ifs0;
+ c = ord(ifs0);
if ((f & DOHEREDOC)) {
/* pseudo-field-split reliably */
if (c == 0)
--newlines;
} else {
while ((c = shf_getc(x.u.shf)) == 0 ||
-#ifdef MKSH_WITH_TEXTMODE
- c == '\r' ||
-#endif
- c == '\n') {
+ ctype(c, C_NL)) {
#ifdef MKSH_WITH_TEXTMODE
if (c == '\r') {
c = shf_getc(x.u.shf);
tilde_ok <<= 1;
/* mark any special second pass chars */
if (!quote)
- switch (c) {
- case '[':
- case '!':
- case '-':
- case ']':
+ switch (ord(c)) {
+ case ord('['):
+ case ord('!'):
+ case ord('-'):
+ case ord(']'):
/*
* For character classes - doesn't hurt
* to have magic !,-,]s outside of
*/
if (f & (DOPAT | DOGLOB)) {
fdo |= DOMAGIC;
- if (c == '[')
+ if (c == ord('['))
fdo |= f & DOGLOB;
*dp++ = MAGIC;
}
break;
- case '*':
- case '?':
+ case ord('*'):
+ case ord('?'):
if (f & (DOPAT | DOGLOB)) {
fdo |= DOMAGIC | (f & DOGLOB);
*dp++ = MAGIC;
}
break;
- case '{':
- case '}':
- case ',':
- if ((f & DOBRACE) && (c == '{' /*}*/ ||
+ case ord('{'):
+ case ord('}'):
+ case ord(','):
+ if ((f & DOBRACE) &&
+ (ord(c) == ord('{' /*}*/) ||
(fdo & DOBRACE))) {
fdo |= DOBRACE|DOMAGIC;
*dp++ = MAGIC;
}
break;
- case '=':
+ case ord('='):
/* Note first unquoted = for ~ */
if (!(f & DOTEMP) && (!Flag(FPOSIX) ||
(f & DOASNTILDE)) && !saw_eq) {
tilde_ok = 1;
}
break;
- case ':':
+ case ord(':'):
/* : */
/* Note unquoted : for ~ */
if (!(f & DOTEMP) && (f & DOASNTILDE))
tilde_ok = 1;
break;
- case '~':
+ case ord('~'):
/*
* tilde_ok is reset whenever
* any of ' " $( $(( ${ } are seen.
struct tbl *vp;
bool zero_ok = false;
- if ((stype = sp[0]) == '\0')
+ if ((stype = ord(sp[0])) == '\0')
/* Bad variable name */
return (-1);
* ${#var}, string length (-U: characters, +U: octets) or array size
* ${%var}, string width (-U: screen columns, +U: octets)
*/
- c = sp[1];
- if (stype == '%' && c == '\0')
+ c = ord(sp[1]);
+ if (stype == ord('%') && c == '\0')
return (-1);
- if ((stype == '#' || stype == '%') && c != '\0') {
+ if (ctype(stype, C_SUB2) && c != '\0') {
/* Can't have any modifiers for ${#...} or ${%...} */
if (*word != CSUBST)
return (-1);
sp++;
/* Check for size of array */
- if ((p = cstrchr(sp, '[')) && (p[1] == '*' || p[1] == '@') &&
- p[2] == ']') {
+ if ((p = cstrchr(sp, '[')) && (ord(p[1]) == ord('*') ||
+ ord(p[1]) == ord('@')) && ord(p[2]) == ord(']')) {
int n = 0;
- if (stype != '#')
+ if (stype != ord('#'))
return (-1);
vp = global(arrayname(sp));
if (vp->flag & (ISSET|ARRAY))
if (vp->flag & ISSET)
n++;
c = n;
- } else if (c == '*' || c == '@') {
- if (stype != '#')
+ } else if (c == ord('*') || c == ord('@')) {
+ if (stype != ord('#'))
return (-1);
c = e->loc->argc;
} else {
p = str_val(global(sp));
zero_ok = p != null;
- if (stype == '#')
+ if (stype == ord('#'))
c = utflen(p);
else {
/* partial utf_mbswidth reimplementation */
if (!UTFMODE || (len = utf_mbtowc(&wc,
s)) == (size_t)-1)
/* not UTFMODE or not UTF-8 */
- wc = (unsigned char)(*s++);
+ wc = rtt2asc(*s++);
else
/* UTFMODE and UTF-8 */
s += len;
xp->str = shf_smprintf(Tf_d, c);
return (XSUB);
}
- if (stype == '!' && c != '\0' && *word == CSUBST) {
+ if (stype == ord('!') && c != '\0' && *word == CSUBST) {
sp++;
- if ((p = cstrchr(sp, '[')) && (p[1] == '*' || p[1] == '@') &&
- p[2] == ']') {
- c = '!';
+ if ((p = cstrchr(sp, '[')) && (ord(p[1]) == ord('*') ||
+ ord(p[1]) == ord('@')) && ord(p[2]) == ord(']')) {
+ c = ord('!');
stype = 0;
goto arraynames;
}
/* Check for qualifiers in word part */
stype = 0;
- c = word[slen + 0] == CHAR ? word[slen + 1] : 0;
- if (c == ':') {
+ c = word[slen + 0] == CHAR ? ord(word[slen + 1]) : 0;
+ if (c == ord(':')) {
slen += 2;
- stype = 0x80;
- c = word[slen + 0] == CHAR ? word[slen + 1] : 0;
+ stype = STYPE_DBL;
+ c = word[slen + 0] == CHAR ? ord(word[slen + 1]) : 0;
}
- if (!stype && c == '/') {
+ if (!stype && c == ord('/')) {
slen += 2;
stype = c;
- if (word[slen] == ADELIM && word[slen + 1] == c) {
+ if (word[slen] == ADELIM &&
+ ord(word[slen + 1]) == (unsigned int)c) {
slen += 2;
- stype |= 0x80;
+ stype |= STYPE_DBL;
}
- } else if (stype == 0x80 && (c == ' ' || c == '0')) {
- stype |= '0';
- } else if (ctype(c, C_SUBOP1)) {
+ } else if (stype == STYPE_DBL && (c == ord(' ') || c == ord('0'))) {
+ stype |= ord('0');
+ } else if (ctype(c, C_SUB1)) {
slen += 2;
stype |= c;
- } else if (ksh_issubop2(c)) {
+ } else if (ctype(c, C_SUB2)) {
/* Note: ksh88 allows :%, :%%, etc */
slen += 2;
stype = c;
- if (word[slen + 0] == CHAR && c == word[slen + 1]) {
- stype |= 0x80;
+ if (word[slen + 0] == CHAR &&
+ ord(word[slen + 1]) == (unsigned int)c) {
+ stype |= STYPE_DBL;
slen += 2;
}
- } else if (c == '@') {
+ } else if (c == ord('@')) {
/* @x where x is command char */
- switch (c = word[slen + 2] == CHAR ? word[slen + 3] : 0) {
- case '#':
- case '/':
- case 'Q':
+ switch (c = ord(word[slen + 2]) == CHAR ?
+ ord(word[slen + 3]) : 0) {
+ case ord('#'):
+ case ord('/'):
+ case ord('Q'):
break;
default:
return (-1);
}
- stype |= 0x100 | c;
+ stype |= STYPE_AT | c;
slen += 4;
} else if (stype)
/* : is not ok */
if (!stype && *word != CSUBST)
return (-1);
- c = sp[0];
- if (c == '*' || c == '@') {
- switch (stype & 0x17F) {
+ c = ord(sp[0]);
+ if (c == ord('*') || c == ord('@')) {
+ switch (stype & STYPE_SINGLE) {
/* can't assign to a vector */
- case '=':
+ case ord('='):
/* can't trim a vector (yet) */
- case '%':
- case '#':
- case '?':
- case '0':
- case 0x100 | '/':
- case '/':
- case 0x100 | '#':
- case 0x100 | 'Q':
+ case ord('%'):
+ case ord('#'):
+ case ord('?'):
+ case ord('0'):
+ case ord('/') | STYPE_AT:
+ case ord('/'):
+ case ord('#') | STYPE_AT:
+ case ord('Q') | STYPE_AT:
return (-1);
}
if (e->loc->argc == 0) {
xp->str = null;
xp->var = global(sp);
- state = c == '@' ? XNULLSUB : XSUB;
+ state = c == ord('@') ? XNULLSUB : XSUB;
} else {
xp->u.strv = (const char **)e->loc->argv + 1;
xp->str = *xp->u.strv++;
/* $@ */
- xp->split = tobool(c == '@');
+ xp->split = tobool(c == ord('@'));
state = XARG;
}
/* POSIX 2009? */
zero_ok = true;
- } else if ((p = cstrchr(sp, '[')) && (p[1] == '*' || p[1] == '@') &&
- p[2] == ']') {
+ } else if ((p = cstrchr(sp, '[')) && (ord(p[1]) == ord('*') ||
+ ord(p[1]) == ord('@')) && ord(p[2]) == ord(']')) {
XPtrV wv;
- switch (stype & 0x17F) {
+ switch (stype & STYPE_SINGLE) {
/* can't assign to a vector */
- case '=':
+ case ord('='):
/* can't trim a vector (yet) */
- case '%':
- case '#':
- case '?':
- case '0':
- case 0x100 | '/':
- case '/':
- case 0x100 | '#':
- case 0x100 | 'Q':
+ case ord('%'):
+ case ord('#'):
+ case ord('?'):
+ case ord('0'):
+ case ord('/') | STYPE_AT:
+ case ord('/'):
+ case ord('#') | STYPE_AT:
+ case ord('Q') | STYPE_AT:
return (-1);
}
c = 0;
for (; vp; vp = vp->u.array) {
if (!(vp->flag&ISSET))
continue;
- XPput(wv, c == '!' ? shf_smprintf(Tf_lu,
+ XPput(wv, c == ord('!') ? shf_smprintf(Tf_lu,
arrayindex(vp)) :
str_val(vp));
}
if (XPsize(wv) == 0) {
xp->str = null;
- state = p[1] == '@' ? XNULLSUB : XSUB;
+ state = ord(p[1]) == ord('@') ? XNULLSUB : XSUB;
XPfree(wv);
} else {
XPput(wv, 0);
xp->u.strv = (const char **)XPptrv(wv);
xp->str = *xp->u.strv++;
/* ${foo[@]} */
- xp->split = tobool(p[1] == '@');
+ xp->split = tobool(ord(p[1]) == ord('@'));
state = XARG;
}
} else {
xp->var = global(sp);
xp->str = str_val(xp->var);
/* can't assign things like $! or $1 */
- if ((stype & 0x17F) == '=' && !*xp->str &&
+ if ((stype & STYPE_SINGLE) == ord('=') && !*xp->str &&
ctype(*sp, C_VAR1 | C_DIGIT))
return (-1);
state = XSUB;
}
- c = stype & 0x7F;
+ c = stype & STYPE_CHAR;
/* test the compiler's code generator */
- if (((stype < 0x100) && (ksh_issubop2(c) ||
- (((stype & 0x80) ? *xp->str == '\0' : xp->str == null) &&
+ if ((!(stype & STYPE_AT) && (ctype(c, C_SUB2) ||
+ (((stype & STYPE_DBL) ? *xp->str == '\0' : xp->str == null) &&
(state != XARG || (ifs0 || xp->split ?
(xp->u.strv[0] == NULL) : !hasnonempty(xp->u.strv))) ?
- c == '=' || c == '-' || c == '?' : c == '+'))) ||
- stype == (0x80 | '0') || stype == (0x100 | '#') ||
- stype == (0x100 | 'Q') || (stype & 0x7F) == '/')
+ ctype(c, C_EQUAL | C_MINUS | C_QUEST) : c == ord('+')))) ||
+ stype == (ord('0') | STYPE_DBL) || stype == (ord('#') | STYPE_AT) ||
+ stype == (ord('Q') | STYPE_AT) || (stype & STYPE_CHAR) == ord('/'))
/* expand word instead of variable value */
state = XBASE;
if (Flag(FNOUNSET) && xp->str == null && !zero_ok &&
- (ksh_issubop2(c) || (state != XBASE && c != '+')))
+ (ctype(c, C_SUB2) || (state != XBASE && c != ord('+'))))
errorf(Tf_parm, sp);
*stypep = stype;
*slenp = slen;
if (!herein(io, &name)) {
xp->str = name;
/* as $(…) requires, trim trailing newlines */
- name += strlen(name);
+ name = strnul(name);
while (name > xp->str && name[-1] == '\n')
--name;
*name = '\0';
char *end = strnul(str);
char *p, c;
- switch (how & 0xFF) {
- case '#':
+ switch (how & (STYPE_CHAR | STYPE_DBL)) {
+ case ord('#'):
/* shortest match at beginning */
for (p = str; p <= end; p += utf_ptradj(p)) {
c = *p; *p = '\0';
*p = c;
}
break;
- case '#'|0x80:
+ case ord('#') | STYPE_DBL:
/* longest match at beginning */
for (p = end; p >= str; p--) {
c = *p; *p = '\0';
*p = c;
}
break;
- case '%':
+ case ord('%'):
/* shortest match at end */
p = end;
while (p >= str) {
goto trimsub_match;
if (UTFMODE) {
char *op = p;
- while ((p-- > str) && ((*p & 0xC0) == 0x80))
+ while ((p-- > str) && ((rtt2asc(*p) & 0xC0) == 0x80))
;
if ((p < str) || (p + utf_ptradj(p) != op))
p = op - 1;
--p;
}
break;
- case '%'|0x80:
+ case ord('%') | STYPE_DBL:
/* longest match at end */
for (p = str; p <= end; p++)
if (gmatchx(p, pat, false)) {
XPput(*wp, debunk(cp, cp, strlen(cp) + 1));
else
qsort(XPptrv(*wp) + oldsize, XPsize(*wp) - oldsize,
- sizeof(void *), xstrcmp);
+ sizeof(void *), ascpstrcmp);
}
#define GF_NONE 0
*np++ = '\0';
} else {
odirsep = '\0'; /* keep gcc quiet */
- se = sp + strlen(sp);
+ se = strnul(sp);
}
* directory isn't readable - if no globbing is needed, only execute
* permission should be required (as per POSIX)).
*/
- if (!has_globbing(sp, se)) {
+ if (!has_globbing(sp)) {
XcheckN(*xs, xp, se - sp + 1);
debunk(xp, sp, Xnleft(*xs, xp));
- xp += strlen(xp);
+ xp = strnul(xp);
*xpp = xp;
globit(xs, xpp, np, wp, check);
} else {
XcheckN(*xs, xp, len);
memcpy(xp, name, len);
*xpp = xp + len - 1;
- globit(xs, xpp, np, wp,
- (check & GF_MARKDIR) | GF_GLOBBED
- | (np ? GF_EXCHECK : GF_NONE));
+ globit(xs, xpp, np, wp, (check & GF_MARKDIR) |
+ GF_GLOBBED | (np ? GF_EXCHECK : GF_NONE));
xp = Xstring(*xs, xp) + prefix_len;
}
closedir(dirp);
memmove(dp, sp, s - sp);
for (d = dp + (s - sp); *s && (d - dp < (ssize_t)dlen); s++)
if (!ISMAGIC(*s) || !(*++s & 0x80) ||
- !vstrchr("*+?@! ", *s & 0x7f))
+ !ctype(*s & 0x7F, C_PATMO | C_SPC))
*d++ = *s;
else {
/* extended pattern operators: *+?@! */
char *p = exp_start;
/* search for open brace */
- while ((p = strchr(p, MAGIC)) && p[1] != '{' /*}*/)
+ while ((p = strchr(p, MAGIC)) && ord(p[1]) != ord('{' /*}*/))
p += 2;
brace_start = p;
p += 2;
while (*p && count) {
if (ISMAGIC(*p++)) {
- if (*p == '{' /*}*/)
+ if (ord(*p) == ord('{' /*}*/))
++count;
- else if (*p == /*{*/ '}')
+ else if (ord(*p) == ord(/*{*/ '}'))
--count;
else if (*p == ',' && count == 1)
comma = p;
count = 1;
for (p = brace_start + 2; p != brace_end; p++) {
if (ISMAGIC(*p)) {
- if (*++p == '{' /*}*/)
+ if (ord(*++p) == ord('{' /*}*/))
++count;
- else if ((*p == /*{*/ '}' && --count == 0) ||
+ else if ((ord(*p) == ord(/*{*/ '}') && --count == 0) ||
(*p == ',' && count == 1)) {
char *news;
int l1, l2, l3;