add read with delimiter, like AT&T ksh93 (thanks Dave for the suggestion)

This commit is contained in:
tg 2011-01-21 22:00:17 +00:00
parent 865b267dbf
commit 846fbde3b8
3 changed files with 56 additions and 17 deletions

26
check.t
View File

@ -1,4 +1,4 @@
# $MirOS: src/bin/mksh/check.t,v 1.398 2011/01/09 21:57:22 tg Exp $ # $MirOS: src/bin/mksh/check.t,v 1.399 2011/01/21 22:00:17 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 $
@ -3411,6 +3411,30 @@ stdin:
expected-stdout: expected-stdout:
[abc] [abc]
--- ---
name: read-delim-1
description:
Check read with delimiters
stdin:
emit() {
printf 'foo bar\tbaz\nblah \0blub\tblech\nmyok meck \0'
}
emit | while IFS= read -d "" foo; do print -r -- "<$foo>"; done
emit | while read -d "" foo; do print -r -- "<$foo>"; done
emit | while read -d "eh?" foo; do print -r -- "<$foo>"; done
expected-stdout:
<foo bar baz
blah >
<blub blech
myok meck >
<foo bar baz
blah>
<blub blech
myok meck>
<foo bar baz
blah blub bl>
<ch
myok m>
---
name: regression-1 name: regression-1
description: description:
Lex array code had problems with this. Lex array code had problems with this.

38
funcs.c
View File

@ -26,7 +26,7 @@
#include "sh.h" #include "sh.h"
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.165 2011/01/09 21:57:26 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.166 2011/01/21 22:00:15 tg Exp $");
#if HAVE_KILLPG #if HAVE_KILLPG
/* /*
@ -2020,11 +2020,14 @@ c_read(const char **wp)
struct shf *shf; struct shf *shf;
XString cs, xs = { NULL, NULL, 0, NULL}; XString cs, xs = { NULL, NULL, 0, NULL};
struct tbl *vp; struct tbl *vp;
char *ccp, *xp = NULL, *wpalloc = NULL; char *ccp, *xp = NULL, *wpalloc = NULL, delim = '\n';
static char REPLY[] = "REPLY"; static char REPLY[] = "REPLY";
while ((optc = ksh_getopt(wp, &builtin_opt, "prsu,")) != -1) while ((optc = ksh_getopt(wp, &builtin_opt, "d:prsu,")) != -1)
switch (optc) { switch (optc) {
case 'd':
delim = builtin_opt.optarg[0];
break;
case 'p': case 'p':
if ((fd = coproc_getfd(R_OK, &emsg)) < 0) { if ((fd = coproc_getfd(R_OK, &emsg)) < 0) {
bi_errorf("%s: %s", "-p", emsg); bi_errorf("%s: %s", "-p", emsg);
@ -2053,7 +2056,8 @@ c_read(const char **wp)
if (*wp == NULL) if (*wp == NULL)
*--wp = REPLY; *--wp = REPLY;
/* Since we can't necessarily seek backwards on non-regular files, /*
* Since we can't necessarily seek backwards on non-regular files,
* don't buffer them so we can't read too much. * don't buffer them so we can't read too much.
*/ */
shf = shf_reopen(fd, SHF_RD | SHF_INTERRUPT | can_seek(fd), shl_spare); shf = shf_reopen(fd, SHF_RD | SHF_INTERRUPT | can_seek(fd), shl_spare);
@ -2063,16 +2067,18 @@ c_read(const char **wp)
wpalloc[cp - *wp] = '\0'; wpalloc[cp - *wp] = '\0';
*wp = wpalloc; *wp = wpalloc;
if (isatty(fd)) { if (isatty(fd)) {
/* AT&T ksh says it prints prompt on fd if it's open /*
* AT&T ksh says it prints prompt on fd if it's open
* for writing and is a tty, but it doesn't do it * for writing and is a tty, but it doesn't do it
* (it also doesn't check the interactive flag, * (it also doesn't check the interactive flag,
* as is indicated in the Kornshell book). * as is indicated in the Korn Shell book).
*/ */
shellf("%s", cp+1); shellf("%s", cp + 1);
} }
} }
/* If we are reading from the co-process for the first time, /*
* If we are reading from the co-process for the first time,
* make sure the other side of the pipe is closed first. This allows * make sure the other side of the pipe is closed first. This allows
* the detection of eof. * the detection of eof.
* *
@ -2089,10 +2095,10 @@ c_read(const char **wp)
Xinit(cs, ccp, 128, ATEMP); Xinit(cs, ccp, 128, ATEMP);
for (; *wp != NULL; wp++) { for (; *wp != NULL; wp++) {
for (ccp = Xstring(cs, ccp); ; ) { for (ccp = Xstring(cs, ccp); ; ) {
if (c == '\n' || c == EOF)
break;
while (1) { while (1) {
c = shf_getc(shf); c = shf_getc(shf);
if (c == delim)
break;
if (c == '\0') if (c == '\0')
continue; continue;
if (c == EOF && shf_error(shf) && if (c == EOF && shf_error(shf) &&
@ -2121,7 +2127,8 @@ c_read(const char **wp)
if (c == '\n') { if (c == '\n') {
c = 0; c = 0;
if (Flag(FTALKING_I) && isatty(fd)) { if (Flag(FTALKING_I) && isatty(fd)) {
/* set prompt in case this is /*
* set prompt in case this is
* called from .profile or $ENV * called from .profile or $ENV
*/ */
set_prompt(PS2, NULL); set_prompt(PS2, NULL);
@ -2135,7 +2142,7 @@ c_read(const char **wp)
expanding = true; expanding = true;
continue; continue;
} }
if (c == '\n' || c == EOF) if (c == delim || c == EOF)
break; break;
if (ctype(c, C_IFS)) { if (ctype(c, C_IFS)) {
if (Xlength(cs, ccp) == 0 && ctype(c, C_IFSWS)) if (Xlength(cs, ccp) == 0 && ctype(c, C_IFSWS))
@ -2174,9 +2181,10 @@ c_read(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);
} }
/* if this is the co-process fd, close the file descriptor /*
* (can get eof if and only if all processes are have died, ie, * if this is the co-process fd, close the file descriptor
* coproc.njobs is 0 and the pipe is closed). * (can get eof if and only if all processes are have died,
* i.e. coproc.njobs is 0 and the pipe is closed).
*/ */
if (c == EOF && !ecode) if (c == EOF && !ecode)
coproc_read_close(fd); coproc_read_close(fd);

