Added support for nested exceptions happening inside a catch block.
[wine] / dlls / msvcrt / process.c
1 /*
2  * msvcrt.dll spawn/exec functions
3  *
4  * Copyright 1996,1998 Marcus Meissner
5  * Copyright 1996 Jukka Iivonen
6  * Copyright 1997,2000 Uwe Bonnes
7  * Copyright 2000 Jon Griffiths
8  *
9  * This library is free software; you can redistribute it and/or
10  * modify it under the terms of the GNU Lesser General Public
11  * License as published by the Free Software Foundation; either
12  * version 2.1 of the License, or (at your option) any later version.
13  *
14  * This library is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
17  * Lesser General Public License for more details.
18  *
19  * You should have received a copy of the GNU Lesser General Public
20  * License along with this library; if not, write to the Free Software
21  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22  *
23  * FIXME:
24  * -File handles need some special handling. Sometimes children get
25  *  open file handles, sometimes not. The docs are confusing
26  * -No check for maximum path/argument/environment size is done
27  */
28 #include "config.h"
29
30 #include <stdarg.h>
31
32 #include "msvcrt.h"
33 #include "msvcrt/errno.h"
34
35 #include "msvcrt/process.h"
36 #include "msvcrt/stdlib.h"
37 #include "msvcrt/string.h"
38
39 #include "wine/debug.h"
40
41 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
42
43 /* FIXME: Check file extensions for app to run */
44 static const unsigned int EXE = 'e' << 16 | 'x' << 8 | 'e';
45 static const unsigned int BAT = 'b' << 16 | 'a' << 8 | 't';
46 static const unsigned int CMD = 'c' << 16 | 'm' << 8 | 'd';
47 static const unsigned int COM = 'c' << 16 | 'o' << 8 | 'm';
48
49 /* INTERNAL: Spawn a child process */
50 static int msvcrt_spawn(int flags, const char* exe, char* cmdline, char* env)
51 {
52   STARTUPINFOA si;
53   PROCESS_INFORMATION pi;
54
55   if (sizeof(HANDLE) != sizeof(int))
56     WARN("This call is unsuitable for your architecture\n");
57
58   if ((unsigned)flags > _P_DETACH)
59   {
60     *MSVCRT__errno() = MSVCRT_EINVAL;
61     return -1;
62   }
63
64   FIXME(":must dup/kill streams for child process\n");
65
66   memset(&si, 0, sizeof(si));
67   si.cb = sizeof(si);
68
69   if (!CreateProcessA(exe, cmdline, NULL, NULL, TRUE,
70                      flags == _P_DETACH ? DETACHED_PROCESS : 0,
71                      env, NULL, &si, &pi))
72   {
73     MSVCRT__set_errno(GetLastError());
74     return -1;
75   }
76
77   switch(flags)
78   {
79   case _P_WAIT:
80     WaitForSingleObject(pi.hProcess,-1); /* wait forvever */
81     GetExitCodeProcess(pi.hProcess,&pi.dwProcessId);
82     CloseHandle(pi.hProcess);
83     CloseHandle(pi.hThread);
84     return (int)pi.dwProcessId;
85   case _P_DETACH:
86     CloseHandle(pi.hProcess);
87     pi.hProcess = 0;
88     /* fall through */
89   case _P_NOWAIT:
90   case _P_NOWAITO:
91     CloseHandle(pi.hThread);
92     return (int)pi.hProcess;
93   case  _P_OVERLAY:
94     MSVCRT__exit(0);
95   }
96   return -1; /* can't reach here */
97 }
98
99 /* INTERNAL: Convert argv list to a single 'delim'-separated string, with an
100  * extra '\0' to terminate it
101  */
102 static char* msvcrt_argvtos(const char* const* arg, char delim)
103 {
104   const char* const* a;
105   long size;
106   char* p;
107   char* ret;
108
109   if (!arg && !delim)
110   {
111       /* Return NULL for an empty environment list */
112       return NULL;
113   }
114
115   /* get length */
116   a = arg;
117   size = 0;
118   while (*a)
119   {
120     size += strlen(*a) + 1;
121     a++;
122   }
123
124   ret = (char*)MSVCRT_malloc(size + 1);
125   if (!ret)
126     return NULL;
127
128   /* fill string */
129   a = arg;
130   p = ret;
131   while (*a)
132   {
133     int len = strlen(*a);
134     memcpy(ret+size,*a,len);
135     p += len;
136     *p++ = delim;
137     a++;
138   }
139   *p='\0';
140   return ret;
141 }
142
143 /* INTERNAL: Convert va_list to a single 'delim'-separated string, with an
144  * extra '\0' to terminate it
145  */
146 static char* msvcrt_valisttos(const char* arg0, va_list alist, char delim)
147 {
148   va_list alist2;
149   long size;
150   const char *arg;
151   char* p;
152   char *ret;
153
154 #if HAVE_VA_COPY
155   va_copy(alist2,alist);
156 #else
157 # if HAVE___VA_COPY
158   __va_copy(alist2,alist);
159 # else
160   alist2 = alist;
161 # endif
162 #endif
163
164   if (!arg0 && !delim)
165   {
166       /* Return NULL for an empty environment list */
167       return NULL;
168   }
169
170   /* get length */
171   arg = arg0;
172   size = 0;
173   do {
174       size += strlen(arg) + 1;
175       arg = va_arg(alist, char*);
176   } while (arg != NULL);
177
178   ret = (char*)MSVCRT_malloc(size + 1);
179   if (!ret)
180     return NULL;
181
182   /* fill string */
183   arg = arg0;
184   p = ret;
185   do {
186       int len = strlen(arg);
187       memcpy(p,arg,len);
188       p += len;
189       *p++ = delim;
190       arg = va_arg(alist2, char*);
191   } while (arg != NULL);
192   *p = '\0';
193   return ret;
194 }
195
196 /*********************************************************************
197  *              _cwait (MSVCRT.@)
198  */
199 int _cwait(int *status, int pid, int action)
200 {
201   HANDLE hPid = (HANDLE)pid;
202   int doserrno;
203
204   action = action; /* Remove warning */
205
206   if (!WaitForSingleObject(hPid, -1)) /* wait forever */
207   {
208     if (status)
209     {
210       DWORD stat;
211       GetExitCodeProcess(hPid, &stat);
212       *status = (int)stat;
213     }
214     return (int)pid;
215   }
216   doserrno = GetLastError();
217
218   if (doserrno == ERROR_INVALID_HANDLE)
219   {
220     *MSVCRT__errno() =  MSVCRT_ECHILD;
221     *__doserrno() = doserrno;
222   }
223   else
224     MSVCRT__set_errno(doserrno);
225
226   return status ? *status = -1 : -1;
227 }
228
229 /*********************************************************************
230  *              _execl (MSVCRT.@)
231  *
232  * Like on Windows, this function does not handle arguments with spaces
233  * or double-quotes.
234  */
235 int _execl(const char* name, const char* arg0, ...)
236 {
237   va_list ap;
238   char * args;
239   int ret;
240
241   va_start(ap, arg0);
242   args = msvcrt_valisttos(arg0, ap, ' ');
243   va_end(ap);
244
245   ret = msvcrt_spawn(_P_OVERLAY, name, args, NULL);
246   MSVCRT_free(args);
247
248   return ret;
249 }
250
251 /*********************************************************************
252  *              _execlp (MSVCRT.@)
253  *
254  * Like on Windows, this function does not handle arguments with spaces
255  * or double-quotes.
256  */
257 int _execlp(const char* name, const char* arg0, ...)
258 {
259   va_list ap;
260   char * args;
261   int ret;
262   char fullname[MAX_PATH];
263
264   _searchenv(name, "PATH", fullname);
265
266   va_start(ap, arg0);
267   args = msvcrt_valisttos(arg0, ap, ' ');
268   va_end(ap);
269
270   ret = msvcrt_spawn(_P_OVERLAY, fullname[0] ? fullname : name, args, NULL);
271   MSVCRT_free(args);
272
273   return ret;
274 }
275
276 /*********************************************************************
277  *              _execv (MSVCRT.@)
278  *
279  * Like on Windows, this function does not handle arguments with spaces
280  * or double-quotes.
281  */
282 int _execv(const char* name, char* const* argv)
283 {
284   return _spawnve(_P_OVERLAY, name, (const char* const*) argv, NULL);
285 }
286
287 /*********************************************************************
288  *              _execve (MSVCRT.@)
289  *
290  * Like on Windows, this function does not handle arguments with spaces
291  * or double-quotes.
292  */
293 int _execve(const char* name, char* const* argv, const char* const* envv)
294 {
295   return _spawnve(_P_OVERLAY, name, (const char* const*) argv, envv);
296 }
297
298 /*********************************************************************
299  *              _execvpe (MSVCRT.@)
300  *
301  * Like on Windows, this function does not handle arguments with spaces
302  * or double-quotes.
303  */
304 int _execvpe(const char* name, char* const* argv, const char* const* envv)
305 {
306   char fullname[MAX_PATH];
307
308   _searchenv(name, "PATH", fullname);
309   return _spawnve(_P_OVERLAY, fullname[0] ? fullname : name,
310                   (const char* const*) argv, envv);
311 }
312
313 /*********************************************************************
314  *              _execvp (MSVCRT.@)
315  *
316  * Like on Windows, this function does not handle arguments with spaces
317  * or double-quotes.
318  */
319 int _execvp(const char* name, char* const* argv)
320 {
321   return _execvpe(name, argv, NULL);
322 }
323
324 /*********************************************************************
325  *              _spawnl (MSVCRT.@)
326  *
327  * Like on Windows, this function does not handle arguments with spaces
328  * or double-quotes.
329  */
330 int _spawnl(int flags, const char* name, const char* arg0, ...)
331 {
332   va_list ap;
333   char * args;
334   int ret;
335
336   va_start(ap, arg0);
337   args = msvcrt_valisttos(arg0, ap, ' ');
338   va_end(ap);
339
340   ret = msvcrt_spawn(flags, name, args, NULL);
341   MSVCRT_free(args);
342
343   return ret;
344 }
345
346 /*********************************************************************
347  *              _spawnlp (MSVCRT.@)
348  *
349  * Like on Windows, this function does not handle arguments with spaces
350  * or double-quotes.
351  */
352 int _spawnlp(int flags, const char* name, const char* arg0, ...)
353 {
354   va_list ap;
355   char * args;
356   int ret;
357   char fullname[MAX_PATH];
358
359   _searchenv(name, "PATH", fullname);
360
361   va_start(ap, arg0);
362   args = msvcrt_valisttos(arg0, ap, ' ');
363   va_end(ap);
364
365   ret = msvcrt_spawn(flags, fullname[0] ? fullname : name, args, NULL);
366   MSVCRT_free(args);
367
368   return ret;
369 }
370
371 /*********************************************************************
372  *              _spawnve (MSVCRT.@)
373  *
374  * Like on Windows, this function does not handle arguments with spaces
375  * or double-quotes.
376  */
377 int _spawnve(int flags, const char* name, const char* const* argv,
378                             const char* const* envv)
379 {
380   char * args = msvcrt_argvtos(argv,' ');
381   char * envs = msvcrt_argvtos(envv,0);
382   const char *fullname = name;
383   int ret = -1;
384
385   FIXME(":not translating name %s to locate program\n",fullname);
386   TRACE(":call (%s), params (%s), env (%s)\n",name,args,envs?"Custom":"Null");
387
388   if (args)
389   {
390     ret = msvcrt_spawn(flags, fullname, args, envs);
391     MSVCRT_free(args);
392   }
393   if (envs)
394     MSVCRT_free(envs);
395
396   return ret;
397 }
398
399 /*********************************************************************
400  *              _spawnv (MSVCRT.@)
401  *
402  * Like on Windows, this function does not handle arguments with spaces
403  * or double-quotes.
404  */
405 int _spawnv(int flags, const char* name, const char* const* argv)
406 {
407   return _spawnve(flags, name, argv, NULL);
408 }
409
410 /*********************************************************************
411  *              _spawnvpe (MSVCRT.@)
412  *
413  * Like on Windows, this function does not handle arguments with spaces
414  * or double-quotes.
415  */
416 int _spawnvpe(int flags, const char* name, const char* const* argv,
417                             const char* const* envv)
418 {
419   char fullname[MAX_PATH];
420   _searchenv(name, "PATH", fullname);
421   return _spawnve(flags, fullname[0] ? fullname : name, argv, envv);
422 }
423
424 /*********************************************************************
425  *              _spawnvp (MSVCRT.@)
426  *
427  * Like on Windows, this function does not handle arguments with spaces
428  * or double-quotes.
429  */
430 int _spawnvp(int flags, const char* name, const char* const* argv)
431 {
432   return _spawnvpe(flags, name, argv, NULL);
433 }
434
435 /*********************************************************************
436  *              system (MSVCRT.@)
437  */
438 int MSVCRT_system(const char* cmd)
439 {
440     char* cmdcopy;
441     int res;
442
443     /* Make a writable copy for CreateProcess */
444     cmdcopy=_strdup(cmd);
445     /* FIXME: should probably launch cmd interpreter in COMSPEC */
446     res=msvcrt_spawn(_P_WAIT, NULL, cmdcopy, NULL);
447     MSVCRT_free(cmdcopy);
448     return res;
449 }
450
451 /*********************************************************************
452  *              _loaddll (MSVCRT.@)
453  */
454 int _loaddll(const char* dllname)
455 {
456   return (int)LoadLibraryA(dllname);
457 }
458
459 /*********************************************************************
460  *              _unloaddll (MSVCRT.@)
461  */
462 int _unloaddll(int dll)
463 {
464   if (FreeLibrary((HMODULE)dll))
465     return 0;
466   else
467   {
468     int err = GetLastError();
469     MSVCRT__set_errno(err);
470     return err;
471   }
472 }