# 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