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