diff --git a/eval.c b/eval.c index 7b8cc6c..4727e35 100644 --- a/eval.c +++ b/eval.c @@ -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; diff --git a/lex.c b/lex.c index 7365a46..62fbe55 100644 --- a/lex.c +++ b/lex.c @@ -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. diff --git a/sh.h b/sh.h index c353c11..23d559c 100644 --- a/sh.h +++ b/sh.h @@ -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; diff --git a/tree.c b/tree.c index 8f63179..9817eaf 100644 --- a/tree.c +++ b/tree.c @@ -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);