tagged release 0.6.4
[parrot.git] / config / gen / platform / win32 / exec.c
blobe27e946ce3ffc475535276fe1aad0bdcfef37077
1 /*
2 * $Id$
3 * Copyright (C) 2004-2008, The Perl Foundation.
4 */
6 /*
8 =head1 NAME
10 config\gen\platform\win32\exec.c
12 =head1 DESCRIPTION
14 Functions for dealing with child processes and Execs.
16 =head2 Functions
18 =over 4
20 =cut
24 #include <process.h>
28 =item C<INTVAL
29 Parrot_Run_OS_Command(Parrot_Interp interp, STRING *command)>
31 Spawn the subprocess specified in C<command>.
32 Waits for the process to complete, and then
33 returns the exit code in POSIX-compatibility mode.
35 =cut
39 INTVAL
40 Parrot_Run_OS_Command(Parrot_Interp interp, STRING *command)
42 DWORD status = 0;
43 STARTUPINFO si;
44 PROCESS_INFORMATION pi;
45 int free_it = 0;
46 char* cmd = mem_sys_allocate(command->strlen + 4);
47 char* shell = Parrot_getenv("ComSpec", &free_it);
48 char* cmdin = string_to_cstring(interp, command);
50 strcpy(cmd, "/c ");
51 strcat(cmd, cmdin);
52 string_cstring_free(cmdin);
54 memset(&si, 0, sizeof (si));
55 si.cb = sizeof (si);
56 memset(&pi, 0, sizeof (pi));
58 /* Start the child process. */
59 if (!CreateProcess(shell, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) {
60 real_exception(interp, NULL, NOSPAWN, "Can't spawn child process");
63 WaitForSingleObject(pi.hProcess, INFINITE);
65 if (!GetExitCodeProcess(pi.hProcess, &status)) {
66 /* RT#48278 njs Should call GetLastError for failure message? */
67 Parrot_warn(interp, PARROT_WARNINGS_PLATFORM_FLAG,
68 "Process completed: Failed to get exit code.");
70 CloseHandle(pi.hProcess);
71 CloseHandle(pi.hThread);
72 if (free_it) free(shell);
73 mem_sys_free(cmd);
75 /* Return exit code left shifted by 8 for POSIX emulation. */
76 return status << 8;
81 =item C<INTVAL
82 Parrot_Run_OS_Command_Argv(Parrot_Interp interp, PMC *cmdargs)>
84 Spawns a subprocess with the arguments provided in the C<cmdargs> PMC array.
85 The first array element should be the name of the process to spawn,
86 and the remainder of the array elements should be arguments.
87 Waits until the child process completes,
88 and returns the exit code in POSIX-compatibility mode.
90 =cut
94 INTVAL
95 Parrot_Run_OS_Command_Argv(Parrot_Interp interp, PMC *cmdargs)
97 DWORD status = 0;
98 STARTUPINFO si;
99 PROCESS_INFORMATION pi;
100 int pmclen;
101 int cmdlinelen = 1000;
102 int cmdlinepos = 0;
103 char *cmdline = mem_sys_allocate(cmdlinelen);
104 int i;
106 /* Ensure there's something in the PMC array. */
107 pmclen = VTABLE_elements(interp, cmdargs);
108 if (pmclen == 0) {
109 real_exception(interp, NULL, NOSPAWN, "Empty argument array for spawnw");
112 /* Now build command line. */
113 for (i = 0; i < pmclen; i++) {
114 STRING *s = VTABLE_get_string_keyed_int(interp, cmdargs, i);
115 char *cs = string_to_cstring(interp, s);
116 if (cmdlinepos + (int)s->strlen + 3 > cmdlinelen) {
117 cmdlinelen += s->strlen + 4;
118 cmdline = mem_sys_realloc(cmdline, cmdlinelen);
120 strcpy(cmdline + cmdlinepos, "\"");
121 strcpy(cmdline + cmdlinepos + 1, cs);
122 strcpy(cmdline + cmdlinepos + 1 + s->strlen, "\" ");
123 cmdlinepos += s->strlen + 3;
126 /* Start the child process. */
127 memset(&si, 0, sizeof (si));
128 si.cb = sizeof (si);
129 memset(&pi, 0, sizeof (pi));
130 if (!CreateProcess(NULL, cmdline, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi))
132 real_exception(interp, NULL, NOSPAWN, "Can't spawn child process");
134 WaitForSingleObject(pi.hProcess, INFINITE);
136 /* Get exit code. */
137 if (!GetExitCodeProcess(pi.hProcess, &status)) {
138 /* RT#48278 njs Should call GetLastError for failure message? */
139 Parrot_warn(interp, PARROT_WARNINGS_PLATFORM_FLAG,
140 "Process completed: Failed to get exit code.");
143 /* Clean up. */
144 CloseHandle(pi.hProcess);
145 CloseHandle(pi.hThread);
146 mem_sys_free(cmdline);
148 /* Return exit code left shifted by 8 for POSIX emulation. */
149 return status << 8;
154 =item C<void
155 Parrot_Exec_OS_Command(Parrot_Interp interp, STRING *command)>
157 Exits parrot and passes control to the specified process. Does not return. Raises an exception
158 if the exec fails.
160 =cut
164 void
165 Parrot_Exec_OS_Command(Parrot_Interp interp, STRING *command)
167 int status;
168 char *in = string_to_cstring(interp, command);
169 char *cmd = NULL;
170 const char **argv = mem_sys_allocate_zeroed(2 * sizeof (int));
172 /* Grab string, extract command and parameters. */
173 char *curPos = in;
174 char *lastCommandStart = in;
175 char seekChar = 0;
176 int argc = 1;
177 while (*curPos)
179 /* If we don't have a seek character and this is a quote... */
180 if (seekChar == 0 && (*curPos == '\'' || *curPos == '"'))
182 seekChar = *curPos;
183 lastCommandStart = curPos;
186 /* If we don't have a seek character and this is not a space... */
187 else if (seekChar == 0 && *curPos != ' ')
189 if (!seekChar)
190 seekChar = ' ';
191 lastCommandStart = curPos;
194 /* If we seek the seek character... */
195 else if (*curPos == seekChar || (*(curPos + 1) == 0 && seekChar == ' '))
197 /* Copy what we found to a temporary string. */
198 char *tmp;
199 int lenFound = curPos - lastCommandStart;
200 if (*(curPos + 1) == 0)
201 lenFound++;
202 tmp = mem_sys_allocate(1 + lenFound);
203 memcpy(tmp, lastCommandStart, lenFound);
204 *(tmp + lenFound) = 0;
206 /* Is it command or argument? */
207 if (cmd == NULL)
209 cmd = tmp;
210 *argv = tmp;
212 else
214 /* Allocate space for another pointer in **argv. */
215 argc++;
216 argv = mem_sys_realloc(argv, (argc + 1) * sizeof (int));
217 *(argv + (argc - 1)) = tmp;
218 *(argv + argc) = NULL;
221 /* Clear seek character. */
222 seekChar = 0;
225 /* Move to next character. */
226 curPos ++;
229 /* If we still have a seek char, then the input was improper. */
230 if (seekChar)
232 real_exception(interp, NULL, NOSPAWN, "Exec failed, invalid command string");
235 /* Now do the exec. */
236 status = _execvp(cmd, argv);
237 if (status) {
238 real_exception(interp, NULL, NOSPAWN, "Exec failed, code %i", status);
244 =back
246 =cut
251 * Local variables:
252 * c-file-style: "parrot"
253 * End:
254 * vim: expandtab shiftwidth=4: