summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org.ua>2017-07-21 15:34:23 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2017-07-21 15:50:53 (GMT)
commit969dab4c1af666d381124fd481821bc936fc94ed (patch) (side-by-side diff)
treeb7bc4b2e75b8cc3f64e240162f3bedff23e9c58b
parent0c0ae29bc7a71fc2cb6d0acf403b1e72715fbe48 (diff)
downloadruncap-969dab4c1af666d381124fd481821bc936fc94ed.tar.gz
runcap-969dab4c1af666d381124fd481821bc936fc94ed.tar.bz2
Fix tell/seek operations
* Makefile (clean): descend into t as well. * t/Makefile (clean): New goal. * runcap.h (runcap_seek): Return off_t. * seek.c (runcap_seek): Change return value. Fix operation. * tell.c (runcap_tell): Bugfix. * t/rt.c: New option -r for testing seek. * t/08seek.t: New testcase. * t/09seek.t: New testcase.
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--Makefile5
-rw-r--r--runcap.h4
-rw-r--r--seek.c10
-rwxr-xr-xt/08seek.t43
-rwxr-xr-xt/09seek.t44
-rw-r--r--t/Makefile11
-rw-r--r--t/rt.c113
-rw-r--r--tell.c1
8 files changed, 218 insertions, 13 deletions
diff --git a/Makefile b/Makefile
index e0a8f06..47bcf17 100644
--- a/Makefile
+++ b/Makefile
@@ -51,9 +51,12 @@ libruncap.a: $(OBJECTS)
ar $(ARFLAGS) libruncap.a $(OBJECTS)
ranlib libruncap.a
-clean:
+clean: subdirs-clean
rm -f libruncap.a $(OBJECTS)
+subdirs-clean:
+ @$(MAKE) -C t clean
+
install: install-lib install-headers install-man
install-lib: libruncap.a
diff --git a/runcap.h b/runcap.h
index 3ed907d..0ece8e7 100644
--- a/runcap.h
+++ b/runcap.h
@@ -90,12 +90,12 @@ runcap_get_capture(struct runcap *rc, int stream)
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);
-int runcap_seek(struct runcap *rc, int stream, off_t off, int whence);
+off_t runcap_seek(struct runcap *rc, int stream, off_t off, int whence);
static inline int
runcap_rewind(struct runcap *rc, int stream)
{
- return runcap_seek(rc, stream, 0, 0);
+ return runcap_seek(rc, stream, 0, 0) != 0;
}
#endif
diff --git a/seek.c b/seek.c
index dfa3d1d..acb42e9 100644
--- a/seek.c
+++ b/seek.c
@@ -19,7 +19,7 @@
#include <errno.h>
#include "runcap.h"
-int
+off_t
runcap_seek(struct runcap *rc, int sd, off_t off, int whence)
{
struct stream_capture *cap;
@@ -32,7 +32,7 @@ runcap_seek(struct runcap *rc, int sd, off_t off, int whence)
cur = runcap_tell(rc, sd);
switch (whence) {
case SEEK_CUR:
- off = cur;
+ off = cur + off;
break;
case SEEK_END:
@@ -52,8 +52,8 @@ runcap_seek(struct runcap *rc, int sd, off_t off, int whence)
return -1;
}
- cur -= cap->sc_level;
-
+ cur -= cap->sc_cur;
+
if (cur <= off && off <= cur + cap->sc_level) {
cap->sc_cur = off - cur;
} else if (cap->sc_storfd != -1) {
@@ -65,7 +65,7 @@ runcap_seek(struct runcap *rc, int sd, off_t off, int whence)
errno = EINVAL;
return -1;
}
- return 0;
+ return off;
}
diff --git a/t/08seek.t b/t/08seek.t
new file mode 100755
index 0000000..c2312bd
--- a/dev/null
+++ b/t/08seek.t
@@ -0,0 +1,43 @@
+#! ./testsuite
+# testsuite for runcap - run program and capture its output
+# Copyright (C) 2017 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/>.
+
+TC_TITLE seek
+
+TC_EXPECT out <<EOT
+res=0
+exit code: 0
+stdout: 71 lines, 4051 bytes
+stderr: 0 lines, 0 bytes
+READ 0:
+ the Rabbit-Hole
+
+Alice was beginning to get very tired of sitting by her sister on the
+bank, and of
+READ 1:
+ on the
+ba
+READ 2:
+nk, and of
+READ 3:
+tten up so
+EOT
+
+rt -r stdout:100:15:0\
+ -r stdout:10:-20:1\
+ -r stdout:10:0:1\
+ -r stdout:10:-20:2\
+ -- genout $testdir/INPUT
diff --git a/t/09seek.t b/t/09seek.t
new file mode 100755
index 0000000..87628f1
--- a/dev/null
+++ b/t/09seek.t
@@ -0,0 +1,44 @@
+#! ./testsuite
+# testsuite for runcap - run program and capture its output
+# Copyright (C) 2017 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/>.
+
+TC_TITLE seek, short buffer
+
+TC_EXPECT out <<EOT
+res=0
+exit code: 0
+stdout: 71 lines, 4051 bytes
+stderr: 0 lines, 0 bytes
+READ 0:
+ the Rabbit-Hole
+
+Alice was beginning to get very tired of sitting by her sister on the
+bank, and of
+READ 1:
+ on the
+ba
+READ 2:
+nk, and of
+READ 3:
+tten up so
+EOT
+
+rt -s 16\
+ -r stdout:100:15:0\
+ -r stdout:10:-20:1\
+ -r stdout:10:0:1\
+ -r stdout:10:-20:2\
+ -- genout $testdir/INPUT
diff --git a/t/Makefile b/t/Makefile
index c24d98e..7a3bb62 100644
--- a/t/Makefile
+++ b/t/Makefile
@@ -14,7 +14,8 @@
# You should have received a copy of the GNU General Public License along
# with Runcap. If not, see <http://www.gnu.org/licenses/>.
-check: genout rt
+TESTPROGS=genout rt
+check: $(TESTPROGS)
@./testsuite
CPPFLAGS=-I..
@@ -37,13 +38,17 @@ TESTSUITE =\
03longout.t\
04stdin.t\
05stdin.t\
- 06mon.t
+ 06mon.t\
+ 08seek.t\
+ 09seek.t
DISTDIR = $(TOPDISTDIR)/t
DISTFILES = Makefile rt.c genout.c $(TESTSUITE) INPUT
-.PHONY: distdir
+.PHONY: distdir clean
distdir:
test -d $(DISTDIR) || mkdir $(DISTDIR)
cp $(DISTFILES) $(DISTDIR)
+clean:
+ rm -rf $(TESTPROGS) testsuite.log testsuite.dir
diff --git a/t/rt.c b/t/rt.c
index 9dbbfa8..12a3232 100644
--- a/t/rt.c
+++ b/t/rt.c
@@ -50,8 +50,13 @@ usage(int code)
fprintf(fp, " -S all|stderr|stdout selects capture for the next -m or -s option\n");
fprintf(fp, " -f FILE reads stdin from FILE\n");
fprintf(fp, " -i inline read (use before -f)\n");
+ 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, " 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, " -s SIZE sets capture size (see -S)\n");
fprintf(fp, " -t SECONDS sets execution timeout\n");
fputc('\n', fp);
@@ -119,6 +124,94 @@ nl(struct runcap *rc, int stream)
printf("%s listing ends\n", what);
}
+struct readreq
+{
+ int what;
+ unsigned long count;
+ long off;
+ int whence;
+};
+
+void
+readreq_parse(struct readreq *req, char *arg)
+{
+ char *s;
+ int i = 0;
+
+ s = strchr(arg, ':');
+ if (s)
+ *s = 0;
+ req->what = whatarg(arg);
+ req->count = 0;
+ req->off = 0;
+ req->whence = 0;
+ if (s)
+ *s++ = ':';
+
+ arg = s;
+ while (*arg) {
+ switch (i++) {
+ case 0:
+ req->count = strtoul(arg, &s, 10);
+ break;
+
+ case 1:
+ 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);
+ }
+ break;
+
+ default:
+ error("too many parts in argument: %s", arg);
+ exit(1);
+ }
+
+ if (*s == ':')
+ arg = s + 1;
+ else if (*s) {
+ error("malformed argument: %s", arg);
+ exit(1);
+ } else
+ arg = s;
+ }
+}
+
+void
+readreq_do(struct runcap *rc, struct readreq *req)
+{
+ int res;
+ size_t i;
+
+ if (runcap_seek(rc, req->what, req->off, req->whence) == -1) {
+ perror("runcap_seek");
+ exit(1);
+ }
+
+ if (req->count == 0)
+ req->count = rc->rc_cap[req->what].sc_size;
+
+ 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);
+ }
+}
+
int
main(int argc, char **argv)
{
@@ -127,6 +220,8 @@ main(int argc, char **argv)
int what = WA_ALL;
int inopt = 0;
int numlines = WA_NONE;
+ struct readreq rq[10];
+ int rqn = 0, i;
int c;
int fd;
@@ -142,7 +237,7 @@ main(int argc, char **argv)
progname++;
else
progname = argv[0];
- while ((c = getopt(argc, argv, "?f:in:mp:S:s:t:")) != EOF) {
+ while ((c = getopt(argc, argv, "?f:in:mp:r:S:s:t:")) != EOF) {
switch (c) {
case 'f':
fd = open(optarg, O_RDONLY);
@@ -200,6 +295,14 @@ main(int argc, char **argv)
case 'n':
numlines = whatarg(optarg);
break;
+ case 'r':
+ /* -r WHAT:N[:OFF:WHENCE] */
+ if (rqn == sizeof(rq)/sizeof(rq[0])) {
+ error("too many read requests");
+ break;
+ }
+ readreq_parse(&rq[rqn++], optarg);
+ break;
case 'm':
if (what & WA_STDOUT) {
rc.rc_cap[RUNCAP_STDOUT].sc_linemon = linemon;
@@ -277,6 +380,12 @@ main(int argc, char **argv)
nl(&rc, RUNCAP_STDOUT);
if (numlines & WA_STDERR)
nl(&rc, RUNCAP_STDERR);
-
+
+ for (i = 0; i < rqn; i++) {
+ printf("READ %d:\n", i);
+ readreq_do(&rc, &rq[i]);
+ putchar('\n');
+ }
+
return 0;
}
diff --git a/tell.c b/tell.c
index d16110c..337e990 100644
--- a/tell.c
+++ b/tell.c
@@ -33,6 +33,7 @@ runcap_tell(struct runcap *rc, int sd)
off = lseek(cap->sc_storfd, 0, SEEK_CUR);
if (off == -1)
return -1;
+ off -= cap->sc_level;
} else
off = 0;

Return to:

Send suggestions and report system problems to the System administrator.