diff options
author | Sergey Poznyakoff <gray@gnu.org.ua> | 2017-07-21 13:25:07 +0300 |
---|---|---|
committer | Sergey Poznyakoff <gray@gnu.org.ua> | 2017-07-21 13:33:04 +0300 |
commit | ec78df167efca7feba360b29700ef052eccf4b69 (patch) | |
tree | 1bcad85c0bc4696c0d87b45faefb9f00daef01cb /capture.c | |
parent | 9565c4d075158f27b5bfd6eab500f0e3f6d8c9ed (diff) | |
download | posixruncapture-ec78df167efca7feba360b29700ef052eccf4b69.tar.gz posixruncapture-ec78df167efca7feba360b29700ef052eccf4b69.tar.bz2 |
Improve constructor calling convention; implement timeout and line monitoring
* Capture.xs: Rewrite constructor to optionally take named arguments.
* Makefile.PL: Remove 'subdirs-test_.*' rules.
* capture.h (capture): New structure. All capture_ functions operate
on it.
* capture.c (capture_new): Change signature. Set line monitoring features
if required.
(capture_DESTROY): Free line buffers and dereference callback references.
* lib/POSIX/Run/Capture.pm: Fix trivial error
(get_lines): New method.
Diffstat (limited to 'capture.c')
-rw-r--r-- | capture.c | 123 |
1 files changed, 103 insertions, 20 deletions
@@ -1,20 +1,64 @@ #include "capture.h" #include <stdlib.h> -struct runcap * -capture_new(AV *av) +static void +call_monitor(SV *cv, const char *ptr, size_t sz) { - struct runcap *rc; + dSP; + + ENTER; + SAVETMPS; + + PUSHMARK(SP); + XPUSHs(sv_2mortal(newSVpv(ptr, sz))); + PUTBACK; + + call_sv(cv, G_DISCARD); + + FREETMPS; + LEAVE; +} + +static void +line_monitor(const char *ptr, size_t sz, void *closure) +{ + struct line_closure *lc = closure; + + if (lc->len || ptr[sz-1] != '\n') { + size_t newsz = lc->len + sz + 1; + + if (newsz > lc->size) { + lc->str = realloc(lc->str, newsz); + if (!lc->str) + croak("Out of memory"); + lc->size = newsz; + } + memcpy(lc->str + lc->len, ptr, sz); + lc->len += sz; + lc->str[lc->len] = 0; + + if (lc->str[lc->len - 1] == '\n') { + call_monitor(lc->cv, lc->str, lc->len); + lc->len = 0; + } + } else + call_monitor(lc->cv, ptr, sz); +} + +struct capture * +capture_new(AV *av, unsigned timeout, SV *cb[2]) +{ + struct capture *cp; I32 i, n; char **argv; - - rc = malloc(sizeof *rc); - if (!rc) + + cp = malloc(sizeof *cp); + if (!cp) goto nomem; - memset(rc, 0, sizeof *rc); + memset(cp, 0, sizeof *cp); n = av_len(av); if (n == -1) - return rc; + return cp; argv = calloc(n + 2, sizeof *argv); if (!argv) goto nomem; @@ -31,30 +75,60 @@ capture_new(AV *av) } argv[i] = NULL; - rc->rc_argv = argv; - - return rc; + cp->rc.rc_argv = argv; + + if (timeout) { + cp->rc.rc_timeout = timeout; + cp->flags |= RCF_TIMEOUT; + } + + cp->closure[0].cv = cb[0]; + if (cb[0] != &PL_sv_undef) { + SvREFCNT_inc(cb[0]); + cp->rc.rc_cap[RUNCAP_STDOUT].sc_linemon = line_monitor; + cp->rc.rc_cap[RUNCAP_STDOUT].sc_monarg = &cp->closure[0]; + cp->flags |= RCF_STDOUT_LINEMON; + } + + cp->closure[1].cv = cb[1]; + if (cb[1] != &PL_sv_undef) { + SvREFCNT_inc(cb[1]); + cp->closure[1].cv = cb[1]; + cp->rc.rc_cap[RUNCAP_STDERR].sc_linemon = line_monitor; + cp->rc.rc_cap[RUNCAP_STDERR].sc_monarg = &cp->closure[1]; + cp->flags |= RCF_STDOUT_LINEMON; + } + + return cp; nomem: return NULL; } void -capture_DESTROY(struct runcap *rc) +capture_DESTROY(struct capture *cp) { // printf("DESTROY\n"); - if (rc->rc_argv) { + if (cp->rc.rc_argv) { size_t i; - for (i = 0; rc->rc_argv[i]; i++) { - free(rc->rc_argv[i]); + for (i = 0; cp->rc.rc_argv[i]; i++) { + free(cp->rc.rc_argv[i]); } - free(rc->rc_argv); + free(cp->rc.rc_argv); } - runcap_free(rc); - free(rc); + runcap_free(&cp->rc); + + free(cp->closure[0].str); + if (cp->closure[0].cv != &PL_sv_undef) + SvREFCNT_dec(cp->closure[0].cv); + + free(cp->closure[1].str); + if (cp->closure[1].cv != &PL_sv_undef) + SvREFCNT_dec(cp->closure[1].cv); + free(cp); } char * -capture_next_line(struct runcap *rc, int fd) +capture_next_line(struct capture *cp, int fd) { char *buf = NULL; size_t sz = 0; @@ -63,7 +137,7 @@ capture_next_line(struct runcap *rc, int fd) if (fd != RUNCAP_STDOUT && fd != RUNCAP_STDERR) { croak("invalid stream number: %d", fd); } - n = runcap_getline(rc, fd, &buf, &sz); + n = runcap_getline(&cp->rc, fd, &buf, &sz); if (n == -1) croak("error getting line: %s", strerror(errno)); if (n == 0) @@ -71,6 +145,15 @@ capture_next_line(struct runcap *rc, int fd) return realloc(buf, n + 1); } +int +capture_run(struct capture *cp) +{ + if (!cp->rc.rc_argv) + croak("no command line given"); + + return runcap(&cp->rc, cp->flags); +} + void capture_wd() { |