winmm: Avoid explicitly casting the pointer returned from Heap(Re)Alloc.
[wine.git] / dlls / msvcrt / process.c
blob630e378df87f28ee85426d921f13036109d870c8
1 /*
2 * msvcrt.dll spawn/exec functions
4 * Copyright 1996,1998 Marcus Meissner
5 * Copyright 1996 Jukka Iivonen
6 * Copyright 1997,2000 Uwe Bonnes
7 * Copyright 2000 Jon Griffiths
8 * Copyright 2007 Hans Leidekker
10 * This library is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU Lesser General Public
12 * License as published by the Free Software Foundation; either
13 * version 2.1 of the License, or (at your option) any later version.
15 * This library is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
18 * Lesser General Public License for more details.
20 * You should have received a copy of the GNU Lesser General Public
21 * License along with this library; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
24 * FIXME:
25 * -File handles need some special handling. Sometimes children get
26 * open file handles, sometimes not. The docs are confusing
27 * -No check for maximum path/argument/environment size is done
30 #include <fcntl.h>
31 #include <io.h>
32 #include <process.h>
33 #include <stdarg.h>
35 #include "msvcrt.h"
36 #include <winnls.h>
37 #include "mtdll.h"
38 #include "wine/debug.h"
40 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
42 static void msvcrt_search_executable(const wchar_t *name, wchar_t *fullname, int use_path)
44 static const wchar_t suffix[][5] =
45 {L".com", L".exe", L".bat", L".cmd"};
47 wchar_t buffer[MAX_PATH];
48 const wchar_t *env, *p, *end;
49 unsigned int i, name_len, path_len;
50 int extension = 1;
52 *fullname = '\0';
53 msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
55 end = name + MAX_PATH - 1;
56 for(p = name; p < end; p++)
57 if(!*p) break;
58 name_len = p - name;
60 /* FIXME extra-long names are silently truncated */
61 memcpy(buffer, name, name_len * sizeof(wchar_t));
62 buffer[name_len] = '\0';
64 /* try current dir first */
65 if (GetFileAttributesW(buffer) != INVALID_FILE_ATTRIBUTES)
67 wcscpy(fullname, buffer);
68 return;
71 for (p--; p >= name; p--)
72 if (*p == '\\' || *p == '/' || *p == ':' || *p == '.') break;
74 /* if there's no extension, try some well-known extensions */
75 if ((p < name || *p != '.') && name_len <= MAX_PATH - 5)
77 for (i = 0; i < 4; i++)
79 memcpy(buffer + name_len, suffix[i], 5 * sizeof(wchar_t));
80 if (GetFileAttributesW(buffer) != INVALID_FILE_ATTRIBUTES)
82 wcscpy(fullname, buffer);
83 return;
86 extension = 0;
89 if (!use_path || !(env = _wgetenv(L"PATH"))) return;
91 /* now try search path */
94 p = env;
95 while (*p && *p != ';') p++;
96 if (p == env) return;
98 path_len = p - env;
99 if (path_len + name_len <= MAX_PATH - 2)
101 memcpy(buffer, env, path_len * sizeof(wchar_t));
102 if (buffer[path_len] != '/' && buffer[path_len] != '\\')
104 buffer[path_len++] = '\\';
105 buffer[path_len] = '\0';
107 else buffer[path_len] = '\0';
109 wcscat(buffer, name);
110 if (GetFileAttributesW(buffer) != INVALID_FILE_ATTRIBUTES)
112 wcscpy(fullname, buffer);
113 return;
116 /* again, if there's no extension, try some well-known extensions */
117 if (!extension && path_len + name_len <= MAX_PATH - 5)
119 for (i = 0; i < 4; i++)
121 memcpy(buffer + path_len + name_len, suffix[i], 5 * sizeof(wchar_t));
122 if (GetFileAttributesW(buffer) != INVALID_FILE_ATTRIBUTES)
124 wcscpy(fullname, buffer);
125 return;
129 env = *p ? p + 1 : p;
130 } while(1);
133 static intptr_t msvcrt_spawn(int flags, const wchar_t* exe, wchar_t* cmdline,
134 wchar_t* env, int use_path)
136 STARTUPINFOW si;
137 PROCESS_INFORMATION pi;
138 wchar_t fullname[MAX_PATH];
139 DWORD create_flags = CREATE_UNICODE_ENVIRONMENT;
141 TRACE("%x %s %s %s %d\n", flags, debugstr_w(exe), debugstr_w(cmdline), debugstr_w(env), use_path);
143 if ((unsigned)flags > _P_DETACH)
145 *_errno() = EINVAL;
146 return -1;
149 msvcrt_search_executable(exe, fullname, use_path);
151 memset(&si, 0, sizeof(si));
152 si.cb = sizeof(si);
153 msvcrt_create_io_inherit_block(&si.cbReserved2, &si.lpReserved2);
154 if (flags == _P_DETACH) create_flags |= DETACHED_PROCESS;
155 if (!CreateProcessW(fullname, cmdline, NULL, NULL, TRUE,
156 create_flags, env, NULL, &si, &pi))
158 msvcrt_set_errno(GetLastError());
159 free(si.lpReserved2);
160 return -1;
163 free(si.lpReserved2);
164 switch(flags)
166 case _P_WAIT:
167 WaitForSingleObject(pi.hProcess, INFINITE);
168 GetExitCodeProcess(pi.hProcess,&pi.dwProcessId);
169 CloseHandle(pi.hProcess);
170 CloseHandle(pi.hThread);
171 return pi.dwProcessId;
172 case _P_DETACH:
173 CloseHandle(pi.hProcess);
174 pi.hProcess = 0;
175 /* fall through */
176 case _P_NOWAIT:
177 case _P_NOWAITO:
178 CloseHandle(pi.hThread);
179 return (intptr_t)pi.hProcess;
180 case _P_OVERLAY:
181 _exit(0);
183 return -1; /* can't reach here */
186 /* INTERNAL: Convert wide argv list to a single 'delim'-separated wide string, with an
187 * extra '\0' to terminate it.
189 static wchar_t* msvcrt_argvtos(const wchar_t* const* arg, wchar_t delim)
191 const wchar_t* const* a;
192 int size;
193 wchar_t* p;
194 wchar_t* ret;
196 if (!arg)
198 /* Return NULL for an empty environment list */
199 return NULL;
202 /* get length */
203 a = arg;
204 size = 0;
205 while (*a)
207 size += wcslen(*a) + 1;
208 a++;
211 ret = malloc((size + 1) * sizeof(wchar_t));
212 if (!ret)
213 return NULL;
215 /* fill string */
216 a = arg;
217 p = ret;
218 while (*a)
220 int len = wcslen(*a);
221 memcpy(p,*a,len * sizeof(wchar_t));
222 p += len;
223 *p++ = delim;
224 a++;
226 if (delim && p > ret) p[-1] = 0;
227 else *p = 0;
228 return ret;
231 /* INTERNAL: Convert ansi argv list to a single 'delim'-separated wide string, with an
232 * extra '\0' to terminate it.
234 static wchar_t *msvcrt_argvtos_aw(const char * const *arg, wchar_t delim)
236 const char * const *a;
237 unsigned int len;
238 wchar_t *p, *ret;
240 if (!arg)
242 /* Return NULL for an empty environment list */
243 return NULL;
246 /* get length */
247 a = arg;
248 len = 0;
249 while (*a)
251 len += MultiByteToWideChar(CP_ACP, 0, *a, -1, NULL, 0);
252 a++;
255 ret = malloc((len + 1) * sizeof(wchar_t));
256 if (!ret)
257 return NULL;
259 /* fill string */
260 a = arg;
261 p = ret;
262 while (*a)
264 p += MultiByteToWideChar(CP_ACP, 0, *a, strlen(*a), p, len - (p - ret));
265 *p++ = delim;
266 a++;
268 if (delim && p > ret) p[-1] = 0;
269 else *p = 0;
270 return ret;
273 /* INTERNAL: Convert wide va_list to a single 'delim'-separated wide string, with an
274 * extra '\0' to terminate it.
276 static wchar_t *msvcrt_valisttos(const wchar_t *arg0, va_list alist, wchar_t delim)
278 unsigned int size = 0, pos = 0;
279 const wchar_t *arg;
280 wchar_t *new, *ret = NULL;
282 for (arg = arg0; arg; arg = va_arg( alist, wchar_t * ))
284 unsigned int len = wcslen( arg ) + 1;
285 if (pos + len >= size)
287 size = max( 256, size * 2 );
288 size = max( size, pos + len + 1 );
289 if (!(new = realloc( ret, size * sizeof(wchar_t) )))
291 free( ret );
292 return NULL;
294 ret = new;
296 wcscpy( ret + pos, arg );
297 pos += len;
298 ret[pos - 1] = delim;
300 if (pos)
302 if (delim) ret[pos - 1] = 0;
303 else ret[pos] = 0;
305 return ret;
308 /* INTERNAL: Convert ansi va_list to a single 'delim'-separated wide string, with an
309 * extra '\0' to terminate it.
311 static wchar_t *msvcrt_valisttos_aw(const char *arg0, va_list alist, wchar_t delim)
313 unsigned int size = 0, pos = 0;
314 const char *arg;
315 wchar_t *new, *ret = NULL;
317 for (arg = arg0; arg; arg = va_arg( alist, char * ))
319 unsigned int len = MultiByteToWideChar( CP_ACP, 0, arg, -1, NULL, 0 );
320 if (pos + len >= size)
322 size = max( 256, size * 2 );
323 size = max( size, pos + len + 1 );
324 if (!(new = realloc( ret, size * sizeof(wchar_t) )))
326 free( ret );
327 return NULL;
329 ret = new;
331 pos += MultiByteToWideChar( CP_ACP, 0, arg, -1, ret + pos, size - pos );
332 ret[pos - 1] = delim;
334 if (pos)
336 if (delim) ret[pos - 1] = 0;
337 else ret[pos] = 0;
339 return ret;
342 /* INTERNAL: retrieve COMSPEC environment variable */
343 static wchar_t *msvcrt_get_comspec(void)
345 wchar_t *ret;
346 unsigned int len;
348 if (!(len = GetEnvironmentVariableW(L"COMSPEC", NULL, 0))) len = 4;
349 if ((ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(wchar_t))))
351 if (!GetEnvironmentVariableW(L"COMSPEC", ret, len)) wcscpy(ret, L"cmd");
353 return ret;
356 /*********************************************************************
357 * _cwait (MSVCRT.@)
359 intptr_t CDECL _cwait(int *status, intptr_t pid, int action)
361 HANDLE hPid = (HANDLE)pid;
362 int doserrno;
364 if (!WaitForSingleObject(hPid, INFINITE))
366 if (status)
368 DWORD stat;
369 GetExitCodeProcess(hPid, &stat);
370 *status = (int)stat;
372 return pid;
374 doserrno = GetLastError();
376 if (doserrno == ERROR_INVALID_HANDLE)
378 *_errno() = ECHILD;
379 *__doserrno() = doserrno;
381 else
382 msvcrt_set_errno(doserrno);
384 return status ? *status = -1 : -1;
387 /*********************************************************************
388 * _wexecl (MSVCRT.@)
390 * Unicode version of _execl
392 intptr_t WINAPIV _wexecl(const wchar_t* name, const wchar_t* arg0, ...)
394 va_list ap;
395 wchar_t *args;
396 intptr_t ret;
398 va_start(ap, arg0);
399 args = msvcrt_valisttos(arg0, ap, ' ');
400 va_end(ap);
402 ret = msvcrt_spawn(_P_OVERLAY, name, args, NULL, 0);
404 free(args);
405 return ret;
408 /*********************************************************************
409 * _execl (MSVCRT.@)
411 * Like on Windows, this function does not handle arguments with spaces
412 * or double-quotes.
414 intptr_t WINAPIV _execl(const char* name, const char* arg0, ...)
416 va_list ap;
417 wchar_t *nameW, *args;
418 intptr_t ret;
420 if (!(nameW = msvcrt_wstrdupa(name))) return -1;
422 va_start(ap, arg0);
423 args = msvcrt_valisttos_aw(arg0, ap, ' ');
424 va_end(ap);
426 ret = msvcrt_spawn(_P_OVERLAY, nameW, args, NULL, 0);
428 free(nameW);
429 free(args);
430 return ret;
433 /*********************************************************************
434 * _wexecle (MSVCRT.@)
436 * Unicode version of _execle
438 intptr_t WINAPIV _wexecle(const wchar_t* name, const wchar_t* arg0, ...)
440 va_list ap;
441 wchar_t *args, *envs = NULL;
442 const wchar_t * const *envp;
443 intptr_t ret;
445 va_start(ap, arg0);
446 args = msvcrt_valisttos(arg0, ap, ' ');
447 va_end(ap);
449 va_start(ap, arg0);
450 while (va_arg( ap, wchar_t * ) != NULL) /*nothing*/;
451 envp = va_arg( ap, const wchar_t * const * );
452 if (envp) envs = msvcrt_argvtos(envp, 0);
453 va_end(ap);
455 ret = msvcrt_spawn(_P_OVERLAY, name, args, envs, 0);
457 free(args);
458 free(envs);
459 return ret;
462 /*********************************************************************
463 * _execle (MSVCRT.@)
465 intptr_t WINAPIV _execle(const char* name, const char* arg0, ...)
467 va_list ap;
468 wchar_t *nameW, *args, *envs = NULL;
469 const char * const *envp;
470 intptr_t ret;
472 if (!(nameW = msvcrt_wstrdupa(name))) return -1;
474 va_start(ap, arg0);
475 args = msvcrt_valisttos_aw(arg0, ap, ' ');
476 va_end(ap);
478 va_start(ap, arg0);
479 while (va_arg( ap, char * ) != NULL) /*nothing*/;
480 envp = va_arg( ap, const char * const * );
481 if (envp) envs = msvcrt_argvtos_aw(envp, 0);
482 va_end(ap);
484 ret = msvcrt_spawn(_P_OVERLAY, nameW, args, envs, 0);
486 free(nameW);
487 free(args);
488 free(envs);
489 return ret;
492 /*********************************************************************
493 * _wexeclp (MSVCRT.@)
495 * Unicode version of _execlp
497 intptr_t WINAPIV _wexeclp(const wchar_t* name, const wchar_t* arg0, ...)
499 va_list ap;
500 wchar_t *args;
501 intptr_t ret;
503 va_start(ap, arg0);
504 args = msvcrt_valisttos(arg0, ap, ' ');
505 va_end(ap);
507 ret = msvcrt_spawn(_P_OVERLAY, name, args, NULL, 1);
509 free(args);
510 return ret;
513 /*********************************************************************
514 * _execlp (MSVCRT.@)
516 * Like on Windows, this function does not handle arguments with spaces
517 * or double-quotes.
519 intptr_t WINAPIV _execlp(const char* name, const char* arg0, ...)
521 va_list ap;
522 wchar_t *nameW, *args;
523 intptr_t ret;
525 if (!(nameW = msvcrt_wstrdupa(name))) return -1;
527 va_start(ap, arg0);
528 args = msvcrt_valisttos_aw(arg0, ap, ' ');
529 va_end(ap);
531 ret = msvcrt_spawn(_P_OVERLAY, nameW, args, NULL, 1);
533 free(nameW);
534 free(args);
535 return ret;
538 /*********************************************************************
539 * _wexeclpe (MSVCRT.@)
541 * Unicode version of _execlpe
543 intptr_t WINAPIV _wexeclpe(const wchar_t* name, const wchar_t* arg0, ...)
545 va_list ap;
546 wchar_t *args, *envs = NULL;
547 const wchar_t * const *envp;
548 intptr_t ret;
550 va_start(ap, arg0);
551 args = msvcrt_valisttos(arg0, ap, ' ');
552 va_end(ap);
554 va_start(ap, arg0);
555 while (va_arg( ap, wchar_t * ) != NULL) /*nothing*/;
556 envp = va_arg( ap, const wchar_t * const * );
557 if (envp) envs = msvcrt_argvtos(envp, 0);
558 va_end(ap);
560 ret = msvcrt_spawn(_P_OVERLAY, name, args, envs, 1);
562 free(args);
563 free(envs);
564 return ret;
567 /*********************************************************************
568 * _execlpe (MSVCRT.@)
570 intptr_t WINAPIV _execlpe(const char* name, const char* arg0, ...)
572 va_list ap;
573 wchar_t *nameW, *args, *envs = NULL;
574 const char * const *envp;
575 intptr_t ret;
577 if (!(nameW = msvcrt_wstrdupa(name))) return -1;
579 va_start(ap, arg0);
580 args = msvcrt_valisttos_aw(arg0, ap, ' ');
581 va_end(ap);
583 va_start(ap, arg0);
584 while (va_arg( ap, char * ) != NULL) /*nothing*/;
585 envp = va_arg( ap, const char * const * );
586 if (envp) envs = msvcrt_argvtos_aw(envp, 0);
587 va_end(ap);
589 ret = msvcrt_spawn(_P_OVERLAY, nameW, args, envs, 1);
591 free(nameW);
592 free(args);
593 free(envs);
594 return ret;
597 /*********************************************************************
598 * _wexecv (MSVCRT.@)
600 * Unicode version of _execv
602 intptr_t CDECL _wexecv(const wchar_t* name, const wchar_t* const* argv)
604 return _wspawnve(_P_OVERLAY, name, argv, NULL);
607 /*********************************************************************
608 * _execv (MSVCRT.@)
610 * Like on Windows, this function does not handle arguments with spaces
611 * or double-quotes.
613 intptr_t CDECL _execv(const char* name, const char* const* argv)
615 return _spawnve(_P_OVERLAY, name, argv, NULL);
618 /*********************************************************************
619 * _wexecve (MSVCRT.@)
621 * Unicode version of _execve
623 intptr_t CDECL _wexecve(const wchar_t* name, const wchar_t* const* argv, const wchar_t* const* envv)
625 return _wspawnve(_P_OVERLAY, name, argv, envv);
628 /*********************************************************************
629 * _execve (MSVCRT.@)
631 * Like on Windows, this function does not handle arguments with spaces
632 * or double-quotes.
634 intptr_t CDECL _execve(const char* name, const char* const* argv, const char* const* envv)
636 return _spawnve(_P_OVERLAY, name, argv, envv);
639 /*********************************************************************
640 * _wexecvpe (MSVCRT.@)
642 * Unicode version of _execvpe
644 intptr_t CDECL _wexecvpe(const wchar_t* name, const wchar_t* const* argv, const wchar_t* const* envv)
646 return _wspawnvpe(_P_OVERLAY, name, argv, envv);
649 /*********************************************************************
650 * _execvpe (MSVCRT.@)
652 * Like on Windows, this function does not handle arguments with spaces
653 * or double-quotes.
655 intptr_t CDECL _execvpe(const char* name, const char* const* argv, const char* const* envv)
657 return _spawnvpe(_P_OVERLAY, name, argv, envv);
660 /*********************************************************************
661 * _wexecvp (MSVCRT.@)
663 * Unicode version of _execvp
665 intptr_t CDECL _wexecvp(const wchar_t* name, const wchar_t* const* argv)
667 return _wexecvpe(name, argv, NULL);
670 /*********************************************************************
671 * _execvp (MSVCRT.@)
673 * Like on Windows, this function does not handle arguments with spaces
674 * or double-quotes.
676 intptr_t CDECL _execvp(const char* name, const char* const* argv)
678 return _execvpe(name, argv, NULL);
681 /*********************************************************************
682 * _wspawnl (MSVCRT.@)
684 * Unicode version of _spawnl
686 intptr_t WINAPIV _wspawnl(int flags, const wchar_t* name, const wchar_t* arg0, ...)
688 va_list ap;
689 wchar_t *args;
690 intptr_t ret;
692 va_start(ap, arg0);
693 args = msvcrt_valisttos(arg0, ap, ' ');
694 va_end(ap);
696 ret = msvcrt_spawn(flags, name, args, NULL, 0);
698 free(args);
699 return ret;
702 /*********************************************************************
703 * _spawnl (MSVCRT.@)
705 * Like on Windows, this function does not handle arguments with spaces
706 * or double-quotes.
708 intptr_t WINAPIV _spawnl(int flags, const char* name, const char* arg0, ...)
710 va_list ap;
711 wchar_t *nameW, *args;
712 intptr_t ret;
714 if (!(nameW = msvcrt_wstrdupa(name))) return -1;
716 va_start(ap, arg0);
717 args = msvcrt_valisttos_aw(arg0, ap, ' ');
718 va_end(ap);
720 ret = msvcrt_spawn(flags, nameW, args, NULL, 0);
722 free(nameW);
723 free(args);
724 return ret;
727 /*********************************************************************
728 * _wspawnle (MSVCRT.@)
730 * Unicode version of _spawnle
732 intptr_t WINAPIV _wspawnle(int flags, const wchar_t* name, const wchar_t* arg0, ...)
734 va_list ap;
735 wchar_t *args, *envs = NULL;
736 const wchar_t * const *envp;
737 intptr_t ret;
739 va_start(ap, arg0);
740 args = msvcrt_valisttos(arg0, ap, ' ');
741 va_end(ap);
743 va_start(ap, arg0);
744 while (va_arg( ap, wchar_t * ) != NULL) /*nothing*/;
745 envp = va_arg( ap, const wchar_t * const * );
746 if (envp) envs = msvcrt_argvtos(envp, 0);
747 va_end(ap);
749 ret = msvcrt_spawn(flags, name, args, envs, 0);
751 free(args);
752 free(envs);
753 return ret;
756 /*********************************************************************
757 * _spawnle (MSVCRT.@)
759 intptr_t WINAPIV _spawnle(int flags, const char* name, const char* arg0, ...)
761 va_list ap;
762 wchar_t *nameW, *args, *envs = NULL;
763 const char * const *envp;
764 intptr_t ret;
766 if (!(nameW = msvcrt_wstrdupa(name))) return -1;
768 va_start(ap, arg0);
769 args = msvcrt_valisttos_aw(arg0, ap, ' ');
770 va_end(ap);
772 va_start(ap, arg0);
773 while (va_arg( ap, char * ) != NULL) /*nothing*/;
774 envp = va_arg( ap, const char * const * );
775 if (envp) envs = msvcrt_argvtos_aw(envp, 0);
776 va_end(ap);
778 ret = msvcrt_spawn(flags, nameW, args, envs, 0);
780 free(nameW);
781 free(args);
782 free(envs);
783 return ret;
786 /*********************************************************************
787 * _wspawnlp (MSVCRT.@)
789 * Unicode version of _spawnlp
791 intptr_t WINAPIV _wspawnlp(int flags, const wchar_t* name, const wchar_t* arg0, ...)
793 va_list ap;
794 wchar_t *args;
795 intptr_t ret;
797 va_start(ap, arg0);
798 args = msvcrt_valisttos(arg0, ap, ' ');
799 va_end(ap);
801 ret = msvcrt_spawn(flags, name, args, NULL, 1);
803 free(args);
804 return ret;
807 /*********************************************************************
808 * _spawnlp (MSVCRT.@)
810 * Like on Windows, this function does not handle arguments with spaces
811 * or double-quotes.
813 intptr_t WINAPIV _spawnlp(int flags, const char* name, const char* arg0, ...)
815 va_list ap;
816 wchar_t *nameW, *args;
817 intptr_t ret;
819 if (!(nameW = msvcrt_wstrdupa(name))) return -1;
821 va_start(ap, arg0);
822 args = msvcrt_valisttos_aw(arg0, ap, ' ');
823 va_end(ap);
825 ret = msvcrt_spawn(flags, nameW, args, NULL, 1);
827 free(nameW);
828 free(args);
829 return ret;
832 /*********************************************************************
833 * _wspawnlpe (MSVCRT.@)
835 * Unicode version of _spawnlpe
837 intptr_t WINAPIV _wspawnlpe(int flags, const wchar_t* name, const wchar_t* arg0, ...)
839 va_list ap;
840 wchar_t *args, *envs = NULL;
841 const wchar_t * const *envp;
842 intptr_t ret;
844 va_start(ap, arg0);
845 args = msvcrt_valisttos(arg0, ap, ' ');
846 va_end(ap);
848 va_start(ap, arg0);
849 while (va_arg( ap, wchar_t * ) != NULL) /*nothing*/;
850 envp = va_arg( ap, const wchar_t * const * );
851 if (envp) envs = msvcrt_argvtos(envp, 0);
852 va_end(ap);
854 ret = msvcrt_spawn(flags, name, args, envs, 1);
856 free(args);
857 free(envs);
858 return ret;
861 /*********************************************************************
862 * _spawnlpe (MSVCRT.@)
864 intptr_t WINAPIV _spawnlpe(int flags, const char* name, const char* arg0, ...)
866 va_list ap;
867 wchar_t *nameW, *args, *envs = NULL;
868 const char * const *envp;
869 intptr_t ret;
871 if (!(nameW = msvcrt_wstrdupa(name))) return -1;
873 va_start(ap, arg0);
874 args = msvcrt_valisttos_aw(arg0, ap, ' ');
875 va_end(ap);
877 va_start(ap, arg0);
878 while (va_arg( ap, char * ) != NULL) /*nothing*/;
879 envp = va_arg( ap, const char * const * );
880 if (envp) envs = msvcrt_argvtos_aw(envp, 0);
881 va_end(ap);
883 ret = msvcrt_spawn(flags, nameW, args, envs, 1);
885 free(nameW);
886 free(args);
887 free(envs);
888 return ret;
891 /*********************************************************************
892 * _spawnve (MSVCRT.@)
894 * Like on Windows, this function does not handle arguments with spaces
895 * or double-quotes.
897 intptr_t CDECL _spawnve(int flags, const char* name, const char* const* argv,
898 const char* const* envv)
900 wchar_t *nameW, *args, *envs;
901 intptr_t ret;
903 if (!(nameW = msvcrt_wstrdupa(name))) return -1;
905 args = msvcrt_argvtos_aw(argv, ' ');
906 envs = msvcrt_argvtos_aw(envv, 0);
908 ret = msvcrt_spawn(flags, nameW, args, envs, 0);
910 free(nameW);
911 free(args);
912 free(envs);
913 return ret;
916 /*********************************************************************
917 * _wspawnve (MSVCRT.@)
919 * Unicode version of _spawnve
921 intptr_t CDECL _wspawnve(int flags, const wchar_t* name, const wchar_t* const* argv,
922 const wchar_t* const* envv)
924 wchar_t *args, *envs;
925 intptr_t ret;
927 args = msvcrt_argvtos(argv, ' ');
928 envs = msvcrt_argvtos(envv, 0);
930 ret = msvcrt_spawn(flags, name, args, envs, 0);
932 free(args);
933 free(envs);
934 return ret;
937 /*********************************************************************
938 * _spawnv (MSVCRT.@)
940 * Like on Windows, this function does not handle arguments with spaces
941 * or double-quotes.
943 intptr_t CDECL _spawnv(int flags, const char* name, const char* const* argv)
945 return _spawnve(flags, name, argv, NULL);
948 /*********************************************************************
949 * _wspawnv (MSVCRT.@)
951 * Unicode version of _spawnv
953 intptr_t CDECL _wspawnv(int flags, const wchar_t* name, const wchar_t* const* argv)
955 return _wspawnve(flags, name, argv, NULL);
958 /*********************************************************************
959 * _spawnvpe (MSVCRT.@)
961 * Like on Windows, this function does not handle arguments with spaces
962 * or double-quotes.
964 intptr_t CDECL _spawnvpe(int flags, const char* name, const char* const* argv,
965 const char* const* envv)
967 wchar_t *nameW, *args, *envs;
968 intptr_t ret;
970 if (!(nameW = msvcrt_wstrdupa(name))) return -1;
972 args = msvcrt_argvtos_aw(argv, ' ');
973 envs = msvcrt_argvtos_aw(envv, 0);
975 ret = msvcrt_spawn(flags, nameW, args, envs, 1);
977 free(nameW);
978 free(args);
979 free(envs);
980 return ret;
983 /*********************************************************************
984 * _wspawnvpe (MSVCRT.@)
986 * Unicode version of _spawnvpe
988 intptr_t CDECL _wspawnvpe(int flags, const wchar_t* name, const wchar_t* const* argv,
989 const wchar_t* const* envv)
991 wchar_t *args, *envs;
992 intptr_t ret;
994 args = msvcrt_argvtos(argv, ' ');
995 envs = msvcrt_argvtos(envv, 0);
997 ret = msvcrt_spawn(flags, name, args, envs, 1);
999 free(args);
1000 free(envs);
1001 return ret;
1004 /*********************************************************************
1005 * _spawnvp (MSVCRT.@)
1007 * Like on Windows, this function does not handle arguments with spaces
1008 * or double-quotes.
1010 intptr_t CDECL _spawnvp(int flags, const char* name, const char* const* argv)
1012 return _spawnvpe(flags, name, argv, NULL);
1015 /*********************************************************************
1016 * _wspawnvp (MSVCRT.@)
1018 * Unicode version of _spawnvp
1020 intptr_t CDECL _wspawnvp(int flags, const wchar_t* name, const wchar_t* const* argv)
1022 return _wspawnvpe(flags, name, argv, NULL);
1025 static struct popen_handle {
1026 FILE *f;
1027 HANDLE proc;
1028 } *popen_handles;
1029 static DWORD popen_handles_size;
1031 void msvcrt_free_popen_data(void)
1033 free(popen_handles);
1036 /*********************************************************************
1037 * _wpopen (MSVCRT.@)
1039 * Unicode version of _popen
1041 FILE* CDECL _wpopen(const wchar_t* command, const wchar_t* mode)
1043 wchar_t *comspec, *fullcmd, fullname[MAX_PATH];
1044 int textmode, fds[2], fd_parent, fd_child;
1045 struct popen_handle *container;
1046 PROCESS_INFORMATION pi;
1047 BOOL read_pipe = TRUE;
1048 const wchar_t *p;
1049 unsigned int len;
1050 STARTUPINFOW si;
1051 FILE *ret;
1052 DWORD i;
1053 BOOL r;
1055 TRACE("(command=%s, mode=%s)\n", debugstr_w(command), debugstr_w(mode));
1057 if (!command || !mode)
1058 return NULL;
1060 _get_fmode(&textmode);
1061 textmode &= _O_BINARY | _O_TEXT;
1062 textmode |= _O_NOINHERIT;
1063 for (p = mode; *p; p++)
1065 switch (*p)
1067 case 'W':
1068 case 'w':
1069 read_pipe = FALSE;
1070 break;
1071 case 'B':
1072 case 'b':
1073 textmode |= _O_BINARY;
1074 textmode &= ~_O_TEXT;
1075 break;
1076 case 'T':
1077 case 't':
1078 textmode |= _O_TEXT;
1079 textmode &= ~_O_BINARY;
1080 break;
1083 if (_pipe(fds, 0, textmode) == -1)
1084 return NULL;
1086 if (read_pipe)
1088 fd_parent = fds[0];
1089 fd_child = _dup(fds[1]);
1090 _close(fds[1]);
1092 else
1094 fd_parent = fds[1];
1095 fd_child = _dup(fds[0]);
1096 _close(fds[0]);
1098 if (fd_child == -1)
1100 _close(fd_parent);
1101 return NULL;
1103 ret = _wfdopen(fd_parent, mode);
1104 if (!ret)
1106 _close(fd_child);
1107 return NULL;
1110 _lock(_POPEN_LOCK);
1111 for (i = 0; i < popen_handles_size; i++)
1113 if (!popen_handles[i].f)
1114 break;
1116 if (i == popen_handles_size)
1118 i = (popen_handles_size ? popen_handles_size * 2 : 8);
1119 container = realloc(popen_handles, i * sizeof(*container));
1120 if (!container) goto error;
1122 popen_handles = container;
1123 container = popen_handles + popen_handles_size;
1124 memset(container, 0, (i - popen_handles_size) * sizeof(*container));
1125 popen_handles_size = i;
1127 else container = popen_handles + i;
1129 if (!(comspec = msvcrt_get_comspec())) goto error;
1130 len = wcslen(comspec) + wcslen(command) + 5;
1132 if (!(fullcmd = HeapAlloc(GetProcessHeap(), 0, len * sizeof(wchar_t))))
1134 HeapFree(GetProcessHeap(), 0, comspec);
1135 goto error;
1138 wcscpy(fullcmd, comspec);
1139 wcscat(fullcmd, L" /c ");
1140 wcscat(fullcmd, command);
1141 msvcrt_search_executable(comspec, fullname, 1);
1143 memset(&si, 0, sizeof(si));
1144 si.cb = sizeof(si);
1145 si.dwFlags = STARTF_USESTDHANDLES;
1146 if (read_pipe)
1148 si.hStdInput = (HANDLE)_get_osfhandle(STDIN_FILENO);
1149 si.hStdOutput = (HANDLE)_get_osfhandle(fd_child);
1151 else
1153 si.hStdInput = (HANDLE)_get_osfhandle(fd_child);
1154 si.hStdOutput = (HANDLE)_get_osfhandle(STDOUT_FILENO);
1156 si.hStdError = (HANDLE)_get_osfhandle(STDERR_FILENO);
1157 r = CreateProcessW(fullname, fullcmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi);
1158 HeapFree(GetProcessHeap(), 0, comspec);
1159 HeapFree(GetProcessHeap(), 0, fullcmd);
1160 if (!r)
1162 msvcrt_set_errno(GetLastError());
1163 goto error;
1165 CloseHandle(pi.hThread);
1166 _close(fd_child);
1167 container->proc = pi.hProcess;
1168 container->f = ret;
1169 _unlock(_POPEN_LOCK);
1170 return ret;
1172 error:
1173 _unlock(_POPEN_LOCK);
1174 _close(fd_child);
1175 fclose(ret);
1176 return NULL;
1179 /*********************************************************************
1180 * _popen (MSVCRT.@)
1182 FILE* CDECL _popen(const char* command, const char* mode)
1184 FILE *ret;
1185 wchar_t *cmdW, *modeW;
1187 TRACE("(command=%s, mode=%s)\n", debugstr_a(command), debugstr_a(mode));
1189 if (!command || !mode)
1190 return NULL;
1192 if (!(cmdW = msvcrt_wstrdupa(command))) return NULL;
1193 if (!(modeW = msvcrt_wstrdupa(mode)))
1195 free(cmdW);
1196 return NULL;
1199 ret = _wpopen(cmdW, modeW);
1201 free(cmdW);
1202 free(modeW);
1203 return ret;
1206 /*********************************************************************
1207 * _pclose (MSVCRT.@)
1209 int CDECL _pclose(FILE* file)
1211 HANDLE h;
1212 DWORD i;
1214 if (!MSVCRT_CHECK_PMT(file != NULL)) return -1;
1216 _lock(_POPEN_LOCK);
1217 for(i=0; i<popen_handles_size; i++)
1219 if (popen_handles[i].f == file)
1220 break;
1222 if(i == popen_handles_size)
1224 _unlock(_POPEN_LOCK);
1225 *_errno() = EBADF;
1226 return -1;
1229 h = popen_handles[i].proc;
1230 popen_handles[i].f = NULL;
1231 _unlock(_POPEN_LOCK);
1233 fclose(file);
1234 if(WaitForSingleObject(h, INFINITE)==WAIT_FAILED || !GetExitCodeProcess(h, &i))
1236 msvcrt_set_errno(GetLastError());
1237 CloseHandle(h);
1238 return -1;
1241 CloseHandle(h);
1242 return i;
1245 /*********************************************************************
1246 * _wsystem (MSVCRT.@)
1248 * Unicode version of system
1250 int CDECL _wsystem(const wchar_t* cmd)
1252 int res;
1253 wchar_t *comspec, *fullcmd;
1254 unsigned int len;
1256 comspec = msvcrt_get_comspec();
1258 if (cmd == NULL)
1260 if (comspec == NULL)
1262 *_errno() = ENOENT;
1263 return 0;
1265 HeapFree(GetProcessHeap(), 0, comspec);
1266 return 1;
1269 if (comspec == NULL)
1270 return -1;
1272 len = wcslen(comspec) + wcslen(cmd) + 5;
1274 if (!(fullcmd = HeapAlloc(GetProcessHeap(), 0, len * sizeof(wchar_t))))
1276 HeapFree(GetProcessHeap(), 0, comspec);
1277 return -1;
1279 wcscpy(fullcmd, comspec);
1280 wcscat(fullcmd, L" /c ");
1281 wcscat(fullcmd, cmd);
1283 res = msvcrt_spawn(_P_WAIT, comspec, fullcmd, NULL, 1);
1285 HeapFree(GetProcessHeap(), 0, comspec);
1286 HeapFree(GetProcessHeap(), 0, fullcmd);
1287 return res;
1290 /*********************************************************************
1291 * system (MSVCRT.@)
1293 int CDECL system(const char* cmd)
1295 int res = -1;
1296 wchar_t *cmdW;
1298 if (cmd == NULL)
1299 return _wsystem(NULL);
1301 if ((cmdW = msvcrt_wstrdupa(cmd)))
1303 res = _wsystem(cmdW);
1304 free(cmdW);
1306 return res;
1309 /*********************************************************************
1310 * _loaddll (MSVCRT.@)
1312 intptr_t CDECL _loaddll(const char* dllname)
1314 return (intptr_t)LoadLibraryA(dllname);
1317 /*********************************************************************
1318 * _unloaddll (MSVCRT.@)
1320 int CDECL _unloaddll(intptr_t dll)
1322 if (FreeLibrary((HMODULE)dll))
1323 return 0;
1324 else
1326 int err = GetLastError();
1327 msvcrt_set_errno(err);
1328 return err;
1332 /*********************************************************************
1333 * _getdllprocaddr (MSVCRT.@)
1335 void * CDECL _getdllprocaddr(intptr_t dll, const char *name, int ordinal)
1337 if (name)
1339 if (ordinal != -1) return NULL;
1340 return GetProcAddress( (HMODULE)dll, name );
1342 if (HIWORD(ordinal)) return NULL;
1343 return GetProcAddress( (HMODULE)dll, (LPCSTR)(ULONG_PTR)ordinal );
1346 /*********************************************************************
1347 * _getpid (MSVCRT.@)
1349 int CDECL _getpid(void)
1351 return GetCurrentProcessId();
1354 #if _MSVCR_VER>=110
1355 /*********************************************************************
1356 * __crtTerminateProcess (MSVCR110.@)
1358 int CDECL __crtTerminateProcess(UINT exit_code)
1360 return TerminateProcess(GetCurrentProcess(), exit_code);
1362 #endif