diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2017-07-21 18:34:23 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2017-07-21 18:50:53 +0300 |
commit | 969dab4c1af666d381124fd481821bc936fc94ed (patch) | |
tree | b7bc4b2e75b8cc3f64e240162f3bedff23e9c58b | |
parent | 0c0ae29bc7a71fc2cb6d0acf403b1e72715fbe48 (diff) | |
download | runcap-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.
-rw-r--r-- | Makefile | 5 | ||||
-rw-r--r-- | runcap.h | 4 | ||||
-rw-r--r-- | seek.c | 10 | ||||
-rwxr-xr-x | t/08seek.t | 43 | ||||
-rwxr-xr-x | t/09seek.t | 44 | ||||
-rw-r--r-- | t/Makefile | 11 | ||||
-rw-r--r-- | t/rt.c | 113 | ||||
-rw-r--r-- | tell.c | 1 |
8 files changed, 218 insertions, 13 deletions
@@ -53,5 +53,8 @@ libruncap.a: $(OBJECTS) -clean: +clean: subdirs-clean rm -f libruncap.a $(OBJECTS) +subdirs-clean: + @$(MAKE) -C t clean + install: install-lib install-headers install-man @@ -92,3 +92,3 @@ 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); @@ -97,3 +97,3 @@ runcap_rewind(struct runcap *rc, int stream) { - return runcap_seek(rc, stream, 0, 0); + return runcap_seek(rc, stream, 0, 0) != 0; } @@ -21,3 +21,3 @@ -int +off_t runcap_seek(struct runcap *rc, int sd, off_t off, int whence) @@ -34,3 +34,3 @@ runcap_seek(struct runcap *rc, int sd, off_t off, int whence) case SEEK_CUR: - off = cur; + off = cur + off; break; @@ -54,4 +54,4 @@ runcap_seek(struct runcap *rc, int sd, off_t off, int whence) - cur -= cap->sc_level; - + cur -= cap->sc_cur; + if (cur <= off && off <= cur + cap->sc_level) { @@ -67,3 +67,3 @@ runcap_seek(struct runcap *rc, int sd, off_t off, int whence) } - return 0; + return off; } diff --git a/t/08seek.t b/t/08seek.t new file mode 100755 index 0000000..c2312bd --- /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 --- /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 @@ -16,3 +16,4 @@ -check: genout rt +TESTPROGS=genout rt +check: $(TESTPROGS) @./testsuite @@ -39,3 +40,5 @@ TESTSUITE =\ 05stdin.t\ - 06mon.t + 06mon.t\ + 08seek.t\ + 09seek.t @@ -44,3 +47,3 @@ DISTDIR = $(TOPDISTDIR)/t DISTFILES = Makefile rt.c genout.c $(TESTSUITE) INPUT -.PHONY: distdir +.PHONY: distdir clean distdir: @@ -49 +52,3 @@ distdir: +clean: + rm -rf $(TESTPROGS) testsuite.log testsuite.dir @@ -52,4 +52,9 @@ usage(int code) 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"); @@ -121,2 +126,90 @@ nl(struct runcap *rc, int stream) +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 @@ -129,2 +222,4 @@ main(int argc, char **argv) int numlines = WA_NONE; + struct readreq rq[10]; + int rqn = 0, i; @@ -144,3 +239,3 @@ main(int argc, char **argv) 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) { @@ -202,2 +297,10 @@ main(int argc, char **argv) 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': @@ -279,3 +382,9 @@ main(int argc, char **argv) nl(&rc, RUNCAP_STDERR); - + + for (i = 0; i < rqn; i++) { + printf("READ %d:\n", i); + readreq_do(&rc, &rq[i]); + putchar('\n'); + } + return 0; @@ -35,2 +35,3 @@ runcap_tell(struct runcap *rc, int sd) return -1; + off -= cap->sc_level; } else |