almost hack ${foo//bar/baz} support for real, now
still one corner case left ☹ → 11:09⎜«Han:#UnixNL» Ik _haat_ bash ⇒ kann ich mich nur anschließen…
This commit is contained in:
parent
01b54f1fd5
commit
85b0cb20eb
69
check.t
69
check.t
@ -1,4 +1,4 @@
|
|||||||
# $MirOS: src/bin/mksh/check.t,v 1.147 2008/02/26 20:43:10 tg Exp $
|
# $MirOS: src/bin/mksh/check.t,v 1.148 2008/02/27 11:24:11 tg Exp $
|
||||||
# $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas 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: 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 $
|
# $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
|
# http://www.research.att.com/~gsf/public/ifs.sh
|
||||||
|
|
||||||
expected-stdout:
|
expected-stdout:
|
||||||
@(#)MIRBSD KSH R33 2008/02/26
|
@(#)MIRBSD KSH R33 2008/02/27
|
||||||
description:
|
description:
|
||||||
Check version of shell.
|
Check version of shell.
|
||||||
category: pdksh
|
category: pdksh
|
||||||
@ -964,7 +964,7 @@ expected-stdout:
|
|||||||
---
|
---
|
||||||
name: eglob-trim-1
|
name: eglob-trim-1
|
||||||
description:
|
description:
|
||||||
Eglobing in trim expressions...
|
Eglobbing in trim expressions...
|
||||||
(at&t ksh fails this - docs say # matches shortest string, ## matches
|
(at&t ksh fails this - docs say # matches shortest string, ## matches
|
||||||
longest...)
|
longest...)
|
||||||
stdin:
|
stdin:
|
||||||
@ -981,7 +981,7 @@ expected-stdout:
|
|||||||
---
|
---
|
||||||
name: eglob-trim-2
|
name: eglob-trim-2
|
||||||
description:
|
description:
|
||||||
Check eglobing works in trims...
|
Check eglobbing works in trims...
|
||||||
stdin:
|
stdin:
|
||||||
x=abcdef
|
x=abcdef
|
||||||
echo 1: ${x#*(a|b)cd}
|
echo 1: ${x#*(a|b)cd}
|
||||||
@ -994,6 +994,65 @@ expected-stdout:
|
|||||||
3: abcdef
|
3: abcdef
|
||||||
4: cdef
|
4: cdef
|
||||||
---
|
---
|
||||||
|
name: eglob-substrpl-1
|
||||||
|
description:
|
||||||
|
Check eglobbing works in substs... and they work at all
|
||||||
|
stdin:
|
||||||
|
x=1222321_ab/cde_b/c_1221
|
||||||
|
echo 1: ${x/2}
|
||||||
|
echo 2: ${x//2}
|
||||||
|
echo 3: ${x/+(2)}
|
||||||
|
echo 4: ${x//+(2)}
|
||||||
|
echo 5: ${x/2/4}
|
||||||
|
echo 6: ${x//2/4}
|
||||||
|
echo 7: ${x/+(2)/4}
|
||||||
|
echo 8: ${x//+(2)/4}
|
||||||
|
echo 9: ${x/b/c/e/f}
|
||||||
|
echo 10: ${x/b\/c/e/f}
|
||||||
|
echo 11: ${x/b\/c/e\/f}
|
||||||
|
echo 12: ${x/b\/c/e\\/f}
|
||||||
|
echo 13: ${x/b\\/c/e\\/f}
|
||||||
|
echo 14: ${x//b/c/e/f}
|
||||||
|
echo 15: ${x//b\/c/e/f}
|
||||||
|
echo 16: ${x//b\/c/e\/f}
|
||||||
|
echo 17: ${x//b\/c/e\\/f}
|
||||||
|
echo 18: ${x//b\\/c/e\\/f}
|
||||||
|
echo 19: ${x/b\/*\/c/x}
|
||||||
|
echo 20: ${x/\//.}
|
||||||
|
echo 21: ${x//\//.}
|
||||||
|
echo 22: ${x///.}
|
||||||
|
echo 23: ${x//#1/9}
|
||||||
|
echo 24: ${x//%1/9}
|
||||||
|
echo 25: ${x//\%1/9}
|
||||||
|
# echo 26: ${x//\%1/9}
|
||||||
|
expected-stdout:
|
||||||
|
1: 122321_ab/cde_b/c_1221
|
||||||
|
2: 131_ab/cde_b/c_11
|
||||||
|
3: 1321_ab/cde_b/c_1221
|
||||||
|
4: 131_ab/cde_b/c_11
|
||||||
|
5: 1422321_ab/cde_b/c_1221
|
||||||
|
6: 1444341_ab/cde_b/c_1441
|
||||||
|
7: 14321_ab/cde_b/c_1221
|
||||||
|
8: 14341_ab/cde_b/c_141
|
||||||
|
9: 1222321_ac/e/f/cde_b/c_1221
|
||||||
|
10: 1222321_ae/fde_b/c_1221
|
||||||
|
11: 1222321_ae/fde_b/c_1221
|
||||||
|
12: 1222321_ae\/fde_b/c_1221
|
||||||
|
13: 1222321_ab/cde_b/c_1221
|
||||||
|
14: 1222321_ac/e/f/cde_c/e/f/c_1221
|
||||||
|
15: 1222321_ae/fde_e/f_1221
|
||||||
|
16: 1222321_ae/fde_e/f_1221
|
||||||
|
17: 1222321_ae\/fde_e\/f_1221
|
||||||
|
18: 1222321_ab/cde_b/c_1221
|
||||||
|
19: 1222321_ax_1221
|
||||||
|
20: 1222321_ab.cde_b/c_1221
|
||||||
|
21: 1222321_ab.cde_b.c_1221
|
||||||
|
22: 1222321_ab/cde_b/c_1221
|
||||||
|
23: 9222321_ab/cde_b/c_1221
|
||||||
|
24: 1222321_ab/cde_b/c_1229
|
||||||
|
25: 1222321_ab/cde_b/c_1229
|
||||||
|
# 26: 1222321_ab/cde_b/c_1221
|
||||||
|
---
|
||||||
name: glob-bad-1
|
name: glob-bad-1
|
||||||
description:
|
description:
|
||||||
Check that globbing isn't done when glob has syntax error
|
Check that globbing isn't done when glob has syntax error
|
||||||
@ -3231,7 +3290,7 @@ expected-stdout:
|
|||||||
---
|
---
|
||||||
name: regression-52
|
name: regression-52
|
||||||
description:
|
description:
|
||||||
Check that globing works in pipelined commands
|
Check that globbing works in pipelined commands
|
||||||
file-setup: file 644 "env"
|
file-setup: file 644 "env"
|
||||||
PS1=P
|
PS1=P
|
||||||
file-setup: file 644 "abc"
|
file-setup: file 644 "abc"
|
||||||
|
102
eval.c
102
eval.c
@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include "sh.h"
|
#include "sh.h"
|
||||||
|
|
||||||
__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.37 2008/02/27 01:00:09 tg Exp $");
|
__RCSID("$MirOS: src/bin/mksh/eval.c,v 1.38 2008/02/27 11:24:11 tg Exp $");
|
||||||
|
|
||||||
#ifdef MKSH_SMALL
|
#ifdef MKSH_SMALL
|
||||||
#define MKSH_NOPWNAM
|
#define MKSH_NOPWNAM
|
||||||
@ -379,7 +379,7 @@ expand(const char *cp, /* input word */
|
|||||||
f = DOPAT | (f&DONTRUNCOMMAND) |
|
f = DOPAT | (f&DONTRUNCOMMAND) |
|
||||||
DOTEMP_;
|
DOTEMP_;
|
||||||
quote = 0;
|
quote = 0;
|
||||||
sqchar = '/';
|
sqchar = 0x100 | '/';
|
||||||
break;
|
break;
|
||||||
case '=':
|
case '=':
|
||||||
/* Enabling tilde expansion
|
/* Enabling tilde expansion
|
||||||
@ -600,8 +600,16 @@ expand(const char *cp, /* input word */
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (quote && sqchar == c)
|
if (sqchar) {
|
||||||
*dp++ = '\\';
|
/* keep backslash before backslash or sqchar */
|
||||||
|
if (quote || c == '\\')
|
||||||
|
*dp++ = '\\';
|
||||||
|
if (sqchar & 0x100 && (quote || (sqchar & 0xFF) != c)) {
|
||||||
|
/* beginning of string, ign. leading sqchars */
|
||||||
|
sqchar &= 0xFF;
|
||||||
|
} else if ((sqchar & 0xFF) == c && !quote)
|
||||||
|
sqchar = 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* check for end of word or IFS separation */
|
/* check for end of word or IFS separation */
|
||||||
if (c == 0 || (!quote && (f & DOBLANK) && doblank &&
|
if (c == 0 || (!quote && (f & DOBLANK) && doblank &&
|
||||||
@ -1004,51 +1012,76 @@ trimsub(char *str, char *pat, int how)
|
|||||||
case '/': /* replace once - SLOW! */
|
case '/': /* replace once - SLOW! */
|
||||||
case '/'|0x80: /* replace all - SLOWER! */
|
case '/'|0x80: /* replace all - SLOWER! */
|
||||||
{
|
{
|
||||||
char *rpat, *rrep, *tpat1, *tpat2, *sbeg, *s, *d;
|
char *rpat, *rrep, *tpat1, *tpat2, *tpat0, *sbeg, *s, *d;
|
||||||
bool gotmatch = false;
|
bool gotmatch = false;
|
||||||
|
|
||||||
sbeg = s = str;
|
|
||||||
/* separate search pattern and replacement string */
|
/* separate search pattern and replacement string */
|
||||||
p = d = rpat = str_save(pat, ATEMP);
|
s = d = rpat = str_save(pat, ATEMP);
|
||||||
while (*p)
|
while ((c = *s++))
|
||||||
if (*p == '\\') {
|
if (c == '\\') {
|
||||||
p++;
|
if (!(*d++ = *s++))
|
||||||
if (*p)
|
break;
|
||||||
p++;
|
} else if (c == '/') {
|
||||||
} else if (*p == '/') {
|
*d++ = '\0';
|
||||||
*p++ = '\0';
|
p = s;
|
||||||
d = p;
|
|
||||||
gotmatch = true;
|
gotmatch = true;
|
||||||
break;
|
break;
|
||||||
} else
|
} else
|
||||||
p++;
|
*d++ = c;
|
||||||
rrep = gotmatch ? d : null;
|
rrep = gotmatch ? p : null;
|
||||||
|
/* do not accept empty pattern */
|
||||||
|
if (!*rpat) {
|
||||||
|
afree(rpat, ATEMP);
|
||||||
|
return (str);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* prepare string on which to work */
|
||||||
|
sbeg = s = str;
|
||||||
|
|
||||||
/* first see if we have any match at all */
|
/* first see if we have any match at all */
|
||||||
tpat1 = shf_smprintf("%c%c%c*%s%c*%c)", MAGIC, '@' | 0x80,
|
tpat0 = rpat;
|
||||||
MAGIC, rpat, MAGIC, MAGIC);
|
if (*rpat == '\\' && (rpat[1] == '#' || rpat[1] == '%'))
|
||||||
tpat2 = shf_smprintf("%c%c%s%c*%c)", MAGIC, '@' | 0x80,
|
tpat0++;
|
||||||
rpat, MAGIC, MAGIC);
|
if (*tpat0 == '#') {
|
||||||
|
/* anchor at the beginning */
|
||||||
|
tpat0++;
|
||||||
|
tpat1 = shf_smprintf("%s%c*", tpat0, MAGIC);
|
||||||
|
tpat2 = tpat1;
|
||||||
|
} else if (*tpat0 == '%') {
|
||||||
|
/* anchor at the end */
|
||||||
|
tpat0++;
|
||||||
|
tpat1 = shf_smprintf("%c*%s", MAGIC, tpat0);
|
||||||
|
tpat2 = tpat0;
|
||||||
|
} else {
|
||||||
|
/* float */
|
||||||
|
tpat1 = shf_smprintf("%c*%s%c*", MAGIC, rpat, MAGIC);
|
||||||
|
tpat2 = tpat1 + 2;
|
||||||
|
}
|
||||||
again_repl:
|
again_repl:
|
||||||
/* this would not be necessary if gmatchx would return
|
/* this would not be necessary if gmatchx would return
|
||||||
* the start and end values of a match found, like re*
|
* the start and end values of a match found, like re*
|
||||||
*/
|
*/
|
||||||
if (!gmatchx(s, tpat1, false))
|
if (!gmatchx(sbeg, tpat1, false))
|
||||||
goto end_repl;
|
goto end_repl;
|
||||||
/* now anchor the beginning of the match */
|
/* now anchor the beginning of the match */
|
||||||
while (sbeg <= end)
|
if (*pat != '#')
|
||||||
if (gmatchx(sbeg, tpat2, false))
|
while (sbeg <= end) {
|
||||||
break;
|
if (gmatchx(sbeg, tpat2, false))
|
||||||
else
|
break;
|
||||||
sbeg++;
|
else
|
||||||
|
sbeg++;
|
||||||
|
}
|
||||||
/* now anchor the end of the match */
|
/* now anchor the end of the match */
|
||||||
for (p = end; p >= sbeg; p--) {
|
p = end;
|
||||||
c = *p; *p = '\0';
|
if (*pat != '%')
|
||||||
gotmatch = gmatchx(sbeg, rpat, false);
|
while (p >= sbeg) {
|
||||||
*p = c;
|
c = *p; *p = '\0';
|
||||||
if (gotmatch)
|
gotmatch = gmatchx(sbeg, tpat0, false);
|
||||||
break;
|
*p = c;
|
||||||
}
|
if (gotmatch)
|
||||||
|
break;
|
||||||
|
p--;
|
||||||
|
}
|
||||||
end = str_nsave(s, sbeg - s, ATEMP);
|
end = str_nsave(s, sbeg - s, ATEMP);
|
||||||
d = shf_smprintf("%s%s%s", end, rrep, p);
|
d = shf_smprintf("%s%s%s", end, rrep, p);
|
||||||
afree(end, ATEMP);
|
afree(end, ATEMP);
|
||||||
@ -1062,7 +1095,6 @@ trimsub(char *str, char *pat, int how)
|
|||||||
end_repl:
|
end_repl:
|
||||||
afree(rpat, ATEMP);
|
afree(rpat, ATEMP);
|
||||||
afree(tpat1, ATEMP);
|
afree(tpat1, ATEMP);
|
||||||
afree(tpat2, ATEMP);
|
|
||||||
return (s);
|
return (s);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
38
mksh.1
38
mksh.1
@ -1,7 +1,7 @@
|
|||||||
.\" $MirOS: src/bin/mksh/mksh.1,v 1.107 2008/02/26 20:43:11 tg Exp $
|
.\" $MirOS: src/bin/mksh/mksh.1,v 1.108 2008/02/27 11:24:12 tg Exp $
|
||||||
.\" $OpenBSD: ksh.1,v 1.120 2007/05/31 20:47:44 otto Exp $
|
.\" $OpenBSD: ksh.1,v 1.120 2007/05/31 20:47:44 otto Exp $
|
||||||
.\"
|
.\"
|
||||||
.Dd February 26, 2008
|
.Dd February 27, 2008
|
||||||
.Dt MKSH 1
|
.Dt MKSH 1
|
||||||
.Os MirBSD
|
.Os MirBSD
|
||||||
.Sh NAME
|
.Sh NAME
|
||||||
@ -1235,6 +1235,40 @@ of them result in the longest match.
|
|||||||
.Xc
|
.Xc
|
||||||
.Sm on
|
.Sm on
|
||||||
Like ${..#..} substitution, but it deletes from the end of the value.
|
Like ${..#..} substitution, but it deletes from the end of the value.
|
||||||
|
.Pp
|
||||||
|
.Sm off
|
||||||
|
.It Xo
|
||||||
|
.Pf ${ Ar name
|
||||||
|
.Pf / Ar pattern / Ar string No }
|
||||||
|
.Xc
|
||||||
|
.It Xo
|
||||||
|
.Pf ${ Ar name
|
||||||
|
.Pf // Ar pattern / Ar string No }
|
||||||
|
.Xc
|
||||||
|
.Sm on
|
||||||
|
Like ${..#..} substitution, but it replaces the longest match of
|
||||||
|
.Ar pattern ,
|
||||||
|
anchored anywhere in the value, with
|
||||||
|
.Ar string .
|
||||||
|
If
|
||||||
|
.Ar pattern
|
||||||
|
begins with
|
||||||
|
.Ql # ,
|
||||||
|
it is anchored at the beginning of the value; if it begins with
|
||||||
|
.Ql % ,
|
||||||
|
it is anchored at the end.
|
||||||
|
A single
|
||||||
|
.Ql /
|
||||||
|
replaces the first occurence of the search
|
||||||
|
.Ar pattern ,
|
||||||
|
and two of them replace all occurences.
|
||||||
|
If
|
||||||
|
.Pf / Ar string
|
||||||
|
is omitted, the
|
||||||
|
.Ar pattern
|
||||||
|
is replaced by the empty string, i.e. deleted.
|
||||||
|
.Pp
|
||||||
|
.Sm off
|
||||||
.It Xo
|
.It Xo
|
||||||
.Pf ${ Ar name : Ns Ar pos
|
.Pf ${ Ar name : Ns Ar pos
|
||||||
.Pf : Ns Ar len Ns }
|
.Pf : Ns Ar len Ns }
|
||||||
|
4
sh.h
4
sh.h
@ -8,8 +8,8 @@
|
|||||||
/* $OpenBSD: c_test.h,v 1.4 2004/12/20 11:34:26 otto Exp $ */
|
/* $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 $ */
|
/* $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.188 2008/02/27 01:00:10 tg Exp $"
|
#define MKSH_SH_H_ID "$MirOS: src/bin/mksh/sh.h,v 1.189 2008/02/27 11:24:12 tg Exp $"
|
||||||
#define MKSH_VERSION "R33 2008/02/26"
|
#define MKSH_VERSION "R33 2008/02/27"
|
||||||
|
|
||||||
#if HAVE_SYS_PARAM_H
|
#if HAVE_SYS_PARAM_H
|
||||||
#include <sys/param.h>
|
#include <sys/param.h>
|
||||||
|
Loading…
x
Reference in New Issue
Block a user