Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 52 additions & 7 deletions jim-aio.c
Original file line number Diff line number Diff line change
Expand Up @@ -1127,15 +1127,60 @@ static int aio_cmd_copy(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
return JIM_OK;
}

/* Like strstr() but optimised in the case the the needle is of length 1 */
static const char *jim_strstr(const char *haystack, int haylen, const char *needle, int needlen)
{
if (needlen == 1) {
return (const char *)memchr(haystack, needle[0], haylen);
}
return strstr(haystack, needle);
}

static int aio_cmd_gets(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
{
AioFile *af = Jim_CmdPrivData(interp);
Jim_Obj *objPtr = NULL;
int len;
int nb;
unsigned flags = AIO_ONEREAD;
char *nl = NULL;
const char *nl = NULL;
int offset = 0;
long keepnl = 0;
const char *nlstr = "\n";
int nlstrlen = 1;

while (argc >= 2) {
enum {OPT_EOL, OPT_KEEP};
static const char * const options[] = {
"-eol",
"-keep",
NULL
};
int opt;

/* Expect an option here */
if (*Jim_String(argv[0]) != '-') {
return JIM_USAGE;
}

if (Jim_GetEnum(interp, argv[0], options, &opt, NULL, JIM_ERRMSG | JIM_ENUM_ABBREV) != JIM_OK) {
return JIM_ERR;
}

switch (opt) {
case OPT_EOL:
nlstr = Jim_GetString(argv[1], &nlstrlen);
break;

case OPT_KEEP:
if (Jim_GetLong(interp, argv[1], &keepnl) != JIM_OK) {
return JIM_ERR;
}
break;
}
argc -= 2;
argv += 2;
}

errno = 0;

Expand All @@ -1148,12 +1193,12 @@ static int aio_cmd_gets(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
while (!aio_eof(af)) {
if (af->readbuf) {
const char *pt = Jim_GetString(af->readbuf, &len);
nl = memchr(pt + offset, '\n', len - offset);
nl = jim_strstr(pt + offset, len - offset, nlstr, nlstrlen);
if (nl) {
/* got a line */
objPtr = Jim_NewStringObj(interp, pt, nl - pt);
/* And consume it plus the newline */
aio_consume(af->readbuf, nl - pt + 1);
objPtr = Jim_NewStringObj(interp, pt, nl - pt + (keepnl ? nlstrlen : 0));
/* And consume it plus the eol */
aio_consume(af->readbuf, nl - pt + nlstrlen);
break;
}
offset = len;
Expand Down Expand Up @@ -2169,10 +2214,10 @@ static const jim_subcmd_type aio_command_table[] = {
/* Description: Internal command to return the taint of the channel. */
},
{ "gets",
"?var?",
"?-eol <str>? ?-keep 0|1? ?var?",
aio_cmd_gets,
0,
1,
-1,
/* Description: Read one line and return it or store it in the var */
},
{ "puts",
Expand Down
15 changes: 12 additions & 3 deletions jim_tcl.txt
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ Changes since 0.83
#. New `info usage` to return the usage for a proc or native command
#. New `info aliases` to list all aliases
#. `expr` supports new +'=*'+ and +'=~'+ matching operators (see <<_expressions,EXPRESSIONS>>)
#. `aio gets` supports +*-eol*+ and +*-keep*+

Changes between 0.82 and 0.83
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down Expand Up @@ -5163,9 +5164,9 @@ aio
to flush the remaining data. As long as the eventloop runs (`vwait`, `update`), the write
data will be automatically flushed.

+$handle *gets* '?varName?'+::
Read one line from the cannel and return it or store it in the
var A terminating newline character is discarded. If +'varName'+
+$handle *gets* ?*-eol* 'str'? ?*-keep 0|1*? '?varName?'+::
Read one line from the channel and return it or store it in the
variable. A terminating newline character is discarded. If +'varName'+
is specified, then the line is placed in the variable by that name
and the return value is a count of the number of characters read
(not including the newline). If the end of the file is reached
Expand All @@ -5179,6 +5180,14 @@ aio
the file is not a newline character, then `gets` behaves as if there
were an additional newline character at the end of the file.

::
If +*-eol*+ is given, the end of line is considered to be the
given string instead of the newline character. If +*-keep 1*+
is given, the end-of-line string is not discarded and instead
is returned as part of the result (and if the return value is the
character count, it includes the end-of-line string).
The default is +*-keep 0*+.

+$handle *getfd*+::
Returns the underlying file descriptor. On Unix platforms this is a small integer.

Expand Down
96 changes: 84 additions & 12 deletions tests/aio.test
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ $f puts test-data
$f close
# create a test file file with several lines
set f [open copy.in wb]
$f puts line1
$f puts line2
$f puts line3
$f puts line1xy
$f puts line2xy
$f puts line3xy
$f close

set f [open testdata.in rb]
Expand Down Expand Up @@ -94,10 +94,82 @@ test aio-3.2 {copy bad length} -body {

set badvar a

test aio-4.1 {gets invalid var} -body {
test aio-4.1 {gets usage} -body {
$f gets abc def
} -returnCodes error -match glob -result {wrong # args: should be "* gets ?-eol <str>? ?-keep 0|1? ?var?"}

test aio-4.2 {gets invalid option} -body {
$f gets -xyz 3 def
} -returnCodes error -result {bad option "-xyz": must be -eol, or -keep}

test aio-4.3 {gets invalid var} -body {
$f gets badvar(abc)
} -returnCodes error -result {can't set "badvar(abc)": variable isn't array}

test aio-4.4 {gets -eol} -body {
set ff [open copy.in]
set rc [$ff gets -eol y\n buf]
$ff close
list $rc $buf
} -result {6 line1x}

test aio-4.5 {gets -eol} -body {
set ff [open copy.in]
set rc [$ff gets -eol 2xy\n buf]
$ff close
list $rc $buf
} -result {12 {line1xy
line}}

test aio-4.6 {gets -keep} -body {
set ff [open copy.in]
set rc [$ff gets -keep 1 buf]
$ff close
list $rc $buf
} -result {8 {line1xy
}}

test aio-4.7 {gets -eol -keep} -body {
set ff [open copy.in]
set rc [$ff gets -keep 1 -eol 2xy\n buf]
$ff close
list $rc $buf
} -result {16 {line1xy
line2xy
}}

test aio-4.8 {gets -eol no var} -body {
set ff [open copy.in]
set buf [$ff gets -eol xy -keep 1]
$ff close
set buf
} -result line1xy

test aio-4.9 {gets -keep 0 count} -body {
set ff [open copy.in]
set count [$ff gets -keep 0 buf]
$ff close
list $count $buf
} -result {7 line1xy}

test aio-4.10 {gets -keep 1 count} -body {
set ff [open copy.in]
set count [$ff gets -keep 1 buf]
$ff close
list $count $buf
} -result {8 {line1xy
}}

test aio-4.11 {gets -eol multiple calls} -body {
set ff [open copy.in]
set lines {}
lappend lines [$ff gets -eol xy\n]
lappend lines [$ff gets -eol xy\n]
lappend lines [$ff gets -eol xy\n]
$ff close
set lines
} -result {line1 line2 line3}

test aio-5.1 {puts usage} -body {
stdout puts -badopt abc
} -returnCodes error -result {wrong # args: should be "stdout puts ?-nonewline? str"}
Expand Down Expand Up @@ -188,19 +260,19 @@ test copyto-1.1 {basic copyto} {
set result [list [$ff gets] [$ff gets] [$ff gets]]
$ff close
set result
} {line1 line2 line3}
} {line1xy line2xy line3xy}

test copyto-1.2 {copyto with limit} {
set in [open copy.in]
set out [open copy.out w]
$in copyto $out 8
$in copyto $out 10
$in close
$out close
set ff [open copy.out]
set result [list [$ff gets] [$ff gets] [$ff gets]]
$ff close
set result
} {line1 li {}}
} {line1xy li {}}

test copyto-1.3 {copyto after gets} {
set in [open copy.in]
Expand All @@ -213,7 +285,7 @@ test copyto-1.3 {copyto after gets} {
set result [list [$ff gets] [$ff gets] [$ff gets]]
$ff close
set result
} {line2 line3 {}}
} {line2xy line3xy {}}

test copyto-1.4 {copyto after read} {
set in [open copy.in]
Expand All @@ -226,7 +298,7 @@ test copyto-1.4 {copyto after read} {
set result [list [$ff gets] [$ff gets] [$ff gets]]
$ff close
set result
} {e1 line2 line3}
} {e1xy line2xy line3xy}

test copyto-1.5 {copyto after gets, seek} {
set in [open copy.in]
Expand All @@ -240,7 +312,7 @@ test copyto-1.5 {copyto after gets, seek} {
set result [list [$ff gets] [$ff gets] [$ff gets]]
$ff close
set result
} {ne1 line2 line3}
} {ne1xy line2xy line3xy}

test copyto-1.6 {copyto from pipe} {
set in [open "|cat copy.in"]
Expand All @@ -252,7 +324,7 @@ test copyto-1.6 {copyto from pipe} {
set result [list [$ff gets] [$ff gets] [$ff gets]]
$ff close
set result
} {line1 line2 line3}
} {line1xy line2xy line3xy}

test copyto-1.6 {copyto to pipe} {
set out [open "|cat >copy.out" w]
Expand All @@ -264,7 +336,7 @@ test copyto-1.6 {copyto to pipe} {
set result [list [$ff gets] [$ff gets] [$ff gets]]
$ff close
set result
} {line1 line2 line3}
} {line1xy line2xy line3xy}

# Creates a child process and returns {pid writehandle}
# The child expects to read $numlines lines of input and exits with a return
Expand Down