while testing haserl-0.9.26 on MirBSD, I discovered that the echo builtin

in FSH mode did in fact, contrary to POSIX and Debian Policy 10.4 behavi-
our (I think), interpret escape sequences; fix and add testsuite for echo
This commit is contained in:
tg
2009-10-10 21:17:31 +00:00
parent b4a32ff5f7
commit 549888a183
4 changed files with 62 additions and 32 deletions

23
check.t
View File

@@ -1,4 +1,4 @@
# $MirOS: src/bin/mksh/check.t,v 1.320 2009/10/10 17:39:48 tg Exp $ # $MirOS: src/bin/mksh/check.t,v 1.321 2009/10/10 21:17:28 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 2009/10/04 @(#)MIRBSD KSH R39 2009/10/10
description: description:
Check version of shell. Check version of shell.
stdin: stdin:
@@ -6571,3 +6571,22 @@ stdin:
expected-stdout: expected-stdout:
fxbar 0 fxbar 0
--- ---
name: echo-test-1
description:
Test what the echo builtin does (mksh)
stdin:
echo -n 'foo\x40bar'
echo -e '\tbaz'
expected-stdout:
foo@bar baz
---
name: echo-test-2
description:
Test what the echo builtin does (POSIX)
arguments: !-o!sh!
stdin:
echo -n 'foo\x40bar'
echo -e '\tbaz'
expected-stdout:
foo\x40bar-e \tbaz
---

59
funcs.c
View File

