process.c 31.1 KB
Newer Older
1 2 3 4 5 6 7
/*
 * msvcrt.dll spawn/exec functions
 *
 * Copyright 1996,1998 Marcus Meissner
 * Copyright 1996 Jukka Iivonen
 * Copyright 1997,2000 Uwe Bonnes
 * Copyright 2000 Jon Griffiths
8
 * Copyright 2007 Hans Leidekker
9
 *
10 11 12 13 14 15 16 17 18 19 20 21
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * 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 25 26 27 28
 * FIXME:
 * -File handles need some special handling. Sometimes children get
 *  open file handles, sometimes not. The docs are confusing
 * -No check for maximum path/argument/environment size is done
 */
29

30
#include <fcntl.h>
31
#include <io.h>
32
#include <process.h>
33 34
#include <stdarg.h>

35
#include "msvcrt.h"
36
#include <winnls.h>
37
#include "mtdll.h"
38 39 40
#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(msvcrt);
41

42
static void msvcrt_search_executable(const wchar_t *name, wchar_t *fullname, int use_path)
43
{
44
  static const wchar_t suffix[][5] =
45
    {L".com", L".exe", L".bat", L".cmd"};
46

47 48
  wchar_t buffer[MAX_PATH];
  const wchar_t *env, *p, *end;
49 50 51 52 53 54
  unsigned int i, name_len, path_len;
  int extension = 1;

  *fullname = '\0';
  msvcrt_set_errno(ERROR_FILE_NOT_FOUND);

55 56 57
  end = name + MAX_PATH - 1;
  for(p = name; p < end; p++)
      if(!*p) break;
58 59 60
  name_len = p - name;

  /* FIXME extra-long names are silently truncated */
61
  memcpy(buffer, name, name_len * sizeof(wchar_t));
62 63 64 65 66
  buffer[name_len] = '\0';

  /* try current dir first */
  if (GetFileAttributesW(buffer) != INVALID_FILE_ATTRIBUTES)
  {
67
    wcscpy(fullname, buffer);
68 69 70 71 72 73 74 75 76 77 78
    return;
  }

  for (p--; p >= name; p--)
    if (*p == '\\' || *p == '/' || *p == ':' || *p == '.') break;

  /* if there's no extension, try some well-known extensions */
  if ((p < name || *p != '.') && name_len <= MAX_PATH - 5)
  {
    for (i = 0; i < 4; i++)
    {
79
      memcpy(buffer + name_len, suffix[i], 5 * sizeof(wchar_t));
80 81
      if (GetFileAttributesW(buffer) != INVALID_FILE_ATTRIBUTES)
      {
82
        wcscpy(fullname, buffer);
83 84 85 86 87 88
        return;
      }
    }
    extension = 0;
  }

89
  if (!use_path || !(env = _wgetenv(L"PATH"))) return;
90 91 92 93 94 95 96 97 98 99 100

  /* now try search path */
  do
  {
    p = env;
    while (*p && *p != ';') p++;
    if (p == env) return;

    path_len = p - env;
    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] != '\\')
103 104 105 106 107 108
      {
        buffer[path_len++] = '\\';
        buffer[path_len] = '\0';
      }
      else buffer[path_len] = '\0';

109
      wcscat(buffer, name);
110 111
      if (GetFileAttributesW(buffer) != INVALID_FILE_ATTRIBUTES)
      {
112
        wcscpy(fullname, buffer);
113 114 115 116 117 118 119 120
        return;
      }
    }
    /* again, if there's no extension, try some well-known extensions */
    if (!extension && path_len + name_len <= MAX_PATH - 5)
    {
      for (i = 0; i < 4; i++)
      {
121
        memcpy(buffer + path_len + name_len, suffix[i], 5 * sizeof(wchar_t));
122 123
        if (GetFileAttributesW(buffer) != INVALID_FILE_ATTRIBUTES)
        {
124
          wcscpy(fullname, buffer);
125 126 127 128 129 130 131 132
          return;
        }
      }
    }
    env = *p ? p + 1 : p;
  } while(1);
}

133
static intptr_t msvcrt_spawn(int flags, const wchar_t* exe, wchar_t* cmdline,
134
                                    wchar_t* env, int use_path)
135 136 137
{
  STARTUPINFOW si;
  PROCESS_INFORMATION pi;
138
  wchar_t fullname[MAX_PATH];
139
  DWORD create_flags = CREATE_UNICODE_ENVIRONMENT;
140 141

  TRACE("%x %s %s %s %d\n", flags, debugstr_w(exe), debugstr_w(cmdline), debugstr_w(env), use_path);
142

143
  if ((unsigned)flags > _P_DETACH)
144
  {
145
    *_errno() = EINVAL;
146 147 148
    return -1;
  }

149 150
  msvcrt_search_executable(exe, fullname, use_path);

151 152 153
  memset(&si, 0, sizeof(si));
  si.cb = sizeof(si);
  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))
