- Implement console I/O
[wine.git] / dlls / crtdll / spawn.c
blobc13c5ba0a7ae6bae77f694e603278ea5b9b3f46b
1 /*
2 * CRTDLL spawn functions
3 *
4 * Copyright 1996,1998 Marcus Meissner
5 * Copyright 1996 Jukka Iivonen
6 * Copyright 1997,2000 Uwe Bonnes
7 * Copyright 2000 Jon Griffiths
9 * These functions differ in whether they pass arguments as an array
10 * (v in the name) or as varags (l in the name), whether they
11 * seach the path (p in the name) and/or whether they take an
12 * environment (e in the name) or pass the parents environment.
13 * Args as Search Take
14 * Name varargs? path? environment?
15 * spawnl N N N
16 * spawnle N N Y
17 * spawnlp N Y N
18 * spawnlpe N Y Y
19 * spawnv Y N N
20 * spawnve Y N Y
21 * spawnvp Y Y N
22 * spawnvpe Y Y Y
24 * Implementation Notes:
25 * MT Safe - But only because of missing functionality.
27 * After translating input arguments into the required format for
28 * CreateProcess(), the internal function __CRTDLL__spawn() is
29 * called to perform the actual spawning.
31 * FIXME:
32 * -File handles need some special handling. Sometimes children get
33 * open file handles, sometimes not. The docs are confusing.
34 * -No check for maximum path/argument/environment size is done.
35 * Unresolved issues Uwe Bonnes 970904:
36 * -system-call calls another wine process, but without debugging arguments
37 * and uses the first wine executable in the path
40 #include "crtdll.h"
41 #include <errno.h>
42 #include <stdlib.h>
45 DEFAULT_DEBUG_CHANNEL(crtdll);
47 /* Process creation flags */
48 #define _P_WAIT 0
49 #define _P_NOWAIT 1
50 #define _P_OVERLAY 2
51 #define _P_NOWAITO 3
52 #define _P_DETACH 4
55 extern void __CRTDLL__set_errno(ULONG err);
56 extern LPVOID __cdecl CRTDLL_calloc(DWORD size, DWORD count);
57 extern VOID __cdecl CRTDLL_free(void *ptr);
58 extern VOID __cdecl CRTDLL__exit(LONG ret);
59 extern INT CRTDLL_doserrno;
62 /* INTERNAL: Spawn a child process */
63 static int __CRTDLL__spawn(INT flags, LPCSTR exe, LPSTR args, LPSTR env)
65 STARTUPINFOA si;
66 PROCESS_INFORMATION pi;
68 if ((unsigned)flags > _P_DETACH)
70 CRTDLL_errno = EINVAL;
71 return -1;
74 FIXME(":must dup/kill streams for child process\n");
76 memset(&si, 0, sizeof(si));
77 si.cb = sizeof(si);
79 if (!CreateProcessA(exe, args, NULL, NULL, TRUE,
80 flags == _P_DETACH ? DETACHED_PROCESS : 0,
81 env, NULL, &si, &pi))
83 __CRTDLL__set_errno(GetLastError());
84 return -1;
87 switch(flags)
89 case _P_WAIT:
90 WaitForSingleObject(pi.hProcess,-1); /* wait forvever */
91 GetExitCodeProcess(pi.hProcess,&pi.dwProcessId);
92 CloseHandle(pi.hProcess);
93 CloseHandle(pi.hThread);
94 return pi.dwProcessId;
95 case _P_DETACH:
96 CloseHandle(pi.hProcess);
97 pi.hProcess = 0;
98 /* fall through */
99 case _P_NOWAIT:
100 case _P_NOWAITO:
101 CloseHandle(pi.hThread);
102 return pi.hProcess;
103 case _P_OVERLAY:
104 CRTDLL__exit(0);
106 return -1; /* cant reach here */
110 /* INTERNAL: Convert argv list to a single 'delim'-seperated string */
111 static LPSTR __CRTDLL__argvtos(LPCSTR *arg, CHAR delim)
113 LPCSTR *search = arg;
114 LONG size = 0;
115 LPSTR ret;
117 if (!arg && !delim)
118 return NULL;
120 /* get length */
121 while(*search)
123 size += strlen(*search) + 1;
124 search++;
127 if (!(ret = (LPSTR)CRTDLL_calloc(size + 1, 1)))
128 return NULL;
130 /* fill string */
131 search = arg;
132 size = 0;
133 while(*search)
135 int strsize = strlen(*search);
136 memcpy(ret+size,*search,strsize);
137 ret[size+strsize] = delim;
138 size += strsize + 1;
139 search++;
141 return ret;
145 /*********************************************************************
146 * _cwait (CRTDLL.069)
148 * Wait for a spawned process to finish.
150 INT __cdecl CRTDLL__cwait(PINT status, INT pid, INT action)
152 HANDLE hPid = (HANDLE)pid;
154 action = action; /* Remove warning */
156 if (!WaitForSingleObject(hPid, -1)) /* wait forvever */
158 if (status)
160 DWORD stat;
161 GetExitCodeProcess(hPid, &stat);
162 *status = (INT)stat;
164 return pid;
166 CRTDLL_doserrno = GetLastError();
168 if (CRTDLL_doserrno == ERROR_INVALID_HANDLE)
169 CRTDLL_errno = ECHILD;
170 else
171 __CRTDLL__set_errno(CRTDLL_doserrno);
173 return status ? *status = -1 : -1;
177 /*********************************************************************
178 * _spawnv (CRTDLL.273)
180 * Spawn a process.
182 HANDLE __cdecl CRTDLL__spawnv(INT flags, LPCSTR name, LPCSTR *argv)
184 return CRTDLL__spawnve(flags, name, argv, NULL);
188 /*********************************************************************
189 * _spawnve (CRTDLL.274)
191 * Spawn a process.
193 HANDLE __cdecl CRTDLL__spawnve(INT flags, LPCSTR name, LPCSTR *argv, LPCSTR *envv)
195 LPSTR args = __CRTDLL__argvtos(argv,' ');
196 LPSTR envs = __CRTDLL__argvtos(envv,0);
197 LPCSTR fullname = name;
198 HANDLE ret = -1;
200 FIXME(":not translating name %s to locate program\n",fullname);
201 TRACE(":call (%s), params (%s), env (%s)\n",name,args,envs?"Custom":"Null");
203 if (args)
205 ret = __CRTDLL__spawn(flags, fullname, args, envs);
206 CRTDLL_free(args);
208 if (envs)
209 CRTDLL_free(envs);
211 return ret;
215 /*********************************************************************
216 * _spawnvp (CRTDLL.275)
218 * Spawn a process.
220 HANDLE __cdecl CRTDLL__spawnvp(INT flags, LPCSTR name, LPCSTR *argv)
222 return CRTDLL__spawnvpe(flags, name, argv, NULL);
226 /*********************************************************************
227 * _spawnvpe (CRTDLL.276)
229 * Spawn a process.
231 HANDLE __cdecl CRTDLL__spawnvpe(INT flags, LPCSTR name, LPCSTR *argv, LPCSTR *envv)
233 char fullname[MAX_PATH];
235 CRTDLL__searchenv(name, "PATH", fullname);
236 return CRTDLL__spawnve(flags, fullname[0] ? fullname : name, argv, envv);
240 /*********************************************************************
241 * system (CRTDLL.485)
243 * Spawn an O/S process.
245 INT __cdecl CRTDLL_system(LPCSTR cmd)
247 /* FIXME: should probably launch cmd interpreter in COMSPEC */
248 return __CRTDLL__spawn(_P_WAIT, cmd, NULL, NULL);