make this pass varexpand-substr-1 and ‘c’ of varexpand-substr-2

by actually using the lexer and parser for that
This commit is contained in:
tg 2007-07-06 01:53:36 +00:00
parent c9db9eb092
commit 26a6e5acc9
4 changed files with 98 additions and 57 deletions

106
eval.c
View File

@ -2,7 +2,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.30 2007/07/01 15:39:22 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.31 2007/07/06 01:53:35 tg Exp $");
#ifdef MKSH_SMALL
#define MKSH_NOPWNAM
@ -311,9 +311,48 @@ expand(const char *cp, /* input word */
if (stype)
sp += slen;
switch (stype & 0x7f) {
case '0':
/* XXX begin arithmetic eval. */
break;
case '0': {
char *beg, *mid, *end, *stg;
long from = 0, num = -1, flen;
/* ! DOBLANK,DOBRACE_,DOTILDE */
f = DOPAT | (f&DONTRUNCOMMAND) |
DOTEMP_;
quote = 0;
beg = wdcopy(sp, ATEMP);
mid = beg + (wdscan(sp, ADELIM) - sp);
mid[-2] = EOS;
if (mid[-1] == /*{*/'}') {
sp += mid - beg - 1;
end = NULL;
} else {
end = mid +
(wdscan(mid, ADELIM) - mid);
end[-2] = EOS;
sp += end - beg - 1;
}
evaluate(stg = wdstrip(beg), &from,
KSH_UNWIND_ERROR, true);
afree(stg, ATEMP);
if (end) {
evaluate(stg = wdstrip(mid),
&num, KSH_UNWIND_ERROR, true);
afree(stg, ATEMP);
}
afree(beg, ATEMP);
beg = str_val(st->var);
flen = strlen(beg);
if (from < 0) {
if (-from < flen)
beg += flen + from;
} else
beg += from < flen ? from : flen;
flen = strlen(beg);
if (num < 0 || num > flen)
num = flen;
x.str = str_nsave(beg, num, ATEMP);
goto do_CSUBST;
}
case '#':
case '%':
/* ! DOBLANK,DOBRACE_,DOTILDE */
@ -365,6 +404,7 @@ expand(const char *cp, /* input word */
continue;
}
case CSUBST: /* only get here if expanding word */
do_CSUBST:
sp++; /* ({) skip the } or x */
tilde_ok = 0; /* in case of ${unset:-} */
*dp = '\0';
@ -427,38 +467,12 @@ expand(const char *cp, /* input word */
(debunk(s, s, strlen(s) + 1), s));
}
case '0':
{
char i, *s = Xrestpos(ds, dp, st->base);
int from = 0, num = 0;
/* bool fromend = false; */
/* XXX use evaluate() from expr.c
XXX or directly parse as 2 exprs */
/* if (*s == '-') {
fromend = true;
++s;
} */
while ((i = *s++) && i != ':')
from = from * 10 + i - '0';
if (i == ':') while ((i = *s++))
num = num * 10 + i - '0';
else
num = -1;
/* if (fromend) {
int flen = strlen(x.str);
if (from < flen)
x.str += flen - from;
} else */
x.str += from;
from = strlen(x.str);
if (num < 0 || num > from)
num = from;
dp = Xstring(ds, dp);
XcheckN(ds, dp, num);
memcpy(dp, x.str, num);
dp += num;
}
dp = Xrestpos(ds, dp, st->base);
type = XSUB;
if (f&DOBLANK)
doblank++;
st = st->prev;
continue;
}
st = st->prev;
type = XBASE;
@ -778,25 +792,9 @@ varsub(Expand *xp, const char *sp, const char *word,
stype = 0x80;
c = word[slen + 0] == CHAR ? word[slen + 1] : 0;
}
if (stype == 0x80 && (ksh_isdigit(c) || c == ':')) {
const char *tp = word + slen + 2;
bool had_colon = false;
if (stype == 0x80 && (ksh_isdigit(c) || c == '('/*)*/ ||
(!c && word[slen] && word[slen] != CHAR))) {
stype |= '0';
/* syntax check: minus, digits, one colon, digits */
/* if (*tp == CHAR && tp[1] == '-')
tp += 2; */
while (*tp != EOS && *tp != CSUBST) {
if (*tp != CHAR)
return (-1);
if (!ksh_isdigit(tp[1])) {
if (!had_colon && tp[1] == ':')
had_colon = true;
else
return (-1);
}
tp += 2;
}
} else if (ctype(c, C_SUBOP1)) {
slen += 2;
stype |= c;

37
lex.c
View File

@ -2,7 +2,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.38 2007/07/05 23:48:53 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.39 2007/07/06 01:53:36 tg Exp $");
/* Structure to keep track of the lexing state and the various pieces of info
* needed for each particular state. */
@ -42,6 +42,13 @@ struct lex_state {
#define ls_sletarray ls_info.u_sletarray
} u_sletarray;
/* ADELIM */
struct sadelim_info {
unsigned char delimiter;
unsigned char num;
#define ls_sadelim ls_info.u_sadelim
} u_sadelim;
Lex_state *base; /* used to point to next state block */
} ls_info;
};
@ -155,6 +162,15 @@ yylex(int cf)
((state == SBASE || state == SHEREDELIM) && ctype(c, C_LEX1)))) {
Xcheck(ws, wp);
switch (state) {
case SADELIM:
if (c == /*{*/ '}' || c == statep->ls_sadelim.delimiter) {
*wp++ = ADELIM;
*wp++ = c;
if (c == /*{*/ '}' || --statep->ls_sadelim.num == 0)
POP_STATE();
break;
}
/* FALLTHROUGH */
case SBASE:
if (c == '[' && (cf & (VARASN|ARRAYVAR))) {
*wp = EOS; /* temporary */
@ -270,6 +286,25 @@ yylex(int cf)
if (c == ':') {
*wp++ = CHAR, *wp++ = c;
c = getsc();
if (c == ':') {
*wp++ = CHAR;
*wp++ = '0';
*wp++ = ADELIM;
*wp++ = ':';
PUSH_STATE(SADELIM);
statep->ls_sadelim.delimiter = ':';
statep->ls_sadelim.num = 1;
break;
} else if (ksh_isdigit(c) ||
c == '('/*)*/ ||
c == '$' /* XXX what else? */) {
/* substring subst. */
ungetsc(c);
PUSH_STATE(SADELIM);
statep->ls_sadelim.delimiter = ':';
statep->ls_sadelim.num = 2;
break;
}
}
/* If this is a trim operation,
* treat (,|,) specially in STBRACE.

4
sh.h
View File

@ -8,7 +8,7 @@
/* $OpenBSD: c_test.h,v 1.4 2004/12/20 11:34:26 otto Exp $ */
/* $OpenBSD: tty.h,v 1.5 2004/12/20 11:34:26 otto Exp $ */
#define MKSH_SH_H_ID "$MirOS: src/bin/mksh/sh.h,v 1.154 2007/07/01 21:47:08 tg Exp $"
#define MKSH_SH_H_ID "$MirOS: src/bin/mksh/sh.h,v 1.155 2007/07/06 01:53:36 tg Exp $"
#define MKSH_VERSION "R29 2007/07/01"
#if HAVE_SYS_PARAM_H
@ -904,6 +904,7 @@ struct op {
#define OPAT 9 /* open pattern: *(, @(, etc. */
#define SPAT 10 /* separate pattern: | */
#define CPAT 11 /* close pattern: ) */
#define ADELIM 12 /* arbitrary delimiter: ${foo:2:3} ${foo/bar/baz} */
/*
* IO redirection
@ -1116,6 +1117,7 @@ struct source {
#define SPATTERN 11 /* parsing *(...|...) pattern (*+?@!) */
#define STBRACE 12 /* parsing ${..[#%]..} */
#define SLETARRAY 13 /* inside =( ), just copy */
#define SADELIM 14 /* like SBASE, looking for delimiter */
typedef union {
int i;

8
tree.c
View File

@ -2,7 +2,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.10 2007/05/13 17:51:24 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.11 2007/07/06 01:53:36 tg Exp $");
#define INDENT 4
@ -268,6 +268,7 @@ tputS(char *wp, struct shf *shf)
switch ((c = *wp++)) {
case EOS:
return;
case ADELIM:
case CHAR:
tputC(*wp++, shf);
break;
@ -484,6 +485,10 @@ wdscan(const char *wp, int c)
switch (*wp++) {
case EOS:
return (wp);
case ADELIM:
if (c == ADELIM)
return (wp + 1);
/* FALLTHROUGH */
case CHAR:
case QCHAR:
wp++;
@ -546,6 +551,7 @@ wdstrip(const char *wp)
switch ((c = *wp++)) {
case EOS:
return shf_sclose(&shf); /* null terminates */
case ADELIM:
case CHAR:
case QCHAR:
shf_putchar(*wp++, &shf);