diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2019-08-17 11:14:43 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2019-08-17 11:15:18 +0300 |
commit | 9faece352b572fd65e4579e178c4df8fc0c53c35 (patch) | |
tree | 0630ccb0804719a174de7c95e4e0c6972b3c34ea | |
parent | 12c5eac517cb62728b5525cab25aff245086525c (diff) | |
download | runcap-1.2.tar.gz runcap-1.2.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.am | 3 | ||||
-rw-r--r-- | read.c | 69 | ||||
-rw-r--r-- | runcap.h | 1 | ||||
-rw-r--r-- | t/Makefile.am | 5 | ||||
-rw-r--r-- | t/nocap.at (renamed from t/nocap00.at) | 15 | ||||
-rw-r--r-- | t/nocap.inc | 78 | ||||
-rw-r--r-- | t/nocap01.at | 22 | ||||
-rw-r--r-- | t/read.at | 65 | ||||
-rw-r--r-- | t/rt.c | 92 | ||||
-rw-r--r-- | t/testsuite.at | 4 |
10 files changed, 221 insertions, 133 deletions
@@ -1,3 +1,3 @@ # Main Makefile.am source for runcap -# Copyright (C) 2017 Sergey Poznyakoff +# Copyright (C) 2017-2019 Sergey Poznyakoff # @@ -34,2 +34,3 @@ RUNCAP_SRC = \ getl.c\ + read.c\ runcap.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; +} @@ -89,2 +89,3 @@ runcap_get_capture(struct runcap *rc, int stream) +ssize_t runcap_read(struct runcap *rc, int sd, char *buf, size_t size); int runcap_getc(struct runcap *rc, int stream, char *cp); diff --git a/t/Makefile.am b/t/Makefile.am index 4e44f05..0a16429 100644 --- a/t/Makefile.am +++ b/t/Makefile.am @@ -49,2 +49,3 @@ TESTSUITE_AT = \ pipe.at\ + read.at\ linemon00.at\ @@ -53,5 +54,3 @@ TESTSUITE_AT = \ linemon03.at\ - nocap.inc\ - nocap00.at\ - nocap01.at\ + nocap.at\ seek00.at\ diff --git a/t/nocap00.at b/t/nocap.at index 9323936..45abd6c 100644 --- a/t/nocap00.at +++ b/t/nocap.at @@ -16,6 +16,17 @@ -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 @@ -57,6 +57,7 @@ usage(int code) 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"); @@ -143,2 +144,3 @@ struct readreq int whence; + int full; }; @@ -153,3 +155,3 @@ readreq_parse(struct readreq *req, char *arg) if (s) - *s = 0; + *s++ = 0; req->what = whatarg(arg); @@ -158,5 +160,5 @@ readreq_parse(struct readreq *req, char *arg) req->whence = 0; - if (s) - *s++ = ':'; - + req->full = 0; + if (!s) + return; arg = s; @@ -165,3 +167,6 @@ readreq_parse(struct readreq *req, char *arg) case 0: - req->count = strtoul(arg, &s, 10); + if (*arg == ':') + s = arg; + else + req->count = strtoul(arg, &s, 10); break; @@ -169,3 +174,6 @@ readreq_parse(struct readreq *req, char *arg) case 1: - req->off = strtol(arg, &s, 10); + if (*arg == ':') + s = arg; + else + req->off = strtol(arg, &s, 10); break; @@ -173,6 +181,10 @@ readreq_parse(struct readreq *req, char *arg) 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); + } } @@ -180,2 +192,14 @@ readreq_parse(struct readreq *req, char *arg) + 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: @@ -207,17 +231,35 @@ 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); } @@ -317,3 +359,3 @@ main(int argc, char **argv) case 'r': - /* -r WHAT:N[:OFF:WHENCE] */ + /* -r WHAT:N[:OFF:WHENCE:FULL] */ if (rqn == sizeof(rq)/sizeof(rq[0])) { diff --git a/t/testsuite.at b/t/testsuite.at index 4f4ba29..850ec3c 100644 --- a/t/testsuite.at +++ b/t/testsuite.at @@ -25,4 +25,3 @@ m4_include([stdin.at]) m4_include([pipe.at]) -m4_include([nocap00.at]) -m4_include([nocap01.at]) +m4_include([nocap.at]) m4_include([linemon00.at]) @@ -33,2 +32,3 @@ m4_include([seek00.at]) m4_include([seek01.at]) +m4_include([read.at]) |