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