add read with delimiter, like AT&T ksh93 (thanks Dave for the suggestion)
This commit is contained in:
parent
865b267dbf
commit
846fbde3b8
26
check.t
26
check.t
@ -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
38
funcs.c
@ -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
9
mksh.1
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user