157 158
  {
    msvcrt_set_errno(GetLastError());
159
    free(si.lpReserved2);
160 161 162
    return -1;
  }

163
  free(si.lpReserved2);
164 165
  switch(flags)
  {
166
  case _P_WAIT:
167 168 169 170 171
    WaitForSingleObject(pi.hProcess, INFINITE);
    GetExitCodeProcess(pi.hProcess,&pi.dwProcessId);
    CloseHandle(pi.hProcess);
    CloseHandle(pi.hThread);
    return pi.dwProcessId;
172
  case _P_DETACH:
173 174 175
    CloseHandle(pi.hProcess);
    pi.hProcess = 0;
    /* fall through */
176 177
  case _P_NOWAIT:
  case _P_NOWAITO:
178
    CloseHandle(pi.hThread);
179
    return (intptr_t)pi.hProcess;
180
  case  _P_OVERLAY:
181
    _exit(0);
182 183 184 185
  }
  return -1; /* can't reach here */
}

186 187 188
/* INTERNAL: Convert wide argv list to a single 'delim'-separated wide string, with an
 * extra '\0' to terminate it.
 */
189
static wchar_t* msvcrt_argvtos(const wchar_t* const* arg, wchar_t delim)
190
{
191
  const wchar_t* const* a;
192
  int size;
193 194
  wchar_t* p;
  wchar_t* ret;
195

196
  if (!arg)
197 198 199 200 201 202 203 204 205 206
  {
      /* Return NULL for an empty environment list */
      return NULL;
  }

  /* get length */
  a = arg;
  size = 0;
  while (*a)
  {
207
    size += wcslen(*a) + 1;
208 209 210
    a++;
  }

211
  ret = malloc((size + 1) * sizeof(wchar_t));
212 213 214 215 216 217 218 219
  if (!ret)
    return NULL;

  /* fill string */
  a = arg;
  p = ret;
  while (*a)
  {
220
    int len = wcslen(*a);
221
    memcpy(p,*a,len * sizeof(wchar_t));
222 223 224 225 226 227 228 229 230
    p += len;
    *p++ = delim;
    a++;
  }
  if (delim && p > ret) p[-1] = 0;
  else *p = 0;
  return ret;
}

231 232
/* INTERNAL: Convert ansi argv list to a single 'delim'-separated wide string, with an
 * extra '\0' to terminate it.
233
 */
234
static wchar_t *msvcrt_argvtos_aw(const char * const *arg, wchar_t delim)
235 236
{
  const char * const *a;
237
  unsigned int len;
238
  wchar_t *p, *ret;
239

240
  if (!arg)
241 242 243 244 245 246 247 248 249 250 251 252 253 254
  {
      /* Return NULL for an empty environment list */
      return NULL;
  }

  /* get length */
  a = arg;
  len = 0;
  while (*a)
  {
    len += MultiByteToWideChar(CP_ACP, 0, *a, -1, NULL, 0);
    a++;
  }

255
  ret = malloc((len + 1) * sizeof(wchar_t));
256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272
  if (!ret)
    return NULL;

  /* fill string */
  a = arg;
  p = ret;
  while (*a)
  {
    p += MultiByteToWideChar(CP_ACP, 0, *a, strlen(*a), p, len - (p - ret));
    *p++ = delim;
    a++;
  }
  if (delim && p > ret) p[-1] = 0;
  else *p = 0;
  return ret;
}

273 274 275
/* INTERNAL: Convert wide va_list to a single 'delim'-separated wide string, with an
 * extra '\0' to terminate it.
 */
276
static wchar_t *msvcrt_valisttos(const wchar_t *arg0, __ms_va_list alist, wchar_t delim)
277
{
278
    unsigned int size = 0, pos = 0;
279 280
    const wchar_t *arg;
    wchar_t *new, *ret = NULL;
281

282
    for (arg = arg0; arg; arg = va_arg( alist, wchar_t * ))
283
    {
284
        unsigned int len = wcslen( arg ) + 1;
285 286 287 288
        if (pos + len >= size)
        {
            size = max( 256, size * 2 );
            size = max( size, pos + len + 1 );
289
            if (!(new = realloc( ret, size * sizeof(wchar_t) )))
290
            {
291
                free( ret );
292 293 294 295
                return NULL;
            }
            ret = new;
        }
296
        wcscpy( ret + pos, arg );
297 298 299 300 301 302 303 304 305
        pos += len;
        ret[pos - 1] = delim;
    }
    if (pos)
    {
        if (delim) ret[pos - 1] = 0;
        else ret[pos] = 0;
    }
    return ret;
306 307
}

308 309 310
/* INTERNAL: Convert ansi va_list to a single 'delim'-separated wide string, with an
 * extra '\0' to terminate it.
 */
