diff options
-rw-r--r-- | Capture.xs | 57 | ||||
-rw-r--r-- | capture.c | 125 | ||||
-rw-r--r-- | capture.h | 8 | ||||
-rw-r--r-- | lib/POSIX/Run/Capture.pm | 5 | ||||
m--------- | runcap | 0 | ||||
-rw-r--r-- | typemap | 8 |
6 files changed, 159 insertions, 44 deletions
@@ -19,14 +19,15 @@ POSIX::Run::Capture capture_new(package, ...) char *package; PREINIT: - AV *argv = NULL; + ARGV argv = NULL; unsigned timeout = 0; SV *cb[2] = { &PL_sv_undef, &PL_sv_undef }; + SV *prog = &PL_sv_undef; CODE: if (items == 2) { SV *sv = ST(1); if (SvROK(sv) && SvTYPE(SvRV(sv)) == SVt_PVAV) { - argv = (AV*) SvRV(sv); + argv = XS_unpack_ARGV(sv); } else croak("single argument must be an array ref"); } else if (items % 2 == 0) @@ -44,7 +45,7 @@ capture_new(package, ...) if (strcmp(kw, "argv") == 0) { if (SvROK(val) && SvTYPE(SvRV(val)) == SVt_PVAV) { - argv = (AV*) SvRV(val); + argv = XS_unpack_ARGV(val); } else croak("argv must be an array ref"); } else if (strcmp(kw, "stdout") == 0 @@ -59,15 +60,16 @@ capture_new(package, ...) timeout = SvUV(val); } else croak("timeout must be a number of seconds"); + } else if (strcmp(kw, "program") == 0) { + if (SvROK(val)) + croak("program argument is not a scalar"); + else + prog = val; } else croak("unknown keyword argument %s", kw); } } - if (!argv) - croak("argv not defined"); - RETVAL = capture_new(argv, timeout, cb); - if (!RETVAL) - croak("Out of memory!"); + RETVAL = capture_new(prog, argv, timeout, cb); OUTPUT: RETVAL @@ -75,6 +77,45 @@ void capture_DESTROY(cp) POSIX::Run::Capture cp; +void +capture_set_argv_ref(cp, argv) + POSIX::Run::Capture cp; + ARGV argv; + +void +capture_set_program(cp, prog) + POSIX::Run::Capture cp; + char *prog; + CODE: + if (cp->program != &PL_sv_undef) + SvREFCNT_dec(cp->program); + cp->program = ST(1); + if (cp->program != &PL_sv_undef) { + SvREFCNT_inc(cp->program); + cp->rc.rc_program = prog; + cp->flags |= RCF_PROGRAM; + } else + cp->flags &= ~RCF_PROGRAM; + +ARGV +capture_argv(cp) + POSIX::Run::Capture cp; + CODE: + RETVAL = cp->rc.rc_argv; + OUTPUT: + RETVAL + +void +capture_program(cp) + POSIX::Run::Capture cp; + PPCODE: + if (cp->program == &PL_sv_undef && cp->rc.rc_argv) { + ST(0) = newSVpv(cp->rc.rc_argv[0], 0); + sv_2mortal(ST(0)); + } else + ST(0) = cp->program; + XSRETURN(1); + int capture_run(cp) POSIX::Run::Capture cp; @@ -1,6 +1,12 @@ #include "capture.h" #include <stdlib.h> +static inline void +croak_nomem(void) +{ + croak("Out of memory"); +} + static void call_monitor(SV *cv, const char *ptr, size_t sz) { @@ -30,7 +36,7 @@ line_monitor(const char *ptr, size_t sz, void *closure) if (newsz > lc->size) { lc->str = realloc(lc->str, newsz); if (!lc->str) - croak("Out of memory"); + croak_nomem(); lc->size = newsz; } memcpy(lc->str + lc->len, ptr, sz); @@ -44,41 +50,90 @@ line_monitor(const char *ptr, size_t sz, void *closure) } else call_monitor(lc->cv, ptr, sz); } + +void +XS_pack_ARGV(SV *const sv, ARGV argv) +{ + AV *av = newAV(); + + if (argv) { + int i; + for (i = 0; argv[i]; i++) + av_push(av, newSVpv(argv[i], 0)); + } + sv_setsv(sv, newRV_inc((SV*)av)); +} + +ARGV +XS_unpack_ARGV(SV *sv) +{ + AV *av; + I32 i, n; + char **argv; + if (!sv || !SvOK(sv) || !SvROK(sv) || (SvTYPE(SvRV(sv)) != SVt_PVAV)) + croak ("array reference expected"); + + av = (AV *)SvRV(sv); + + n = av_len(av); + if (n == -1) { + argv = NULL; + } else { + argv = calloc(n + 2, sizeof *argv); + if (!argv) + croak_nomem(); + for (i = 0; i <= n; i++) { + SV *sv, **psv = av_fetch(av, i, 0); + if (!psv) + croak("element %d doesn't exist", i); + sv = *psv; + if (SvROK(sv)) { + croak("argument #%d is not a scalar", i); + } else { + char *s = SvPV_nolen(sv); + if ((argv[i] = strdup(s)) == NULL) + croak_nomem(); + } + } + argv[i] = NULL; + } + return argv; +} + +static void +free_argv(struct capture *cp) +{ + if (cp->rc.rc_argv) { + size_t i; + for (i = 0; cp->rc.rc_argv[i]; i++) { + free(cp->rc.rc_argv[i]); + } + free(cp->rc.rc_argv); + cp->rc.rc_argv = NULL; + } +} + struct capture * -capture_new(AV *av, unsigned timeout, SV *cb[2]) +capture_new(SV *program, ARGV argv, unsigned timeout, SV *cb[2]) { struct capture *cp; I32 i, n; - char **argv; cp = malloc(sizeof *cp); if (!cp) - goto nomem; + croak_nomem(); memset(cp, 0, sizeof *cp); - n = av_len(av); - if (n == -1) - return cp; - argv = calloc(n + 2, sizeof *argv); - if (!argv) - goto nomem; - for (i = 0; i <= n; i++) { - SV *sv, **psv = av_fetch(av, i, 0); - if (!psv) - croak("element %d doesn't exist", i); - sv = *psv; - if (SvROK(sv)) { - croak("argument #%d is not a scalar", i); - } else { - char *s = SvPV_nolen(sv); - if ((argv[i] = strdup(s)) == NULL) - goto nomem; - } - } - argv[i] = NULL; cp->rc.rc_argv = argv; + cp->program = program; + if (program != &PL_sv_undef) { + SvREFCNT_inc(program); + cp->rc.rc_program = SvPV_nolen(program); + cp->flags |= RCF_PROGRAM; + } + if (timeout) { cp->rc.rc_timeout = timeout; cp->flags |= RCF_TIMEOUT; @@ -102,24 +157,19 @@ capture_new(AV *av, unsigned timeout, SV *cb[2]) } return cp; - nomem: - return NULL; } void capture_DESTROY(struct capture *cp) { -// printf("DESTROY\n"); - if (cp->rc.rc_argv) { - size_t i; - for (i = 0; cp->rc.rc_argv[i]; i++) { - free(cp->rc.rc_argv[i]); - } - free(cp->rc.rc_argv); - } + free_argv(cp); runcap_free(&cp->rc); free(cp->closure[0].str); + + if (cp->program != &PL_sv_undef) + SvREFCNT_dec(cp->program); + if (cp->closure[0].cv != &PL_sv_undef) SvREFCNT_dec(cp->closure[0].cv); @@ -129,6 +179,13 @@ capture_DESTROY(struct capture *cp) free(cp); } +void +capture_set_argv_ref(struct capture *cp, ARGV argv) +{ + free_argv(cp); + cp->rc.rc_argv = argv; +} + char * capture_next_line(struct capture *cp, int fd) { @@ -19,11 +19,17 @@ struct capture { struct runcap rc; int flags; struct line_closure closure[2]; + SV *program; }; typedef struct capture *POSIX__Run__Capture; +typedef char** ARGV; -struct capture *capture_new(AV *av, unsigned timeout, SV *cb[2]); +ARGV XS_unpack_ARGV(SV *sv); +void XS_pack_ARGV(SV *const sv, ARGV argv); + +struct capture *capture_new(SV *pn, ARGV argv, unsigned timeout, SV *cb[2]); void capture_DESTROY(struct capture *rc); char *capture_next_line(struct capture *rc, int fd); int capture_run(struct capture *cp); +void capture_set_argv_ref(struct capture *cp, ARGV av); diff --git a/lib/POSIX/Run/Capture.pm b/lib/POSIX/Run/Capture.pm index af28880..dacdcfd 100644 --- a/lib/POSIX/Run/Capture.pm +++ b/lib/POSIX/Run/Capture.pm @@ -50,7 +50,10 @@ sub get_lines { return \@lines; } - +sub set_argv { + my $self = shift; + $self->set_argv_ref([@_]); +} 1; __END__ diff --git a/runcap b/runcap -Subproject 969dab4c1af666d381124fd481821bc936fc94e +Subproject 3f686a2e5768174553b39697576171f5862433e @@ -1 +1,9 @@ POSIX::Run::Capture T_PTROBJ +ARGV T_ARGV + +INPUT +T_ARGV + $var = XS_unpack_ARGV($arg); +OUTPUT +T_ARGV + XS_pack_ARGV($arg, $var); |