• use a flag for determining here strings, don’t parse delimiter every time

• don’t leak memory parsing possible I/O redirection tokens
• get rid of volatile by using more const (also helps codegen, methinks)
• support empty here document markers (mksh extension)
• pimp the manpage
This commit is contained in:
tg 2011-05-05 00:05:01 +00:00
parent 4345dd1fb8
commit c021aa4cad
6 changed files with 120 additions and 50 deletions

43
check.t

@ -1,4 +1,4 @@
# $MirOS: src/bin/mksh/check.t,v 1.449 2011/05/04 23:16:00 tg Exp $ # $MirOS: src/bin/mksh/check.t,v 1.450 2011/05/05 00:04:55 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 $
@ -25,7 +25,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 R39 2011/05/02 @(#)MIRBSD KSH R39 2011/05/04
description: description:
Check version of shell. Check version of shell.
stdin: stdin:
@ -2129,6 +2129,45 @@ expected-stdout:
} vf={=f $x @= } vf={=f $x @=
} | } |
--- ---
name: heredoc-11
description:
Check here documents with no or empty delimiter
stdin:
x=u
va=<<
=a $x \x40=
<<
vb=<<''
=b $x \x40=
function foo {
vc=<<-
=c $x \x40=
<<
vd=<<-''
=d $x \x40=
}
typeset -f foo
foo
print -r -- "| va={$va} vb={$vb} vc={$vc} vd={$vd} |"
expected-stdout:
function foo {
vc= <<-
=c $x \x40=
<<
vd= <<-""
=d $x \x40=
}
| va={=a u \x40=
} vb={=b $x \x40=
} vc={=c u \x40=
} vd={=d $x \x40=
} |
---
name: heredoc-comsub-1 name: heredoc-comsub-1
description: description:
Tests for here documents in COMSUB, taken from Austin ML Tests for here documents in COMSUB, taken from Austin ML

23
lex.c

