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: 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 $
@ -25,7 +25,7 @@
# http://www.research.att.com/~gsf/public/ifs.sh
expected-stdout:
@(#)MIRBSD KSH R39 2009/10/04
@(#)MIRBSD KSH R39 2009/10/10
description:
Check version of shell.
stdin:
@ -6571,3 +6571,22 @@ stdin:
expected-stdout:
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"
__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
/*
@ -507,31 +507,38 @@ c_print(const char **wp)
#define PO_PMINUSMINUS BIT(2) /* print a -- argument */
#define PO_HIST BIT(3) /* print to history instead of stdout */
#define PO_COPROC BIT(4) /* printing to coprocess: block SIGPIPE */
int fd = 1;
int fd = 1, c;
int flags = PO_EXPAND|PO_NL;
const char *s, *emsg;
XString xs;
char *xp;
if (wp[0][0] == 'e') { /* echo command */
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 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 (wp[0][0] == 'e') {
/* echo builtin */
wp++;
if (Flag(FSH)) {
if (*wp && strcmp(*wp, "-n") == 0) {
flags &= ~PO_NL;
/* Debian Policy 10.4 compliant "echo" builtin */
if (*wp && !strcmp(*wp, "-n")) {
/* we recognise "-n" only as the first arg */
flags = 0;
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)
if (*s == 'n')
@ -546,14 +553,17 @@ c_print(const char **wp)
* nflags, print argument
*/
break;
if (*s)
break;
wp++;
flags = nflags;
}
}
} else {
int optc;
const char *opts = "Rnprsu,";
while ((optc = ksh_getopt(wp, &builtin_opt, opts)) != -1)
switch (optc) {
case 'R': /* fake BSD echo command */
@ -590,6 +600,7 @@ c_print(const char **wp)
case '?':
return (1);
}
if (!(builtin_opt.info & GI_MINUSMINUS)) {
/* treat a lone - like -- */
if (wp[builtin_opt.optind] &&
@ -603,7 +614,6 @@ c_print(const char **wp)
Xinit(xs, xp, 128, ATEMP);
while (*wp != NULL) {
int c;
s = *wp;
while ((c = *s++) != '\0') {
Xcheck(xs, xp);
@ -649,7 +659,7 @@ c_print(const char **wp)
histsave(&source->line, Xstring(xs, xp), true, false);
Xfree(xs, xp);
} else {
int n, len = Xlength(xs, xp);
int len = Xlength(xs, xp);
int opipe = 0;
/* Ensure we aren't killed by a SIGPIPE while writing to
@ -662,8 +672,7 @@ c_print(const char **wp)
opipe = block_pipe();
}
for (s = Xstring(xs, xp); len > 0; ) {
n = write(fd, s, len);
if (n < 0) {
if ((c = write(fd, s, len)) < 0) {
if (flags & PO_COPROC)
restore_pipe(opipe);
if (errno == EINTR) {
@ -675,8 +684,8 @@ c_print(const char **wp)
}
return (1);
}
s += n;
len -= n;
s += c;
len -= c;
}
if (flags & PO_COPROC)
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 $
.\"-
.\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009
@ -48,7 +48,7 @@
.el .xD \\$1 \\$2 \\$3 \\$4 \\$5 \\$6 \\$7 \\$8
..
.\"-
.Dd $Mdocdate: October 2 2009 $
.Dd $Mdocdate: October 10 2009 $
.Dt MKSH 1
.Os MirBSD
.Sh NAME
@ -2694,7 +2694,7 @@ assignments are performed and exported for the duration of the command.
.Pp
The following describes the special and regular built-in commands:
.Pp
.Bl -tag -width Ds -compact
.Bl -tag -width false -compact
.It Ic \&. Ar file Op Ar arg ...
This is called the
.Dq dot
@ -3034,6 +3034,8 @@ If the
option is set, only the first argument is treated as an option, and only
if it is exactly
.Dq Fl n .
Backslash interpretation is disabled.
.Pp
.It Ic eval Ar command ...
The arguments are concatenated (with spaces between them) to form a single
string which the shell then parses and executes in the current environment.

4
sh.h
View File

@ -134,9 +134,9 @@
#endif
#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
#define MKSH_VERSION "R39 2009/10/04"
#define MKSH_VERSION "R39 2009/10/10"
#ifndef MKSH_INCLUDES_ONLY