Skip to content

Commit 6a92a40

Browse files
committed
[MSVCRT] Reimplement system/_wsystem
The new implementation is closely based on UCRT code and passes all tests for Vista+.
1 parent 46d3aee commit 6a92a40

3 files changed

Lines changed: 126 additions & 0 deletions

File tree

dll/win32/msvcrt/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,7 @@ list(APPEND MSVCRT_SOURCE
131131
${msvcrt_shared_asm}
132132
reactos/chkesp_failed.c
133133
reactos/misc.c
134+
reactos/system.cpp
134135
concurrency.c
135136
console.c
136137
ctype.c

dll/win32/msvcrt/process.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,6 +1245,7 @@ int CDECL _pclose(FILE* file)
12451245
return i;
12461246
}
12471247

1248+
#ifndef __REACTOS__
12481249
/*********************************************************************
12491250
* _wsystem (MSVCRT.@)
12501251
*
@@ -1308,6 +1309,7 @@ int CDECL system(const char* cmd)
13081309
}
13091310
return res;
13101311
}
1312+
#endif
13111313

13121314
/*********************************************************************
13131315
* _loaddll (MSVCRT.@)
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
/*
2+
* PROJECT: ReactOS msvcrt
3+
* LICENSE: MIT (https://spdx.org/licenses/MIT)
4+
* PURPOSE: Implementation of system / _wsystem
5+
* COPYRIGHT: Copyright (c) Microsoft Corporation. All rights reserved.
6+
* COPYRIGHT: Copyright 2025 Timo Kreuzer <timo.kreuzer@reactos.org>
7+
*/
8+
9+
#include <process.h>
10+
#include <io.h>
11+
#include <stdlib.h>
12+
#include <errno.h>
13+
14+
extern "C" int _cdecl _access_s(const char* filename, int mode);
15+
extern "C" int _cdecl _waccess_s(const wchar_t* filename, int mode);
16+
17+
int _cdecl _taccess_s(const char* filename, int mode)
18+
{
19+
return _access_s(filename, mode);
20+
}
21+
22+
int _cdecl _taccess_s(const wchar_t* filename, int mode)
23+
{
24+
return _waccess_s(filename, mode);
25+
}
26+
27+
char* __cdecl _tgetenv(_In_z_ char const* _VarName)
28+
{
29+
return getenv(_VarName);
30+
}
31+
32+
wchar_t* __cdecl _tgetenv(_In_z_ wchar_t const* _VarName)
33+
{
34+
return _wgetenv(_VarName);
35+
}
36+
37+
intptr_t __cdecl _tspawnve(int flags, const char* name, const char* const* argv,
38+
const char* const* envv)
39+
{
40+
return _spawnve(flags, name, argv, envv);
41+
}
42+
43+
intptr_t __cdecl _tspawnve(int flags, const wchar_t* name, const wchar_t* const* argv,
44+
const wchar_t* const* envv)
45+
{
46+
return _wspawnve(flags, name, argv, envv);
47+
}
48+
49+
intptr_t __cdecl _tspawnvpe(int flags, const char* name, const char* const* argv,
50+
const char* const* envv)
51+
{
52+
return _spawnvpe(flags, name, argv, envv);
53+
}
54+
55+
intptr_t __cdecl _tspawnvpe(int flags, const wchar_t* name, const wchar_t* const* argv,
56+
const wchar_t* const* envv)
57+
{
58+
return _wspawnvpe(flags, name, argv, envv);
59+
}
60+
61+
template <typename Character>
62+
static int __cdecl common_system(Character const* const command) throw()
63+
{
64+
static Character const comspec_name[] = { 'C', 'O', 'M', 'S', 'P', 'E', 'C', '\0' }; // "COMSPEC"
65+
static Character const cmd_exe[] = { 'c', 'm', 'd', '.', 'e', 'x', 'e', '\0' }; // "cmd.exe"
66+
static Character const slash_c[] = { '/', 'c', '\0' }; // "/c"
67+
68+
Character const * comspec_value = _tgetenv(comspec_name);
69+
70+
// If the command is null, return TRUE only if %COMSPEC% is set and the file
71+
// to which it points exists.
72+
if (!command)
73+
{
74+
if (!comspec_value)
75+
return 0;
76+
77+
return _taccess_s(comspec_value, 0) == 0;
78+
}
79+
80+
Character const* arguments[4] =
81+
{
82+
comspec_value,
83+
slash_c,
84+
command,
85+
nullptr
86+
};
87+
88+
if (comspec_value)
89+
{
90+
errno_t const saved_errno = errno;
91+
errno = 0;
92+
93+
int const result = static_cast<int>(_tspawnve(_P_WAIT, arguments[0], arguments, nullptr));
94+
if (result != -1)
95+
{
96+
errno = saved_errno;
97+
return result;
98+
}
99+
100+
if (errno != ENOENT && errno != EACCES)
101+
{
102+
return result;
103+
}
104+
105+
// If the error wasn't one of those two errors, try again with cmd.exe...
106+
errno = saved_errno;
107+
}
108+
109+
arguments[0] = cmd_exe;
110+
return static_cast<int>(_tspawnvpe(_P_WAIT, arguments[0], arguments, nullptr));
111+
112+
return 0;
113+
}
114+
115+
extern "C" int __cdecl system(char const* const command)
116+
{
117+
return common_system(command);
118+
}
119+
120+
extern "C" int __cdecl _wsystem(wchar_t const* const command)
121+
{
122+
return common_system(command);
123+
}

0 commit comments

Comments
 (0)