@ -22,7 +22,7 @@
#include "sh.h" #include "sh.h"
__RCSID("$MirOS: src/bin/mksh/lex.c,v 1.147 2011/05/02 22:52:51 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/lex.c,v 1.148 2011/05/05 00:04:57 tg Exp $");
/* /*
* states while lexing word * states while lexing word
@ -980,10 +980,14 @@ yylex(int cf)
iop->flag |= c == c2 ? iop->flag |= c == c2 ?
(c == '>' ? IOCAT : IOHERE) : IORDWR; (c == '>' ? IOCAT : IOHERE) : IORDWR;
if (iop->flag == IOHERE) { if (iop->flag == IOHERE) {
if ((c2 = getsc()) == '-') if ((c2 = getsc()) == '-') {
iop->flag |= IOSKIP; iop->flag |= IOSKIP;
else c2 = getsc();
} else if (c2 == '<')
iop->flag |= IOHERESTR;
ungetsc(c2); ungetsc(c2);
if (c2 == '\n')
iop->flag |= IONDELIM;
} }
} else if (c2 == '&') } else if (c2 == '&')
iop->flag |= IODUP | (c == '<' ? IORDUP : 0); iop->flag |= IODUP | (c == '<' ? IORDUP : 0);
@ -1003,7 +1007,7 @@ yylex(int cf)
yylval.iop = iop; yylval.iop = iop;
return (REDIR); return (REDIR);
no_iop: no_iop:
; afree(iop, ATEMP);
} }
if (wp == dp && state == SBASE) { if (wp == dp && state == SBASE) {
@ -1142,7 +1146,7 @@ gethere(bool iseof)
struct ioword **p; struct ioword **p;
for (p = heres; p < herep; p++) for (p = heres; p < herep; p++)
if (iseof && (*p)->delim[1] != '<') if (iseof && !((*p)->flag & IOHERESTR))
/* only here strings at EOF */ /* only here strings at EOF */
return; return;
else else
@ -1158,22 +1162,21 @@ static void
readhere(struct ioword *iop) readhere(struct ioword *iop)
{ {
int c; int c;
char *volatile eof; const char *eof, *eofp;
char *eofp;
XString xs; XString xs;
char *xp; char *xp;
int xpos; int xpos;
if (iop->delim[1] == '<') { if (iop->flag & IOHERESTR) {
/* process the here string */ /* process the here string */
xp = iop->heredoc = evalstr(iop->delim, DOBLANK); iop->heredoc = xp = evalstr(iop->delim, DOBLANK);
c = strlen(xp) - 1; c = strlen(xp) - 1;
memmove(xp, xp + 1, c); memmove(xp, xp + 1, c);
xp[c] = '\n'; xp[c] = '\n';
return; return;
} }
eof = evalstr(iop->delim, 0); eof = iop->flag & IONDELIM ? "<<" : evalstr(iop->delim, 0);
if (!(iop->flag & IOEVAL)) if (!(iop->flag & IOEVAL))
ignore_backslash_newline++; ignore_backslash_newline++;

55
mksh.1

@ -1,4 +1,4 @@
.\" $MirOS: src/bin/mksh/mksh.1,v 1.258 2011/05/04 23:16:03 tg Exp $ .\" $MirOS: src/bin/mksh/mksh.1,v 1.259 2011/05/05 00:04:58 tg Exp $
.\" $OpenBSD: ksh.1,v 1.140 2011/04/23 10:14:59 sobrado Exp $ .\" $OpenBSD: ksh.1,v 1.140 2011/04/23 10:14:59 sobrado Exp $
.\"- .\"-
.\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, .\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
@ -72,7 +72,7 @@
.\" with -mandoc, it might implement .Mx itself, but we want to .\" with -mandoc, it might implement .Mx itself, but we want to
.\" use our own definition. And .Dd must come *first*, always. .\" use our own definition. And .Dd must come *first*, always.
.\" .\"
.Dd $Mdocdate: May 4 2011 $ .Dd $Mdocdate: May 5 2011 $
.\" .\"
.\" Check which macro package we use .\" Check which macro package we use
.\" .\"
@ -1461,7 +1461,9 @@ on it; if
.Ar word .Ar word
is not needed, it is not evaluated. is not needed, it is not evaluated.
.Pp .Pp
The following forms of parameter substitution can also be used: The following forms of parameter substitution can also be used (if
.Ar name
is an array, its element #0 will be substituted in a scalar context):
.Pp .Pp
.Bl -tag -width Ds -compact .Bl -tag -width Ds -compact
.It Pf ${# Ns Ar name Ns \&} .It Pf ${# Ns Ar name Ns \&}
@ -1525,6 +1527,8 @@ A single
.Ql # .Ql #
results in the shortest match, and two results in the shortest match, and two
of them result in the longest match. of them result in the longest match.
Cannot be applied to a vector
.Pq ${*} or ${@} or ${array[*]} or ${array[@]} .
.Pp .Pp
.Sm off .Sm off
.It Xo .It Xo
@ -1537,6 +1541,7 @@ 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.
Cannot be applied to a vector.
.Pp .Pp
.Sm off .Sm off
.It Xo .It Xo
@ -1569,6 +1574,8 @@ If
is omitted, the is omitted, the
.Ar pattern .Ar pattern
is replaced by the empty string, i.e. deleted. is replaced by the empty string, i.e. deleted.
Cannot be applied to a vector.
Inefficiently implemented.
.Pp .Pp
.Sm off .Sm off
.It Xo .It Xo
@ -1604,6 +1611,8 @@ are evaluated as arithmetic expressions.
Currently, Currently,
.Ar pos .Ar pos
must start with a space, opening parenthesis or digit to be recognised. must start with a space, opening parenthesis or digit to be recognised.
Cannot be applied to a vector.
.Pp
.It Pf ${ Ns Ar name Ns @#} .It Pf ${ Ns Ar name Ns @#}
The internal hash of the expansion of The internal hash of the expansion of
.Ar name . .Ar name .
@ -1614,12 +1623,15 @@ This is the hash the shell uses internally for its associative arrays.
.Pp .Pp
Note that Note that
.Ar pattern .Ar pattern
may need to be escaped as an extended globbing pattern may need extended globbing pattern
.Pq @(...) , .Pq @(...) ,
with single quotes single
.Pq \&\*(aq...\&\*(aq .Pq \&\*(aq...\&\*(aq
or double quotes or double
.Pq \&"...\&" . .Pq \&"...\&"
quote escaping unless
.Fl o Ic sh
is set.
.Pp .Pp
The following special parameters are implicitly set by the shell and cannot be The following special parameters are implicitly set by the shell and cannot be
set directly using assignments: set directly using assignments:
@ -1692,8 +1704,9 @@ arguments or splitting arguments with spaces.
.El .El
.Pp .Pp
The following parameters are set and/or used by the shell: The following parameters are set and/or used by the shell:
.Bl -tag -width "PIPESTATUS" .Bl -tag -width "KSH_VERSION"
.It Ev _ No (underscore) .It Ev _
.Pq underscore
When an external command is executed by the shell, this parameter is set in the When an external command is executed by the shell, this parameter is set in the
environment of the new process to the path of the executed command. environment of the new process to the path of the executed command.
In interactive use, this parameter is also set in the parent shell to the last In interactive use, this parameter is also set in the parent shell to the last
@ -2217,7 +2230,7 @@ asynchronous commands created when job control is disabled, for which standard
input is initially set to be from input is initially set to be from
.Pa /dev/null , .Pa /dev/null ,
and commands for which any of the following redirections have been specified: and commands for which any of the following redirections have been specified:
.Bl -tag -width Ds .Bl -tag -width XXxxmarker
.It \*(Gt Ar file .It \*(Gt Ar file
Standard output is redirected to Standard output is redirected to
.Ar file . .Ar file .
@ -2283,6 +2296,20 @@ but not for
.Ql \&" . .Ql \&" .
If multiple here documents are used on the same command line, they are saved in If multiple here documents are used on the same command line, they are saved in
order. order.
.Pp
If no
.Ar marker
is given, the here document ends at the next
.Ic \*(Lt\*(Lt
and substitution will be performed.
If
.Ar marker
is only a set of either single
.Dq \*(aq\*(aq
or double
.Sq \&""
quotes with nothing in between, the here document ends at the next empty line
and substitution will not be performed.
.It \*(Lt\*(Lt\- Ar marker .It \*(Lt\*(Lt\- Ar marker
Same as Same as
.Ic \*(Lt\*(Lt , .Ic \*(Lt\*(Lt ,
@ -2373,13 +2400,9 @@ statements, etc.
any redirections must appear at the end. any redirections must appear at the end.
Redirections are processed after Redirections are processed after
pipelines are created and in the order they are given, so the following pipelines are created and in the order they are given, so the following
will print an error with a line number prepended to it, if you have a will print an error with a line number prepended to it:
.Xr cat 1
that supports the
.Fl n
option:
.Pp .Pp
.D1 $ cat /foo/bar 2\*(Gt&1 \*(Gt/dev/null \*(Ba cat \-n .D1 $ cat /foo/bar 2\*(Gt&1 \*(Gt/dev/null \*(Ba pr \-n \-t
.Pp .Pp
File descriptors created by input/output redirections are private to the File descriptors created by input/output redirections are private to the
Korn shell, but passed to sub-processes if Korn shell, but passed to sub-processes if

6
sh.h

@ -151,9 +151,9 @@
#endif #endif
#ifdef EXTERN #ifdef EXTERN
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.467 2011/05/02 22:52:52 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/sh.h,v 1.468 2011/05/05 00:04:59 tg Exp $");
#endif #endif
#define MKSH_VERSION "R39 2011/05/02" #define MKSH_VERSION "R39 2011/05/04"
#ifndef MKSH_INCLUDES_ONLY #ifndef MKSH_INCLUDES_ONLY
@ -1185,6 +1185,8 @@ struct ioword {
#define IORDUP BIT(7) /* x<&y (as opposed to x>&y) */ #define IORDUP BIT(7) /* x<&y (as opposed to x>&y) */
#define IONAMEXP BIT(8) /* name has been expanded */ #define IONAMEXP BIT(8) /* name has been expanded */
#define IOBASH BIT(9) /* &> etc. */ #define IOBASH BIT(9) /* &> etc. */
#define IOHERESTR BIT(10) /* <<< (here string) */
#define IONDELIM BIT(11) /* null delimiter (<<) */
/* execute/exchild flags */ /* execute/exchild flags */
#define XEXEC BIT(0) /* execute without forking */ #define XEXEC BIT(0) /* execute without forking */

5
syn.c

@ -22,7 +22,7 @@
#include "sh.h" #include "sh.h"
__RCSID("$MirOS: src/bin/mksh/syn.c,v 1.62 2011/05/02 22:52:53 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/syn.c,v 1.63 2011/05/05 00:05:01 tg Exp $");
extern short subshell_nesting_level; extern short subshell_nesting_level;
@ -179,12 +179,15 @@ synio(int cf)
return (NULL); return (NULL);
ACCEPT; ACCEPT;
iop = yylval.iop; iop = yylval.iop;
if (iop->flag & IONDELIM)
goto gotnulldelim;
ishere = (iop->flag & IOTYPE) == IOHERE; ishere = (iop->flag & IOTYPE) == IOHERE;
musthave(LWORD, ishere ? HEREDELIM : 0); musthave(LWORD, ishere ? HEREDELIM : 0);
if (ishere) { if (ishere) {
iop->delim = yylval.cp; iop->delim = yylval.cp;
if (*ident != 0) if (*ident != 0)
/* unquoted */ /* unquoted */
gotnulldelim:
iop->flag |= IOEVAL; iop->flag |= IOEVAL;
if (herep > &heres[HERES - 1]) if (herep > &heres[HERES - 1])
yyerror("too many %ss\n", "<<"); yyerror("too many %ss\n", "<<");

8
tree.c

@ -22,7 +22,7 @@
#include "sh.h" #include "sh.h"
__RCSID("$MirOS: src/bin/mksh/tree.c,v 1.46 2011/05/04 22:38:27 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/tree.c,v 1.47 2011/05/05 00:05:01 tg Exp $");
#define INDENT 8 #define INDENT 8
@ -198,12 +198,12 @@ ptree(struct op *t, int indent, struct shf *shf)
struct ioword *iop = *ioact++; struct ioword *iop = *ioact++;
/* heredoc is 0 when tracing (set -x) */ /* heredoc is 0 when tracing (set -x) */
if ((iop->flag & IOTYPE) == IOHERE && iop->heredoc && if ((iop->flag & (IOTYPE | IOHERESTR)) == IOHERE &&
/* iop->delim[1] == '<' means here string */ iop->heredoc) {
(!iop->delim || iop->delim[1] != '<')) {
shf_putc('\n', shf); shf_putc('\n', shf);
shf_puts(iop->heredoc, shf); shf_puts(iop->heredoc, shf);
fptreef(shf, indent, "%s", fptreef(shf, indent, "%s",
iop->flag & IONDELIM ? "<<" :
evalstr(iop->delim, 0)); evalstr(iop->delim, 0));
need_nl = true; need_nl = true;
} }