Winspool expects NULLs to be preserved in ascii to unicode
[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(p,*a,len);
135     p += len;
136     *p++ = delim;
137     a++;
138   }
139   if (delim && p > ret) p[-1] = 0;
140   else *p = 0;
141   return ret;
142 }
143
144 /* INTERNAL: Convert va_list to a single 'delim'-separated string, with an
145  * extra '\0' to terminate it
146  */
147 static char* msvcrt_valisttos(const char* arg0, va_list alist, char delim)
148 {
149   va_list alist2;
150   long size;
151   const char *arg;
152   char* p;
153   char *ret;
154
155 #if HAVE_VA_COPY
156   va_copy(alist2,alist);
157 #else
158 # if HAVE___VA_COPY
159   __va_copy(alist2,alist);
160 # else
161   alist2 = alist;
162 # endif
163 #endif
164
165   if (!arg0 && !delim)
166   {
167       /* Return NULL for an empty environment list */
168       return NULL;
169   }
170
171   /* get length */
172   arg = arg0;
173   size = 0;
174   do {
175       size += strlen(arg) + 1;
176       arg = va_arg(alist, char*);
177   } while (arg != NULL);
178
179   ret = (char*)MSVCRT_malloc(size + 1);
180   if (!ret)
181     return NULL;
182
183   /* fill string */
184   arg = arg0;
185   p = ret;
186   do {
187       int len = strlen(arg);
188       memcpy(p,arg,len);
189       p += len;
190       *p++ = delim;
191       arg = va_arg(alist2, char*);
192   } while (arg != NULL);
193   if (delim && p > ret) p[-1] = 0;
194   else *p = 0;
195   return ret;
196 }
197
198 /*********************************************************************
199  *              _cwait (MSVCRT.@)
200  */
201 int _cwait(int *status, int pid, int action)
202 {
203   HANDLE hPid = (HANDLE)pid;
204   int doserrno;
205
206   action = action; /* Remove warning */
207
208   if (!WaitForSingleObject(hPid, -1)) /* wait forever */
209   {
210     if (status)
211     {
212       DWORD stat;
213       GetExitCodeProcess(hPid, &stat);
214       *status = (int)stat;
215     }
216     return (int)pid;
217   }
218   doserrno = GetLastError();
219
220   if (doserrno == ERROR_INVALID_HANDLE)
221   {
222     *MSVCRT__errno() =  MSVCRT_ECHILD;
223     *__doserrno() = doserrno;
224   }
225   else
226     MSVCRT__set_errno(doserrno);
227
228   return status ? *status = -1 : -1;
229 }
230
231 /*********************************************************************
232  *              _execl (MSVCRT.@)
233  *
234  * Like on Windows, this function does not handle arguments with spaces
235  * or double-quotes.
236  */
237 int _execl(const char* name, const char* arg0, ...)
238 {
239   va_list ap;
240   char * args;
241   int ret;
242
243   va_start(ap, arg0);
244   args = msvcrt_valisttos(arg0, ap, ' ');
245   va_end(ap);
246
247   ret = msvcrt_spawn(_P_OVERLAY, name, args, NULL);
248   MSVCRT_free(args);
249
250   return ret;
251 }
252
253 /*********************************************************************
254  *              _execlp (MSVCRT.@)
255  *
256  * Like on Windows, this function does not handle arguments with spaces
257  * or double-quotes.
258  */
259 int _execlp(const char* name, const char* arg0, ...)
260 {
261   va_list ap;
262   char * args;
263   int ret;
264   char fullname[MAX_PATH];
265
266   _searchenv(name, "PATH", fullname);
267
268   va_start(ap, arg0);
269   args = msvcrt_valisttos(arg0, ap, ' ');
270   va_end(ap);
271
272   ret = msvcrt_spawn(_P_OVERLAY, fullname[0] ? fullname : name, args, NULL);
273   MSVCRT_free(args);
274
275   return ret;
276 }
277
278 /*********************************************************************
279  *              _execv (MSVCRT.@)
280  *
281  * Like on Windows, this function does not handle arguments with spaces
282  * or double-quotes.
283  */
284 int _execv(const char* name, char* const* argv)
285 {
286   return _spawnve(_P_OVERLAY, name, (const char* const*) argv, NULL);
287 }
288
289 /*********************************************************************
290  *              _execve (MSVCRT.@)
291  *
292  * Like on Windows, this function does not handle arguments with spaces
293  * or double-quotes.
294  */
295 int _execve(const char* name, char* const* argv, const char* const* envv)
296 {
297   return _spawnve(_P_OVERLAY, name, (const char* const*) argv, envv);
298 }
299
300 /*********************************************************************
301  *              _execvpe (MSVCRT.@)
302  *
303  * Like on Windows, this function does not handle arguments with spaces
304  * or double-quotes.
305  */
306 int _execvpe(const char* name, char* const* argv, const char* const* envv)
307 {
308   char fullname[MAX_PATH];
309
310   _searchenv(name, "PATH", fullname);
311   return _spawnve(_P_OVERLAY, fullname[0] ? fullname : name,
312                   (const char* const*) argv, envv);
313 }
314
315 /*********************************************************************
316  *              _execvp (MSVCRT.@)
317  *
318  * Like on Windows, this function does not handle arguments with spaces
319  * or double-quotes.
320  */
321 int _execvp(const char* name, char* const* argv)
322 {
323   return _execvpe(name, argv, NULL);
324 }
325
326 /*********************************************************************
327  *              _spawnl (MSVCRT.@)
328  *
329  * Like on Windows, this function does not handle arguments with spaces
330  * or double-quotes.
331  */
332 int _spawnl(int flags, const char* name, const char* arg0, ...)
333 {
334   va_list ap;
335   char * args;
336   int ret;
337
338   va_start(ap, arg0);
339   args = msvcrt_valisttos(arg0, ap, ' ');
340   va_end(ap);
341
342   ret = msvcrt_spawn(flags, name, args, NULL);
343   MSVCRT_free(args);
344
345   return ret;
346 }
347
348 /*********************************************************************
349  *              _spawnlp (MSVCRT.@)
350  *
351  * Like on Windows, this function does not handle arguments with spaces
352  * or double-quotes.
353  */
354 int _spawnlp(int flags, const char* name, const char* arg0, ...)
355 {
356   va_list ap;
357   char * args;
358   int ret;
359   char fullname[MAX_PATH];
360
361   _searchenv(name, "PATH", fullname);
362
363   va_start(ap, arg0);
364   args = msvcrt_valisttos(arg0, ap, ' ');
365   va_end(ap);
366
367   ret = msvcrt_spawn(flags, fullname[0] ? fullname : name, args, NULL);
368   MSVCRT_free(args);
369
370   return ret;
371 }
372
373 /*********************************************************************
374  *              _spawnve (MSVCRT.@)
375  *
376  * Like on Windows, this function does not handle arguments with spaces
377  * or double-quotes.
378  */
379 int _spawnve(int flags, const char* name, const char* const* argv,
380                             const char* const* envv)
381 {
382   char * args = msvcrt_argvtos(argv,' ');
383   char * envs = msvcrt_argvtos(envv,0);
384   const char *fullname = name;
385   int ret = -1;
386
387   FIXME(":not translating name %s to locate program\n",fullname);
388   TRACE(":call (%s), params (%s), env (%s)\n",name,args,envs?"Custom":"Null");
389
390   if (args)
391   {
392     ret = msvcrt_spawn(flags, fullname, args, envs);
393     MSVCRT_free(args);
394   }
395   if (envs)
396     MSVCRT_free(envs);
397
398   return ret;
399 }
400
401 /*********************************************************************
402  *              _spawnv (MSVCRT.@)
403  *
404  * Like on Windows, this function does not handle arguments with spaces
405  * or double-quotes.
406  */
407 int _spawnv(int flags, const char* name, const char* const* argv)
408 {
409   return _spawnve(flags, name, argv, NULL);
410 }
411
412 /*********************************************************************
413  *              _spawnvpe (MSVCRT.@)
414  *
415  * Like on Windows, this function does not handle arguments with spaces
416  * or double-quotes.
417  */
418 int _spawnvpe(int flags, const char* name, const char* const* argv,
419                             const char* const* envv)
420 {
421   char fullname[MAX_PATH];
422   _searchenv(name, "PATH", fullname);
423   return _spawnve(flags, fullname[0] ? fullname : name, argv, envv);
424 }
425
426 /*********************************************************************
427  *              _spawnvp (MSVCRT.@)
428  *
429  * Like on Windows, this function does not handle arguments with spaces
430  * or double-quotes.
431  */
432 int _spawnvp(int flags, const char* name, const char* const* argv)
433 {
434   return _spawnvpe(flags, name, argv, NULL);
435 }
436
437 /*********************************************************************
438  *              system (MSVCRT.@)
439  */
440 int MSVCRT_system(const char* cmd)
441 {
442     char* cmdcopy;
443     int res;
444
445     /* Make a writable copy for CreateProcess */
446     cmdcopy=_strdup(cmd);
447     /* FIXME: should probably launch cmd interpreter in COMSPEC */
448     res=msvcrt_spawn(_P_WAIT, NULL, cmdcopy, NULL);
449     MSVCRT_free(cmdcopy);
450     return res;
451 }
452
453 /*********************************************************************
454  *              _loaddll (MSVCRT.@)
455  */
456 int _loaddll(const char* dllname)
457 {
458   return (int)LoadLibraryA(dllname);
459 }
460
461 /*********************************************************************
462  *              _unloaddll (MSVCRT.@)
463  */
464 int _unloaddll(int dll)
465 {
466   if (FreeLibrary((HMODULE)dll))
467     return 0;
468   else
469   {
470     int err = GetLastError();
471     MSVCRT__set_errno(err);
472     return err;
473   }
474 }