aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Poznyakoff <gray@gnu.org.ua>2017-07-22 09:26:47 +0300
committerSergey Poznyakoff <gray@gnu.org.ua>2017-07-22 09:32:47 +0300
commit4da9775f1d88787517e54f5c1fe1c43f1e023480 (patch)
treea214263c46aea4199cdf32ee0763f53e1e80a05a
parent5ea83707e0b082687b59469fa422611e18e812bc (diff)
downloadposixruncapture-4da9775f1d88787517e54f5c1fe1c43f1e023480.tar.gz
posixruncapture-4da9775f1d88787517e54f5c1fe1c43f1e023480.tar.bz2
Add new methods for manipulating argv and program pathname
* Capture.xs (capture_new): Use new ARGV typedef. Handle the new "program" keyword. (capture_set_argv_ref, capture_set_program) (capture_argv, capture_program): New methods. * capture.c: Handle out of memory errors. (XS_pack_ARGV, XS_unpack_ARGV): New functions. (capture_new): Change signature. Set the rc_program field. (capture_DESTROY): Destroy cp->program (capture_set_argv_ref): New function. * capture.h (capture) <program>: New member. (ARGV): New typedef. (capture_new): Change signature. (XS_unpack_ARGV, XS_pack_ARGV) (capture_set_argv_ref): New protos. * lib/POSIX/Run/Capture.pm (set_argv): New method. * typemap: Hande ARGV conversions. * runcap: Update.
-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
@@ -16,20 +16,21 @@ PROTOTYPES: ENABLE
=cut
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)
croak("Bad number of arguments");
else {
int i;
@@ -41,13 +42,13 @@ capture_new(package, ...)
if (!SvPOK(sv))
croak("bad arguments near #%d", i);
kw = SvPV_nolen(sv);
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
|| strcmp(kw, "stderr") == 0) {
if (SvROK(val)
&& SvTYPE(SvRV(val)) == SVt_PVCV) {
@@ -56,28 +57,68 @@ capture_new(package, ...)
croak("%s must be a code ref", kw);
} else if (strcmp(kw, "timeout") == 0) {
if (SvIOK(val)) {
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
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;
int
capture_status(cp)
diff --git a/capture.c b/capture.c
index 4d2c04c..471b2bf 100644
--- a/capture.c
+++ b/capture.c
@@ -1,9 +1,15 @@
#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)
{
dSP;
ENTER;
@@ -27,13 +33,13 @@ line_monitor(const char *ptr, size_t sz, void *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");
+ croak_nomem();
lc->size = newsz;
}
memcpy(lc->str + lc->len, ptr, sz);
lc->len += sz;
lc->str[lc->len] = 0;
@@ -41,47 +47,96 @@ line_monitor(const char *ptr, size_t sz, void *closure)
call_monitor(lc->cv, lc->str, lc->len);
lc->len = 0;
}
} 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;
}
cp->closure[0].cv = cb[0];
@@ -99,39 +154,41 @@ capture_new(AV *av, unsigned timeout, SV *cb[2])
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 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);
free(cp->closure[1].str);
if (cp->closure[1].cv != &PL_sv_undef)
SvREFCNT_dec(cp->closure[1].cv);
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)
{
char *buf = NULL;
size_t sz = 0;
ssize_t n;
diff --git a/capture.h b/capture.h
index 8806ea3..64bb55f 100644
--- a/capture.h
+++ b/capture.h
@@ -16,14 +16,20 @@ struct line_closure
};
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
@@ -47,13 +47,16 @@ sub get_lines {
while (my $s = $self->next_line($fd)) {
push @lines, $s;
}
return \@lines;
}
-
+sub set_argv {
+ my $self = shift;
+ $self->set_argv_ref([@_]);
+}
1;
__END__
=head1 NAME
POSIX::Run::Capture - run command and capture its output
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.