9
mksh.1
View File

@ -1,4 +1,4 @@
.\" $MirOS: src/bin/mksh/mksh.1,v 1.245 2011/01/21 21:04:45 tg Exp $ .\" $MirOS: src/bin/mksh/mksh.1,v 1.246 2011/01/21 22:00:14 tg Exp $
.\" $OpenBSD: ksh.1,v 1.138 2010/09/20 07:41:17 jmc Exp $ .\" $OpenBSD: ksh.1,v 1.138 2010/09/20 07:41:17 jmc Exp $
.\"- .\"-
.\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, .\" Copyright © 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009,
@ -3568,6 +3568,7 @@ directories to the root directory) is printed.
.Pp .Pp
.It Xo .It Xo
.Ic read .Ic read
.Op Fl d Ar delimiter
.Op Fl prsu Ns Op Ar n .Op Fl prsu Ns Op Ar n
.Op Ar parameter ... .Op Ar parameter ...
.Xc .Xc
@ -3577,6 +3578,12 @@ using the
parameter (see parameter (see
.Sx Substitution .Sx Substitution
above), and assigns each field to the specified parameters. above), and assigns each field to the specified parameters.
Lines are delimited by the first character of
.Ar delimiter ,
.Dv NUL
if empty, if
.Fl d
was used, a newline otherwise.
If there are more parameters than fields, the extra parameters are set to If there are more parameters than fields, the extra parameters are set to
.Dv NULL , .Dv NULL ,
or alternatively, if there are more fields than parameters, the last parameter or alternatively, if there are more fields than parameters, the last parameter