diff --git a/check.t b/check.t index a68d6cf..5177dd0 100644 --- a/check.t +++ b/check.t @@ -1,4 +1,4 @@ -# $MirOS: src/bin/mksh/check.t,v 1.117 2007/06/23 22:48:47 tg Exp $ +# $MirOS: src/bin/mksh/check.t,v 1.118 2007/06/27 23:12:58 tg Exp $ # $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas Exp $ # $OpenBSD: history.t,v 1.5 2001/01/28 23:04:56 niklas Exp $ # $OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $ @@ -7,7 +7,7 @@ # http://www.research.att.com/~gsf/public/ifs.sh expected-stdout: - @(#)MIRBSD KSH R29 2007/06/22 + @(#)MIRBSD KSH R29 2007/06/27 description: Check version of shell. category: pdksh @@ -4030,3 +4030,45 @@ stdin: expected-stdout: 5|a|$v|c d|$v|b| --- +name: varexpand-substr-1 +description: + Check if bash-style substring expansion works + when using positive numerics +stdin: + x=abcdefghi + typeset -i y=123456789 + typeset -i 16 z=123456789 # 16#75bcd15 + print a ${x:2:3} ${y:2:3} ${z:2:3} a + print b ${x::3} ${y::3} ${z::3} b + print c ${x:2:} ${y:2:} ${z:2:} c + print d ${x:2} ${y:2} ${z:2} d + print e ${x:2:6} ${y:2:6} ${z:2:7} e + print f ${x:2:7} ${y:2:7} ${z:2:8} f + print g ${x:2:8} ${y:2:8} ${z:2:9} g +expected-stdout: + a cde 345 #75 a + b abc 123 16# b + c c + d cdefghi 3456789 #75bcd15 d + e cdefgh 345678 #75bcd1 e + f cdefghi 3456789 #75bcd15 f + g cdefghi 3456789 #75bcd15 g +--- +name: varexpand-substr-2 +description: + Check if bash-style substring expansion works + when using negative numerics or expressions +stdin: + x=abcdefghi + typeset -i y=123456789 + typeset -i 16 z=123456789 # 16#75bcd15 + n=2 + print a ${x:$n:3} ${y:$n:3} ${z:$n:3} a + print b ${x:n:3} ${y:n:3} ${z:n:3} b + print c ${x:(-2):1} ${y:(-2):1} ${z:(-2):1} c +expected-fail: yes +expected-stdout: + a cde 345 #75 a + b cde 345 #75 b + c h 8 1 c +--- diff --git a/eval.c b/eval.c index 792f03f..1ec2135 100644 --- a/eval.c +++ b/eval.c @@ -2,7 +2,7 @@ #include "sh.h" -__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.28 2007/06/06 23:28:14 tg Exp $"); +__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.29 2007/06/27 23:12:58 tg Exp $"); #ifdef MKSH_SMALL #define MKSH_NOPWNAM @@ -311,6 +311,9 @@ expand(const char *cp, /* input word */ if (stype) sp += slen; switch (stype & 0x7f) { + case '0': + /* XXX begin arithmetic eval. */ + break; case '#': case '%': /* ! DOBLANK,DOBRACE_,DOTILDE */ @@ -423,6 +426,39 @@ expand(const char *cp, /* input word */ "parameter null or not set" : (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; + } } st = st->prev; type = XBASE; @@ -742,7 +778,26 @@ varsub(Expand *xp, const char *sp, const char *word, stype = 0x80; c = word[slen + 0] == CHAR ? word[slen + 1] : 0; } - if (ctype(c, C_SUBOP1)) { + if (stype == 0x80 && (ksh_isdigit(c) || c == ':')) { + const char *tp = word + slen + 2; + bool had_colon = false; + + 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; } else if (ctype(c, C_SUBOP2)) { /* Note: ksh88 allows :%, :%%, etc */ @@ -820,7 +875,7 @@ varsub(Expand *xp, const char *sp, const char *word, c = stype&0x7f; /* test the compiler's code generator */ - if (ctype(c, C_SUBOP2) || + if (ctype(c, C_SUBOP2) || stype == (0x80 | '0') || (((stype&0x80) ? *xp->str=='\0' : xp->str==null) ? /* undef? */ c == '=' || c == '-' || c == '?' : c == '+')) state = XBASE; /* expand word instead of variable value */ diff --git a/mksh.1 b/mksh.1 index acb2a0d..89b5ca1 100644 --- a/mksh.1 +++ b/mksh.1 @@ -1,7 +1,7 @@ -.\" $MirOS: src/bin/mksh/mksh.1,v 1.89 2007/06/23 19:07:14 tg Exp $ +.\" $MirOS: src/bin/mksh/mksh.1,v 1.90 2007/06/27 23:12:59 tg Exp $ .\" $OpenBSD: ksh.1,v 1.120 2007/05/31 20:47:44 otto Exp $ .\" -.Dd June 23, 2007 +.Dd June 27, 2007 .Dt MKSH 1 .Os MirBSD .Sh NAME @@ -1235,6 +1235,35 @@ of them result in the longest match. .Xc .Sm on Like ${..#..} substitution, but it deletes from the end of the value. +.It Xo +.Pf ${ Ar name : Ns Ar pos +.Pf : Ns Ar len Ns } +.Xc +The first +.Ar len +bytes of +.Ar name , +starting at position +.Ar pos , +are substituted. +Both +.Ar pos +and +.Pf : Ns Ar len +are optional. +If +.Ar pos +.\"is negative, counting starts at the end of the string; if it +is omitted, it defaults to 0. +If +.Ar len +is omitted or greater than the length of the remaining string, +all of it is substituted. +.\"Both +.\".Ar pos +.\"and +.\".Ar len +.\"are evaluated as arithmetic expressions. .El .Pp The following special parameters are implicitly set by the shell and cannot be diff --git a/sh.h b/sh.h index dba80df..8b40d0d 100644 --- a/sh.h +++ b/sh.h @@ -8,8 +8,8 @@ /* $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.150 2007/06/22 23:34:41 tg Exp $" -#define MKSH_VERSION "R29 2007/06/22" +#define MKSH_SH_H_ID "$MirOS: src/bin/mksh/sh.h,v 1.151 2007/06/27 23:12:59 tg Exp $" +#define MKSH_VERSION "R29 2007/06/27" #if HAVE_SYS_PARAM_H #include