this is bash compatibility week, and by suggestion of actual users,

namely Dr. Robert “Pfeffer” Arnold (in this case, in FreeWRT), make
a half-completed attempt at implementing ${foo:2:3} substring evals
(of course, negatives can't work right now and that the numbers are
in face expressions is something I only read later too – this is to
be revisited later, but it's already late)

don't depend on this behaviour yet though

if someone wants to add more regression tests, feel free to…
This commit is contained in:
tg 2007-06-27 23:12:59 +00:00
parent 0675b8f25b
commit ca17798533
4 changed files with 135 additions and 9 deletions

46
check.t
View File

@ -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
---

61
eval.c
View File

@ -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 */

33
mksh.1
View File

@ -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

4
sh.h
View File

@ -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 <sys/param.h>