aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Capture.xs57
-rw-r--r--capture.c125
-rw-r--r--capture.h8
-rw-r--r--lib/POSIX/Run/Capture.pm5
m---------runcap0
-rw-r--r--typemap8
6 files changed, 159 insertions, 44 deletions
diff --git a/Capture.xs b/Capture.xs
index df47544..d85b74c 100644
--- a/Capture.xs
+++ b/Capture.xs
@@ -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;
diff --git a/capture.c b/capture.c
index 4d2c04c..471b2bf 100644
--- a/capture.c
+++ b/capture.c
@@ -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)
{
diff --git a/capture.h b/capture.h
index 8806ea3..64bb55f 100644
--- a/capture.h
+++ b/capture.h
@@ -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
diff --git a/typemap b/typemap
index 6b7457f..5ffa887 100644
--- a/typemap
+++ b/typemap
@@ -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);

Return to:

Send suggestions and report system problems to the System administrator.