aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2019-08-17 11:14:43 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2019-08-17 11:15:18 +0300
commit9faece352b572fd65e4579e178c4df8fc0c53c35 (patch)
tree0630ccb0804719a174de7c95e4e0c6972b3c34ea
parent12c5eac517cb62728b5525cab25aff245086525c (diff)
downloadruncap-9faece352b572fd65e4579e178c4df8fc0c53c35.tar.gz
runcap-9faece352b572fd65e4579e178c4df8fc0c53c35.tar.bz2
Implement runcap_read functionv1.2
* Make.am (RUNCAP_SRC): Add read.c * read.c: New file * runcap.h (runcap_read): New proto. * t/rt: Expand read request to include a flag for selecting * t/read.at: New file. * t/nocap.at: New file * t/nocap00.at: Remove. * t/nocap01.at: Remove. * t/Makefile.am (TESTSUITE_AT): Add new test. Merge two nocap tests to one. * t/testsuite.at: Likewise.
-rw-r--r--Make.am3
-rw-r--r--read.c69
-rw-r--r--runcap.h1
-rw-r--r--t/Makefile.am5
-rw-r--r--t/nocap.at (renamed from t/nocap00.at)15
-rw-r--r--t/nocap.inc78
-rw-r--r--t/nocap01.at22
-rw-r--r--t/read.at65
-rw-r--r--t/rt.c92
-rw-r--r--t/testsuite.at4
10 files changed, 221 insertions, 133 deletions
diff --git a/Make.am b/Make.am
index 7d5f0e6..32c35c9 100644
--- a/Make.am
+++ b/Make.am
@@ -1,5 +1,5 @@
# Main Makefile.am source for runcap
-# Copyright (C) 2017 Sergey Poznyakoff
+# Copyright (C) 2017-2019 Sergey Poznyakoff
#
# Runcap is free software; you can redistribute it and/or modify it
# under the terms of the GNU General Public License as published by the
@@ -32,6 +32,7 @@
RUNCAP_SRC = \
getc.c\
getl.c\
+ read.c\
runcap.c\
seek.c\
tell.c
diff --git a/read.c b/read.c
new file mode 100644
index 0000000..a57d9b9
--- /dev/null
+++ b/read.c
@@ -0,0 +1,69 @@
+/* runcap - run program and capture its output
+ Copyright (C) 2019 Sergey Poznyakoff
+
+ Runcap is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by the
+ Free Software Foundation; either version 3 of the License, or (at your
+ option) any later version.
+
+ Runcap is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License along
+ with Runcap. If not, see <http://www.gnu.org/licenses/>. */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <string.h>
+#include "runcap.h"
+
+ssize_t
+runcap_read(struct runcap *rc, int sd, char *buf, size_t size)
+{
+ struct stream_capture *cap;
+ ssize_t nread = 0;
+
+ if (!buf) {
+ errno = EINVAL;
+ return -1;
+ }
+ if (size == 0)
+ return 0;
+
+ cap = runcap_get_capture(rc, sd);
+ if (!cap)
+ return -1;
+
+ while (size) {
+ size_t avail = cap->sc_level - cap->sc_cur;
+ if (avail == 0) {
+ if (cap->sc_storfd != -1) {
+ ssize_t r = read(cap->sc_storfd,
+ cap->sc_base,
+ cap->sc_size);
+ if (r < 0)
+ return -1;
+ else if (r == 0)
+ break;
+ avail = r;
+ cap->sc_level = r;
+ cap->sc_cur = 0;
+ } else {
+ break;
+ }
+ }
+
+ if (avail > size)
+ avail = size;
+ memcpy(buf + nread, cap->sc_base + cap->sc_cur, avail);
+
+ cap->sc_cur += avail;
+ nread += avail;
+ size -= avail;
+ }
+
+ return nread;
+}
diff --git a/runcap.h b/runcap.h
index efafdf3..94ee2e5 100644
--- a/runcap.h
+++ b/runcap.h
@@ -87,6 +87,7 @@ runcap_get_capture(struct runcap *rc, int stream)
return fp;
}
+ssize_t runcap_read(struct runcap *rc, int sd, char *buf, size_t size);
int runcap_getc(struct runcap *rc, int stream, char *cp);
ssize_t runcap_getline(struct runcap *rc, int stream, char **pstr, size_t *psize);
off_t runcap_tell(struct runcap *rc, int stream);
diff --git a/t/Makefile.am b/t/Makefile.am
index 4e44f05..0a16429 100644
--- a/t/Makefile.am
+++ b/t/Makefile.am
@@ -47,13 +47,12 @@ TESTSUITE_AT = \
longout.at\
stdin.at\
pipe.at\
+ read.at\
linemon00.at\
linemon01.at\
linemon02.at\
linemon03.at\
- nocap.inc\
- nocap00.at\
- nocap01.at\
+ nocap.at\
seek00.at\
seek01.at
# Add more files here
diff --git a/t/nocap00.at b/t/nocap.at
index 9323936..45abd6c 100644
--- a/t/nocap00.at
+++ b/t/nocap.at
@@ -14,9 +14,20 @@
# You should have received a copy of the GNU General Public License along
# with Runcap. If not, see <http://www.gnu.org/licenses/>.
-AT_SETUP([disable capture: size 0])
+AT_SETUP([disable capture])
AT_KEYWORDS([nocap])
-m4_include([nocap.inc])
+# Create expout for the two tests that follow.
+AT_CHECK([cat $INPUT > expout
+cat >> expout <<\EOF
+res=0
+exit code: 0
+stdout: 0 lines, 0 bytes
+stderr: 0 lines, 0 bytes
+EOF
+])
+# Method 1: set buffer size to 0.
AT_CHECK([rt -S stdout -s 0 -- genout $INPUT],[0],[expout])
+# Method 2: use the RCF_STDOUT_NOCAP flag.
+AT_CHECK([rt -S stdout -N -- genout $INPUT],[0],[expout])
AT_CLEANUP
diff --git a/t/nocap.inc b/t/nocap.inc
deleted file mode 100644
index fb1e20c..0000000
--- a/t/nocap.inc
+++ /dev/null
@@ -1,78 +0,0 @@
-AT_DATA([expout],
-[CHAPTER I. Down the Rabbit-Hole
-
-Alice was beginning to get very tired of sitting by her sister on the
-bank, and of having nothing to do: once or twice she had peeped into the
-book her sister was reading, but it had no pictures or conversations
-in it, 'and what is the use of a book,' thought Alice 'without
-pictures or conversations?'
-
-So she was considering in her own mind (as well as she could, for the
-hot day made her feel very sleepy and stupid), whether the pleasure of
-making a daisy-chain would be worth the trouble of getting up and picking
-the daisies, when suddenly a White Rabbit with pink eyes ran close by her.
-
-There was nothing so very remarkable in that; nor did Alice think it
-so very much out of the way to hear the Rabbit say to itself, 'Oh
-dear! Oh dear! I shall be late!' (when she thought it over afterwards,
-it occurred to her that she ought to have wondered at this, but at the
-time it all seemed quite natural); but when the Rabbit actually took a
-watch out of its waistcoat-pocket, and looked at it, and then hurried on,
-Alice started to her feet, for it flashed across her mind that she had
-never before seen a rabbit with either a waistcoat-pocket, or a watch
-to take out of it, and burning with curiosity, she ran across the field
-after it, and fortunately was just in time to see it pop down a large
-rabbit-hole under the hedge.
-
-In another moment down went Alice after it, never once considering how
-in the world she was to get out again.
-
-The rabbit-hole went straight on like a tunnel for some way, and then
-dipped suddenly down, so suddenly that Alice had not a moment to think
-about stopping herself before she found herself falling down a very
-deep well.
-
-Either the well was very deep, or she fell very slowly, for she had plenty
-of time as she went down to look about her and to wonder what was going
-to happen next. First, she tried to look down and make out what she was
-coming to, but it was too dark to see anything; then she looked at the
-sides of the well, and noticed that they were filled with cupboards
-and book-shelves; here and there she saw maps and pictures hung upon
-pegs. She took down a jar from one of the shelves as she passed; it was
-labelled 'ORANGE MARMALADE', but to her great disappointment it was
-empty: she did not like to drop the jar for fear of killing somebody,
-so managed to put it into one of the cupboards as she fell past it.
-
-'Well!' thought Alice to herself, 'after such a fall as this,
-I shall think nothing of tumbling down stairs! How brave they'll all
-think me at home! Why, I wouldn't say anything about it, even if I
-fell off the top of the house!' (Which was very likely true.)
-
-Down, down, down. Would the fall never come to an end! 'I wonder how
-many miles I've fallen by this time?' she said aloud. 'I must be
-getting somewhere near the centre of the earth. Let me see: that would be
-four thousand miles down, I think--' (for, you see, Alice had learnt
-several things of this sort in her lessons in the schoolroom, and though
-this was not a very good opportunity for showing off her knowledge,
-as there was no one to listen to her, still it was good practice to
-say it over) '--yes, that's about the right distance--but then I
-wonder what Latitude or Longitude I've got to?' (Alice had no idea
-what Latitude was, or Longitude either, but thought they were nice grand
-words to say.)
-
-Presently she began again. 'I wonder if I shall fall right through
-the earth! How funny it'll seem to come out among the people that
-walk with their heads downward! The Antipathies, I think--' (she was
-rather glad there was no one listening, this time, as it didn't sound
-at all the right word) '--but I shall have to ask them what the name
-of the country is, you know. Please, Ma'am, is this New Zealand or
-Australia?' (and she tried to curtsey as she spoke--fancy curtseying
-as you're falling through the air! Do you think you could manage
-it?) 'And what an ignorant little girl she'll think me for asking! No,
-it'll never do to ask: perhaps I shall see it written up somewhere.'
-res=0
-exit code: 0
-stdout: 0 lines, 0 bytes
-stderr: 0 lines, 0 bytes
-])
-
diff --git a/t/nocap01.at b/t/nocap01.at
deleted file mode 100644
index 38f6b00..0000000
--- a/t/nocap01.at
+++ /dev/null
@@ -1,22 +0,0 @@
-# Testsuite for runcap - run program and capture its output -*- autotest -*-
-# Copyright (C) 2017-2019 Sergey Poznyakoff
-#
-# Runcap is free software; you can redistribute it and/or modify it
-# under the terms of the GNU General Public License as published by the
-# Free Software Foundation; either version 3 of the License, or (at your
-# option) any later version.
-#
-# Runcap is distributed in the hope that it will be useful,
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-# GNU General Public License for more details.
-#
-# You should have received a copy of the GNU General Public License along
-# with Runcap. If not, see <http://www.gnu.org/licenses/>.
-
-AT_SETUP([disable capture: nocap flag])
-AT_KEYWORDS([nocap])
-m4_include([nocap.inc])
-AT_CHECK([rt -S stdout -N -- genout $INPUT],[0],[expout])
-AT_CLEANUP
-
diff --git a/t/read.at b/t/read.at
new file mode 100644
index 0000000..7484190
--- /dev/null
+++ b/t/read.at
@@ -0,0 +1,65 @@
+# Testcase for runcap - run program and capture its output -*- autotest -*-
+# Copyright (C) 2019 Sergey Poznyakoff
+#
+# Runcap is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published by the
+# Free Software Foundation; either version 3 of the License, or (at your
+# option) any later version.
+#
+# Runcap is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License along
+# with Runcap. If not, see <http://www.gnu.org/licenses/>.
+
+AT_SETUP([runcap_read])
+AT_KEYWORDS([read])
+
+# Prepare expout for the three subsequent tests
+AT_CHECK([
+AT_DATA([expout],
+[res=0
+exit code: 0
+stdout: 71 lines, 4051 bytes
+stderr: 0 lines, 0 bytes
+READ 0:
+])
+cat $INPUT >> expout
+echo "" >> expout
+])
+
+# Test reading on full buffer capacity
+AT_CHECK([rt -r stdout::::t -- genout $INPUT],
+[0],
+[expout])
+
+# Test reading with ridiculously small buffer
+AT_CHECK([rt -s 4 -r stdout::::t -- genout $INPUT],
+[0],
+[expout])
+
+# Test reading with extremely small buffer
+AT_CHECK([rt -s 1 -r stdout::::t -- genout $INPUT],
+[0],
+[expout])
+
+# Test a combination of seeks and reads
+AT_CHECK([rt -s 10 -r stdout:12:5::t -r stdout:80:55::t -r stdout:15:23::t -- genout $INPUT],[0],
+[res=0
+exit code: 0
+stdout: 71 lines, 4051 bytes
+stderr: 0 lines, 0 bytes
+READ 0:
+ER I. Down t
+READ 1:
+ get very tired of sitting by her sister on the
+bank, and of having nothing to d
+READ 2:
+bit-Hole
+
+Alice
+])
+
+AT_CLEANUP
diff --git a/t/rt.c b/t/rt.c
index 65310d7..ec7c088 100644
--- a/t/rt.c
+++ b/t/rt.c
@@ -55,10 +55,11 @@ usage(int code)
fprintf(fp, " -n all|stderr|stdout print lines from the requested capture\n");
fprintf(fp, " -m monitors each line recevied from the program (see -S)\n");
fprintf(fp, " -p PROGNAME sets program name to use instead of COMMAND\n");
- fprintf(fp, " -r STREAM[:COUNT:OFF:WHENCE]\n");
+ fprintf(fp, " -r STREAM[:COUNT:OFF:WHENCE:FULL]\n");
fprintf(fp, " read and print COUNT bytes from STREAM (stdout or\n");
fprintf(fp, " stderr) starting from OFFset located using WHENCE\n");
- fprintf(fp, " (0, 1, 2).\n");
+ fprintf(fp, " (0, 1, 2). Use runcap_getc if FULL is 't' and\n");
+ fprintf(fp, " runcap_read if it is 'f'. Default is MAX:0:0:f.\n");
fprintf(fp, " -s SIZE sets capture size (see -S)\n");
fprintf(fp, " -t SECONDS sets execution timeout\n");
fputc('\n', fp);
@@ -141,6 +142,7 @@ struct readreq
unsigned long count;
long off;
int whence;
+ int full;
};
void
@@ -151,33 +153,55 @@ readreq_parse(struct readreq *req, char *arg)
s = strchr(arg, ':');
if (s)
- *s = 0;
+ *s++ = 0;
req->what = whatarg(arg);
req->count = 0;
req->off = 0;
req->whence = 0;
- if (s)
- *s++ = ':';
-
+ req->full = 0;
+ if (!s)
+ return;
arg = s;
while (*arg) {
switch (i++) {
case 0:
- req->count = strtoul(arg, &s, 10);
+ if (*arg == ':')
+ s = arg;
+ else
+ req->count = strtoul(arg, &s, 10);
break;
case 1:
- req->off = strtol(arg, &s, 10);
+ if (*arg == ':')
+ s = arg;
+ else
+ req->off = strtol(arg, &s, 10);
break;
case 2:
- req->whence = strtol(arg, &s, 10);
- if (!(0 <= req->whence && req->whence <= 2)) {
- error("bad whence: %s", arg);
- exit(1);
+ if (*arg == ':')
+ s = arg;
+ else {
+ req->whence = strtol(arg, &s, 10);
+ if (!(0 <= req->whence && req->whence <= 2)) {
+ error("bad whence: %s", arg);
+ exit(1);
+ }
}
break;
+ case 3:
+ if (*arg == 't')
+ req->full = 1;
+ else if (*arg == 'f')
+ req->full = 0;
+ else {
+ error("bad full: %s", arg);
+ exit(1);
+ }
+ s = arg + 1;
+ break;
+
default:
error("too many parts in argument: %s", arg);
exit(1);
@@ -205,21 +229,39 @@ readreq_do(struct runcap *rc, struct readreq *req)
}
if (req->count == 0)
- req->count = rc->rc_cap[req->what].sc_size;
-
- for (i = 0; i < req->count; i++) {
- char c;
+ req->count = rc->rc_cap[req->what].sc_leng;
+
+ if (req->full) {
+ char *buf = malloc(req->count);
+ ssize_t n;
- res = runcap_getc(rc, req->what, &c);
- if (res == 0) {
- error("unexpected eof at byte %zu\n", i);
- break;
+ if (!buf) {
+ perror("malloc");
+ abort();
}
- if (res == -1) {
- error("%s at byte %zu\n", strerror (errno), i);
- break;
+ n = runcap_read(rc, req->what, buf, req->count);
+ if (n < 0) {
+ perror("runcap_read");
+ exit(1);
+ }
+ if (n > 0)
+ fwrite(buf, n, 1, stdout);
+ free(buf);
+ } else {
+ for (i = 0; i < req->count; i++) {
+ char c;
+
+ res = runcap_getc(rc, req->what, &c);
+ if (res == 0) {
+ error("unexpected eof at byte %zu\n", i);
+ break;
+ }
+ if (res == -1) {
+ error("%s at byte %zu\n", strerror(errno), i);
+ break;
+ }
+ putchar(c);
}
- putchar(c);
}
}
@@ -315,7 +357,7 @@ main(int argc, char **argv)
numlines = whatarg(optarg);
break;
case 'r':
- /* -r WHAT:N[:OFF:WHENCE] */
+ /* -r WHAT:N[:OFF:WHENCE:FULL] */
if (rqn == sizeof(rq)/sizeof(rq[0])) {
error("too many read requests");
break;
diff --git a/t/testsuite.at b/t/testsuite.at
index 4f4ba29..850ec3c 100644
--- a/t/testsuite.at
+++ b/t/testsuite.at
@@ -23,12 +23,12 @@ m4_include([two.at])
m4_include([longout.at])
m4_include([stdin.at])
m4_include([pipe.at])
-m4_include([nocap00.at])
-m4_include([nocap01.at])
+m4_include([nocap.at])
m4_include([linemon00.at])
m4_include([linemon01.at])
m4_include([linemon02.at])
m4_include([linemon03.at])
m4_include([seek00.at])
m4_include([seek01.at])
+m4_include([read.at])

Return to:

Send suggestions and report system problems to the System administrator.