@@ -25,7 +25,7 @@
#include "sh.h" #include "sh.h"
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.136 2009/10/02 18:08:33 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.137 2009/10/10 21:17:29 tg Exp $");
#if HAVE_KILLPG #if HAVE_KILLPG
/* /*
@@ -507,31 +507,38 @@ c_print(const char **wp)
#define PO_PMINUSMINUS BIT(2) /* print a -- argument */ #define PO_PMINUSMINUS BIT(2) /* print a -- argument */
#define PO_HIST BIT(3) /* print to history instead of stdout */ #define PO_HIST BIT(3) /* print to history instead of stdout */
#define PO_COPROC BIT(4) /* printing to coprocess: block SIGPIPE */ #define PO_COPROC BIT(4) /* printing to coprocess: block SIGPIPE */
int fd = 1; int fd = 1, c;
int flags = PO_EXPAND|PO_NL; int flags = PO_EXPAND|PO_NL;
const char *s, *emsg; const char *s, *emsg;
XString xs; XString xs;
char *xp; char *xp;
if (wp[0][0] == 'e') { /* echo command */ if (wp[0][0] == 'e') {
int nflags = flags; /* echo builtin */
wp++;
/* A compromise between sysV and BSD echo commands:
* escape sequences are enabled by default, and
* -n, -e and -E are recognised if they appear
* in arguments with no illegal options (ie, echo -nq
* will print -nq).
* Different from sysV echo since options are recognised,
* different from BSD echo since escape sequences are enabled
* by default.
*/
wp += 1;
if (Flag(FSH)) { if (Flag(FSH)) {
if (*wp && strcmp(*wp, "-n") == 0) { /* Debian Policy 10.4 compliant "echo" builtin */
flags &= ~PO_NL; if (*wp && !strcmp(*wp, "-n")) {
/* we recognise "-n" only as the first arg */
flags = 0;
wp++; wp++;
} } else
} else /* otherwise, we print everything as-is */
flags = PO_NL;
} else {
int nflags = flags;
/**
* a compromise between sysV and BSD echo commands:
* escape sequences are enabled by default, and -n,
* -e and -E are recognised if they appear in argu-
* ments with no illegal options (ie, echo -nq will
* print -nq).
* Different from sysV echo since options are reco-
* gnised, different from BSD echo since escape se-
* quences are enabled by default.
*/
while ((s = *wp) && *s == '-' && s[1]) { while ((s = *wp) && *s == '-' && s[1]) {
while (*++s) while (*++s)
if (*s == 'n') if (*s == 'n')
@@ -546,14 +553,17 @@ c_print(const char **wp)
* nflags, print argument * nflags, print argument
*/ */
break; break;
if (*s) if (*s)
break; break;
wp++; wp++;
flags = nflags; flags = nflags;
} }
}
} else { } else {
int optc; int optc;
const char *opts = "Rnprsu,"; const char *opts = "Rnprsu,";
while ((optc = ksh_getopt(wp, &builtin_opt, opts)) != -1) while ((optc = ksh_getopt(wp, &builtin_opt, opts)) != -1)
switch (optc) { switch (optc) {
case 'R': /* fake BSD echo command */ case 'R': /* fake BSD echo command */
@@ -590,6 +600,7 @@ c_print(const char **wp)
case '?': case '?':
return (1); return (1);
} }
if (!(builtin_opt.info & GI_MINUSMINUS)) { if (!(builtin_opt.info & GI_MINUSMINUS)) {
/* treat a lone - like -- */ /* treat a lone - like -- */
if (wp[builtin_opt.optind] && if (wp[builtin_opt.optind] &&
@@ -603,7 +614,6 @@ c_print(const char **wp)
Xinit(xs, xp, 128, ATEMP); Xinit(xs, xp, 128, ATEMP);
while (*wp != NULL) { while (*wp != NULL) {
int c;
s = *wp; s = *wp;
while ((c = *s++) != '\0') { while ((c = *s++) != '\0') {
Xcheck(xs, xp); Xcheck(xs, xp);
@@ -649,7 +659,7 @@ c_print(const char **wp)
histsave(&source->line, Xstring(xs, xp), true, false); histsave(&source->line, Xstring(xs, xp), true, false);
Xfree(xs, xp); Xfree(xs, xp);
} else { } else {
int n, len = Xlength(xs, xp); int len = Xlength(xs, xp);
int opipe = 0; int opipe = 0;
/* Ensure we aren't killed by a SIGPIPE while writing to /* Ensure we aren't killed by a SIGPIPE while writing to
@@ -662,8 +672,7 @@ c_print(const char **wp)
opipe = block_pipe(); opipe = block_pipe();
} }
for (s = Xstring(xs, xp); len > 0; ) { for (s = Xstring(xs, xp); len > 0; ) {
n = write(fd, s, len); if ((c = write(fd, s, len)) < 0) {
if (n < 0) {
if (flags & PO_COPROC) if (flags & PO_COPROC)
restore_pipe(opipe); restore_pipe(opipe);
if (errno == EINTR) { if (errno == EINTR) {
@@ -675,8 +684,8 @@ c_print(const char **wp)
} }
return (1); return (1);
} }
s += n; s += c;
len -= n; len -= c;
} }
if (flags & PO_COPROC) if (flags & PO_COPROC)
restore_pipe(opipe); restore_pipe(opipe);

8
mksh.1
View File

@@ -1,4 +1,4 @@
.\" $MirOS: src/bin/mksh/mksh.1,v 1.193 2009/10/02 18:08:35 tg Exp $ .\" $MirOS: src/bin/mksh/mksh.1,v 1.194 2009/10/10 21:17:30 tg Exp $
.\" $OpenBSD: ksh.1,v 1.129 2009/05/28 06:09:06 jmc Exp $ .\" $OpenBSD: ksh.1,v 1.129 2009/05/28 06:09:06 jmc Exp $
.\"- .\"-
.\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009 .\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
@@ -48,7 +48,7 @@
.el .xD \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8 .el .xD \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8
.. ..
.\"- .\"-
.Dd $Mdocdate: October 2 2009 $ .Dd $Mdocdate: October 10 2009 $
.Dt MKSH 1 .Dt MKSH 1
.Os MirBSD .Os MirBSD
.Sh NAME .Sh NAME
@@ -2694,7 +2694,7 @@ assignments are performed and exported for the duration of the command.
.Pp .Pp
The following describes the special and regular built-in commands: The following describes the special and regular built-in commands:
.Pp .Pp
.Bl -tag -width Ds -compact .Bl -tag -width false -compact
.It Ic \&. Ar file Op Ar arg ... .It Ic \&. Ar file Op Ar arg ...
This is called the This is called the
.Dq dot .Dq dot
@@ -3034,6 +3034,8 @@ If the
option is set, only the first argument is treated as an option, and only option is set, only the first argument is treated as an option, and only
if it is exactly if it is exactly
.Dq Fl n . .Dq Fl n .
Backslash interpretation is disabled.
.Pp
.It Ic eval Ar command ... .It Ic eval Ar command ...
The arguments are concatenated (with spaces between them) to form a single The arguments are concatenated (with spaces between them) to form a single
string which the shell then parses and executes in the current environment. string which the shell then parses and executes in the current environment.

4
sh.h
View File

@@ -134,9 +134,9 @@
#endif #endif
#ifdef EXTERN #ifdef EXTERN
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.353 2009/10/04 13:19:33 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/sh.h,v 1.354 2009/10/10 21:17:31 tg Exp $");
#endif #endif
#define MKSH_VERSION "R39 2009/10/04" #define MKSH_VERSION "R39 2009/10/10"
#ifndef MKSH_INCLUDES_ONLY #ifndef MKSH_INCLUDES_ONLY