msvcrt: undname: correctly handle multi-dimensional arrays.
[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 = _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   long 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 long 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, va_list alist, MSVCRT_wchar_t delim)
273 {
274   va_list alist2;
275   unsigned long len;
276   const MSVCRT_wchar_t *arg;
277   MSVCRT_wchar_t *p, *ret;
278
279 #ifdef HAVE_VA_COPY
280   va_copy(alist2,alist);
281 #else
282 # ifdef HAVE___VA_COPY
283   __va_copy(alist2,alist);
284 # else
285   alist2 = alist;
286 # endif
287 #endif
288
289   if (!arg0)
290   {
291       /* Return NULL for an empty environment list */
292       return NULL;
293   }
294
295   /* get length */
296   arg = arg0;
297   len = 0;
298   do {
299       len += strlenW(arg) + 1;
300       arg = va_arg(alist, MSVCRT_wchar_t*);
301   } while (arg != NULL);
302
303   ret = MSVCRT_malloc((len + 1) * sizeof(MSVCRT_wchar_t));
304   if (!ret)
305     return NULL;
306
307   /* fill string */
308   arg = arg0;
309   p = ret;
310   do {
311       len = strlenW(arg);
312       memcpy(p, arg, len * sizeof(MSVCRT_wchar_t));
313       p += len;
314       *p++ = delim;
315       arg = va_arg(alist2, MSVCRT_wchar_t*);
316   } while (arg != NULL);
317   if (delim && p > ret) p[-1] = 0;
318   else *p = 0;
319   return ret;
320 }
321
322 /* INTERNAL: Convert ansi va_list to a single 'delim'-separated wide string, with an
323  * extra '\0' to terminate it.
324  */
325 static MSVCRT_wchar_t *msvcrt_valisttos_aw(const char *arg0, va_list alist, MSVCRT_wchar_t delim)
326 {
327   va_list alist2;
328   unsigned long len;
329   const char *arg;
330   MSVCRT_wchar_t *p, *ret;
331
332 #ifdef HAVE_VA_COPY
333   va_copy(alist2,alist);
334 #else
335 # ifdef HAVE___VA_COPY
336   __va_copy(alist2,alist);
337 # else
338   alist2 = alist;
339 # endif
340 #endif
341
342   if (!arg0)
343   {
344       /* Return NULL for an empty environment list */
345       return NULL;
346   }
347
348   /* get length */
349   arg = arg0;
350   len = 0;
351   do {
352       len += MultiByteToWideChar(CP_ACP, 0, arg, -1, NULL, 0);
353       arg = va_arg(alist, char*);
354   } while (arg != NULL);
355
356   ret = MSVCRT_malloc((len + 1) * sizeof(MSVCRT_wchar_t));
357   if (!ret)
358     return NULL;
359
360   /* fill string */
361   arg = arg0;
362   p = ret;
363   do {
364       p += MultiByteToWideChar(CP_ACP, 0, arg, strlen(arg), p, len - (p - ret));
365       *p++ = delim;
366       arg = va_arg(alist2, char*);
367   } while (arg != NULL);
368   if (delim && p > ret) p[-1] = 0;
369   else *p = 0;
370   return ret;
371 }
372
373 /* INTERNAL: retrieve COMSPEC environment variable */
374 static MSVCRT_wchar_t *msvcrt_get_comspec(void)
375 {
376   static const MSVCRT_wchar_t cmd[] = {'c','m','d',0};
377   static const MSVCRT_wchar_t comspec[] = {'C','O','M','S','P','E','C',0};
378   MSVCRT_wchar_t *ret;
379   unsigned int len;
380
381   if (!(len = GetEnvironmentVariableW(comspec, NULL, 0))) len = sizeof(cmd)/sizeof(MSVCRT_wchar_t);
382   if ((ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(MSVCRT_wchar_t))))
383   {
384     if (!GetEnvironmentVariableW(comspec, ret, len)) strcpyW(ret, cmd);
385   }
386   return ret;
387 }
388
389 /*********************************************************************
390  *              _cwait (MSVCRT.@)
391  */
392 MSVCRT_intptr_t CDECL _cwait(int *status, MSVCRT_intptr_t pid, int action)
393 {
394   HANDLE hPid = (HANDLE)pid;
395   int doserrno;
396
397   action = action; /* Remove warning */
398
399   if (!WaitForSingleObject(hPid, INFINITE))
400   {
401     if (status)
402     {
403       DWORD stat;
404       GetExitCodeProcess(hPid, &stat);
405       *status = (int)stat;
406     }
407     return pid;
408   }
409   doserrno = GetLastError();
410
411   if (doserrno == ERROR_INVALID_HANDLE)
412   {
413     *MSVCRT__errno() =  MSVCRT_ECHILD;
414     *MSVCRT___doserrno() = doserrno;
415   }
416   else
417     msvcrt_set_errno(doserrno);
418
419   return status ? *status = -1 : -1;
420 }
421
422 /*********************************************************************
423  *      _wexecl (MSVCRT.@)
424  *
425  * Unicode version of _execl
426  */
427 MSVCRT_intptr_t CDECL _wexecl(const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* arg0, ...)
428 {
429   va_list ap;
430   MSVCRT_wchar_t *args;
431   MSVCRT_intptr_t ret;
432
433   va_start(ap, arg0);
434   args = msvcrt_valisttos(arg0, ap, ' ');
435   va_end(ap);
436
437   ret = msvcrt_spawn(MSVCRT__P_OVERLAY, name, args, NULL, 0);
438
439   MSVCRT_free(args);
440   return ret;
441 }
442
443 /*********************************************************************
444  *              _execl (MSVCRT.@)
445  *
446  * Like on Windows, this function does not handle arguments with spaces
447  * or double-quotes.
448  */
449 MSVCRT_intptr_t CDECL _execl(const char* name, const char* arg0, ...)
450 {
451   va_list ap;
452   MSVCRT_wchar_t *nameW, *args;
453   MSVCRT_intptr_t ret;
454
455   if (!(nameW = msvcrt_wstrdupa(name))) return -1;
456
457   va_start(ap, arg0);
458   args = msvcrt_valisttos_aw(arg0, ap, ' ');
459   va_end(ap);
460
461   ret = msvcrt_spawn(MSVCRT__P_OVERLAY, nameW, args, NULL, 0);
462
463   MSVCRT_free(nameW);
464   MSVCRT_free(args);
465   return ret;
466 }
467
468 /*********************************************************************
469  *      _wexecle (MSVCRT.@)
470  *
471  * Unicode version of _execle
472  */
473 MSVCRT_intptr_t CDECL _wexecle(const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* arg0, ...)
474 {
475   va_list ap;
476   MSVCRT_wchar_t *args, *envs = NULL;
477   const MSVCRT_wchar_t * const *envp;
478   MSVCRT_intptr_t ret;
479
480   va_start(ap, arg0);
481   args = msvcrt_valisttos(arg0, ap, ' ');
482   va_end(ap);
483
484   va_start(ap, arg0);
485   while (va_arg( ap, MSVCRT_wchar_t * ) != NULL) /*nothing*/;
486   envp = va_arg( ap, const MSVCRT_wchar_t * const * );
487   if (envp) envs = msvcrt_argvtos(envp, 0);
488   va_end(ap);
489
490   ret = msvcrt_spawn(MSVCRT__P_OVERLAY, name, args, envs, 0);
491
492   MSVCRT_free(args);
493   MSVCRT_free(envs);
494   return ret;
495 }
496
497 /*********************************************************************
498  *              _execle (MSVCRT.@)
499  */
500 MSVCRT_intptr_t CDECL _execle(const char* name, const char* arg0, ...)
501 {
502   va_list ap;
503   MSVCRT_wchar_t *nameW, *args, *envs = NULL;
504   const char * const *envp;
505   MSVCRT_intptr_t ret;
506
507   if (!(nameW = msvcrt_wstrdupa(name))) return -1;
508
509   va_start(ap, arg0);
510   args = msvcrt_valisttos_aw(arg0, ap, ' ');
511   va_end(ap);
512
513   va_start(ap, arg0);
514   while (va_arg( ap, char * ) != NULL) /*nothing*/;
515   envp = va_arg( ap, const char * const * );
516   if (envp) envs = msvcrt_argvtos_aw(envp, 0);
517   va_end(ap);
518
519   ret = msvcrt_spawn(MSVCRT__P_OVERLAY, nameW, args, envs, 0);
520
521   MSVCRT_free(nameW);
522   MSVCRT_free(args);
523   MSVCRT_free(envs);
524   return ret;
525 }
526
527 /*********************************************************************
528  *      _wexeclp (MSVCRT.@)
529  *
530  * Unicode version of _execlp
531  */
532 MSVCRT_intptr_t CDECL _wexeclp(const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* arg0, ...)
533 {
534   va_list ap;
535   MSVCRT_wchar_t *args;
536   MSVCRT_intptr_t ret;
537
538   va_start(ap, arg0);
539   args = msvcrt_valisttos(arg0, ap, ' ');
540   va_end(ap);
541
542   ret = msvcrt_spawn(MSVCRT__P_OVERLAY, name, args, NULL, 1);
543
544   MSVCRT_free(args);
545   return ret;
546 }
547
548 /*********************************************************************
549  *              _execlp (MSVCRT.@)
550  *
551  * Like on Windows, this function does not handle arguments with spaces
552  * or double-quotes.
553  */
554 MSVCRT_intptr_t CDECL _execlp(const char* name, const char* arg0, ...)
555 {
556   va_list ap;
557   MSVCRT_wchar_t *nameW, *args;
558   MSVCRT_intptr_t ret;
559
560   if (!(nameW = msvcrt_wstrdupa(name))) return -1;
561
562   va_start(ap, arg0);
563   args = msvcrt_valisttos_aw(arg0, ap, ' ');
564   va_end(ap);
565
566   ret = msvcrt_spawn(MSVCRT__P_OVERLAY, nameW, args, NULL, 1);
567
568   MSVCRT_free(nameW);
569   MSVCRT_free(args);
570   return ret;
571 }
572
573 /*********************************************************************
574  *      _wexeclpe (MSVCRT.@)
575  *
576  * Unicode version of _execlpe
577  */
578 MSVCRT_intptr_t CDECL _wexeclpe(const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* arg0, ...)
579 {
580   va_list ap;
581   MSVCRT_wchar_t *args, *envs = NULL;
582   const MSVCRT_wchar_t * const *envp;
583   MSVCRT_intptr_t ret;
584
585   va_start(ap, arg0);
586   args = msvcrt_valisttos(arg0, ap, ' ');
587   va_end(ap);
588
589   va_start(ap, arg0);
590   while (va_arg( ap, MSVCRT_wchar_t * ) != NULL) /*nothing*/;
591   envp = va_arg( ap, const MSVCRT_wchar_t * const * );
592   if (envp) envs = msvcrt_argvtos(envp, 0);
593   va_end(ap);
594
595   ret = msvcrt_spawn(MSVCRT__P_OVERLAY, name, args, envs, 1);
596
597   MSVCRT_free(args);
598   MSVCRT_free(envs);
599   return ret;
600 }
601
602 /*********************************************************************
603  *              _execlpe (MSVCRT.@)
604  */
605 MSVCRT_intptr_t CDECL _execlpe(const char* name, const char* arg0, ...)
606 {
607   va_list ap;
608   MSVCRT_wchar_t *nameW, *args, *envs = NULL;
609   const char * const *envp;
610   MSVCRT_intptr_t ret;
611
612   if (!(nameW = msvcrt_wstrdupa(name))) return -1;
613
614   va_start(ap, arg0);
615   args = msvcrt_valisttos_aw(arg0, ap, ' ');
616   va_end(ap);
617
618   va_start(ap, arg0);
619   while (va_arg( ap, char * ) != NULL) /*nothing*/;
620   envp = va_arg( ap, const char * const * );
621   if (envp) envs = msvcrt_argvtos_aw(envp, 0);
622   va_end(ap);
623
624   ret = msvcrt_spawn(MSVCRT__P_OVERLAY, nameW, args, envs, 1);
625
626   MSVCRT_free(nameW);
627   MSVCRT_free(args);
628   MSVCRT_free(envs);
629   return ret;
630 }
631
632 /*********************************************************************
633  *      _wexecv (MSVCRT.@)
634  *
635  * Unicode version of _execv
636  */
637 MSVCRT_intptr_t CDECL _wexecv(const MSVCRT_wchar_t* name, MSVCRT_wchar_t* const* argv)
638 {
639   return _wspawnve(MSVCRT__P_OVERLAY, name, (const MSVCRT_wchar_t* const*) argv, NULL);
640 }
641
642 /*********************************************************************
643  *              _execv (MSVCRT.@)
644  *
645  * Like on Windows, this function does not handle arguments with spaces
646  * or double-quotes.
647  */
648 MSVCRT_intptr_t CDECL _execv(const char* name, char* const* argv)
649 {
650   return _spawnve(MSVCRT__P_OVERLAY, name, (const char* const*) argv, NULL);
651 }
652
653 /*********************************************************************
654  *      _wexecve (MSVCRT.@)
655  *
656  * Unicode version of _execve
657  */
658 MSVCRT_intptr_t CDECL _wexecve(const MSVCRT_wchar_t* name, MSVCRT_wchar_t* const* argv, const MSVCRT_wchar_t* const* envv)
659 {
660   return _wspawnve(MSVCRT__P_OVERLAY, name, (const MSVCRT_wchar_t* const*) argv, envv);
661 }
662
663 /*********************************************************************
664  *              _execve (MSVCRT.@)
665  *
666  * Like on Windows, this function does not handle arguments with spaces
667  * or double-quotes.
668  */
669 MSVCRT_intptr_t CDECL MSVCRT__execve(const char* name, char* const* argv, const char* const* envv)
670 {
671   return _spawnve(MSVCRT__P_OVERLAY, name, (const char* const*) argv, envv);
672 }
673
674 /*********************************************************************
675  *      _wexecvpe (MSVCRT.@)
676  *
677  * Unicode version of _execvpe
678  */
679 MSVCRT_intptr_t CDECL _wexecvpe(const MSVCRT_wchar_t* name, MSVCRT_wchar_t* const* argv, const MSVCRT_wchar_t* const* envv)
680 {
681   return _wspawnvpe(MSVCRT__P_OVERLAY, name, (const MSVCRT_wchar_t* const*) argv, envv);
682 }
683
684 /*********************************************************************
685  *              _execvpe (MSVCRT.@)
686  *
687  * Like on Windows, this function does not handle arguments with spaces
688  * or double-quotes.
689  */
690 MSVCRT_intptr_t CDECL _execvpe(const char* name, char* const* argv, const char* const* envv)
691 {
692   return _spawnvpe(MSVCRT__P_OVERLAY, name, (const char* const*) argv, envv);
693 }
694
695 /*********************************************************************
696  *      _wexecvp (MSVCRT.@)
697  *
698  * Unicode version of _execvp
699  */
700 MSVCRT_intptr_t CDECL _wexecvp(const MSVCRT_wchar_t* name, MSVCRT_wchar_t* const* argv)
701 {
702   return _wexecvpe(name, argv, NULL);
703 }
704
705 /*********************************************************************
706  *              _execvp (MSVCRT.@)
707  *
708  * Like on Windows, this function does not handle arguments with spaces
709  * or double-quotes.
710  */
711 MSVCRT_intptr_t CDECL _execvp(const char* name, char* const* argv)
712 {
713   return _execvpe(name, argv, NULL);
714 }
715
716 /*********************************************************************
717  *      _wspawnl (MSVCRT.@)
718  *
719  * Unicode version of _spawnl
720  */
721 MSVCRT_intptr_t CDECL _wspawnl(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* arg0, ...)
722 {
723   va_list ap;
724   MSVCRT_wchar_t *args;
725   MSVCRT_intptr_t ret;
726
727   va_start(ap, arg0);
728   args = msvcrt_valisttos(arg0, ap, ' ');
729   va_end(ap);
730
731   ret = msvcrt_spawn(flags, name, args, NULL, 0);
732
733   MSVCRT_free(args);
734   return ret;
735 }
736
737 /*********************************************************************
738  *              _spawnl (MSVCRT.@)
739  *
740  * Like on Windows, this function does not handle arguments with spaces
741  * or double-quotes.
742  */
743 MSVCRT_intptr_t CDECL _spawnl(int flags, const char* name, const char* arg0, ...)
744 {
745   va_list ap;
746   MSVCRT_wchar_t *nameW, *args;
747   MSVCRT_intptr_t ret;
748
749   if (!(nameW = msvcrt_wstrdupa(name))) return -1;
750
751   va_start(ap, arg0);
752   args = msvcrt_valisttos_aw(arg0, ap, ' ');
753   va_end(ap);
754
755   ret = msvcrt_spawn(flags, nameW, args, NULL, 0);
756
757   MSVCRT_free(nameW);
758   MSVCRT_free(args);
759   return ret;
760 }
761
762 /*********************************************************************
763  *      _wspawnle (MSVCRT.@)
764  *
765  * Unicode version of _spawnle
766  */
767 MSVCRT_intptr_t CDECL _wspawnle(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* arg0, ...)
768 {
769   va_list ap;
770   MSVCRT_wchar_t *args, *envs = NULL;
771   const MSVCRT_wchar_t * const *envp;
772   MSVCRT_intptr_t ret;
773
774   va_start(ap, arg0);
775   args = msvcrt_valisttos(arg0, ap, ' ');
776   va_end(ap);
777
778   va_start(ap, arg0);
779   while (va_arg( ap, MSVCRT_wchar_t * ) != NULL) /*nothing*/;
780   envp = va_arg( ap, const MSVCRT_wchar_t * const * );
781   if (envp) envs = msvcrt_argvtos(envp, 0);
782   va_end(ap);
783
784   ret = msvcrt_spawn(flags, name, args, envs, 0);
785
786   MSVCRT_free(args);
787   MSVCRT_free(envs);
788   return ret;
789 }
790
791 /*********************************************************************
792  *              _spawnle (MSVCRT.@)
793  */
794 MSVCRT_intptr_t CDECL _spawnle(int flags, const char* name, const char* arg0, ...)
795 {
796   va_list ap;
797   MSVCRT_wchar_t *nameW, *args, *envs = NULL;
798   const char * const *envp;
799   MSVCRT_intptr_t ret;
800
801   if (!(nameW = msvcrt_wstrdupa(name))) return -1;
802
803   va_start(ap, arg0);
804   args = msvcrt_valisttos_aw(arg0, ap, ' ');
805   va_end(ap);
806
807   va_start(ap, arg0);
808   while (va_arg( ap, char * ) != NULL) /*nothing*/;
809   envp = va_arg( ap, const char * const * );
810   if (envp) envs = msvcrt_argvtos_aw(envp, 0);
811   va_end(ap);
812
813   ret = msvcrt_spawn(flags, nameW, args, envs, 0);
814
815   MSVCRT_free(nameW);
816   MSVCRT_free(args);
817   MSVCRT_free(envs);
818   return ret;
819 }
820
821 /*********************************************************************
822  *      _wspawnlp (MSVCRT.@)
823  *
824  * Unicode version of _spawnlp
825  */
826 MSVCRT_intptr_t CDECL _wspawnlp(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* arg0, ...)
827 {
828   va_list ap;
829   MSVCRT_wchar_t *args;
830   MSVCRT_intptr_t ret;
831
832   va_start(ap, arg0);
833   args = msvcrt_valisttos(arg0, ap, ' ');
834   va_end(ap);
835
836   ret = msvcrt_spawn(flags, name, args, NULL, 1);
837
838   MSVCRT_free(args);
839   return ret;
840 }
841
842 /*********************************************************************
843  *              _spawnlp (MSVCRT.@)
844  *
845  * Like on Windows, this function does not handle arguments with spaces
846  * or double-quotes.
847  */
848 MSVCRT_intptr_t CDECL _spawnlp(int flags, const char* name, const char* arg0, ...)
849 {
850   va_list ap;
851   MSVCRT_wchar_t *nameW, *args;
852   MSVCRT_intptr_t ret;
853
854   if (!(nameW = msvcrt_wstrdupa(name))) return -1;
855
856   va_start(ap, arg0);
857   args = msvcrt_valisttos_aw(arg0, ap, ' ');
858   va_end(ap);
859
860   ret = msvcrt_spawn(flags, nameW, args, NULL, 1);
861
862   MSVCRT_free(nameW);
863   MSVCRT_free(args);
864   return ret;
865 }
866
867 /*********************************************************************
868  *      _wspawnlpe (MSVCRT.@)
869  *
870  * Unicode version of _spawnlpe
871  */
872 MSVCRT_intptr_t CDECL _wspawnlpe(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* arg0, ...)
873 {
874   va_list ap;
875   MSVCRT_wchar_t *args, *envs = NULL;
876   const MSVCRT_wchar_t * const *envp;
877   MSVCRT_intptr_t ret;
878
879   va_start(ap, arg0);
880   args = msvcrt_valisttos(arg0, ap, ' ');
881   va_end(ap);
882
883   va_start(ap, arg0);
884   while (va_arg( ap, MSVCRT_wchar_t * ) != NULL) /*nothing*/;
885   envp = va_arg( ap, const MSVCRT_wchar_t * const * );
886   if (envp) envs = msvcrt_argvtos(envp, 0);
887   va_end(ap);
888
889   ret = msvcrt_spawn(flags, name, args, envs, 1);
890
891   MSVCRT_free(args);
892   MSVCRT_free(envs);
893   return ret;
894 }
895
896 /*********************************************************************
897  *              _spawnlpe (MSVCRT.@)
898  */
899 MSVCRT_intptr_t CDECL _spawnlpe(int flags, const char* name, const char* arg0, ...)
900 {
901   va_list ap;
902   MSVCRT_wchar_t *nameW, *args, *envs = NULL;
903   const char * const *envp;
904   MSVCRT_intptr_t ret;
905
906   if (!(nameW = msvcrt_wstrdupa(name))) return -1;
907
908   va_start(ap, arg0);
909   args = msvcrt_valisttos_aw(arg0, ap, ' ');
910   va_end(ap);
911
912   va_start(ap, arg0);
913   while (va_arg( ap, char * ) != NULL) /*nothing*/;
914   envp = va_arg( ap, const char * const * );
915   if (envp) envs = msvcrt_argvtos_aw(envp, 0);
916   va_end(ap);
917
918   ret = msvcrt_spawn(flags, nameW, args, envs, 1);
919
920   MSVCRT_free(nameW);
921   MSVCRT_free(args);
922   MSVCRT_free(envs);
923   return ret;
924 }
925
926 /*********************************************************************
927  *              _spawnve (MSVCRT.@)
928  *
929  * Like on Windows, this function does not handle arguments with spaces
930  * or double-quotes.
931  */
932 MSVCRT_intptr_t CDECL _spawnve(int flags, const char* name, const char* const* argv,
933                                const char* const* envv)
934 {
935   MSVCRT_wchar_t *nameW, *args, *envs;
936   MSVCRT_intptr_t ret;
937
938   if (!(nameW = msvcrt_wstrdupa(name))) return -1;
939
940   args = msvcrt_argvtos_aw(argv, ' ');
941   envs = msvcrt_argvtos_aw(envv, 0);
942
943   ret = msvcrt_spawn(flags, nameW, args, envs, 0);
944
945   MSVCRT_free(nameW);
946   MSVCRT_free(args);
947   MSVCRT_free(envs);
948   return ret;
949 }
950
951 /*********************************************************************
952  *      _wspawnve (MSVCRT.@)
953  *
954  * Unicode version of _spawnve
955  */
956 MSVCRT_intptr_t CDECL _wspawnve(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* const* argv,
957                                 const MSVCRT_wchar_t* const* envv)
958 {
959   MSVCRT_wchar_t *args, *envs;
960   MSVCRT_intptr_t ret;
961
962   args = msvcrt_argvtos(argv, ' ');
963   envs = msvcrt_argvtos(envv, 0);
964
965   ret = msvcrt_spawn(flags, name, args, envs, 0);
966
967   MSVCRT_free(args);
968   MSVCRT_free(envs);
969   return ret;
970 }
971
972 /*********************************************************************
973  *              _spawnv (MSVCRT.@)
974  *
975  * Like on Windows, this function does not handle arguments with spaces
976  * or double-quotes.
977  */
978 MSVCRT_intptr_t CDECL _spawnv(int flags, const char* name, const char* const* argv)
979 {
980   return _spawnve(flags, name, argv, NULL);
981 }
982
983 /*********************************************************************
984  *      _wspawnv (MSVCRT.@)
985  *
986  * Unicode version of _spawnv
987  */
988 MSVCRT_intptr_t CDECL _wspawnv(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* const* argv)
989 {
990   return _wspawnve(flags, name, argv, NULL);
991 }
992
993 /*********************************************************************
994  *              _spawnvpe (MSVCRT.@)
995  *
996  * Like on Windows, this function does not handle arguments with spaces
997  * or double-quotes.
998  */
999 MSVCRT_intptr_t CDECL _spawnvpe(int flags, const char* name, const char* const* argv,
1000                                 const char* const* envv)
1001 {
1002   MSVCRT_wchar_t *nameW, *args, *envs;
1003   MSVCRT_intptr_t ret;
1004
1005   if (!(nameW = msvcrt_wstrdupa(name))) return -1;
1006
1007   args = msvcrt_argvtos_aw(argv, ' ');
1008   envs = msvcrt_argvtos_aw(envv, 0);
1009
1010   ret = msvcrt_spawn(flags, nameW, args, envs, 1);
1011
1012   MSVCRT_free(nameW);
1013   MSVCRT_free(args);
1014   MSVCRT_free(envs);
1015   return ret;
1016 }
1017
1018 /*********************************************************************
1019  *      _wspawnvpe (MSVCRT.@)
1020  *
1021  * Unicode version of _spawnvpe
1022  */
1023 MSVCRT_intptr_t CDECL _wspawnvpe(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* const* argv,
1024                                  const MSVCRT_wchar_t* const* envv)
1025 {
1026   MSVCRT_wchar_t *args, *envs;
1027   MSVCRT_intptr_t ret;
1028
1029   args = msvcrt_argvtos(argv, ' ');
1030   envs = msvcrt_argvtos(envv, 0);
1031
1032   ret = msvcrt_spawn(flags, name, args, envs, 1);
1033
1034   MSVCRT_free(args);
1035   MSVCRT_free(envs);
1036   return ret;
1037 }
1038
1039 /*********************************************************************
1040  *              _spawnvp (MSVCRT.@)
1041  *
1042  * Like on Windows, this function does not handle arguments with spaces
1043  * or double-quotes.
1044  */
1045 MSVCRT_intptr_t CDECL _spawnvp(int flags, const char* name, const char* const* argv)
1046 {
1047   return _spawnvpe(flags, name, argv, NULL);
1048 }
1049
1050 /*********************************************************************
1051  *      _wspawnvp (MSVCRT.@)
1052  *
1053  * Unicode version of _spawnvp
1054  */
1055 MSVCRT_intptr_t CDECL _wspawnvp(int flags, const MSVCRT_wchar_t* name, const MSVCRT_wchar_t* const* argv)
1056 {
1057   return _wspawnvpe(flags, name, argv, NULL);
1058 }
1059
1060 /*********************************************************************
1061  *              _wpopen (MSVCRT.@)
1062  *
1063  * Unicode version of _popen
1064  */
1065 MSVCRT_FILE* CDECL MSVCRT__wpopen(const MSVCRT_wchar_t* command, const MSVCRT_wchar_t* mode)
1066 {
1067   MSVCRT_FILE *ret;
1068   BOOL readPipe = TRUE;
1069   int textmode, fds[2], fdToDup, fdToOpen, fdStdHandle = -1, fdStdErr = -1;
1070   const MSVCRT_wchar_t *p;
1071   MSVCRT_wchar_t *comspec, *fullcmd;
1072   unsigned int len;
1073   static const MSVCRT_wchar_t flag[] = {' ','/','c',' ',0};
1074
1075   TRACE("(command=%s, mode=%s)\n", debugstr_w(command), debugstr_w(mode));
1076
1077   if (!command || !mode)
1078     return NULL;
1079
1080   textmode = *__p__fmode() & (MSVCRT__O_BINARY | MSVCRT__O_TEXT);
1081   for (p = mode; *p; p++)
1082   {
1083     switch (*p)
1084     {
1085       case 'W':
1086       case 'w':
1087         readPipe = FALSE;
1088         break;
1089       case 'B':
1090       case 'b':
1091         textmode |= MSVCRT__O_BINARY;
1092         textmode &= ~MSVCRT__O_TEXT;
1093         break;
1094       case 'T':
1095       case 't':
1096         textmode |= MSVCRT__O_TEXT;
1097         textmode &= ~MSVCRT__O_BINARY;
1098         break;
1099     }
1100   }
1101   if (MSVCRT__pipe(fds, 0, textmode) == -1)
1102     return NULL;
1103
1104   fdToDup = readPipe ? 1 : 0;
1105   fdToOpen = readPipe ? 0 : 1;
1106
1107   if ((fdStdHandle = MSVCRT__dup(fdToDup)) == -1)
1108     goto error;
1109   if (MSVCRT__dup2(fds[fdToDup], fdToDup) != 0)
1110     goto error;
1111   if (readPipe)
1112   {
1113     if ((fdStdErr = MSVCRT__dup(MSVCRT_STDERR_FILENO)) == -1)
1114       goto error;
1115     if (MSVCRT__dup2(fds[fdToDup], MSVCRT_STDERR_FILENO) != 0)
1116       goto error;
1117   }
1118
1119   MSVCRT__close(fds[fdToDup]);
1120
1121   if (!(comspec = msvcrt_get_comspec())) goto error;
1122   len = strlenW(comspec) + strlenW(flag) + strlenW(command) + 1;
1123
1124   if (!(fullcmd = HeapAlloc(GetProcessHeap(), 0, len * sizeof(MSVCRT_wchar_t)))) goto error;
1125   strcpyW(fullcmd, comspec);
1126   strcatW(fullcmd, flag);
1127   strcatW(fullcmd, command);
1128   HeapFree(GetProcessHeap(), 0, comspec);
1129
1130   if (msvcrt_spawn(MSVCRT__P_NOWAIT, NULL, fullcmd, NULL, 1) == -1)
1131   {
1132     MSVCRT__close(fds[fdToOpen]);
1133     ret = NULL;
1134   }
1135   else
1136   {
1137     ret = MSVCRT__wfdopen(fds[fdToOpen], mode);
1138     if (!ret)
1139       MSVCRT__close(fds[fdToOpen]);
1140   }
1141   HeapFree(GetProcessHeap(), 0, fullcmd);
1142   MSVCRT__dup2(fdStdHandle, fdToDup);
1143   MSVCRT__close(fdStdHandle);
1144   if (readPipe)
1145   {
1146     MSVCRT__dup2(fdStdErr, MSVCRT_STDERR_FILENO);
1147     MSVCRT__close(fdStdErr);
1148   }
1149   return ret;
1150
1151 error:
1152   if (fdStdHandle != -1) MSVCRT__close(fdStdHandle);
1153   if (fdStdErr != -1)    MSVCRT__close(fdStdErr);
1154   MSVCRT__close(fds[0]);
1155   MSVCRT__close(fds[1]);
1156   return NULL;
1157 }
1158
1159 /*********************************************************************
1160  *      _popen (MSVCRT.@)
1161  */
1162 MSVCRT_FILE* CDECL MSVCRT__popen(const char* command, const char* mode)
1163 {
1164   MSVCRT_FILE *ret;
1165   MSVCRT_wchar_t *cmdW, *modeW;
1166
1167   TRACE("(command=%s, mode=%s)\n", debugstr_a(command), debugstr_a(mode));
1168
1169   if (!command || !mode)
1170     return NULL;
1171
1172   if (!(cmdW = msvcrt_wstrdupa(command))) return NULL;
1173   if (!(modeW = msvcrt_wstrdupa(mode)))
1174   {
1175     HeapFree(GetProcessHeap(), 0, cmdW);
1176     return NULL;
1177   }
1178
1179   ret = MSVCRT__wpopen(cmdW, modeW);
1180
1181   HeapFree(GetProcessHeap(), 0, cmdW);
1182   HeapFree(GetProcessHeap(), 0, modeW);
1183   return ret;
1184 }
1185
1186 /*********************************************************************
1187  *              _pclose (MSVCRT.@)
1188  */
1189 int CDECL MSVCRT__pclose(MSVCRT_FILE* file)
1190 {
1191   return MSVCRT_fclose(file);
1192 }
1193
1194 /*********************************************************************
1195  *      _wsystem (MSVCRT.@)
1196  *
1197  * Unicode version of system
1198  */
1199 int CDECL _wsystem(const MSVCRT_wchar_t* cmd)
1200 {
1201   int res;
1202   MSVCRT_wchar_t *comspec, *fullcmd;
1203   unsigned int len;
1204   static const MSVCRT_wchar_t flag[] = {' ','/','c',' ',0};
1205
1206   if (!(comspec = msvcrt_get_comspec())) return -1;
1207   len = strlenW(comspec) + strlenW(flag) + strlenW(cmd) + 1;
1208
1209   if (!(fullcmd = HeapAlloc(GetProcessHeap(), 0, len * sizeof(MSVCRT_wchar_t))))
1210   {
1211     HeapFree(GetProcessHeap(), 0, comspec);
1212     return -1;
1213   }
1214   strcpyW(fullcmd, comspec);
1215   strcatW(fullcmd, flag);
1216   strcatW(fullcmd, cmd);
1217
1218   res = msvcrt_spawn(MSVCRT__P_WAIT, comspec, fullcmd, NULL, 1);
1219
1220   HeapFree(GetProcessHeap(), 0, comspec);
1221   HeapFree(GetProcessHeap(), 0, fullcmd);
1222   return res;
1223 }
1224
1225 /*********************************************************************
1226  *              system (MSVCRT.@)
1227  */
1228 int CDECL MSVCRT_system(const char* cmd)
1229 {
1230   int res = -1;
1231   MSVCRT_wchar_t *cmdW;
1232
1233   if ((cmdW = msvcrt_wstrdupa(cmd)))
1234   {
1235     res = _wsystem(cmdW);
1236     HeapFree(GetProcessHeap(), 0, cmdW);
1237   }
1238   return res;
1239 }
1240
1241 /*********************************************************************
1242  *              _loaddll (MSVCRT.@)
1243  */
1244 MSVCRT_intptr_t CDECL _loaddll(const char* dllname)
1245 {
1246   return (MSVCRT_intptr_t)LoadLibraryA(dllname);
1247 }
1248
1249 /*********************************************************************
1250  *              _unloaddll (MSVCRT.@)
1251  */
1252 int CDECL _unloaddll(MSVCRT_intptr_t dll)
1253 {
1254   if (FreeLibrary((HMODULE)dll))
1255     return 0;
1256   else
1257   {
1258     int err = GetLastError();
1259     msvcrt_set_errno(err);
1260     return err;
1261   }
1262 }
1263
1264 /*********************************************************************
1265  *              _getdllprocaddr (MSVCRT.@)
1266  */
1267 void * CDECL _getdllprocaddr(MSVCRT_intptr_t dll, const char *name, int ordinal)
1268 {
1269     if (name)
1270     {
1271         if (ordinal != -1) return NULL;
1272         return GetProcAddress( (HMODULE)dll, name );
1273     }
1274     if (HIWORD(ordinal)) return NULL;
1275     return GetProcAddress( (HMODULE)dll, (LPCSTR)(ULONG_PTR)ordinal );
1276 }