311
static wchar_t *msvcrt_valisttos_aw(const char *arg0, __ms_va_list alist, wchar_t delim)
312
{
313 314
    unsigned int size = 0, pos = 0;
    const char *arg;
315
    wchar_t *new, *ret = NULL;
316

317 318 319 320 321 322 323
    for (arg = arg0; arg; arg = va_arg( alist, char * ))
    {
        unsigned int len = MultiByteToWideChar( CP_ACP, 0, arg, -1, NULL, 0 );
        if (pos + len >= size)
        {
            size = max( 256, size * 2 );
            size = max( size, pos + len + 1 );
324
            if (!(new = realloc( ret, size * sizeof(wchar_t) )))
325
            {
326
                free( ret );
327 328 329 330 331 332 333 334 335 336 337 338 339
                return NULL;
            }
            ret = new;
        }
        pos += MultiByteToWideChar( CP_ACP, 0, arg, -1, ret + pos, size - pos );
        ret[pos - 1] = delim;
    }
    if (pos)
    {
        if (delim) ret[pos - 1] = 0;
        else ret[pos] = 0;
    }
    return ret;
340 341
}

342
/* INTERNAL: retrieve COMSPEC environment variable */
343
static wchar_t *msvcrt_get_comspec(void)
344
{
345
  wchar_t *ret;
346 347
  unsigned int len;

348
  if (!(len = GetEnvironmentVariableW(L"COMSPEC", NULL, 0))) len = 4;
349
  if ((ret = HeapAlloc(GetProcessHeap(), 0, len * sizeof(wchar_t))))
350
  {
351
    if (!GetEnvironmentVariableW(L"COMSPEC", ret, len)) wcscpy(ret, L"cmd");
352 353 354 355
  }
  return ret;
}

356 357 358
/*********************************************************************
 *		_cwait (MSVCRT.@)
 */
359
intptr_t CDECL _cwait(int *status, intptr_t pid, int action)
360 361 362 363
{
  HANDLE hPid = (HANDLE)pid;
  int doserrno;

364
  if (!WaitForSingleObject(hPid, INFINITE))
365 366 367 368 369 370 371
  {
    if (status)
    {
      DWORD stat;
      GetExitCodeProcess(hPid, &stat);
      *status = (int)stat;
    }
372
    return pid;
373 374 375 376 377
  }
  doserrno = GetLastError();

  if (doserrno == ERROR_INVALID_HANDLE)
  {
378 379
    *_errno() =  ECHILD;
    *__doserrno() = doserrno;
380 381
  }
  else
382
    msvcrt_set_errno(doserrno);
383 384 385 386

  return status ? *status = -1 : -1;
}

387 388 389 390 391
/*********************************************************************
 *      _wexecl (MSVCRT.@)
 *
 * Unicode version of _execl
 */
392
intptr_t WINAPIV _wexecl(const wchar_t* name, const wchar_t* arg0, ...)
393
{
394
  __ms_va_list ap;
395
  wchar_t *args;
396
  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(_P_OVERLAY, name, args, NULL, 0);
403

404
  free(args);
405 406 407
  return ret;
}

408 409
/*********************************************************************
 *		_execl (MSVCRT.@)
410
 *
411
 * Like on Windows, this function does not handle arguments with spaces
412
 * or double-quotes.
413
 */
414
intptr_t WINAPIV _execl(const char* name, const char* arg0, ...)
415
{
416
  __ms_va_list ap;
417
  wchar_t *nameW, *args;
418
  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(_P_OVERLAY, nameW, args, NULL, 0);
427

428 429
  free(nameW);
  free(args);
430 431 432
  return ret;
}

433 434 435 436 437
/*********************************************************************
 *      _wexecle (MSVCRT.@)
 *
 * Unicode version of _execle
 */
438
intptr_t WINAPIV _wexecle(const wchar_t* name, const wchar_t* arg0, ...)
439
{
440
  __ms_va_list ap;
441 442
  wchar_t *args, *envs = NULL;
  const wchar_t * const *envp;
443
  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 451
  while (va_arg( ap, wchar_t * ) != NULL) /*nothing*/;
  envp = va_arg( ap, const wchar_t * const * );
452
  if (envp) envs = msvcrt_argvtos(envp, 0);
453
  __ms_va_end(ap);
454

455
  ret = msvcrt_spawn(_P_OVERLAY, name, args, envs, 0);
456

457 458
  free(args);
  free(envs);
459 460 461
  return ret;
}

462 463 464
/*********************************************************************
 *		_execle (MSVCRT.@)
 */
