---------- Forwarded message ----------
Date: Mon, 9 May 2005 14:32:22 -0400 (EDT)
From: Jeff Horwitz <[EMAIL PROTECTED]>
To: [EMAIL PROTECTED]
Subject: [PATCH] allow array of args for spawnw

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

Reply via email to