# New Ticket Created by Jeff Horwitz
# Please include the string: [perl #35365]
# in the subject line of all future correspondence about this issue.
# <URL: https://rt.perl.org/rt3/Ticket/Display.html?id=35365 >
the attached patch adds a new signature for spawnw so it can take a PMC
array of arguments rather than a single string. with this, parrot can
support perl's system($cmd) as well as system(@args). tests are
included, though i only have unix platforms to test on right now.
-jeff
Index: ops/ops.num
===================================================================
--- ops/ops.num (revision 8028)
+++ ops/ops.num (working copy)
@@ -1341,3 +1341,4 @@
not_i 1311
not_p 1312
n_not_p_p 1313
+spawnw_i_p 1314
Index: ops/sys.ops
===================================================================
--- ops/sys.ops (revision 8028)
+++ ops/sys.ops (working copy)
@@ -20,9 +20,16 @@
=item B<spawnw>(out INT, in STR)
-Spawn a subprocess and wait for it to finish. The return status, which is
-very system-dependent, goes in $1.
+Spawn a subprocess whose program name and arguments are contained in the string
+$2 and wait for it to finish. The return status, which is very
+system-dependent, goes in $1.
+=item B<spawnw>(out INT, in PMC)
+
+Spawn a subprocess whose program name and arguments are contained in the array
+$2 and wait for it to finish. The return status, which is very
+system-dependent, goes in $1.
+
=cut
inline op spawnw(out INT, in STR) {
@@ -30,6 +37,11 @@
goto NEXT();
}
+inline op spawnw(out INT, in PMC) {
+ $1 = Parrot_Run_OS_Command_Argv(interpreter, $2);
+ goto NEXT();
+}
+
###############################################################################
=item B<err>(out INT)
Index: t/op/spawnw.t
===================================================================
--- t/op/spawnw.t (revision 8028)
+++ t/op/spawnw.t (working copy)
@@ -13,12 +13,12 @@
Tests spawning external commands.
-spanwn does not capture STDOUT and STDERR from the spawnde command.
+spawnw does not capture STDOUT and STDERR from the spawned command.
So only the exit code can be tested.
The returned value is actually returned from the 'waitpid' system call.
-In order to get the exit code from the spawned process, it needs to be right
shifted
-by 8 bit.
+In order to get the exit code from the spawned process, it needs to be right
+shifted by 8 bit.
=head1 TODO
@@ -34,11 +34,13 @@
=cut
-use Parrot::Test tests => 3;
+use Parrot::Test tests => 6;
# perl command coded this way to avoid platform
# quoting issue.
+# test string version of spawnw
+
pasm_output_is(<<'CODE', <<'OUTPUT', "exit code: 0");
set S1, 'perl -e "exit(0)"'
set I1, 99
@@ -65,7 +67,6 @@
return code: 123
OUTPUT
-
output_is(<<'CODE', <<'OUTPUT', "exit code: 3");
set S1, 'perl -e "exit(3)"'
set I1, 99
@@ -78,3 +79,56 @@
CODE
return code: 3
OUTPUT
+
+# test array version of spawnw
+
+output_is(<<'CODE', <<'OUTPUT', "exit code: 0");
+ new P0, .Array
+ set P0, 3
+ set P0[0], "perl"
+ set P0[1], "-e"
+ set P0[2], "exit(0)"
+ set I1, 99
+ spawnw I1, P0
+ shr I2, I1, 8
+ print "return code: "
+ print I2
+ print "\n"
+ end
+CODE
+return code: 0
+OUTPUT
+
+output_is(<<'CODE', <<'OUTPUT', "exit code: 123");
+ new P0, .Array
+ set P0, 3
+ set P0[0], "perl"
+ set P0[1], "-e"
+ set P0[2], "exit(123)"
+ set I1, 99
+ spawnw I1, P0
+ shr I2, I1, 8
+ print "return code: "
+ print I2
+ print "\n"
+ end
+CODE
+return code: 123
+OUTPUT
+
+output_is(<<'CODE', <<'OUTPUT', "exit code: 3");
+ new P0, .Array
+ set P0, 3
+ set P0[0], "perl"
+ set P0[1], "-e"
+ set P0[2], "exit(3)"
+ set I1, 99
+ spawnw I1, P0
+ shr I2, I1, 8
+ print "return code: "
+ print I2
+ print "\n"
+ end
+CODE
+return code: 3
+OUTPUT
Index: config/gen/platform/platform_interface.h
===================================================================
--- config/gen/platform/platform_interface.h (revision 8028)
+++ config/gen/platform/platform_interface.h (working copy)
@@ -123,6 +123,8 @@
struct parrot_string_t;
INTVAL Parrot_Run_OS_Command(Interp*, struct parrot_string_t *);
void Parrot_Exec_OS_Command(Interp*, struct parrot_string_t *);
+INTVAL Parrot_Run_OS_Command_Argv(Interp*, struct PMC *);
+void Parrot_Exec_OS_Command_Argv(Interp*, struct PMC *);
/*
* Local variables:
Index: config/gen/platform/generic/exec.c
===================================================================
--- config/gen/platform/generic/exec.c (revision 8028)
+++ config/gen/platform/generic/exec.c (working copy)
@@ -40,6 +40,51 @@
return 1; /* make gcc happy */
}
+INTVAL
+Parrot_Run_OS_Command_Argv(Parrot_Interp interpreter, PMC *cmdargs)
+{
+ pid_t child;
+ int len = VTABLE_elements(interpreter, cmdargs);
+ if (len == 0) {
+ internal_exception(NOSPAWN, "Empty argument array for execvp");
+ }
+ child = fork();
+ /* Did we fail? */
+ if (-1 == child) {
+ internal_exception(NOSPAWN, "Can't spawn child process");
+ }
+ /* Are we the parent or child? */
+ if (child) {
+ /* parent */
+ int status;
+ pid_t returnstat;
+ returnstat = waitpid(child, &status, 0);
+ return status;
+ } else {
+ /* child. Be horribly profligate with memory, since we're
+ about to be something else */
+ int status, i;
+ char **argv;
+ STRING *s;
+ char *cmd;
+
+ argv = (char **)mem_sys_allocate((len+1)*sizeof(char *));
+ for (i = 0; i < len; ++i) {
+ s = VTABLE_get_string_keyed_int(interpreter, cmdargs, i);
+ argv[i] = string_to_cstring(interpreter, s);
+ }
+ cmd = argv[0];
+ argv[i] = NULL;
+
+ status = execvp(cmd, argv);
+ /* if we get here, something's horribly wrong... */
+ if (status) {
+ exit(status);
+ }
+ }
+ return 1; /* make gcc happy */
+}
+
void
Parrot_Exec_OS_Command(Parrot_Interp interpreter, STRING *command) {
/* Be horribly profligate with memory, since we're