summaryrefslogtreecommitdiffabout
authorSergey Poznyakoff <gray@gnu.org.ua>2017-07-18 14:50:34 (GMT)
committer Sergey Poznyakoff <gray@gnu.org.ua>2017-07-18 14:50:34 (GMT)
commit24b9e009c9c2eef1b6d1accb3ac7ccc53c44c0a8 (patch) (side-by-side diff)
treefbd53229d5f87f9a99cbd64a89ac4fb1d06bd7ad
parent3488a182f66e35b091f441b9201ad43ad6d0f1ac (diff)
downloadruncap-24b9e009c9c2eef1b6d1accb3ac7ccc53c44c0a8.tar.gz
runcap-24b9e009c9c2eef1b6d1accb3ac7ccc53c44c0a8.tar.bz2
Add missing API calls, provide testsuite
Diffstat (more/less context) (ignore whitespace changes)
-rw-r--r--.gitignore7
-rw-r--r--Makefile9
-rw-r--r--getc.c54
-rw-r--r--getl.c90
-rw-r--r--runcap.h49
-rw-r--r--seek.c73
-rw-r--r--t/.gitignore4
-rwxr-xr-xt/00simple.t30
-rwxr-xr-xt/01lines.t101
-rwxr-xr-xt/02two.t51
-rwxr-xr-xt/03longout.t101
-rwxr-xr-xt/04stdin.t50
-rwxr-xr-xt/05stdin.t50
-rw-r--r--t/INPUT71
-rw-r--r--t/Makefile28
-rw-r--r--t/genout.c80
-rw-r--r--t/rt.c39
-rwxr-xr-xt/testsuite137
-rw-r--r--tell.c41
19 files changed, 1053 insertions, 12 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..f6aee58
--- a/dev/null
+++ b/.gitignore
@@ -0,0 +1,7 @@
+*.o
+*.a
+*~
+core
+.emacs.*
+.gdbinit
+tmp
diff --git a/Makefile b/Makefile
index b0cec8a..4eb3a1c 100644
--- a/Makefile
+++ b/Makefile
@@ -28,7 +28,7 @@ MKHIER = install -d
# Compiler options
O = -ggdb -Wall
-SOURCES = runcap.c
+SOURCES = runcap.c getc.c getl.c seek.c tell.c
OBJECTS = $(SOURCES:.c=.o)
HEADERS = runcap.h
@@ -38,6 +38,8 @@ ARFLAGS = cru
all: libruncap.a
+$(OBJECTS): $(HEADERS)
+
libruncap.a: $(OBJECTS)
ar $(ARFLAGS) libruncap.a $(OBJECTS)
ranlib libruncap.a
@@ -55,3 +57,8 @@ install-headers: runcap.h
install-man:;
# $(MKHIER) $(DESTDIR)$(MAN2DIR)
# $(INSTALL) runcap.2 $(DESTDIR)$(MAN2DIR)
+
+.PHONY: check
+check:
+ $(MAKE) -C t check
+
diff --git a/getc.c b/getc.c
new file mode 100644
index 0000000..3c203d9
--- a/dev/null
+++ b/getc.c
@@ -0,0 +1,54 @@
+/* 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/>. */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "runcap.h"
+
+int
+runcap_getc(struct runcap *rc, int stream, char *cp)
+{
+ struct filecapture *fp;
+
+ if (!cp) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ fp = runcap_filecapture(rc, stream);
+ if (!fp)
+ return -1;
+
+ if (fp->fc_level == fp->fc_linestart) {
+ if (fp->fc_tmpfd != -1) {
+ ssize_t r = read(fp->fc_tmpfd, fp->fc_base,
+ fp->fc_size);
+ if (r < 0)
+ return -1;
+ else if (r == 0)
+ return 0;
+ fp->fc_level = r;
+ fp->fc_linestart = 0;
+ } else {
+ return 0;
+ }
+ }
+ *cp = fp->fc_base[fp->fc_linestart++];
+ return 1;
+}
+
diff --git a/getl.c b/getl.c
new file mode 100644
index 0000000..d989aa9
--- a/dev/null
+++ b/getl.c
@@ -0,0 +1,90 @@
+/* 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/>. */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "runcap.h"
+
+ssize_t
+runcap_getline(struct runcap *rc, int stream, char **pstr, size_t *psize)
+{
+ struct filecapture *fp;
+ char *str;
+ size_t size;
+ size_t n;
+ char c;
+ int res;
+
+ if (!pstr || !psize) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ str = *pstr;
+ size = *psize;
+
+ fp = runcap_filecapture(rc, stream);
+ if (!fp)
+ return -1;
+
+ if (!str || size == 0) {
+ /* Initial allocation */
+ size = 16;
+ str = malloc(size);
+ if (!str)
+ return -1;
+ *pstr = str;
+ *psize = size;
+ }
+
+ n = 0;
+ while ((res = runcap_getc(rc, stream, &c)) == 1) {
+ if (n == size) {
+ char *p;
+ size_t sz;
+
+ if (size >= (size_t) -1 / 3 * 2) {
+ errno = ENOMEM;
+ return -1;
+ }
+ sz = size + (size + 1) / 2;
+ p = realloc(str, sz);
+ if (!p)
+ return -1;
+ *pstr = str = p;
+ *psize = size = sz;
+ }
+ str[n++] = c;
+ if (c == '\n')
+ break;
+ }
+
+ if (res == -1)
+ return -1;
+
+ if (n == size) {
+ char *p = realloc(str, size + 1);
+ if (!p)
+ return -1;
+ *pstr = str = p;
+ *psize = ++size;
+ }
+ str[n] = 0;
+ return n;
+}
+
diff --git a/runcap.h b/runcap.h
index b677f05..517cd43 100644
--- a/runcap.h
+++ b/runcap.h
@@ -19,16 +19,17 @@
struct filecapture
{
- size_t fc_size;
- size_t fc_leng;
- size_t fc_nlines;
- size_t fc_linestart;
- char * fc_base;
- size_t fc_level;
+ size_t fc_size; /* size of the buffer */
+ off_t fc_leng; /* total length of captured data */
+ size_t fc_nlines; /* number of captured lines */
+ size_t fc_linestart; /* current offset in buffer */
+ char * fc_base; /* buffer space */
+ size_t fc_level; /* number of characters currently in buffer */
void (*fc_linemon) (const char *, size_t, void *);
- void *fc_monarg;
- int fc_tmpfd;
- int fc_fd;
+ /* Line monitor function */
+ void *fc_monarg; /* Line monitor argument */
+ int fc_tmpfd; /* Storage file descriptor */
+ int fc_fd; /* Input descriptor */
};
#define FC_BUFSIZE 4096
@@ -66,4 +67,34 @@ void filecapture_free(struct filecapture *fc);
int runcap(struct runcap *rc, int flags);
void runcap_free(struct runcap *rc);
+static inline struct filecapture *
+runcap_filecapture(struct runcap *rc, int stream)
+{
+ struct filecapture *fp;
+
+ if (stream != RUNCAP_STDOUT && stream != RUNCAP_STDERR) {
+ errno = EINVAL;
+ return NULL;
+ }
+
+ fp = &rc->rc_cap[stream];
+
+ if (!fp->fc_base || fp->fc_size == 0) {
+ errno = EINVAL;
+ return NULL;
+ }
+ return fp;
+}
+
+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);
+
+static inline int
+runcap_rewind(struct runcap *rc, int stream)
+{
+ return runcap_seek(rc, stream, 0, 0);
+}
+
#endif
diff --git a/seek.c b/seek.c
new file mode 100644
index 0000000..5b5b111
--- a/dev/null
+++ b/seek.c
@@ -0,0 +1,73 @@
+/* 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/>. */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include "runcap.h"
+
+int
+runcap_seek(struct runcap *rc, int stream, off_t off, int whence)
+{
+ struct filecapture *fp;
+ off_t cur;
+
+ fp = runcap_filecapture(rc, stream);
+ if (!fp)
+ return -1;
+
+ cur = runcap_tell(rc, stream);
+ switch (whence) {
+ case SEEK_CUR:
+ off = cur;
+ break;
+
+ case SEEK_END:
+ off = fp->fc_leng + off;
+ break;
+
+ case SEEK_SET:
+ break;
+
+ default:
+ errno = EINVAL;
+ return -1;
+ }
+
+ if (off < 0) {
+ errno = EINVAL;
+ return -1;
+ }
+
+ cur -= fp->fc_level;
+
+ if (cur <= off && off <= cur + fp->fc_level) {
+ fp->fc_linestart = off - cur;
+ } else if (fp->fc_tmpfd != -1) {
+ if (lseek(fp->fc_tmpfd, off, SEEK_SET) == -1)
+ return -1;
+ fp->fc_level = 0;
+ fp->fc_linestart = 0;
+ } else {
+ errno = EINVAL;
+ return -1;
+ }
+ return 0;
+}
+
+
+
+
diff --git a/t/.gitignore b/t/.gitignore
new file mode 100644
index 0000000..bb11f3b
--- a/dev/null
+++ b/t/.gitignore
@@ -0,0 +1,4 @@
+/testsuite.dir
+/testsuite.log
+/rt
+/genout
diff --git a/t/00simple.t b/t/00simple.t
new file mode 100755
index 0000000..31a4da2
--- a/dev/null
+++ b/t/00simple.t
@@ -0,0 +1,30 @@
+#! ./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 simple capture
+
+TC_EXPECT out <<EOT
+res=0
+exit code: 0
+stdout: 71 lines, 4051 bytes
+stderr: 0 lines, 0 bytes
+EOT
+
+rt genout $testdir/INPUT
+
+
+
diff --git a/t/01lines.t b/t/01lines.t
new file mode 100755
index 0000000..0d20dcd
--- a/dev/null
+++ b/t/01lines.t
@@ -0,0 +1,101 @@
+#! ./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 read lines
+
+TC_EXPECT out <<EOT
+res=0
+exit code: 0
+stdout: 71 lines, 4051 bytes
+stderr: 0 lines, 0 bytes
+stdout listing:
+ 1: CHAPTER I. Down the Rabbit-Hole
+ 2:
+ 3: Alice was beginning to get very tired of sitting by her sister on the
+ 4: bank, and of having nothing to do: once or twice she had peeped into the
+ 5: book her sister was reading, but it had no pictures or conversations
+ 6: in it, 'and what is the use of a book,' thought Alice 'without
+ 7: pictures or conversations?'
+ 8:
+ 9: So she was considering in her own mind (as well as she could, for the
+ 10: hot day made her feel very sleepy and stupid), whether the pleasure of
+ 11: making a daisy-chain would be worth the trouble of getting up and picking
+ 12: the daisies, when suddenly a White Rabbit with pink eyes ran close by her.
+ 13:
+ 14: There was nothing so very remarkable in that; nor did Alice think it
+ 15: so very much out of the way to hear the Rabbit say to itself, 'Oh
+ 16: dear! Oh dear! I shall be late!' (when she thought it over afterwards,
+ 17: it occurred to her that she ought to have wondered at this, but at the
+ 18: time it all seemed quite natural); but when the Rabbit actually took a
+ 19: watch out of its waistcoat-pocket, and looked at it, and then hurried on,
+ 20: Alice started to her feet, for it flashed across her mind that she had
+ 21: never before seen a rabbit with either a waistcoat-pocket, or a watch
+ 22: to take out of it, and burning with curiosity, she ran across the field
+ 23: after it, and fortunately was just in time to see it pop down a large
+ 24: rabbit-hole under the hedge.
+ 25:
+ 26: In another moment down went Alice after it, never once considering how
+ 27: in the world she was to get out again.
+ 28:
+ 29: The rabbit-hole went straight on like a tunnel for some way, and then
+ 30: dipped suddenly down, so suddenly that Alice had not a moment to think
+ 31: about stopping herself before she found herself falling down a very
+ 32: deep well.
+ 33:
+ 34: Either the well was very deep, or she fell very slowly, for she had plenty
+ 35: of time as she went down to look about her and to wonder what was going
+ 36: to happen next. First, she tried to look down and make out what she was
+ 37: coming to, but it was too dark to see anything; then she looked at the
+ 38: sides of the well, and noticed that they were filled with cupboards
+ 39: and book-shelves; here and there she saw maps and pictures hung upon
+ 40: pegs. She took down a jar from one of the shelves as she passed; it was
+ 41: labelled 'ORANGE MARMALADE', but to her great disappointment it was
+ 42: empty: she did not like to drop the jar for fear of killing somebody,
+ 43: so managed to put it into one of the cupboards as she fell past it.
+ 44:
+ 45: 'Well!' thought Alice to herself, 'after such a fall as this,
+ 46: I shall think nothing of tumbling down stairs! How brave they'll all
+ 47: think me at home! Why, I wouldn't say anything about it, even if I
+ 48: fell off the top of the house!' (Which was very likely true.)
+ 49:
+ 50: Down, down, down. Would the fall never come to an end! 'I wonder how
+ 51: many miles I've fallen by this time?' she said aloud. 'I must be
+ 52: getting somewhere near the centre of the earth. Let me see: that would be
+ 53: four thousand miles down, I think--' (for, you see, Alice had learnt
+ 54: several things of this sort in her lessons in the schoolroom, and though
+ 55: this was not a very good opportunity for showing off her knowledge,
+ 56: as there was no one to listen to her, still it was good practice to
+ 57: say it over) '--yes, that's about the right distance--but then I
+ 58: wonder what Latitude or Longitude I've got to?' (Alice had no idea
+ 59: what Latitude was, or Longitude either, but thought they were nice grand
+ 60: words to say.)
+ 61:
+ 62: Presently she began again. 'I wonder if I shall fall right through
+ 63: the earth! How funny it'll seem to come out among the people that
+ 64: walk with their heads downward! The Antipathies, I think--' (she was
+ 65: rather glad there was no one listening, this time, as it didn't sound
+ 66: at all the right word) '--but I shall have to ask them what the name
+ 67: of the country is, you know. Please, Ma'am, is this New Zealand or
+ 68: Australia?' (and she tried to curtsey as she spoke--fancy curtseying
+ 69: as you're falling through the air! Do you think you could manage
+ 70: it?) 'And what an ignorant little girl she'll think me for asking! No,
+ 71: it'll never do to ask: perhaps I shall see it written up somewhere.'
+stdout listing ends
+EOT
+
+rt -n stdout -- genout $testdir/INPUT
+
diff --git a/t/02two.t b/t/02two.t
new file mode 100755
index 0000000..5abf3d9
--- a/dev/null
+++ b/t/02two.t
@@ -0,0 +1,51 @@
+#! ./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 capture both stdout and stder
+
+TC_EXPECT out <<EOT
+res=0
+exit code: 0
+stdout: 8 lines, 337 bytes
+stderr: 11 lines, 734 bytes
+stdout listing:
+ 1: CHAPTER I. Down the Rabbit-Hole
+ 2:
+ 3: Alice was beginning to get very tired of sitting by her sister on the
+ 4: bank, and of having nothing to do: once or twice she had peeped into the
+ 5: book her sister was reading, but it had no pictures or conversations
+ 6: in it, 'and what is the use of a book,' thought Alice 'without
+ 7: pictures or conversations?'
+ 8:
+stdout listing ends
+stderr listing:
+ 1: There was nothing so very remarkable in that; nor did Alice think it
+ 2: so very much out of the way to hear the Rabbit say to itself, 'Oh
+ 3: dear! Oh dear! I shall be late!' (when she thought it over afterwards,
+ 4: it occurred to her that she ought to have wondered at this, but at the
+ 5: time it all seemed quite natural); but when the Rabbit actually took a
+ 6: watch out of its waistcoat-pocket, and looked at it, and then hurried on,
+ 7: Alice started to her feet, for it flashed across her mind that she had
+ 8: never before seen a rabbit with either a waistcoat-pocket, or a watch
+ 9: to take out of it, and burning with curiosity, she ran across the field
+ 10: after it, and fortunately was just in time to see it pop down a large
+ 11: rabbit-hole under the hedge.
+stderr listing ends
+EOT
+
+rt -n all -- genout -l 337 -o $testdir/INPUT -s 628 -l 734 -e $testdir/INPUT
+
diff --git a/t/03longout.t b/t/03longout.t
new file mode 100755
index 0000000..8204168
--- a/dev/null
+++ b/t/03longout.t
@@ -0,0 +1,101 @@
+#! ./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 file buffered output
+
+TC_EXPECT out <<EOT
+res=0
+exit code: 0
+stdout: 71 lines, 4051 bytes
+stderr: 0 lines, 0 bytes
+stdout listing:
+ 1: CHAPTER I. Down the Rabbit-Hole
+ 2:
+ 3: Alice was beginning to get very tired of sitting by her sister on the
+ 4: bank, and of having nothing to do: once or twice she had peeped into the
+ 5: book her sister was reading, but it had no pictures or conversations
+ 6: in it, 'and what is the use of a book,' thought Alice 'without
+ 7: pictures or conversations?'
+ 8:
+ 9: So she was considering in her own mind (as well as she could, for the
+ 10: hot day made her feel very sleepy and stupid), whether the pleasure of
+ 11: making a daisy-chain would be worth the trouble of getting up and picking
+ 12: the daisies, when suddenly a White Rabbit with pink eyes ran close by her.
+ 13:
+ 14: There was nothing so very remarkable in that; nor did Alice think it
+ 15: so very much out of the way to hear the Rabbit say to itself, 'Oh
+ 16: dear! Oh dear! I shall be late!' (when she thought it over afterwards,
+ 17: it occurred to her that she ought to have wondered at this, but at the
+ 18: time it all seemed quite natural); but when the Rabbit actually took a
+ 19: watch out of its waistcoat-pocket, and looked at it, and then hurried on,
+ 20: Alice started to her feet, for it flashed across her mind that she had
+ 21: never before seen a rabbit with either a waistcoat-pocket, or a watch
+ 22: to take out of it, and burning with curiosity, she ran across the field
+ 23: after it, and fortunately was just in time to see it pop down a large
+ 24: rabbit-hole under the hedge.
+ 25:
+ 26: In another moment down went Alice after it, never once considering how
+ 27: in the world she was to get out again.
+ 28:
+ 29: The rabbit-hole went straight on like a tunnel for some way, and then
+ 30: dipped suddenly down, so suddenly that Alice had not a moment to think
+ 31: about stopping herself before she found herself falling down a very
+ 32: deep well.
+ 33:
+ 34: Either the well was very deep, or she fell very slowly, for she had plenty
+ 35: of time as she went down to look about her and to wonder what was going
+ 36: to happen next. First, she tried to look down and make out what she was
+ 37: coming to, but it was too dark to see anything; then she looked at the
+ 38: sides of the well, and noticed that they were filled with cupboards
+ 39: and book-shelves; here and there she saw maps and pictures hung upon
+ 40: pegs. She took down a jar from one of the shelves as she passed; it was
+ 41: labelled 'ORANGE MARMALADE', but to her great disappointment it was
+ 42: empty: she did not like to drop the jar for fear of killing somebody,
+ 43: so managed to put it into one of the cupboards as she fell past it.
+ 44:
+ 45: 'Well!' thought Alice to herself, 'after such a fall as this,
+ 46: I shall think nothing of tumbling down stairs! How brave they'll all
+ 47: think me at home! Why, I wouldn't say anything about it, even if I
+ 48: fell off the top of the house!' (Which was very likely true.)
+ 49:
+ 50: Down, down, down. Would the fall never come to an end! 'I wonder how
+ 51: many miles I've fallen by this time?' she said aloud. 'I must be
+ 52: getting somewhere near the centre of the earth. Let me see: that would be
+ 53: four thousand miles down, I think--' (for, you see, Alice had learnt
+ 54: several things of this sort in her lessons in the schoolroom, and though
+ 55: this was not a very good opportunity for showing off her knowledge,
+ 56: as there was no one to listen to her, still it was good practice to
+ 57: say it over) '--yes, that's about the right distance--but then I
+ 58: wonder what Latitude or Longitude I've got to?' (Alice had no idea
+ 59: what Latitude was, or Longitude either, but thought they were nice grand
+ 60: words to say.)
+ 61:
+ 62: Presently she began again. 'I wonder if I shall fall right through
+ 63: the earth! How funny it'll seem to come out among the people that
+ 64: walk with their heads downward! The Antipathies, I think--' (she was
+ 65: rather glad there was no one listening, this time, as it didn't sound
+ 66: at all the right word) '--but I shall have to ask them what the name
+ 67: of the country is, you know. Please, Ma'am, is this New Zealand or
+ 68: Australia?' (and she tried to curtsey as she spoke--fancy curtseying
+ 69: as you're falling through the air! Do you think you could manage
+ 70: it?) 'And what an ignorant little girl she'll think me for asking! No,
+ 71: it'll never do to ask: perhaps I shall see it written up somewhere.'
+stdout listing ends
+EOT
+
+rt -s 16 -n stdout -- genout $testdir/INPUT
+
diff --git a/t/04stdin.t b/t/04stdin.t
new file mode 100755
index 0000000..9b05e16
--- a/dev/null
+++ b/t/04stdin.t
@@ -0,0 +1,50 @@
+#! ./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 supply stdin
+
+TC_EXPECT out <<EOT
+res=0
+exit code: 0
+stdout: 8 lines, 337 bytes
+stderr: 11 lines, 734 bytes
+stdout listing:
+ 1: CHAPTER I. Down the Rabbit-Hole
+ 2:
+ 3: Alice was beginning to get very tired of sitting by her sister on the
+ 4: bank, and of having nothing to do: once or twice she had peeped into the
+ 5: book her sister was reading, but it had no pictures or conversations
+ 6: in it, 'and what is the use of a book,' thought Alice 'without
+ 7: pictures or conversations?'
+ 8:
+stdout listing ends
+stderr listing:
+ 1: There was nothing so very remarkable in that; nor did Alice think it
+ 2: so very much out of the way to hear the Rabbit say to itself, 'Oh
+ 3: dear! Oh dear! I shall be late!' (when she thought it over afterwards,
+ 4: it occurred to her that she ought to have wondered at this, but at the
+ 5: time it all seemed quite natural); but when the Rabbit actually took a
+ 6: watch out of its waistcoat-pocket, and looked at it, and then hurried on,
+ 7: Alice started to her feet, for it flashed across her mind that she had
+ 8: never before seen a rabbit with either a waistcoat-pocket, or a watch
+ 9: to take out of it, and burning with curiosity, she ran across the field
+ 10: after it, and fortunately was just in time to see it pop down a large
+ 11: rabbit-hole under the hedge.
+stderr listing ends
+EOT
+
+rt -n all -f $testdir/INPUT -- genout -l 337 -o - -s 628 -l 734 -e $testdir/INPUT
diff --git a/t/05stdin.t b/t/05stdin.t
new file mode 100755
index 0000000..6f9de3d
--- a/dev/null
+++ b/t/05stdin.t
@@ -0,0 +1,50 @@
+#! ./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 pipe stdin
+
+TC_EXPECT out <<EOT
+res=0
+exit code: 0
+stdout: 8 lines, 337 bytes
+stderr: 11 lines, 734 bytes
+stdout listing:
+ 1: CHAPTER I. Down the Rabbit-Hole
+ 2:
+ 3: Alice was beginning to get very tired of sitting by her sister on the
+ 4: bank, and of having nothing to do: once or twice she had peeped into the
+ 5: book her sister was reading, but it had no pictures or conversations
+ 6: in it, 'and what is the use of a book,' thought Alice 'without
+ 7: pictures or conversations?'
+ 8:
+stdout listing ends
+stderr listing:
+ 1: There was nothing so very remarkable in that; nor did Alice think it
+ 2: so very much out of the way to hear the Rabbit say to itself, 'Oh
+ 3: dear! Oh dear! I shall be late!' (when she thought it over afterwards,
+ 4: it occurred to her that she ought to have wondered at this, but at the
+ 5: time it all seemed quite natural); but when the Rabbit actually took a
+ 6: watch out of its waistcoat-pocket, and looked at it, and then hurried on,
+ 7: Alice started to her feet, for it flashed across her mind that she had
+ 8: never before seen a rabbit with either a waistcoat-pocket, or a watch
+ 9: to take out of it, and burning with curiosity, she ran across the field
+ 10: after it, and fortunately was just in time to see it pop down a large
+ 11: rabbit-hole under the hedge.
+stderr listing ends
+EOT
+
+rt -n all -i -f $testdir/INPUT -- genout -l 337 -o - -s 628 -l 734 -e $testdir/INPUT
diff --git a/t/INPUT b/t/INPUT
new file mode 100644
index 0000000..d1113a3
--- a/dev/null
+++ b/t/INPUT
@@ -0,0 +1,71 @@
+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.'
diff --git a/t/Makefile b/t/Makefile
new file mode 100644
index 0000000..a8c8bac
--- a/dev/null
+++ b/t/Makefile
@@ -0,0 +1,28 @@
+# 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/>.
+
+check: genout rt
+ @./testsuite
+
+CPPFLAGS=-I..
+CFLAGS = -ggdb -Wall
+
+VPATH=..
+
+rt: rt.o libruncap.a
+ cc $(CFLAGS) -o$@ $^
+
+genout: genout.o
diff --git a/t/genout.c b/t/genout.c
new file mode 100644
index 0000000..fcfd40b
--- a/dev/null
+++ b/t/genout.c
@@ -0,0 +1,80 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <assert.h>
+
+int skip;
+int length;
+
+static void
+cat(char const *filename, FILE *out)
+{
+ FILE *in;
+ int c;
+
+ if (strcmp (filename, "-") == 0)
+ in = stdin;
+ else {
+ in = fopen(filename, "r");
+ if (!in) {
+ perror(filename);
+ exit(1);
+ }
+ }
+ while ((c = fgetc(in)) != EOF) {
+ if (skip) {
+ skip--;
+ continue;
+ }
+ fputc(c, out);
+ if (length && --length == 0)
+ break;
+ }
+ if (strcmp (filename, "-") == 0 && !feof(in)) {
+ /* drain input */
+ while (fgetc(in) != EOF)
+ ;
+ }
+ fclose(in);
+}
+
+int
+main(int argc, char **argv)
+{
+ if (argc == 1)
+ cat("-", stdout);
+ else {
+ int c;
+ while ((c = getopt(argc, argv, "o:e:w:s:l:")) != EOF) {
+ switch (c) {
+ case 'o':
+ cat(optarg, stdout);
+ break;
+ case 'e':
+ cat(optarg, stderr);
+ break;
+ case 'w':
+ sleep(atoi(optarg));
+ break;
+ case 's':
+ skip = atoi(optarg);
+ assert(skip >= 0);
+ break;
+ case 'l':
+ length = atoi(optarg);
+ assert(length >= 0);
+ break;
+ default:
+ return 1;
+ }
+ }
+ argc -= optind;
+ argv += optind;
+ while (argc--)
+ cat(*argv++, stdout);
+ }
+ return 0;
+}
+
diff --git a/t/rt.c b/t/rt.c
index eecf1d4..a465640 100644
--- a/t/rt.c
+++ b/t/rt.c
@@ -57,6 +57,7 @@ usage(int code)
exit(code);
}
+#define WA_NONE 0
#define WA_STDOUT 0x01
#define WA_STDERR 0x02
#define WA_ALL (WA_STDOUT|WA_STDERR)
@@ -82,6 +83,31 @@ linemon(const char *ptr, size_t len, void *data)
fputc('\n', stdout);
}
+static void
+nl(struct runcap *rc, int stream)
+{
+ int width;
+ size_t n;
+ char *buf = NULL;
+ size_t size = 0;
+ ssize_t res;
+ char const *what = stream == RUNCAP_STDOUT ? "stdout" : "stderr";
+ for (n = rc->rc_cap[stream].fc_nlines, width = 1; n > 0; n /= 10)
+ width++;
+
+ printf("%s listing:\n", what);
+ runcap_rewind(rc, stream);
+ n = 1;
+ while ((res = runcap_getline(rc, stream, &buf, &size)) > 0) {
+ buf[res-1] = 0;
+ printf("% *d: %s\n", width, n, buf);
+ n++;
+ }
+ if (res)
+ error("error getting lines: %s", strerror(errno));
+ printf("%s listing ends\n", what);
+}
+
int
main(int argc, char **argv)
{
@@ -89,7 +115,8 @@ main(int argc, char **argv)
int rcf = 0;
int what = WA_ALL;
int inopt = 0;
-
+ int numlines = WA_NONE;
+
int c;
int fd;
unsigned long size;
@@ -99,7 +126,7 @@ main(int argc, char **argv)
progname++;
else
progname = argv[0];
- while ((c = getopt(argc, argv, "?f:imp:S:s:t:")) != EOF) {
+ while ((c = getopt(argc, argv, "?f:in:mp:S:s:t:")) != EOF) {
switch (c) {
case 'f':
fd = open(optarg, O_RDONLY);
@@ -154,6 +181,9 @@ main(int argc, char **argv)
case 'S':
what = whatarg(optarg);
break;
+ case 'n':
+ numlines = whatarg(optarg);
+ break;
case 'm':
if (what & WA_STDOUT) {
rc.rc_cap[RUNCAP_STDOUT].fc_linemon = linemon;
@@ -224,6 +254,11 @@ main(int argc, char **argv)
printf("stderr: %zu lines, %zu bytes\n",
rc.rc_cap[RUNCAP_STDERR].fc_nlines,
rc.rc_cap[RUNCAP_STDERR].fc_leng);
+
+ if (numlines & WA_STDOUT)
+ nl(&rc, RUNCAP_STDOUT);
+ if (numlines & WA_STDERR)
+ nl(&rc, RUNCAP_STDERR);
return 0;
}
diff --git a/t/testsuite b/t/testsuite
new file mode 100755
index 0000000..84d4c9d
--- a/dev/null
+++ b/t/testsuite
@@ -0,0 +1,137 @@
+#! /bin/sh
+# 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/>.
+
+testdir=$(cd $(dirname $0); pwd)
+progname=$(basename $0)
+
+workdir=$testdir/testsuite.dir
+if [ ! -d $workdir ]; then
+ mkdir $workdir
+fi
+
+cd $testdir
+numfiles=$(ls -1 *.t 2>/dev/null| sed -n '$=')
+
+if [ ${numfiles:-0} -eq 0 ]; then
+ echo >&2 "$progname: no test files in $testdir"
+ exit 2
+fi
+
+printheader() {
+ awk -v P=$numfiles 'NR==1 { num=$1; next }
+ NR==2 { printf("%0d: %s", num, $1); next }
+ { if (NF!=0) printf(" - %s", $0);
+ printf(": "); }' <<EOF
+$1
+$2
+$3
+EOF
+}
+
+PATH=$testdir:$PATH
+
+TC_EXPECT() {
+ cat > exp$1
+}
+TC_TITLE() {
+ :
+}
+
+numtests=0
+numfail=0
+cd $testdir
+exec 3>testsuite.log
+
+if [ $# -gt 0 ]; then
+ testlist=$(ls $*) || exit 1
+else
+ testlist=$(ls *.t)
+fi
+
+for tc in $testlist
+do
+ cd $testdir
+ tc=$(echo $tc|sed 's|\./||')
+ # Skip if invalid name
+ echo "$tc" | grep -q '[^a-zA-Z0-9._-]' && continue
+ # Skip if not executable
+ test -x $tc || continue
+
+ cd $workdir
+
+ dirname=${tc%%.t}
+ if [ -d $dirname ]; then
+ rm -rf $dirname/*
+ else
+ mkdir $dirname || continue
+ fi
+ cd $dirname
+
+ descr=$(sed -n '/TC_TITLE /s///p' ../../$tc)
+ printheader $numtests $tc "$descr"
+ ( . ../../$tc ) >out 2>err
+ retcode=$?
+ numtests=$(( $numtests + 1 ))
+ cd $workdir
+
+ exec 4>templog
+ if [ $retcode -eq 77 ]; then
+ echo "SKIP"
+ continue
+ fi
+ if [ $retcode -ne 0 ]; then
+ echo >&4 "# exit code: $retcode"
+ fi
+
+ test -r $dirname/expout || > $dirname/expout
+ if ! cmp $dirname/expout $dirname/out 2>/dev/null >&2; then
+ echo >&4 "# stdout diff"
+ diff -pu $dirname/expout $dirname/out >&4
+ fi
+ test -r $dirname/experr || > $dirname/experr
+ if ! cmp $dirname/experr $dirname/err 2>/dev/null >&2; then
+ echo >&4 "# stderr diff"
+ diff -pu $dirname/experr $dirname/err >&4
+ fi
+
+ if [ -s templog ]; then
+ echo "FAIL"
+ numfail=$(( $numfail + 1 ))
+ echo >&3 "# Testcase $tc FAILED"
+ cat >&3 templog
+ echo >&3 "# Content:"
+ cat >&3 $testdir/$tc
+ echo >&3 "# stdout:"
+ cat >&3 $dirname/out
+ echo >&3 "# stderr:"
+ cat >&3 $dirname/err
+ else
+ echo "OK"
+ rm -rf $dirname
+ fi
+done
+
+cd $testdir
+
+if [ $numfail -ne 0 ]; then
+ echo >&2 "# $numfail out of $numtests tests failed"
+ echo >&2 "# See testsuite.log for more info"
+ exit 1
+else
+ rmdir $workdir 2>/dev/null
+ rm testsuite.log
+fi
diff --git a/tell.c b/tell.c
new file mode 100644
index 0000000..7044ddd
--- a/dev/null
+++ b/tell.c
@@ -0,0 +1,41 @@
+/* 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/>. */
+
+#include <sys/types.h>
+#include <unistd.h>
+#include <errno.h>
+#include "runcap.h"
+
+off_t
+runcap_tell(struct runcap *rc, int stream)
+{
+ struct filecapture *fp;
+ off_t off;
+
+ fp = runcap_filecapture(rc, stream);
+ if (!fp)
+ return -1;
+
+ if (fp->fc_tmpfd != -1) {
+ off = lseek(fp->fc_tmpfd, 0, SEEK_CUR);
+ if (off == -1)
+ return -1;
+ } else
+ off = 0;
+
+ return off + fp->fc_linestart;
+}
+

Return to:

Send suggestions and report system problems to the System administrator.