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