From cf87f3c78915f9cbfd900c9c34033cb924f912e7 Mon Sep 17 00:00:00 2001 From: Sergey Poznyakoff Date: Wed, 19 Jul 2017 23:27:00 +0300 Subject: Invokee linemon for partial lines as well --- runcap.3 | 11 ++++++- runcap.c | 20 +++++++++---- t/02two.t | 2 +- t/07mon.t | 101 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ t/rt.c | 28 +++++++++++++---- 5 files changed, 149 insertions(+), 13 deletions(-) create mode 100755 t/07mon.t diff --git a/runcap.3 b/runcap.3 index aa51e4e..3c7161e 100644 --- a/runcap.3 +++ b/runcap.3 @@ -153,13 +153,22 @@ A pointer to the line monitor function. If set, the \fIflags\fR. .sp The line monitor function allows the caller to monitor the arrival of -each input line in the corresponding stream. Its signature is: +the new data in the corresponding stream. Its signature is: .sp .BI "void linemon(const char *" line ", size_t " size ", void *" data ) .sp where \fIline\fR is the line that has been read, \fIsize\fR is its length, and \fIdata\fR is an opaque pointer to application-specific data, supplied in the \fBsc_monarg\fR member. +.sp +The line monitor function is invoked each time a newline character is +encountered in the stream, or when the stream buffer becomes full (and, +therefore is about to be flushed into the storage file) and some +characters remain unreported. This means that, if the +\fBsc_linemon\fR function is designed to log each input line, it +should keep the state of processing (e.g. in the \fIdata\fR argument), +and concatenate the \fIline\fR parameters until +\fBline[size-1] == '\\n'\fR. .TP .B sc_monarg The value of the \fIdata\fR parameter for the \fBsc_linemon\fR diff --git a/runcap.c b/runcap.c index bbe735f..f36d5b1 100644 --- a/runcap.c +++ b/runcap.c @@ -113,6 +113,10 @@ stream_capture_flush(struct stream_capture *cap) if (cap->sc_level == 0) return 0; + if (cap->sc_linemon && cap->sc_cur < cap->sc_level) + cap->sc_linemon(cap->sc_base + cap->sc_cur, + cap->sc_level - cap->sc_cur, + cap->sc_monarg); if (cap->sc_storfd == -1) { int fd; char tmpl[] = "/tmp/rcXXXXXX"; @@ -155,8 +159,8 @@ stream_capture_get(struct stream_capture *cap, int *feof) if (c == '\n') { if (cap->sc_linemon) cap->sc_linemon(cap->sc_base + cap->sc_cur, - cap->sc_level - cap->sc_cur, - cap->sc_monarg); + cap->sc_level - cap->sc_cur, + cap->sc_monarg); cap->sc_cur = cap->sc_level; cap->sc_nlines++; } @@ -439,7 +443,8 @@ runcap_init(struct runcap *rc, int flags) res = stream_capture_alloc(&rc->rc_cap[RUNCAP_STDOUT], rc->rc_cap[RUNCAP_STDOUT].sc_size); else - res = stream_capture_init(&rc->rc_cap[RUNCAP_STDOUT], STRCAP_BUFSIZE); + res = stream_capture_init(&rc->rc_cap[RUNCAP_STDOUT], + STRCAP_BUFSIZE); if (res) return res; @@ -452,7 +457,8 @@ runcap_init(struct runcap *rc, int flags) res = stream_capture_alloc(&rc->rc_cap[RUNCAP_STDERR], rc->rc_cap[RUNCAP_STDERR].sc_size); else - res = stream_capture_init(&rc->rc_cap[RUNCAP_STDERR], STRCAP_BUFSIZE); + res = stream_capture_init(&rc->rc_cap[RUNCAP_STDERR], + STRCAP_BUFSIZE); if (res) return res; @@ -526,7 +532,11 @@ runcap(struct runcap *rc, int flags) lseek(rc->rc_cap[RUNCAP_STDERR].sc_storfd, 0, SEEK_SET); } } - return rc->rc_errno == 0 ? 0 : -1; + if (rc->rc_errno) { + errno = rc->rc_errno; + return -1; + } + return 0; } diff --git a/t/02two.t b/t/02two.t index 5abf3d9..142bbce 100755 --- a/t/02two.t +++ b/t/02two.t @@ -15,7 +15,7 @@ # You should have received a copy of the GNU General Public License along # with Runcap. If not, see . -TC_TITLE capture both stdout and stder +TC_TITLE capture both stdout and stderr TC_EXPECT out <. + +TC_TITLE line monitor, short buffer + +TC_EXPECT out <cont) + fprintf(stdout, "[%s]: ", clos->prefix); + fwrite(ptr, len, 1, stdout); + clos->cont = ptr[len-1] != '\n'; } static void @@ -122,7 +131,12 @@ main(int argc, char **argv) int c; int fd; unsigned long size; - + + static struct linemon_closure cl[] = { + { "stdout" }, + { "stderr" } + }; + progname = strrchr(argv[0], '/'); if (progname) progname++; @@ -189,12 +203,14 @@ main(int argc, char **argv) case 'm': if (what & WA_STDOUT) { rc.rc_cap[RUNCAP_STDOUT].sc_linemon = linemon; - rc.rc_cap[RUNCAP_STDOUT].sc_monarg = "stdout"; + rc.rc_cap[RUNCAP_STDOUT].sc_monarg = + &cl[RUNCAP_STDOUT-1]; rcf |= RCF_STDOUT_LINEMON; } if (what & WA_STDERR) { rc.rc_cap[RUNCAP_STDERR].sc_linemon = linemon; - rc.rc_cap[RUNCAP_STDERR].sc_monarg = "stderr"; + rc.rc_cap[RUNCAP_STDERR].sc_monarg = + &cl[RUNCAP_STDERR-1]; rcf |= RCF_STDERR_LINEMON; } break; -- cgit v1.2.1