465
intptr_t WINAPIV _execle(const char* name, const char* arg0, ...)
466
{
467
  __ms_va_list ap;
468
  wchar_t *nameW, *args, *envs = NULL;
469
  const char * const *envp;
470
  intptr_t ret;
471 472 473

  if (!(nameW = msvcrt_wstrdupa(name))) return -1;

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 480 481
  while (va_arg( ap, char * ) != NULL) /*nothing*/;
  envp = va_arg( ap, const char * const * );
  if (envp) envs = msvcrt_argvtos_aw(envp, 0);
482
  __ms_va_end(ap);
483

484
  ret = msvcrt_spawn(_P_OVERLAY, nameW, args, envs, 0);
485

486 487 488
  free(nameW);
  free(args);
  free(envs);
489
  return ret;
490 491
}

492 493 494 495 496
/*********************************************************************
 *      _wexeclp (MSVCRT.@)
 *
 * Unicode version of _execlp
 */
497
intptr_t WINAPIV _wexeclp(const wchar_t* name, const wchar_t* arg0, ...)
498
{
499
  __ms_va_list ap;
500
  wchar_t *args;
501
  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(_P_OVERLAY, name, args, NULL, 1);
508

509
  free(args);
510 511 512
  return ret;
}

513 514
/*********************************************************************
 *		_execlp (MSVCRT.@)
515
 *
516
 * Like on Windows, this function does not handle arguments with spaces
517
 * or double-quotes.
518
 */
519
intptr_t WINAPIV _execlp(const char* name, const char* arg0, ...)
520
{
521
  __ms_va_list ap;
522
  wchar_t *nameW, *args;
523
  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(_P_OVERLAY, nameW, args, NULL, 1);
532

533 534
  free(nameW);
  free(args);
535 536 537
  return ret;
}

538 539 540 541 542
/*********************************************************************
 *      _wexeclpe (MSVCRT.@)
 *
 * Unicode version of _execlpe
 */
543
intptr_t WINAPIV _wexeclpe(const wchar_t* name, const wchar_t* arg0, ...)
544
{
545
  __ms_va_list ap;
546 547
  wchar_t *args, *envs = NULL;
  const wchar_t * const *envp;
548
  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 556
  while (va_arg( ap, wchar_t * ) != NULL) /*nothing*/;
  envp = va_arg( ap, const wchar_t * const * );
557
  if (envp) envs = msvcrt_argvtos(envp, 0);
558
  __ms_va_end(ap);
559

560
  ret = msvcrt_spawn(_P_OVERLAY, name, args, envs, 1);
561

562 563
  free(args);
  free(envs);
564 565 566
  return ret;
}

567 568 569
/*********************************************************************
 *		_execlpe (MSVCRT.@)
 */
570
intptr_t WINAPIV _execlpe(const char* name, const char* arg0, ...)
571
{
572
  __ms_va_list ap;
573
  wchar_t *nameW, *args, *envs = NULL;
574
  const char * const *envp;
575
  intptr_t ret;
576 577 578

  if (!(nameW = msvcrt_wstrdupa(name))) return -1;

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 585 586
  while (va_arg( ap, char * ) != NULL) /*nothing*/;
  envp = va_arg( ap, const char * const * );
  if (envp) envs = msvcrt_argvtos_aw(envp, 0);
587
  __ms_va_end(ap);
588

589
  ret = msvcrt_spawn(_P_OVERLAY, nameW, args, envs, 1);
590

591 592 593
  free(nameW);
  free(args);
  free(envs);
594
  return ret;
595 596
}

597 598 599 600 601
/*********************************************************************
 *      _wexecv (MSVCRT.@)
 *
 * Unicode version of _execv
 */
