Added an initial (mostly stub) implementation of MSHTML.DLL.
[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/stdio.h"
36 #include "msvcrt/process.h"
37 #include "msvcrt/stdlib.h"
38 #include "msvcrt/string.h"
39
40 #include "wine/debug.h"
41
42 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
43
44 /* FIXME: Check file extensions for app to run */
45 static const unsigned int EXE = 'e' << 16 | 'x' << 8 | 'e';
46 static const unsigned int BAT = 'b' << 16 | 'a' << 8 | 't';
47 static const unsigned int CMD = 'c' << 16 | 'm' << 8 | 'd';
48 static const unsigned int COM = 'c' << 16 | 'o' << 8 | 'm';
49
50 /* INTERNAL: Spawn a child process */
51 static int msvcrt_spawn(int flags, const char* exe, char* cmdline, char* env)
52 {
53   STARTUPINFOA si;
54   PROCESS_INFORMATION pi;
55
56   if (sizeof(HANDLE) != sizeof(int))
57     WARN("This call is unsuitable for your architecture\n");
58
59   if ((unsigned)flags > _P_DETACH)
60   {
61     *MSVCRT__errno() = MSVCRT_EINVAL;
62     return -1;
63   }
64
65   FIXME(":must dup/kill streams for child process\n");
66
67   memset(&si, 0, sizeof(si));
68   si.cb = sizeof(si);
69
70   if (!CreateProcessA(exe, cmdline, NULL, NULL, TRUE,
71                      flags == _P_DETACH ? DETACHED_PROCESS : 0,
72                      env, NULL, &si, &pi))
73   {
74     MSVCRT__set_errno(GetLastError());
75     return -1;
76   }
77
78   switch(flags)
79   {
80   case _P_WAIT:
81     WaitForSingleObject(pi.hProcess,-1); /* wait forvever */
82     GetExitCodeProcess(pi.hProcess,&pi.dwProcessId);
83     CloseHandle(pi.hProcess);
84     CloseHandle(pi.hThread);
85     return (int)pi.dwProcessId;
86   case _P_DETACH:
87     CloseHandle(pi.hProcess);
88     pi.hProcess = 0;
89     /* fall through */
90   case _P_NOWAIT:
91   case _P_NOWAITO:
92     CloseHandle(pi.hThread);
93     return (int)pi.hProcess;
94   case  _P_OVERLAY:
95     MSVCRT__exit(0);
96   }
97   return -1; /* can't reach here */
98 }
99
100 /* INTERNAL: Convert argv list to a single 'delim'-separated string, with an
101  * extra '\0' to terminate it
102  */
103 static char* msvcrt_argvtos(const char* const* arg, char delim)
104 {
105   const char* const* a;
106   long size;
107   char* p;
108   char* ret;
109
110   if (!arg && !delim)
111   {
112       /* Return NULL for an empty environment list */
113       return NULL;
114   }
115
116   /* get length */
117   a = arg;
118   size = 0;
119   while (*a)
120   {
121     size += strlen(*a) + 1;
122     a++;
123   }
124
125   ret = (char*)MSVCRT_malloc(size + 1);
126   if (!ret)
127     return NULL;
128
129   /* fill string */
130   a = arg;
131   p = ret;
132   while (*a)
133   {
134     int len = strlen(*a);
135     memcpy(p,*a,len);
136     p += len;
137     *p++ = delim;
138     a++;
139   }
140   if (delim && p > ret) p[-1] = 0;
141   else *p = 0;
142   return ret;
143 }
144
145 /* INTERNAL: Convert va_list to a single 'delim'-separated string, with an
146  * extra '\0' to terminate it
147  */
148 static char* msvcrt_valisttos(const char* arg0, va_list alist, char delim)
149 {
150   va_list alist2;
151   long size;
152   const char *arg;
153   char* p;
154   char *ret;
155
156 #if HAVE_VA_COPY
157   va_copy(alist2,alist);
158 #else
159 # if HAVE___VA_COPY
160   __va_copy(alist2,alist);
161 # else
162   alist2 = alist;
163 # endif
164 #endif
165
166   if (!arg0 && !delim)
167   {
168       /* Return NULL for an empty environment list */
169       return NULL;
170   }
171
172   /* get length */
173   arg = arg0;
174   size = 0;
175   do {
176       size += strlen(arg) + 1;
177       arg = va_arg(alist, char*);
178   } while (arg != NULL);
179
180   ret = (char*)MSVCRT_malloc(size + 1);
181   if (!ret)
182     return NULL;
183
184   /* fill string */
185   arg = arg0;
186   p = ret;
187   do {
188       int len = strlen(arg);
189       memcpy(p,arg,len);
190       p += len;
191       *p++ = delim;
192       arg = va_arg(alist2, char*);
193   } while (arg != NULL);
194   if (delim && p > ret) p[-1] = 0;
195   else *p = 0;
196   return ret;
197 }
198
199 /*********************************************************************
200  *              _cwait (MSVCRT.@)
201  */
202 int _cwait(int *status, int pid, int action)
203 {
204   HANDLE hPid = (HANDLE)pid;
205   int doserrno;
206
207   action = action; /* Remove warning */
208
209   if (!WaitForSingleObject(hPid, -1)) /* wait forever */
210   {
211     if (status)
212     {
213       DWORD stat;
214       GetExitCodeProcess(hPid, &stat);
215       *status = (int)stat;
216     }
217     return (int)pid;
218   }
219   doserrno = GetLastError();
220
221   if (doserrno == ERROR_INVALID_HANDLE)
222   {
223     *MSVCRT__errno() =  MSVCRT_ECHILD;
224     *__doserrno() = doserrno;
225   }
226   else
227     MSVCRT__set_errno(doserrno);
228
229   return status ? *status = -1 : -1;
230 }
231
232 /*********************************************************************
233  *              _execl (MSVCRT.@)
234  *
235  * Like on Windows, this function does not handle arguments with spaces
236  * or double-quotes.
237  */
238 int _execl(const char* name, const char* arg0, ...)
239 {
240   va_list ap;
241   char * args;
242   int ret;
243
244   va_start(ap, arg0);
245   args = msvcrt_valisttos(arg0, ap, ' ');
246   va_end(ap);
247
248   ret = msvcrt_spawn(_P_OVERLAY, name, args, NULL);
249   MSVCRT_free(args);
250
251   return ret;
252 }
253
254 /*********************************************************************
255  *              _execlp (MSVCRT.@)
256  *
257  * Like on Windows, this function does not handle arguments with spaces
258  * or double-quotes.
259  */
260 int _execlp(const char* name, const char* arg0, ...)
261 {
262   va_list ap;
263   char * args;
264   int ret;
265   char fullname[MAX_PATH];
266
267   _searchenv(name, "PATH", fullname);
268
269   va_start(ap, arg0);
270   args = msvcrt_valisttos(arg0, ap, ' ');
271   va_end(ap);
272
273   ret = msvcrt_spawn(_P_OVERLAY, fullname[0] ? fullname : name, args, NULL);
274   MSVCRT_free(args);
275
276   return ret;
277 }
278
279 /*********************************************************************
280  *              _execv (MSVCRT.@)
281  *
282  * Like on Windows, this function does not handle arguments with spaces
283  * or double-quotes.
284  */
285 int _execv(const char* name, char* const* argv)
286 {
287   return _spawnve(_P_OVERLAY, name, (const char* const*) argv, NULL);
288 }
289
290 /*********************************************************************
291  *              _execve (MSVCRT.@)
292  *
293  * Like on Windows, this function does not handle arguments with spaces
294  * or double-quotes.
295  */
296 int _execve(const char* name, char* const* argv, const char* const* envv)
297 {
298   return _spawnve(_P_OVERLAY, name, (const char* const*) argv, envv);
299 }
300
301 /*********************************************************************
302  *              _execvpe (MSVCRT.@)
303  *
304  * Like on Windows, this function does not handle arguments with spaces
305  * or double-quotes.
306  */
307 int _execvpe(const char* name, char* const* argv, const char* const* envv)
308 {
309   char fullname[MAX_PATH];
310
311   _searchenv(name, "PATH", fullname);
312   return _spawnve(_P_OVERLAY, fullname[0] ? fullname : name,
313                   (const char* const*) argv, envv);
314 }
315
316 /*********************************************************************
317  *              _execvp (MSVCRT.@)
318  *
319  * Like on Windows, this function does not handle arguments with spaces
320  * or double-quotes.
321  */
322 int _execvp(const char* name, char* const* argv)
323 {
324   return _execvpe(name, argv, NULL);
325 }
326
327 /*********************************************************************
328  *              _spawnl (MSVCRT.@)
329  *
330  * Like on Windows, this function does not handle arguments with spaces
331  * or double-quotes.
332  */
333 int _spawnl(int flags, const char* name, const char* arg0, ...)
334 {
335   va_list ap;
336   char * args;
337   int ret;
338
339   va_start(ap, arg0);
340   args = msvcrt_valisttos(arg0, ap, ' ');
341   va_end(ap);
342
343   ret = msvcrt_spawn(flags, name, args, NULL);
344   MSVCRT_free(args);
345
346   return ret;
347 }
348
349 /*********************************************************************
350  *              _spawnlp (MSVCRT.@)
351  *
352  * Like on Windows, this function does not handle arguments with spaces
353  * or double-quotes.
354  */
355 int _spawnlp(int flags, const char* name, const char* arg0, ...)
356 {
357   va_list ap;
358   char * args;
359   int ret;
360   char fullname[MAX_PATH];
361
362   _searchenv(name, "PATH", fullname);
363
364   va_start(ap, arg0);
365   args = msvcrt_valisttos(arg0, ap, ' ');
366   va_end(ap);
367
368   ret = msvcrt_spawn(flags, fullname[0] ? fullname : name, args, NULL);
369   MSVCRT_free(args);
370
371   return ret;
372 }
373
374 /*********************************************************************
375  *              _spawnve (MSVCRT.@)
376  *
377  * Like on Windows, this function does not handle arguments with spaces
378  * or double-quotes.
379  */
380 int _spawnve(int flags, const char* name, const char* const* argv,
381                             const char* const* envv)
382 {
383   char * args = msvcrt_argvtos(argv,' ');
384   char * envs = msvcrt_argvtos(envv,0);
385   const char *fullname = name;
386   int ret = -1;
387
388   FIXME(":not translating name %s to locate program\n",fullname);
389   TRACE(":call (%s), params (%s), env (%s)\n",name,args,envs?"Custom":"Null");
390
391   if (args)
392   {
393     ret = msvcrt_spawn(flags, fullname, args, envs);
394     MSVCRT_free(args);
395   }
396   if (envs)
397     MSVCRT_free(envs);
398
399   return ret;
400 }
401
402 /*********************************************************************
403  *              _spawnv (MSVCRT.@)
404  *
405  * Like on Windows, this function does not handle arguments with spaces
406  * or double-quotes.
407  */
408 int _spawnv(int flags, const char* name, const char* const* argv)
409 {
410   return _spawnve(flags, name, argv, NULL);
411 }
412
413 /*********************************************************************
414  *              _spawnvpe (MSVCRT.@)
415  *
416  * Like on Windows, this function does not handle arguments with spaces
417  * or double-quotes.
418  */
419 int _spawnvpe(int flags, const char* name, const char* const* argv,
420                             const char* const* envv)
421 {
422   char fullname[MAX_PATH];
423   _searchenv(name, "PATH", fullname);
424   return _spawnve(flags, fullname[0] ? fullname : name, argv, envv);
425 }
426
427 /*********************************************************************
428  *              _spawnvp (MSVCRT.@)
429  *
430  * Like on Windows, this function does not handle arguments with spaces
431  * or double-quotes.
432  */
433 int _spawnvp(int flags, const char* name, const char* const* argv)
434 {
435   return _spawnvpe(flags, name, argv, NULL);
436 }
437
438 /*********************************************************************
439  *              _popen (MSVCRT.@)
440  */
441 MSVCRT_FILE* _popen(const char* command, const char* mode)
442 {
443   FIXME("(command=%s, mode=%s): stub\n", debugstr_a(command), debugstr_a(mode));
444   return NULL;
445 }
446
447 /*********************************************************************
448  *              _wpopen (MSVCRT.@)
449  */
450 MSVCRT_FILE* _wpopen(const MSVCRT_wchar_t* command, const MSVCRT_wchar_t* mode)
451 {
452   FIXME("(command=%s, mode=%s): stub\n", debugstr_w(command), debugstr_w(mode));
453   return NULL;
454 }
455
456 /*********************************************************************
457  *              _pclose (MSVCRT.@)
458  */
459 int _pclose(MSVCRT_FILE* file)
460 {
461   FIXME("(file=%p): stub\n", file);
462   return 0;
463 }
464
465 /*********************************************************************
466  *              system (MSVCRT.@)
467  */
468 int MSVCRT_system(const char* cmd)
469 {
470     char* cmdcopy;
471     int res;
472
473     /* Make a writable copy for CreateProcess */
474     cmdcopy=_strdup(cmd);
475     /* FIXME: should probably launch cmd interpreter in COMSPEC */
476     res=msvcrt_spawn(_P_WAIT, NULL, cmdcopy, NULL);
477     MSVCRT_free(cmdcopy);
478     return res;
479 }
480
481 /*********************************************************************
482  *              _loaddll (MSVCRT.@)
483  */
484 int _loaddll(const char* dllname)
485 {
486   return (int)LoadLibraryA(dllname);
487 }
488
489 /*********************************************************************
490  *              _unloaddll (MSVCRT.@)
491  */
492 int _unloaddll(int dll)
493 {
494   if (FreeLibrary((HMODULE)dll))
495     return 0;
496   else
497   {
498     int err = GetLastError();
499     MSVCRT__set_errno(err);
500     return err;
501   }
502 }
503
504 /*********************************************************************
505  *              _getdllprocaddr (MSVCRT.@)
506  */
507 void *_getdllprocaddr(int dll, const char *name, int ordinal)
508 {
509     if (name)
510     {
511         if (ordinal != -1) return NULL;
512         return GetProcAddress( (HMODULE)dll, name );
513     }
514     if (HIWORD(ordinal)) return NULL;
515     return GetProcAddress( (HMODULE)dll, (LPCSTR)(ULONG_PTR)ordinal );
516 }