msvcrt: Added _Getmonths implementation.
[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  * Copyright 2007 Hans Leidekker
9  *
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.
14  *
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.
19  *
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
23  *
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
28  */
29 #include "config.h"
30
31 #include <stdarg.h>
32
33 #include "msvcrt.h"
34 #include "wine/debug.h"
35 #include "wine/unicode.h"
36
37 WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
38
39 static void msvcrt_search_executable(const MSVCRT_wchar_t *name, MSVCRT_wchar_t *fullname, int use_path)
40 {
41   static const MSVCRT_wchar_t path[] = {'P','A','T','H',0};
42   static const MSVCRT_wchar_t suffix[][5] =
43     {{'.','c','o','m',0}, {'.','e','x','e',0}, {'.','b','a','t',0}, {'.','c','m','d',0}};
44
45   MSVCRT_wchar_t buffer[MAX_PATH];
46   const MSVCRT_wchar_t *env, *p;
47   unsigned int i, name_len, path_len;
48   int extension = 1;
49
50   *fullname = '\0';
51   msvcrt_set_errno(ERROR_FILE_NOT_FOUND);
52
53   p = memchrW(name, '\0', MAX_PATH);
54   if (!p) p = name + MAX_PATH - 1;
55   name_len = p - name;
56
57   /* FIXME extra-long names are silently truncated */
58   memcpy(buffer, name, name_len * sizeof(MSVCRT_wchar_t));
59   buffer[name_len] = '\0';
60
61   /* try current dir first */
62   if (GetFileAttributesW(buffer) != INVALID_FILE_ATTRIBUTES)
63   {
64     strcpyW(fullname, buffer);
65     return;
66   }
67
68   for (p--; p >= name; p--)
69     if (*p == '\\' || *p == '/' || *p == ':' || *p == '.') break;
70
71   /* if there's no extension, try some well-known extensions */
72   if ((p < name || *p != '.') && name_len <= MAX_PATH - 5)
73   {
74     for (i = 0; i < 4; i++)
75     {
76       memcpy(buffer + name_len, suffix[i], 5 * sizeof(MSVCRT_wchar_t));
77       if (GetFileAttributesW(buffer) != INVALID_FILE_ATTRIBUTES)
78       {
79         strcpyW(fullname, buffer);
80         return;
81       }
82     }
83     extension = 0;
84   }
85
86   if (!use_path || !(env = MSVCRT__wgetenv(path))) return;
87
88   /* now try search path */
89   do
90   {
91     p = env;
92     while (*p && *p != ';') p++;
93     if (p == env) return;
94
95     path_len = p - env;
96     if (path_len + name_len <= MAX_PATH - 2)
97     {
98       memcpy(buffer, env, path_len * sizeof(MSVCRT_wchar_t));
99       if (buffer[path_len] != '/' && buffer[path_len] != '\\')
100       {
101         buffer[path_len++] = '\\';
102         buffer[path_len] = '\0';
103       }
104       else buffer[path_len] = '\0';
105
106       strcatW(buffer, name);
107       if (GetFileAttributesW(buffer) != INVALID_FILE_ATTRIBUTES)
108       {
109         strcpyW(fullname, buffer);
110         return;
111       }
112     }
113     /* again, if there's no extension, try some well-known extensions */
114     if (!extension && path_len + name_len <= MAX_PATH - 5)
115     {
116       for (i = 0; i < 4; i++)
117       {
118         memcpy(buffer + path_len + name_len, suffix[i], 5 * sizeof(MSVCRT_wchar_t));
119         if (GetFileAttributesW(buffer) != INVALID_FILE_ATTRIBUTES)
120         {
121           strcpyW(fullname, buffer);
122           return;
123         }
124       }
125     }
126     env = *p ? p + 1 : p;
127   } while(1);
128 }
129
130 static MSVCRT_intptr_t msvcrt_spawn(int flags, const MSVCRT_wchar_t* exe, MSVCRT_wchar_t* cmdline,
131                                     MSVCRT_wchar_t* env, int use_path)
132 {
133   STARTUPINFOW si;
134   PROCESS_INFORMATION pi;
135   MSVCRT_wchar_t fullname[MAX_PATH];
136
137   TRACE("%x %s %s %s %d\n", flags, debugstr_w(exe), debugstr_w(cmdline), debugstr_w(env), use_path);
138
139   if ((unsigned)flags > MSVCRT__P_DETACH)
140   {
141     *MSVCRT__errno() = MSVCRT_EINVAL;
142     return -1;
143   }
144
145   msvcrt_search_executable(exe, fullname, use_path);
146
147   memset(&si, 0, sizeof(si));
148   si.cb = sizeof(si);
149   msvcrt_create_io_inherit_block(&si.cbReserved2, &si.lpReserved2);
150   if (!CreateProcessW(fullname, cmdline, NULL, NULL, TRUE,
151                      flags == MSVCRT__P_DETACH ? DETACHED_PROCESS : 0,
152                      env, NULL, &si, &pi))
153   {
154     msvcrt_set_errno(GetLastError());
155     MSVCRT_free(si.lpReserved2);
156     return -1;
157   }
158
159   MSVCRT_free(si.lpReserved2);
160   switch(flags)
161   {
162   case MSVCRT__P_WAIT:
163     WaitForSingleObject(pi.hProcess, INFINITE);
164     GetExitCodeProcess(pi.hProcess,&pi.dwProcessId);
165     CloseHandle(pi.hProcess);
166     CloseHandle(pi.hThread);
167     return pi.dwProcessId;
168   case MSVCRT__P_DETACH:
169     CloseHandle(pi.hProcess);
170     pi.hProcess = 0;
171     /* fall through */
172   case MSVCRT__P_NOWAIT:
173   case MSVCRT__P_NOWAITO:
174     CloseHandle(pi.hThread);
175     return (MSVCRT_intptr_t)pi.hProcess;
176   case  MSVCRT__P_OVERLAY:
177     MSVCRT__exit(0);
178   }
179   return -1; /* can't reach here */
180 }
181
182 /* INTERNAL: Convert wide argv list to a single 'delim'-separated wide string, with an
183  * extra '\0' to terminate it.
184  */
185 static MSVCRT_wchar_t* msvcrt_argvtos(const MSVCRT_wchar_t* const* arg, MSVCRT_wchar_t delim)
186 {
187   const MSVCRT_wchar_t* const* a;
188   int size;
189   MSVCRT_wchar_t* p;
190   MSVCRT_wchar_t* ret;
191
192   if (!arg)
193   {
194       /* Return NULL for an empty environment list */
195       return NULL;
196   }
197
198   /* get length */
199   a = arg;
200   size = 0;
201   while (*a)
202   {
203     size += strlenW(*a) + 1;
204     a++;
205   }
206
207   ret = MSVCRT_malloc((size + 1) * sizeof(MSVCRT_wchar_t));
208   if (!ret)
209     return NULL;
210
211   /* fill string */
212   a = arg;
213   p = ret;
214   while (*a)
215   {
216     int len = strlenW(*a);
217     memcpy(p,*a,len * sizeof(MSVCRT_wchar_t));
218     p += len;
219     *p++ = delim;
220     a++;
221   }
222   if (delim && p > ret) p[-1] = 0;
223   else *p = 0;
224   return ret;
225 }
226
227 /* INTERNAL: Convert ansi argv list to a single 'delim'-separated wide string, with an
228  * extra '\0' to terminate it.
229  */
230 static MSVCRT_wchar_t *msvcrt_argvtos_aw(const char * const *arg, MSVCRT_wchar_t delim)
231 {
232   const char * const *a;
233   unsigned int len;
234   MSVCRT_wchar_t *p, *ret;
235
236   if (!arg)
237   {
238       /* Return NULL for an empty environment list */
239       return NULL;
240   }
241
242   /* get length */
243   a = arg;
244   len = 0;
245   while (*a)
246   {
247     len += MultiByteToWideChar(CP_ACP, 0, *a, -1, NULL, 0);
248     a++;
249   }
250
251   ret = MSVCRT_malloc((len + 1) * sizeof(MSVCRT_wchar_t));
252   if (!ret)
253     return NULL;
254
255   /* fill string */
256   a = arg;
257   p = ret;
258   while (*a)
259   {
260     p += MultiByteToWideChar(CP_ACP, 0, *a, strlen(*a), p, len - (p - ret));
261     *p++ = delim;
262     a++;
263   }
264   if (delim && p > ret) p[-1] = 0;
265   else *p = 0;
266   return ret;
267 }
268
269 /* INTERNAL: Convert wide va_list to a single 'delim'-separated wide string, with an
270  * extra '\0' to terminate it.
271  */
272 static MSVCRT_wchar_t *msvcrt_valisttos(const MSVCRT_wchar_t *arg0, __ms_va_list alist, MSVCRT_wchar_t delim)
273 {
274     unsigned int size = 0, pos = 0;
275     const MSVCRT_wchar_t *arg;
276     MSVCRT_wchar_t *new, *ret = NULL;
277
278     for (arg = arg0; arg; arg = va_arg( alist, MSVCRT_wchar_t * ))
279     {
280         unsigned int len = strlenW( arg ) + 1;
281         if (pos + len >= size)
282         {
283             size = max( 256, size * 2 );
284             size = max( size, pos + len + 1 );
285             if (!(new = MSVCRT_realloc( ret, size * sizeof(MSVCRT_wchar_t) )))
286             {
287                 MSVCRT_free( ret );
288                 return NULL;
289             }
290             ret = new;
291         }
292         strcpyW( ret + pos, arg );
293         pos += len;
294         ret[pos - 1] = delim;
295     }
296     if (pos)
297     {
298         if (delim) ret[pos - 1] = 0;
299         else ret[pos] = 0;
300     }
301     return ret;
302 }
303
304 /* INTERNAL: Convert ansi va_list to a single 'delim'-separated wide string, with an
305  * extra '\0' to terminate it.
306  */
307 static MSVCRT_wchar_t *msvcrt_valisttos_aw(const char *arg0, __ms_va_list alist, MSVCRT_wchar_t delim)
308 {
309     unsigned int size = 0, pos = 0;
310     const char *arg;
311     MSVCRT_wchar_t *new, *ret = NULL;
312
313     for (arg = arg0; arg; arg = va_arg( alist, char * ))
314     {
315         unsigned int len = MultiByteToWideChar( CP_ACP, 0, arg, -1, NULL, 0 );
316         if (pos + len >= size)
317         {
318             size = max( 256, size * 2 );
319             size = max( size, pos + len + 1 );
320             if (!(new = MSVCRT_realloc( ret, size * sizeof(MSVCRT_wchar_t) )))
321             {
322                 MSVCRT_free( ret );
323                 return NULL;
324             }
325             ret = new;
326         }
327         pos += MultiByteToWideChar( CP_ACP, 0, arg, -1, ret + pos, size - pos );
328         ret[pos - 1] = delim;
329     }
330     if (pos)
331     {
332         if (delim) ret[pos - 1] = 0;
333         else ret[pos] = 0;
334     }
335     return ret;
336 }
337
338 /* INTERNAL: retrieve COMSPEC environment variable */
339 static MSVCRT_wchar_t *msvcrt_get_comspec(void)
340 {
341   static const MSVCRT_wchar_t cmd[] = {'c','m','d',0};
342   static const MSVCRT_wchar_t comspec[] = {'C','O','M','S','P','E','C',0};
343   MSVCRT_wchar_t *ret;
344   unsigned int len;
345
346   if (!(len = GetEnvironmentVariableW(comspec, NULL, 0))) len = sizeof(cmd)/sizeof(MSVCRT_wchar_t);
347   if ((ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(MSVCRT_wchar_t))))
348   {
349     if (!GetEnvironmentVariableW(comspec, ret, len)) strcpyW(ret, cmd);
350   }
351   return ret;
352 }
353
354 /*********************************************************************
355  *              _cwait (MSVCRT.@)
356  */
357 MSVCRT_intptr_t CDECL _cwait(int *status, MSVCRT_intptr_t pid, int action)
358 {
359   HANDLE hPid = (HANDLE)pid;
360   int doserrno;
361
362   action = action; /* Remove warning */
363
364   if (!WaitForSingleObject(hPid, INFINITE))
365   {
366     if (status)
367     {
368       DWORD stat;
369       GetExitCodeProcess(hPid, &stat);
370       *status = (int)stat;
371     }
372     return pid;
373   }
374   doserrno = GetLastError();
375
376   if (doserrno == ERROR_INVALID_HANDLE)
377   {
378     *MSVCRT__errno() =  MSVCRT_ECHILD;
379     *MSVCRT___doserrno() = doserrno;
380   }
381   else
382     msvcrt_set_errno(doserrno);
383
384   return status ? *status = -1 : -1;
385 }
386
387 /*********************************************************************
388  *      _wexecl (MSVCRT.@)
389  *
390  * Unicode version of _execl
391  */
392 MSVCRT_intptr_t CDECL _wexecl(const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* arg0, ...)
393 {
394   __ms_va_list ap;
395   MSVCRT_wchar_t *args;
396   MSVCRT_intptr_t ret;
397
398   __ms_va_start(ap, arg0);
399   args = msvcrt_valisttos(arg0, ap, ' ');
400   __ms_va_end(ap);
401
402   ret = msvcrt_spawn(MSVCRT__P_OVERLAY, name, args, NULL, 0);
403
404   MSVCRT_free(args);
405   return ret;
406 }
407
408 /*********************************************************************
409  *              _execl (MSVCRT.@)
410  *
411  * Like on Windows, this function does not handle arguments with spaces
412  * or double-quotes.
413  */
414 MSVCRT_intptr_t CDECL _execl(const char* name, const char* arg0, ...)
415 {
416   __ms_va_list ap;
417   MSVCRT_wchar_t *nameW, *args;
418   MSVCRT_intptr_t ret;
419
420   if (!(nameW = msvcrt_wstrdupa(name))) return -1;
421
422   __ms_va_start(ap, arg0);
423   args = msvcrt_valisttos_aw(arg0, ap, ' ');
424   __ms_va_end(ap);
425
426   ret = msvcrt_spawn(MSVCRT__P_OVERLAY, nameW, args, NULL, 0);
427
428   MSVCRT_free(nameW);
429   MSVCRT_free(args);
430   return ret;
431 }
432
433 /*********************************************************************
434  *      _wexecle (MSVCRT.@)
435  *
436  * Unicode version of _execle
437  */
438 MSVCRT_intptr_t CDECL _wexecle(const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* arg0, ...)
439 {
440   __ms_va_list ap;
441   MSVCRT_wchar_t *args, *envs = NULL;
442   const MSVCRT_wchar_t * const *envp;
443   MSVCRT_intptr_t ret;
444
445   __ms_va_start(ap, arg0);
446   args = msvcrt_valisttos(arg0, ap, ' ');
447   __ms_va_end(ap);
448
449   __ms_va_start(ap, arg0);
450   while (va_arg( ap, MSVCRT_wchar_t * ) != NULL) /*nothing*/;
451   envp = va_arg( ap, const MSVCRT_wchar_t * const * );
452   if (envp) envs = msvcrt_argvtos(envp, 0);
453   __ms_va_end(ap);
454
455   ret = msvcrt_spawn(MSVCRT__P_OVERLAY, name, args, envs, 0);
456
457   MSVCRT_free(args);
458   MSVCRT_free(envs);
459   return ret;
460 }
461
462 /*********************************************************************
463  *              _execle (MSVCRT.@)
464  */
465 MSVCRT_intptr_t CDECL _execle(const char* name, const char* arg0, ...)
466 {
467   __ms_va_list ap;
468   MSVCRT_wchar_t *nameW, *args, *envs = NULL;
469   const char * const *envp;
470   MSVCRT_intptr_t ret;
471
472   if (!(nameW = msvcrt_wstrdupa(name))) return -1;
473
474   __ms_va_start(ap, arg0);
475   args = msvcrt_valisttos_aw(arg0, ap, ' ');
476   __ms_va_end(ap);
477
478   __ms_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   __ms_va_end(ap);
483
484   ret = msvcrt_spawn(MSVCRT__P_OVERLAY, nameW, args, envs, 0);
485
486   MSVCRT_free(nameW);
487   MSVCRT_free(args);
488   MSVCRT_free(envs);
489   return ret;
490 }
491
492 /*********************************************************************
493  *      _wexeclp (MSVCRT.@)
494  *
495  * Unicode version of _execlp
496  */
497 MSVCRT_intptr_t CDECL _wexeclp(const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* arg0, ...)
498 {
499   __ms_va_list ap;
500   MSVCRT_wchar_t *args;
501   MSVCRT_intptr_t ret;
502
503   __ms_va_start(ap, arg0);
504   args = msvcrt_valisttos(arg0, ap, ' ');
505   __ms_va_end(ap);
506
507   ret = msvcrt_spawn(MSVCRT__P_OVERLAY, name, args, NULL, 1);
508
509   MSVCRT_free(args);
510   return ret;
511 }
512
513 /*********************************************************************
514  *              _execlp (MSVCRT.@)
515  *
516  * Like on Windows, this function does not handle arguments with spaces
517  * or double-quotes.
518  */
519 MSVCRT_intptr_t CDECL _execlp(const char* name, const char* arg0, ...)
520 {
521   __ms_va_list ap;
522   MSVCRT_wchar_t *nameW, *args;
523   MSVCRT_intptr_t ret;
524
525   if (!(nameW = msvcrt_wstrdupa(name))) return -1;
526
527   __ms_va_start(ap, arg0);
528   args = msvcrt_valisttos_aw(arg0, ap, ' ');
529   __ms_va_end(ap);
530
531   ret = msvcrt_spawn(MSVCRT__P_OVERLAY, nameW, args, NULL, 1);
532
533   MSVCRT_free(nameW);
534   MSVCRT_free(args);
535   return ret;
536 }
537
538 /*********************************************************************
539  *      _wexeclpe (MSVCRT.@)
540  *
541  * Unicode version of _execlpe
542  */
543 MSVCRT_intptr_t CDECL _wexeclpe(const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* arg0, ...)
544 {
545   __ms_va_list ap;
546   MSVCRT_wchar_t *args, *envs = NULL;
547   const MSVCRT_wchar_t * const *envp;
548   MSVCRT_intptr_t ret;
549
550   __ms_va_start(ap, arg0);
551   args = msvcrt_valisttos(arg0, ap, ' ');
552   __ms_va_end(ap);
553
554   __ms_va_start(ap, arg0);
555   while (va_arg( ap, MSVCRT_wchar_t * ) != NULL) /*nothing*/;
556   envp = va_arg( ap, const MSVCRT_wchar_t * const * );
557   if (envp) envs = msvcrt_argvtos(envp, 0);
558   __ms_va_end(ap);
559
560   ret = msvcrt_spawn(MSVCRT__P_OVERLAY, name, args, envs, 1);
561
562   MSVCRT_free(args);
563   MSVCRT_free(envs);
564   return ret;
565 }
566
567 /*********************************************************************
568  *              _execlpe (MSVCRT.@)
569  */
570 MSVCRT_intptr_t CDECL _execlpe(const char* name, const char* arg0, ...)
571 {
572   __ms_va_list ap;
573   MSVCRT_wchar_t *nameW, *args, *envs = NULL;
574   const char * const *envp;
575   MSVCRT_intptr_t ret;
576
577   if (!(nameW = msvcrt_wstrdupa(name))) return -1;
578
579   __ms_va_start(ap, arg0);
580   args = msvcrt_valisttos_aw(arg0, ap, ' ');
581   __ms_va_end(ap);
582
583   __ms_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   __ms_va_end(ap);
588
589   ret = msvcrt_spawn(MSVCRT__P_OVERLAY, nameW, args, envs, 1);
590
591   MSVCRT_free(nameW);
592   MSVCRT_free(args);
593   MSVCRT_free(envs);
594   return ret;
595 }
596
597 /*********************************************************************
598  *      _wexecv (MSVCRT.@)
599  *
600  * Unicode version of _execv
601  */
602 MSVCRT_intptr_t CDECL _wexecv(const MSVCRT_wchar_t* name, MSVCRT_wchar_t* const* argv)
603 {
604   return MSVCRT__wspawnve(MSVCRT__P_OVERLAY, name, (const MSVCRT_wchar_t* const*) argv, NULL);
605 }
606
607 /*********************************************************************
608  *              _execv (MSVCRT.@)
609  *
610  * Like on Windows, this function does not handle arguments with spaces
611  * or double-quotes.
612  */
613 MSVCRT_intptr_t CDECL _execv(const char* name, char* const* argv)
614 {
615   return MSVCRT__spawnve(MSVCRT__P_OVERLAY, name, (const char* const*) argv, NULL);
616 }
617
618 /*********************************************************************
619  *      _wexecve (MSVCRT.@)
620  *
621  * Unicode version of _execve
622  */
623 MSVCRT_intptr_t CDECL _wexecve(const MSVCRT_wchar_t* name, MSVCRT_wchar_t* const* argv, const MSVCRT_wchar_t* const* envv)
624 {
625   return MSVCRT__wspawnve(MSVCRT__P_OVERLAY, name, (const MSVCRT_wchar_t* const*) argv, envv);
626 }
627
628 /*********************************************************************
629  *              _execve (MSVCRT.@)
630  *
631  * Like on Windows, this function does not handle arguments with spaces
632  * or double-quotes.
633  */
634 MSVCRT_intptr_t CDECL MSVCRT__execve(const char* name, char* const* argv, const char* const* envv)
635 {
636   return MSVCRT__spawnve(MSVCRT__P_OVERLAY, name, (const char* const*) argv, envv);
637 }
638
639 /*********************************************************************
640  *      _wexecvpe (MSVCRT.@)
641  *
642  * Unicode version of _execvpe
643  */
644 MSVCRT_intptr_t CDECL _wexecvpe(const MSVCRT_wchar_t* name, MSVCRT_wchar_t* const* argv, const MSVCRT_wchar_t* const* envv)
645 {
646   return MSVCRT__wspawnvpe(MSVCRT__P_OVERLAY, name, (const MSVCRT_wchar_t* const*) argv, envv);
647 }
648
649 /*********************************************************************
650  *              _execvpe (MSVCRT.@)
651  *
652  * Like on Windows, this function does not handle arguments with spaces
653  * or double-quotes.
654  */
655 MSVCRT_intptr_t CDECL _execvpe(const char* name, char* const* argv, const char* const* envv)
656 {
657   return MSVCRT__spawnvpe(MSVCRT__P_OVERLAY, name, (const char* const*) argv, envv);
658 }
659
660 /*********************************************************************
661  *      _wexecvp (MSVCRT.@)
662  *
663  * Unicode version of _execvp
664  */
665 MSVCRT_intptr_t CDECL _wexecvp(const MSVCRT_wchar_t* name, MSVCRT_wchar_t* const* argv)
666 {
667   return _wexecvpe(name, argv, NULL);
668 }
669
670 /*********************************************************************
671  *              _execvp (MSVCRT.@)
672  *
673  * Like on Windows, this function does not handle arguments with spaces
674  * or double-quotes.
675  */
676 MSVCRT_intptr_t CDECL _execvp(const char* name, char* const* argv)
677 {
678   return _execvpe(name, argv, NULL);
679 }
680
681 /*********************************************************************
682  *      _wspawnl (MSVCRT.@)
683  *
684  * Unicode version of _spawnl
685  */
686 MSVCRT_intptr_t CDECL _wspawnl(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* arg0, ...)
687 {
688   __ms_va_list ap;
689   MSVCRT_wchar_t *args;
690   MSVCRT_intptr_t ret;
691
692   __ms_va_start(ap, arg0);
693   args = msvcrt_valisttos(arg0, ap, ' ');
694   __ms_va_end(ap);
695
696   ret = msvcrt_spawn(flags, name, args, NULL, 0);
697
698   MSVCRT_free(args);
699   return ret;
700 }
701
702 /*********************************************************************
703  *              _spawnl (MSVCRT.@)
704  *
705  * Like on Windows, this function does not handle arguments with spaces
706  * or double-quotes.
707  */
708 MSVCRT_intptr_t CDECL _spawnl(int flags, const char* name, const char* arg0, ...)
709 {
710   __ms_va_list ap;
711   MSVCRT_wchar_t *nameW, *args;
712   MSVCRT_intptr_t ret;
713
714   if (!(nameW = msvcrt_wstrdupa(name))) return -1;
715
716   __ms_va_start(ap, arg0);
717   args = msvcrt_valisttos_aw(arg0, ap, ' ');
718   __ms_va_end(ap);
719
720   ret = msvcrt_spawn(flags, nameW, args, NULL, 0);
721
722   MSVCRT_free(nameW);
723   MSVCRT_free(args);
724   return ret;
725 }
726
727 /*********************************************************************
728  *      _wspawnle (MSVCRT.@)
729  *
730  * Unicode version of _spawnle
731  */
732 MSVCRT_intptr_t CDECL _wspawnle(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* arg0, ...)
733 {
734   __ms_va_list ap;
735   MSVCRT_wchar_t *args, *envs = NULL;
736   const MSVCRT_wchar_t * const *envp;
737   MSVCRT_intptr_t ret;
738
739   __ms_va_start(ap, arg0);
740   args = msvcrt_valisttos(arg0, ap, ' ');
741   __ms_va_end(ap);
742
743   __ms_va_start(ap, arg0);
744   while (va_arg( ap, MSVCRT_wchar_t * ) != NULL) /*nothing*/;
745   envp = va_arg( ap, const MSVCRT_wchar_t * const * );
746   if (envp) envs = msvcrt_argvtos(envp, 0);
747   __ms_va_end(ap);
748
749   ret = msvcrt_spawn(flags, name, args, envs, 0);
750
751   MSVCRT_free(args);
752   MSVCRT_free(envs);
753   return ret;
754 }
755
756 /*********************************************************************
757  *              _spawnle (MSVCRT.@)
758  */
759 MSVCRT_intptr_t CDECL _spawnle(int flags, const char* name, const char* arg0, ...)
760 {
761   __ms_va_list ap;
762   MSVCRT_wchar_t *nameW, *args, *envs = NULL;
763   const char * const *envp;
764   MSVCRT_intptr_t ret;
765
766   if (!(nameW = msvcrt_wstrdupa(name))) return -1;
767
768   __ms_va_start(ap, arg0);
769   args = msvcrt_valisttos_aw(arg0, ap, ' ');
770   __ms_va_end(ap);
771
772   __ms_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   __ms_va_end(ap);
777
778   ret = msvcrt_spawn(flags, nameW, args, envs, 0);
779
780   MSVCRT_free(nameW);
781   MSVCRT_free(args);
782   MSVCRT_free(envs);
783   return ret;
784 }
785
786 /*********************************************************************
787  *      _wspawnlp (MSVCRT.@)
788  *
789  * Unicode version of _spawnlp
790  */
791 MSVCRT_intptr_t CDECL _wspawnlp(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* arg0, ...)
792 {
793   __ms_va_list ap;
794   MSVCRT_wchar_t *args;
795   MSVCRT_intptr_t ret;
796
797   __ms_va_start(ap, arg0);
798   args = msvcrt_valisttos(arg0, ap, ' ');
799   __ms_va_end(ap);
800
801   ret = msvcrt_spawn(flags, name, args, NULL, 1);
802
803   MSVCRT_free(args);
804   return ret;
805 }
806
807 /*********************************************************************
808  *              _spawnlp (MSVCRT.@)
809  *
810  * Like on Windows, this function does not handle arguments with spaces
811  * or double-quotes.
812  */
813 MSVCRT_intptr_t CDECL _spawnlp(int flags, const char* name, const char* arg0, ...)
814 {
815   __ms_va_list ap;
816   MSVCRT_wchar_t *nameW, *args;
817   MSVCRT_intptr_t ret;
818
819   if (!(nameW = msvcrt_wstrdupa(name))) return -1;
820
821   __ms_va_start(ap, arg0);
822   args = msvcrt_valisttos_aw(arg0, ap, ' ');
823   __ms_va_end(ap);
824
825   ret = msvcrt_spawn(flags, nameW, args, NULL, 1);
826
827   MSVCRT_free(nameW);
828   MSVCRT_free(args);
829   return ret;
830 }
831
832 /*********************************************************************
833  *      _wspawnlpe (MSVCRT.@)
834  *
835  * Unicode version of _spawnlpe
836  */
837 MSVCRT_intptr_t CDECL _wspawnlpe(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* arg0, ...)
838 {
839   __ms_va_list ap;
840   MSVCRT_wchar_t *args, *envs = NULL;
841   const MSVCRT_wchar_t * const *envp;
842   MSVCRT_intptr_t ret;
843
844   __ms_va_start(ap, arg0);
845   args = msvcrt_valisttos(arg0, ap, ' ');
846   __ms_va_end(ap);
847
848   __ms_va_start(ap, arg0);
849   while (va_arg( ap, MSVCRT_wchar_t * ) != NULL) /*nothing*/;
850   envp = va_arg( ap, const MSVCRT_wchar_t * const * );
851   if (envp) envs = msvcrt_argvtos(envp, 0);
852   __ms_va_end(ap);
853
854   ret = msvcrt_spawn(flags, name, args, envs, 1);
855
856   MSVCRT_free(args);
857   MSVCRT_free(envs);
858   return ret;
859 }
860
861 /*********************************************************************
862  *              _spawnlpe (MSVCRT.@)
863  */
864 MSVCRT_intptr_t CDECL _spawnlpe(int flags, const char* name, const char* arg0, ...)
865 {
866   __ms_va_list ap;
867   MSVCRT_wchar_t *nameW, *args, *envs = NULL;
868   const char * const *envp;
869   MSVCRT_intptr_t ret;
870
871   if (!(nameW = msvcrt_wstrdupa(name))) return -1;
872
873   __ms_va_start(ap, arg0);
874   args = msvcrt_valisttos_aw(arg0, ap, ' ');
875   __ms_va_end(ap);
876
877   __ms_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   __ms_va_end(ap);
882
883   ret = msvcrt_spawn(flags, nameW, args, envs, 1);
884
885   MSVCRT_free(nameW);
886   MSVCRT_free(args);
887   MSVCRT_free(envs);
888   return ret;
889 }
890
891 /*********************************************************************
892  *              _spawnve (MSVCRT.@)
893  *
894  * Like on Windows, this function does not handle arguments with spaces
895  * or double-quotes.
896  */
897 MSVCRT_intptr_t CDECL MSVCRT__spawnve(int flags, const char* name, const char* const* argv,
898                                const char* const* envv)
899 {
900   MSVCRT_wchar_t *nameW, *args, *envs;
901   MSVCRT_intptr_t ret;
902
903   if (!(nameW = msvcrt_wstrdupa(name))) return -1;
904
905   args = msvcrt_argvtos_aw(argv, ' ');
906   envs = msvcrt_argvtos_aw(envv, 0);
907
908   ret = msvcrt_spawn(flags, nameW, args, envs, 0);
909
910   MSVCRT_free(nameW);
911   MSVCRT_free(args);
912   MSVCRT_free(envs);
913   return ret;
914 }
915
916 /*********************************************************************
917  *      _wspawnve (MSVCRT.@)
918  *
919  * Unicode version of _spawnve
920  */
921 MSVCRT_intptr_t CDECL MSVCRT__wspawnve(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* const* argv,
922                                 const MSVCRT_wchar_t* const* envv)
923 {
924   MSVCRT_wchar_t *args, *envs;
925   MSVCRT_intptr_t ret;
926
927   args = msvcrt_argvtos(argv, ' ');
928   envs = msvcrt_argvtos(envv, 0);
929
930   ret = msvcrt_spawn(flags, name, args, envs, 0);
931
932   MSVCRT_free(args);
933   MSVCRT_free(envs);
934   return ret;
935 }
936
937 /*********************************************************************
938  *              _spawnv (MSVCRT.@)
939  *
940  * Like on Windows, this function does not handle arguments with spaces
941  * or double-quotes.
942  */
943 MSVCRT_intptr_t CDECL _spawnv(int flags, const char* name, const char* const* argv)
944 {
945   return MSVCRT__spawnve(flags, name, argv, NULL);
946 }
947
948 /*********************************************************************
949  *      _wspawnv (MSVCRT.@)
950  *
951  * Unicode version of _spawnv
952  */
953 MSVCRT_intptr_t CDECL _wspawnv(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* const* argv)
954 {
955   return MSVCRT__wspawnve(flags, name, argv, NULL);
956 }
957
958 /*********************************************************************
959  *              _spawnvpe (MSVCRT.@)
960  *
961  * Like on Windows, this function does not handle arguments with spaces
962  * or double-quotes.
963  */
964 MSVCRT_intptr_t CDECL MSVCRT__spawnvpe(int flags, const char* name, const char* const* argv,
965                                 const char* const* envv)
966 {
967   MSVCRT_wchar_t *nameW, *args, *envs;
968   MSVCRT_intptr_t ret;
969
970   if (!(nameW = msvcrt_wstrdupa(name))) return -1;
971
972   args = msvcrt_argvtos_aw(argv, ' ');
973   envs = msvcrt_argvtos_aw(envv, 0);
974
975   ret = msvcrt_spawn(flags, nameW, args, envs, 1);
976
977   MSVCRT_free(nameW);
978   MSVCRT_free(args);
979   MSVCRT_free(envs);
980   return ret;
981 }
982
983 /*********************************************************************
984  *      _wspawnvpe (MSVCRT.@)
985  *
986  * Unicode version of _spawnvpe
987  */
988 MSVCRT_intptr_t CDECL MSVCRT__wspawnvpe(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* const* argv,
989                                  const MSVCRT_wchar_t* const* envv)
990 {
991   MSVCRT_wchar_t *args, *envs;
992   MSVCRT_intptr_t ret;
993
994   args = msvcrt_argvtos(argv, ' ');
995   envs = msvcrt_argvtos(envv, 0);
996
997   ret = msvcrt_spawn(flags, name, args, envs, 1);
998
999   MSVCRT_free(args);
1000   MSVCRT_free(envs);
1001   return ret;
1002 }
1003
1004 /*********************************************************************
1005  *              _spawnvp (MSVCRT.@)
1006  *
1007  * Like on Windows, this function does not handle arguments with spaces
1008  * or double-quotes.
1009  */
1010 MSVCRT_intptr_t CDECL _spawnvp(int flags, const char* name, const char* const* argv)
1011 {
1012   return MSVCRT__spawnvpe(flags, name, argv, NULL);
1013 }
1014
1015 /*********************************************************************
1016  *      _wspawnvp (MSVCRT.@)
1017  *
1018  * Unicode version of _spawnvp
1019  */
1020 MSVCRT_intptr_t CDECL _wspawnvp(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* const* argv)
1021 {
1022   return MSVCRT__wspawnvpe(flags, name, argv, NULL);
1023 }
1024
1025 /*********************************************************************
1026  *              _wpopen (MSVCRT.@)
1027  *
1028  * Unicode version of _popen
1029  */
1030 MSVCRT_FILE* CDECL MSVCRT__wpopen(const MSVCRT_wchar_t* command, const MSVCRT_wchar_t* mode)
1031 {
1032   MSVCRT_FILE *ret;
1033   BOOL readPipe = TRUE;
1034   int textmode, fds[2], fdToDup, fdToOpen, fdStdHandle = -1;
1035   const MSVCRT_wchar_t *p;
1036   MSVCRT_wchar_t *comspec, *fullcmd;
1037   unsigned int len;
1038   static const MSVCRT_wchar_t flag[] = {' ','/','c',' ',0};
1039
1040   TRACE("(command=%s, mode=%s)\n", debugstr_w(command), debugstr_w(mode));
1041
1042   if (!command || !mode)
1043     return NULL;
1044
1045   textmode = *__p__fmode() & (MSVCRT__O_BINARY | MSVCRT__O_TEXT);
1046   for (p = mode; *p; p++)
1047   {
1048     switch (*p)
1049     {
1050       case 'W':
1051       case 'w':
1052         readPipe = FALSE;
1053         break;
1054       case 'B':
1055       case 'b':
1056         textmode |= MSVCRT__O_BINARY;
1057         textmode &= ~MSVCRT__O_TEXT;
1058         break;
1059       case 'T':
1060       case 't':
1061         textmode |= MSVCRT__O_TEXT;
1062         textmode &= ~MSVCRT__O_BINARY;
1063         break;
1064     }
1065   }
1066   if (MSVCRT__pipe(fds, 0, textmode) == -1)
1067     return NULL;
1068
1069   fdToDup = readPipe ? 1 : 0;
1070   fdToOpen = readPipe ? 0 : 1;
1071
1072   if ((fdStdHandle = MSVCRT__dup(fdToDup)) == -1)
1073     goto error;
1074   if (MSVCRT__dup2(fds[fdToDup], fdToDup) != 0)
1075     goto error;
1076
1077   MSVCRT__close(fds[fdToDup]);
1078
1079   if (!(comspec = msvcrt_get_comspec())) goto error;
1080   len = strlenW(comspec) + strlenW(flag) + strlenW(command) + 1;
1081
1082   if (!(fullcmd = HeapAlloc(GetProcessHeap(), 0, len * sizeof(MSVCRT_wchar_t))))
1083   {
1084     HeapFree(GetProcessHeap(), 0, comspec);
1085     goto error;
1086   }
1087
1088   strcpyW(fullcmd, comspec);
1089   strcatW(fullcmd, flag);
1090   strcatW(fullcmd, command);
1091
1092   if (msvcrt_spawn(MSVCRT__P_NOWAIT, comspec, fullcmd, NULL, 1) == -1)
1093   {
1094     MSVCRT__close(fds[fdToOpen]);
1095     ret = NULL;
1096   }
1097   else
1098   {
1099     ret = MSVCRT__wfdopen(fds[fdToOpen], mode);
1100     if (!ret)
1101       MSVCRT__close(fds[fdToOpen]);
1102   }
1103   HeapFree(GetProcessHeap(), 0, comspec);
1104   HeapFree(GetProcessHeap(), 0, fullcmd);
1105   MSVCRT__dup2(fdStdHandle, fdToDup);
1106   MSVCRT__close(fdStdHandle);
1107   return ret;
1108
1109 error:
1110   if (fdStdHandle != -1) MSVCRT__close(fdStdHandle);
1111   MSVCRT__close(fds[0]);
1112   MSVCRT__close(fds[1]);
1113   return NULL;
1114 }
1115
1116 /*********************************************************************
1117  *      _popen (MSVCRT.@)
1118  */
1119 MSVCRT_FILE* CDECL MSVCRT__popen(const char* command, const char* mode)
1120 {
1121   MSVCRT_FILE *ret;
1122   MSVCRT_wchar_t *cmdW, *modeW;
1123
1124   TRACE("(command=%s, mode=%s)\n", debugstr_a(command), debugstr_a(mode));
1125
1126   if (!command || !mode)
1127     return NULL;
1128
1129   if (!(cmdW = msvcrt_wstrdupa(command))) return NULL;
1130   if (!(modeW = msvcrt_wstrdupa(mode)))
1131   {
1132     HeapFree(GetProcessHeap(), 0, cmdW);
1133     return NULL;
1134   }
1135
1136   ret = MSVCRT__wpopen(cmdW, modeW);
1137
1138   HeapFree(GetProcessHeap(), 0, cmdW);
1139   HeapFree(GetProcessHeap(), 0, modeW);
1140   return ret;
1141 }
1142
1143 /*********************************************************************
1144  *              _pclose (MSVCRT.@)
1145  */
1146 int CDECL MSVCRT__pclose(MSVCRT_FILE* file)
1147 {
1148   return MSVCRT_fclose(file);
1149 }
1150
1151 /*********************************************************************
1152  *      _wsystem (MSVCRT.@)
1153  *
1154  * Unicode version of system
1155  */
1156 int CDECL _wsystem(const MSVCRT_wchar_t* cmd)
1157 {
1158   int res;
1159   MSVCRT_wchar_t *comspec, *fullcmd;
1160   unsigned int len;
1161   static const MSVCRT_wchar_t flag[] = {' ','/','c',' ',0};
1162
1163   comspec = msvcrt_get_comspec();
1164
1165   if (cmd == NULL)
1166   {
1167     if (comspec == NULL)
1168     {
1169         *MSVCRT__errno() = MSVCRT_ENOENT;
1170         return 0;
1171     }
1172     HeapFree(GetProcessHeap(), 0, comspec);
1173     return 1;
1174   }
1175
1176   if ( comspec == NULL)
1177     return -1;
1178
1179   len = strlenW(comspec) + strlenW(flag) + strlenW(cmd) + 1;
1180
1181   if (!(fullcmd = HeapAlloc(GetProcessHeap(), 0, len * sizeof(MSVCRT_wchar_t))))
1182   {
1183     HeapFree(GetProcessHeap(), 0, comspec);
1184     return -1;
1185   }
1186   strcpyW(fullcmd, comspec);
1187   strcatW(fullcmd, flag);
1188   strcatW(fullcmd, cmd);
1189
1190   res = msvcrt_spawn(MSVCRT__P_WAIT, comspec, fullcmd, NULL, 1);
1191
1192   HeapFree(GetProcessHeap(), 0, comspec);
1193   HeapFree(GetProcessHeap(), 0, fullcmd);
1194   return res;
1195 }
1196
1197 /*********************************************************************
1198  *              system (MSVCRT.@)
1199  */
1200 int CDECL MSVCRT_system(const char* cmd)
1201 {
1202   int res = -1;
1203   MSVCRT_wchar_t *cmdW;
1204
1205   if (cmd == NULL)
1206     return _wsystem(NULL);
1207
1208   if ((cmdW = msvcrt_wstrdupa(cmd)))
1209   {
1210     res = _wsystem(cmdW);
1211     HeapFree(GetProcessHeap(), 0, cmdW);
1212   }
1213   return res;
1214 }
1215
1216 /*********************************************************************
1217  *              _loaddll (MSVCRT.@)
1218  */
1219 MSVCRT_intptr_t CDECL _loaddll(const char* dllname)
1220 {
1221   return (MSVCRT_intptr_t)LoadLibraryA(dllname);
1222 }
1223
1224 /*********************************************************************
1225  *              _unloaddll (MSVCRT.@)
1226  */
1227 int CDECL _unloaddll(MSVCRT_intptr_t dll)
1228 {
1229   if (FreeLibrary((HMODULE)dll))
1230     return 0;
1231   else
1232   {
1233     int err = GetLastError();
1234     msvcrt_set_errno(err);
1235     return err;
1236   }
1237 }
1238
1239 /*********************************************************************
1240  *              _getdllprocaddr (MSVCRT.@)
1241  */
1242 void * CDECL _getdllprocaddr(MSVCRT_intptr_t dll, const char *name, int ordinal)
1243 {
1244     if (name)
1245     {
1246         if (ordinal != -1) return NULL;
1247         return GetProcAddress( (HMODULE)dll, name );
1248     }
1249     if (HIWORD(ordinal)) return NULL;
1250     return GetProcAddress( (HMODULE)dll, (LPCSTR)(ULONG_PTR)ordinal );
1251 }