602
intptr_t CDECL _wexecv(const wchar_t* name, const wchar_t* const* argv)
603
{
604
  return _wspawnve(_P_OVERLAY, name, 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
intptr_t CDECL _execv(const char* name, const char* const* argv)
614
{
615
  return _spawnve(_P_OVERLAY, name, argv, NULL);
616 617
}

618 619 620 621 622
/*********************************************************************
 *      _wexecve (MSVCRT.@)
 *
 * Unicode version of _execve
 */
623
intptr_t CDECL _wexecve(const wchar_t* name, const wchar_t* const* argv, const wchar_t* const* envv)
624
{
625
  return _wspawnve(_P_OVERLAY, name, 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
intptr_t CDECL _execve(const char* name, const char* const* argv, const char* const* envv)
635
{
636
  return _spawnve(_P_OVERLAY, name, argv, envv);
637 638
}

639 640 641 642 643
/*********************************************************************
 *      _wexecvpe (MSVCRT.@)
 *
 * Unicode version of _execvpe
 */
644
intptr_t CDECL _wexecvpe(const wchar_t* name, const wchar_t* const* argv, const wchar_t* const* envv)
645
{
646
  return _wspawnvpe(_P_OVERLAY, name, 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
intptr_t CDECL _execvpe(const char* name, const char* const* argv, const char* const* envv)
656
{
657
  return _spawnvpe(_P_OVERLAY, name, argv, envv);
658 659
}

660 661 662 663 664
/*********************************************************************
 *      _wexecvp (MSVCRT.@)
 *
 * Unicode version of _execvp
 */
665
intptr_t CDECL _wexecvp(const wchar_t* name, const wchar_t* const* argv)
666 667 668 669
{
  return _wexecvpe(name, argv, NULL);
}

670 671
/*********************************************************************
 *		_execvp (MSVCRT.@)
672
 *
673
 * Like on Windows, this function does not handle arguments with spaces
674
 * or double-quotes.
675
 */
676
intptr_t CDECL _execvp(const char* name, const char* const* argv)
677 678 679 680
{
  return _execvpe(name, argv, NULL);
}

681 682 683 684 685
/*********************************************************************
 *      _wspawnl (MSVCRT.@)
 *
 * Unicode version of _spawnl
 */
686
intptr_t WINAPIV _wspawnl(int flags, const wchar_t* name, const wchar_t* arg0, ...)
687
{
688
  __ms_va_list ap;
689
  wchar_t *args;
690
  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
  free(args);
699 700 701
  return ret;
}

702 703
/*********************************************************************
 *		_spawnl (MSVCRT.@)
704
 *
705
 * Like on Windows, this function does not handle arguments with spaces
706
 * or double-quotes.
707
 */
708
intptr_t WINAPIV _spawnl(int flags, const char* name, const char* arg0, ...)
709
{
710
  __ms_va_list ap;
711
  wchar_t *nameW, *args;
712
  intptr_t ret;
713

714 715
  if (!(nameW = msvcrt_wstrdupa(name))) return -1;

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 723
  free(nameW);
  free(args);
724 725 726
  return ret;
}

727 728 729 730 731
/*********************************************************************
 *      _wspawnle (MSVCRT.@)
 *
 * Unicode version of _spawnle
 */
732
intptr_t WINAPIV _wspawnle(int flags, const wchar_t* name, const wchar_t* arg0, ...)
733
{
734
  __ms_va_list ap;
735 736
  wchar_t *args, *envs = NULL;
  const wchar_t * const *envp;
737
  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 745
  while (va_arg( ap, wchar_t * ) != NULL) /*nothing*/;
  envp = va_arg( ap, const 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 752
  free(args);
  free(envs);
753 754 755
  return ret;
}

756 757 758
/*********************************************************************
 *		_spawnle (MSVCRT.@)
 */
759
intptr_t WINAPIV _spawnle(int flags, const char* name, const char* arg0, ...)
760
{
761
  __ms_va_list ap;
762
  wchar_t *nameW, *args, *envs = NULL;
763
  const char * const *envp;
764
  intptr_t ret;
765 766 767

  if (!(nameW = msvcrt_wstrdupa(name))) return -1;

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 774 775
  while (va_arg( ap, char * ) != NULL) /*nothing*/;
  envp = va_arg( ap, const char * const * );
  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 781 782
  free(nameW);
  free(args);
  free(envs);
783
  return ret;
784 785
}

786 787 788 789 790
/*********************************************************************
 *      _wspawnlp (MSVCRT.@)
 *
 * Unicode version of _spawnlp
 */
791
intptr_t WINAPIV _wspawnlp(int flags, const wchar_t* name, const wchar_t* arg0, ...)
792
{
793
  __ms_va_list ap;
794
  wchar_t *args;
795
  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
  free(args);
804 805
  return ret;
}
806

807
/*********************************************************************
808
 *		_spawnlp (MSVCRT.@)
809
 *
810
 * Like on Windows, this function does not handle arguments with spaces
811
 * or double-quotes.
812
 */
813
intptr_t WINAPIV _spawnlp(int flags, const char* name, const char* arg0, ...)
814
{
815
  __ms_va_list ap;
816
  wchar_t *nameW, *args;
817
  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 828
  free(nameW);
  free(args);
829 830 831
  return ret;
}

832 833 834 835 836
/*********************************************************************
 *      _wspawnlpe (MSVCRT.@)
 *
 * Unicode version of _spawnlpe
 */
837
intptr_t WINAPIV _wspawnlpe(int flags, const wchar_t* name, const wchar_t* arg0, ...)
838
{
839
  __ms_va_list ap;
840 841
  wchar_t *args, *envs = NULL;
  const wchar_t * const *envp;
842
  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 850
  while (va_arg( ap, wchar_t * ) != NULL) /*nothing*/;
  envp = va_arg( ap, const 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 857
  free(args);
  free(envs);
858 859 860
  return ret;
}

861 862 863
/*********************************************************************
 *		_spawnlpe (MSVCRT.@)
 */
864
intptr_t WINAPIV _spawnlpe(int flags, const char* name, const char* arg0, ...)
865
{
866
  __ms_va_list ap;
867
  wchar_t *nameW, *args, *envs = NULL;
868
  const char * const *envp;
869
  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 879 880
  while (va_arg( ap, char * ) != NULL) /*nothing*/;
  envp = va_arg( ap, const char * const * );
  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 886 887
  free(nameW);
  free(args);
  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
intptr_t CDECL _spawnve(int flags, const char* name, const char* const* argv,
898
                               const char* const* envv)
899
{
900
  wchar_t *nameW, *args, *envs;
901
  intptr_t ret;
902

903
  if (!(nameW = msvcrt_wstrdupa(name))) return -1;
904

905 906
  args = msvcrt_argvtos_aw(argv, ' ');
  envs = msvcrt_argvtos_aw(envv, 0);
907

908
  ret = msvcrt_spawn(flags, nameW, args, envs, 0);
909

910 911 912
  free(nameW);
  free(args);
  free(envs);
913 914 915
  return ret;
}

916 917 918 919 920
/*********************************************************************
 *      _wspawnve (MSVCRT.@)
 *
 * 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)
923
{
924
  wchar_t *args, *envs;
925
  intptr_t ret;
926

927 928
  args = msvcrt_argvtos(argv, ' ');
  envs = msvcrt_argvtos(envv, 0);
929

930
  ret = msvcrt_spawn(flags, name, args, envs, 0);
931

932 933
  free(args);
  free(envs);
934 935 936
  return ret;
}

937 938
/*********************************************************************
 *		_spawnv (MSVCRT.@)
939
 *
940
 * Like on Windows, this function does not handle arguments with spaces
941
 * or double-quotes.
942
 */
943
intptr_t CDECL _spawnv(int flags, const char* name, const char* const* argv)
944
{
945
  return _spawnve(flags, name, argv, NULL);
946 947
}

948 949 950 951 952
/*********************************************************************
 *      _wspawnv (MSVCRT.@)
 *
 * Unicode version of _spawnv
 */
953
intptr_t CDECL _wspawnv(int flags, const wchar_t* name, const wchar_t* const* argv)
954
{
955
  return _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
intptr_t CDECL _spawnvpe(int flags, const char* name, const char* const* argv,
965
                                const char* const* envv)
966
{
967
  wchar_t *nameW, *args, *envs;
968
  intptr_t ret;
969 970 971 972 973 974 975 976

  if (!(nameW = msvcrt_wstrdupa(name))) return -1;

  args = msvcrt_argvtos_aw(argv, ' ');
  envs = msvcrt_argvtos_aw(envv, 0);

  ret = msvcrt_spawn(flags, nameW, args, envs, 1);

977 978 979
  free(nameW);
  free(args);
  free(envs);
980
  return ret;
981 982
}

983 984 985 986 987
/*********************************************************************
 *      _wspawnvpe (MSVCRT.@)
 *
 * 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)
990
{
991
  wchar_t *args, *envs;
992
  intptr_t ret;
993

994 995 996 997 998
  args = msvcrt_argvtos(argv, ' ');
  envs = msvcrt_argvtos(envv, 0);

  ret = msvcrt_spawn(flags, name, args, envs, 1);

999 1000
  free(args);
  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
intptr_t CDECL _spawnvp(int flags, const char* name, const char* const* argv)
1011
{
1012
  return _spawnvpe(flags, name, argv, NULL);
1013 1014
}

1015 1016 1017 1018 1019
/*********************************************************************
 *      _wspawnvp (MSVCRT.@)
 *
 * Unicode version of _spawnvp
 */
1020
intptr_t CDECL _wspawnvp(int flags, const wchar_t* name, const wchar_t* const* argv)
1021
{
1022
  return _wspawnvpe(flags, name, argv, NULL);
1023 1024
}

1025
static struct popen_handle {
1026
    FILE *f;
1027 1028 1029 1030 1031 1032
    HANDLE proc;
} *popen_handles;
static DWORD popen_handles_size;

void msvcrt_free_popen_data(void)
{
1033
    free(popen_handles);
1034 1035
}

1036
/*********************************************************************
1037 1038 1039
 *		_wpopen (MSVCRT.@)
 *
 * Unicode version of _popen
1040
 */
1041
FILE* CDECL _wpopen(const wchar_t* command, const wchar_t* mode)
1042
{
1043
  FILE *ret;
1044
  BOOL readPipe = TRUE;
1045
  int textmode, fds[2], fdToDup, fdToOpen, fdStdHandle = -1, fmode;
1046 1047
  const wchar_t *p;
  wchar_t *comspec, *fullcmd;
1048
  unsigned int len;
1049 1050
  struct popen_handle *container;
  DWORD i;
1051

1052
  TRACE("(command=%s, mode=%s)\n", debugstr_w(command), debugstr_w(mode));
1053 1054 1055 1056

  if (!command || !mode)
    return NULL;

1057
  _get_fmode(&fmode);
1058
  textmode = fmode & (_O_BINARY | _O_TEXT);
1059 1060 1061 1062 1063 1064 1065 1066 1067 1068
  for (p = mode; *p; p++)
  {
    switch (*p)
    {
      case 'W':
      case 'w':
        readPipe = FALSE;
        break;
      case 'B':
      case 'b':
1069 1070
        textmode |= _O_BINARY;
        textmode &= ~_O_TEXT;
1071 1072 1073
        break;
      case 'T':
      case 't':
1074 1075
        textmode |= _O_TEXT;
        textmode &= ~_O_BINARY;
1076 1077 1078
        break;
    }
  }
1079
  if (_pipe(fds, 0, textmode) == -1)
1080 1081 1082 1083 1084
    return NULL;

  fdToDup = readPipe ? 1 : 0;
  fdToOpen = readPipe ? 0 : 1;

1085
  _lock(_POPEN_LOCK);
1086 1087 1088 1089 1090 1091 1092 1093
  for(i=0; i<popen_handles_size; i++)
  {
    if (!popen_handles[i].f)
      break;
  }
  if (i==popen_handles_size)
  {
    i = (popen_handles_size ? popen_handles_size*2 : 8);
1094
    container = realloc(popen_handles, i*sizeof(*container));
1095 1096 1097 1098 1099 1100 1101 1102 1103
    if (!container) goto error;

    popen_handles = container;
    container = popen_handles+popen_handles_size;
    memset(container, 0, (i-popen_handles_size)*sizeof(*container));
    popen_handles_size = i;
  }
  else container = popen_handles+i;

1104
  if ((fdStdHandle = _dup(fdToDup)) == -1)
1105
    goto error;
1106
  if (_dup2(fds[fdToDup], fdToDup) != 0)
1107 1108
    goto error;

1109
  _close(fds[fdToDup]);
1110

1111
  if (!(comspec = msvcrt_get_comspec())) goto error;
1112
  len = wcslen(comspec) + wcslen(command) + 5;
1113

1114
  if (!(fullcmd = HeapAlloc(GetProcessHeap(), 0, len * sizeof(wchar_t))))
1115 1116 1117 1118 1119
  {
    HeapFree(GetProcessHeap(), 0, comspec);
    goto error;
  }

1120 1121 1122
  wcscpy(fullcmd, comspec);
  wcscat(fullcmd, L" /c ");
  wcscat(fullcmd, command);
1123

1124
  if ((container->proc = (HANDLE)msvcrt_spawn(_P_NOWAIT, comspec, fullcmd, NULL, 1))
1125
          == INVALID_HANDLE_VALUE)
1126
  {
1127
    _close(fds[fdToOpen]);
1128 1129 1130 1131
    ret = NULL;
  }
  else
  {
1132
    ret = _wfdopen(fds[fdToOpen], mode);
1133
    if (!ret)
1134
      _close(fds[fdToOpen]);
1135
    container->f = ret;
1136
  }
1137
  _unlock(_POPEN_LOCK);
1138
  HeapFree(GetProcessHeap(), 0, comspec);
1139
  HeapFree(GetProcessHeap(), 0, fullcmd);
1140 1141
  _dup2(fdStdHandle, fdToDup);
  _close(fdStdHandle);
1142 1143 1144
  return ret;

error:
1145
  _unlock(_POPEN_LOCK);
1146 1147 1148
  if (fdStdHandle != -1) _close(fdStdHandle);
  _close(fds[0]);
  _close(fds[1]);
1149 1150 1151 1152
  return NULL;
}

/*********************************************************************
1153
 *      _popen (MSVCRT.@)
1154
 */
1155
FILE* CDECL _popen(const char* command, const char* mode)
1156
{
1157
  FILE *ret;
1158
  wchar_t *cmdW, *modeW;
1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 1170 1171

  TRACE("(command=%s, mode=%s)\n", debugstr_a(command), debugstr_a(mode));

  if (!command || !mode)
    return NULL;

  if (!(cmdW = msvcrt_wstrdupa(command))) return NULL;
  if (!(modeW = msvcrt_wstrdupa(mode)))
  {
    HeapFree(GetProcessHeap(), 0, cmdW);
    return NULL;
  }

1172
  ret = _wpopen(cmdW, modeW);
1173 1174 1175 1176

  HeapFree(GetProcessHeap(), 0, cmdW);
  HeapFree(GetProcessHeap(), 0, modeW);
  return ret;
1177 1178 1179 1180 1181
}

/*********************************************************************
 *		_pclose (MSVCRT.@)
 */
1182
int CDECL _pclose(FILE* file)
1183
{
1184 1185 1186 1187 1188
  HANDLE h;
  DWORD i;

  if (!MSVCRT_CHECK_PMT(file != NULL)) return -1;

1189
  _lock(_POPEN_LOCK);
1190 1191 1192 1193 1194 1195 1196
  for(i=0; i<popen_handles_size; i++)
  {
    if (popen_handles[i].f == file)
      break;
  }
  if(i == popen_handles_size)
  {
1197
    _unlock(_POPEN_LOCK);
1198
    *_errno() = EBADF;
1199 1200 1201 1202 1203
    return -1;
  }

  h = popen_handles[i].proc;
  popen_handles[i].f = NULL;
1204
  _unlock(_POPEN_LOCK);
1205

1206
  fclose(file);
1207 1208 1209 1210 1211 1212 1213 1214 1215
  if(WaitForSingleObject(h, INFINITE)==WAIT_FAILED || !GetExitCodeProcess(h, &i))
  {
    msvcrt_set_errno(GetLastError());
    CloseHandle(h);
    return -1;
  }

  CloseHandle(h);
  return i;
1216 1217
}

1218 1219 1220 1221 1222
/*********************************************************************
 *      _wsystem (MSVCRT.@)
 *
 * Unicode version of system
 */
1223
int CDECL _wsystem(const wchar_t* cmd)
1224 1225
{
  int res;
1226
  wchar_t *comspec, *fullcmd;
1227 1228
  unsigned int len;

1229 1230 1231 1232 1233 1234
  comspec = msvcrt_get_comspec();

  if (cmd == NULL)
  {
    if (comspec == NULL)
    {
1235
        *_errno() = ENOENT;
1236 1237
        return 0;
    }
1238
    HeapFree(GetProcessHeap(), 0, comspec);
1239 1240 1241
    return 1;
  }

1242
  if (comspec == NULL)
1243 1244
    return -1;

1245
  len = wcslen(comspec) + wcslen(cmd) + 5;
1246

1247
  if (!(fullcmd = HeapAlloc(GetProcessHeap(), 0, len * sizeof(wchar_t))))
1248 1249 1250 1251
  {
    HeapFree(GetProcessHeap(), 0, comspec);
    return -1;
  }
1252 1253 1254
  wcscpy(fullcmd, comspec);
  wcscat(fullcmd, L" /c ");
  wcscat(fullcmd, cmd);
1255

1256
  res = msvcrt_spawn(_P_WAIT, comspec, fullcmd, NULL, 1);
1257 1258 1259 1260 1261 1262

  HeapFree(GetProcessHeap(), 0, comspec);
  HeapFree(GetProcessHeap(), 0, fullcmd);
  return res;
}

1263 1264 1265
/*********************************************************************
 *		system (MSVCRT.@)
 */
1266
int CDECL system(const char* cmd)
1267
{
1268
  int res = -1;
1269
  wchar_t *cmdW;
1270

1271 1272 1273
  if (cmd == NULL)
    return _wsystem(NULL);

1274 1275 1276 1277 1278 1279
  if ((cmdW = msvcrt_wstrdupa(cmd)))
  {
    res = _wsystem(cmdW);
    HeapFree(GetProcessHeap(), 0, cmdW);
  }
  return res;
1280 1281 1282 1283 1284
}

/*********************************************************************
 *		_loaddll (MSVCRT.@)
 */
1285
intptr_t CDECL _loaddll(const char* dllname)
1286
{
1287
  return (intptr_t)LoadLibraryA(dllname);
1288 1289 1290 1291 1292
}

/*********************************************************************
 *		_unloaddll (MSVCRT.@)
 */
1293
int CDECL _unloaddll(intptr_t dll)
1294
{
1295
  if (FreeLibrary((HMODULE)dll))
1296 1297 1298 1299
    return 0;
  else
  {
    int err = GetLastError();
1300
    msvcrt_set_errno(err);
1301 1302 1303
    return err;
  }
}
1304 1305 1306 1307

/*********************************************************************
 *		_getdllprocaddr (MSVCRT.@)
 */
1308
void * CDECL _getdllprocaddr(intptr_t dll, const char *name, int ordinal)
1309 1310 1311 1312 1313 1314 1315 1316 1317
{
    if (name)
    {
        if (ordinal != -1) return NULL;
        return GetProcAddress( (HMODULE)dll, name );
    }
    if (HIWORD(ordinal)) return NULL;
    return GetProcAddress( (HMODULE)dll, (LPCSTR)(ULONG_PTR)ordinal );
}
1318 1319 1320 1321 1322 1323 1324 1325

/*********************************************************************
 *              _getpid (MSVCRT.@)
 */
int CDECL _getpid(void)
{
    return GetCurrentProcessId();
}
1326

1327
#if _MSVCR_VER>=110
1328 1329 1330
/*********************************************************************
 *  __crtTerminateProcess (MSVCR110.@)
 */
1331
int CDECL __crtTerminateProcess(UINT exit_code)
1332 1333 1334
{
    return TerminateProcess(GetCurrentProcess(), exit_code);
}
1335
#endif