diff --git a/src/backend/os.c b/src/backend/os.c
index 8d966390f6c7..4678c466364b 100644
--- a/src/backend/os.c
+++ b/src/backend/os.c
@@ -651,7 +651,7 @@ int os_file_exists(const char *name)
DWORD dw;
int result;
- dw = GetFileAttributes(name);
+ dw = GetFileAttributesA(name);
if (dw == -1L)
result = 0;
else if (dw & FILE_ATTRIBUTE_DIRECTORY)
@@ -710,7 +710,7 @@ char *file_8dot3name(const char *filename)
char *buf;
int i;
- h = FindFirstFile(filename,&fileinfo);
+ h = FindFirstFileA(filename,&fileinfo);
if (h == INVALID_HANDLE_VALUE)
return NULL;
if (fileinfo.cAlternateFileName[0])
@@ -770,7 +770,7 @@ int file_write(char *name, void *buffer, unsigned len)
HANDLE h;
DWORD numwritten;
- h = CreateFileA((LPTSTR)name,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,
+ h = CreateFileA((LPCSTR)name,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL);
if (h == INVALID_HANDLE_VALUE)
{
@@ -778,7 +778,7 @@ int file_write(char *name, void *buffer, unsigned len)
{
if (!file_createdirs(name))
{
- h = CreateFileA((LPTSTR)name,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,
+ h = CreateFileA((LPCSTR)name, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL);
if (h != INVALID_HANDLE_VALUE)
goto Lok;
diff --git a/src/dmd_msc.vcxproj b/src/dmd_msc.vcxproj
index 266cecaa811f..f22ba9e92959 100644
--- a/src/dmd_msc.vcxproj
+++ b/src/dmd_msc.vcxproj
@@ -28,6 +28,18 @@
Application
true
+
+ Unicode
+
+
+ Unicode
+
+
+ Unicode
+
+
+ Unicode
+
@@ -43,7 +55,7 @@
.\root;.\tk;.\backend;.;vcbuild;%(AdditionalIncludeDirectories)
- DEBUG;_DEBUG;TARGET_WINDOS%(PreprocessorDefinitions)
+ DEBUG;_DEBUG;TARGET_WINDOS;%(PreprocessorDefinitions)
TARGET_WINDOS;%(PreprocessorDefinitions)
MultiThreadedDebug
MultiThreaded
@@ -237,6 +249,7 @@
+
Building and running $(IntDir)%(Filename).exe
dmd -od$(IntDir) -of$(IntDir)%(Filename).exe %(Filename)%(Extension) && $(IntDir)%(Filename).exe
@@ -363,6 +376,7 @@
+
diff --git a/src/dmd_msc.vcxproj.filters b/src/dmd_msc.vcxproj.filters
index ae3c2ca190c8..558d3babfd83 100644
--- a/src/dmd_msc.vcxproj.filters
+++ b/src/dmd_msc.vcxproj.filters
@@ -426,9 +426,6 @@
src\root
-
- src\root
-
src\root
@@ -462,6 +459,9 @@
src\root
+
+ src\root
+
src\generated
@@ -758,6 +758,9 @@
src\root
+
+ src\root
+
src\generated
@@ -779,9 +782,6 @@
src
-
- src\backend
-
src
@@ -790,9 +790,6 @@
-
- src\gen
-
src\gen
@@ -803,5 +800,6 @@
src\vcbuild
+
\ No newline at end of file
diff --git a/src/errors.c b/src/errors.c
index 428d3f3574ed..3b601613b2fb 100644
--- a/src/errors.c
+++ b/src/errors.c
@@ -25,6 +25,7 @@
#include "errors.h"
#include "outbuffer.h"
#include "rmem.h"
+#include "utils.h"
enum COLOR
{
@@ -176,8 +177,15 @@ void verrorPrint(Loc loc, COLOR headerColor, const char *header, const char *for
if (global.params.color)
setConsoleColorBright(true);
- if (*p)
+ if (*p) {
+#ifdef _WIN32
+ LPCWSTR wstr = UTF8toWide(p);
+ fwprintf(stderr, L"%s\n", wstr);
+ free((void *)wstr);
+#else
fprintf(stderr, "%s: ", p);
+#endif
+ }
mem.xfree(p);
if (global.params.color)
@@ -191,7 +199,13 @@ void verrorPrint(Loc loc, COLOR headerColor, const char *header, const char *for
fprintf(stderr, "%s ", p2);
OutBuffer tmp;
tmp.vprintf(format, ap);
+#ifdef _WIN32
+ LPCWSTR wstr = UTF8toWide(tmp.peekString());
+ fwprintf(stderr, L"%s\n", wstr);
+ free((void *)wstr);
+#else
fprintf(stderr, "%s\n", tmp.peekString());
+#endif
fflush(stderr);
}
diff --git a/src/inifile.c b/src/inifile.c
index bcdab2f0cd55..5dee7b80cdd6 100644
--- a/src/inifile.c
+++ b/src/inifile.c
@@ -31,6 +31,7 @@
#include "root.h"
#include "rmem.h"
#include "port.h"
+#include "utils.h"
#define LOG 0
@@ -63,15 +64,17 @@ const char *findConfFile(const char *argv0, const char *inifile)
* o directory off of argv0
* o SYSCONFDIR (default=/etc/) (non-windows)
*/
- const char *filename = FileName::combine(getenv("HOME"), inifile);
+ const char *filename = FileName::combine(dgetenv("HOME"), inifile);
if (FileName::exists(filename))
return filename;
#if _WIN32 // This fix by Tim Matthews
- char resolved_name[MAX_PATH + 1];
- if (GetModuleFileNameA(NULL, resolved_name, MAX_PATH + 1) && FileName::exists(resolved_name))
+ WCHAR wresolved_name[MAX_PATH + 1];
+ if (GetModuleFileNameW(NULL, wresolved_name, MAX_PATH + 1) && FileName::exists(wresolved_name))
{
+ char *resolved_name = wideToUTF8(wresolved_name);
filename = FileName::replaceName(resolved_name, inifile);
+ free(resolved_name);
if (FileName::exists(filename))
return filename;
}
@@ -204,7 +207,7 @@ void parseConfFile(const char *filename, const char *envsectionname)
memcpy(p, &line[k + 1], len2);
p[len2] = 0;
Port::strupr(p);
- char *penv = getenv(p);
+ char *penv = dgetenv(p);
if (penv)
buf.writestring(penv);
free(p);
@@ -267,7 +270,7 @@ void parseConfFile(const char *filename, const char *envsectionname)
else if (p[0] == '?' && p[1] == '=')
{
*p = '\0';
- if (getenv(pn))
+ if (dgetenv(pn))
{
pn = NULL;
break;
@@ -289,7 +292,7 @@ void parseConfFile(const char *filename, const char *envsectionname)
if (pn)
{
- putenv(strdup(pn));
+ dputenv(strdup(pn));
#if LOG
printf("\tputenv('%s')\n", pn);
//printf("getenv(\"TEST\") = '%s'\n",getenv("TEST"));
diff --git a/src/link.c b/src/link.c
index 7d3b3a9b2c35..f4a2132e018f 100644
--- a/src/link.c
+++ b/src/link.c
@@ -16,28 +16,13 @@
#include
#include
-#if _WIN32
-#include
-#ifdef _MSC_VER
-#include
-#endif
-#endif
-
#if __linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun
#include
#include
#include
#endif
-#if __linux__ || __APPLE__
- #define HAS_POSIX_SPAWN 1
- #include
- #if __APPLE__
- #include
- #endif
-#else
- #define HAS_POSIX_SPAWN 0
-#endif
+#include "utils.h"
#include "root.h"
@@ -248,7 +233,7 @@ int runLINK()
/* Append the path to the VC lib files, and then the SDK lib files
*/
- const char *vcinstalldir = getenv("VCINSTALLDIR");
+ const char *vcinstalldir = dgetenv("VCINSTALLDIR");
if (vcinstalldir)
{ cmdbuf.writestring(" /LIBPATH:\"");
cmdbuf.writestring(vcinstalldir);
@@ -258,7 +243,7 @@ int runLINK()
cmdbuf.writestring("\\lib\"");
}
- const char *windowssdkdir = getenv("WindowsSdkDir");
+ const char *windowssdkdir = dgetenv("WindowsSdkDir");
if (windowssdkdir)
{ cmdbuf.writestring(" /LIBPATH:\"");
cmdbuf.writestring(windowssdkdir);
@@ -284,9 +269,9 @@ int runLINK()
sprintf(p, "@%s", lnkfilename);
}
- const char *linkcmd = getenv(global.params.is64bit ? "LINKCMD64" : "LINKCMD");
+ const char *linkcmd = dgetenv(global.params.is64bit ? "LINKCMD64" : "LINKCMD");
if (!linkcmd)
- linkcmd = getenv("LINKCMD"); // backward compatible
+ linkcmd = dgetenv("LINKCMD"); // backward compatible
if (!linkcmd)
{
if (vcinstalldir)
@@ -435,7 +420,7 @@ int runLINK()
sprintf(p, "@%s", lnkfilename);
}
- const char *linkcmd = getenv("LINKCMD");
+ const char *linkcmd = dgetenv("LINKCMD");
if (!linkcmd)
linkcmd = "link";
int status = executecmd(linkcmd, p);
@@ -747,7 +732,6 @@ int executecmd(const char *cmd, const char *args)
{
int status;
size_t len;
-
if (global.params.verbose)
fprintf(global.stdmsg, "%s %s\n", cmd, args);
@@ -757,7 +741,7 @@ int executecmd(const char *cmd, const char *args)
{
char *q = (char *) alloca(8 + len + 1);
sprintf(q,"_CMDLINE=%s", args);
- status = putenv(q);
+ status = dputenv(q);
if (status == 0)
{
args = "@_CMDLINE";
@@ -772,23 +756,10 @@ int executecmd(const char *cmd, const char *args)
// Normalize executable path separators, see Bugzilla 9330
cmd = toWinPath(cmd);
-#ifdef _MSC_VER
- if(strchr(cmd, ' '))
- {
- // MSVCRT: spawn does not work with spaces in the executable
- size_t cmdlen = strlen(cmd);
- char* shortName = new char[cmdlen + 1]; // enough space
- DWORD len = GetShortPathName(cmd, shortName, cmdlen + 1);
- if(len > 0 && len <= cmdlen)
- cmd = shortName;
- }
-#endif
-
status = executearg0(cmd,args);
if (status == -1)
{
- // spawnlp returns intptr_t in some systems, not int
- status = spawnlp(0,cmd,cmd,args,NULL);
+ status = dspawnlp(0,cmd,cmd,args,NULL);
}
// if (global.params.verbose)
@@ -827,8 +798,7 @@ int executearg0(const char *cmd, const char *args)
file = FileName::replaceName(argv0, cmd);
//printf("spawning '%s'\n",file);
- // spawnlp returns intptr_t in some systems, not int
- return spawnl(0,file,file,args,NULL);
+ return dspawnl(0,file,file,args,NULL);
}
#endif
@@ -854,15 +824,6 @@ int runProgram()
argv.push(global.params.exefile);
for (size_t i = 0; i < global.params.runargs_length; i++)
{ const char *a = global.params.runargs[i];
-
-#if _WIN32
- // BUG: what about " appearing in the string?
- if (strchr(a, ' '))
- { char *b = (char *)mem.xmalloc(3 + strlen(a));
- sprintf(b, "\"%s\"", a);
- a = b;
- }
-#endif
argv.push(a);
}
argv.push(NULL);
@@ -873,8 +834,7 @@ int runProgram()
ex = FileName::combine(".", ex);
else
ex = global.params.exefile;
- // spawnlp returns intptr_t in some systems, not int
- return spawnv(0,ex,argv.tdata());
+ return dspawnv(0,ex,argv.tdata());
#elif __linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun
pid_t childpid;
int status;
diff --git a/src/magicport.json b/src/magicport.json
index 05832d77153a..fc5546fa222e 100644
--- a/src/magicport.json
+++ b/src/magicport.json
@@ -27,7 +27,8 @@
"root/speller.h", "root/speller.c",
"root/outbuffer.h", "root/outbuffer.c",
"root/stringtable.h", "root/stringtable.c",
- "root/man.c", "root/response.c"
+ "root/man.c", "root/response.c",
+ "root/utils.c"
],
"mapping" :
[
@@ -724,6 +725,7 @@
"root.array",
"root.filename",
"root.rmem",
+ "root.utils",
"core.sys.windows.windows",
"core.sys.posix.sys.types",
"core.sys.posix.utime",
@@ -1362,6 +1364,7 @@
"root.outbuffer",
"root.rmem",
"root.rootobject",
+ "root.utils",
"core.sys.windows.windows",
"core.sys.posix.sys.stat",
"core.sys.posix.stdlib"
@@ -1372,7 +1375,7 @@
"version (Windows) alias _mkdir = mkdir;",
"version (Posix) extern (C) char* canonicalize_file_name(const char*);",
"version (Windows) extern (C) int stricmp(const char*, const char*);",
- "version (Windows) extern (Windows) DWORD GetFullPathNameA(LPCTSTR lpFileName, DWORD nBufferLength, LPTSTR lpBuffer, LPTSTR* lpFilePart);"
+ "version (Windows) extern (Windows) DWORD GetFullPathNameW(LPCWSTR lpFileName, DWORD nBufferLength, LPWSTR lpBuffer, LPWSTR* lpFilePart);"
],
"members" :
[
@@ -1699,6 +1702,7 @@
"root.filename",
"root.outbuffer",
"root.port",
+ "root.utils",
"core.sys.windows.windows",
"core.sys.posix.stdlib"
],
@@ -1964,6 +1968,7 @@
"root.filename",
"root.outbuffer",
"root.rmem",
+ "root.utils",
"core.sys.posix.sys.wait",
"core.sys.posix.stdlib",
"core.sys.posix.stdio",
@@ -1979,7 +1984,6 @@
],
"members" :
[
- "version variable HAS_POSIX_SPAWN",
"function writeFilenameOutBuffer*char*size_t",
"function writeFilenameOutBuffer*char*",
"version function findNoMainError",
@@ -2512,6 +2516,7 @@
"root.outbuffer",
"root.rmem",
"root.response",
+ "root.utils",
"target",
"tokens",
"traits"
@@ -2533,6 +2538,7 @@
"function genCmain",
"function tryMain",
"function main",
+ "function wmain",
"function getenv_setargv",
"function escapePath",
"function parse_arch_arg",
@@ -3113,7 +3119,8 @@
"core.sys.windows.windows",
"globals",
"root.outbuffer",
- "root.rmem"
+ "root.rmem",
+ "root.utils"
],
"extra" :
[
@@ -3122,7 +3129,8 @@
"version (Windows) int _fileno(FILE* f)",
"{",
" return f._file;",
- "}"
+ "}",
+ "version (Windows) extern (Windows) int fwprintf(FILE* _File, const wchar_t* _Format, ...);"
],
"members" :
[
@@ -3196,7 +3204,8 @@
"core.stdc.stdio",
"core.stdc.stdlib",
"core.stdc.string",
- "root.file"
+ "root.file",
+ "root.utils"
],
"members" :
[
@@ -3204,6 +3213,30 @@
"function addargp",
"function response_expand"
]
+ },
+ {
+ "module" : "utils",
+ "package" : "root",
+ "imports" : [
+ "core.stdc.stdio",
+ "core.stdc.stdlib",
+ "core.sys.windows.windows"
+ ],
+ "extra" :
+ [
+ "enum _MSC_VER = 0;",
+ "version (Windows) extern (Windows) wchar_t* _wgetenv(const wchar_t*);",
+ "version (Windows) extern (Windows) int _wputenv(const wchar_t*);",
+ "version (Windows) extern (Windows) int _wmkdir(const wchar_t*);",
+ "version (Windows) extern (Windows) int iswspace(short);",
+ "version (Windows) extern (Windows) intptr_t _wspawnlp(int, const wchar_t*, const wchar_t*, ...);",
+ "version (Windows) extern (Windows) intptr_t _wspawnl(int, const wchar_t*, const wchar_t*, ...);",
+ "version (Windows) extern (Windows) intptr_t _wspawnv(int, const wchar_t*, const wchar_t **);"
+ ],
+ "members" :
+ [
+ "version function wideToUTF8"
+ ]
}
],
"basicTypes" :
@@ -3223,6 +3256,8 @@
"size_t",
"time_t",
+ "wchar_t",
+ "intptr_t",
"longdouble",
"volatile_longdouble",
"uinteger_t",
@@ -3247,6 +3282,10 @@
"hash_t",
"DWORD",
"WORD",
+ "WCHAR",
+ "LPSTR",
+ "LPWSTR",
+ "LPCWSTR",
"HANDLE",
"Key",
"Value",
diff --git a/src/magicport/parser.d b/src/magicport/parser.d
index 0eb4e6503992..d335c8d0fcd9 100644
--- a/src/magicport/parser.d
+++ b/src/magicport/parser.d
@@ -496,8 +496,16 @@ Expression parsePrimaryExpr()
else if (t.text == "static" || t.text == "STATIC" || t.text == "struct" || t.text == "const" || t.text == "union" || t.text == "class" || t.text == "enum" || t.text == "typedef" || t.text == "register")
{
return new DeclarationExpr(parseDecl(null, true));
- }
- else if (isType())
+ } else if (t.text == "L")
+ {
+ nextToken();
+ string e;
+ e ~= nextToken()[0..$-1];
+ while(t.type == TOKstring)
+ e ~= nextToken()[1..$-1];
+ e ~= "\"";
+ return new LitExpr(e);
+ } else if (isType())
{
auto type = parseType();
if (t.type == TOKid)
diff --git a/src/mars.c b/src/mars.c
index 9a34be07c2ca..322d39326e30 100644
--- a/src/mars.c
+++ b/src/mars.c
@@ -15,6 +15,7 @@
#include
#include
#include
+#include
#if __linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun
#include
@@ -38,6 +39,7 @@
#include "declaration.h"
#include "hdrgen.h"
#include "doc.h"
+#include "utils.h"
bool response_expand(size_t *pargc, const char ***pargv);
@@ -1658,14 +1660,22 @@ Language changes listed by -transition=id:\n\
return status;
}
-int main(int argc, const char *argv[])
-{
- int status = -1;
-
- status = tryMain(argc, argv);
+#if _WIN32
+int wmain(int argc, const wchar_t *wargv[])
+{
+ _wsetlocale(LC_ALL, L"");
+ const char **argv = getUTF8argvs(argc, wargv);
+ int status = tryMain(argc, argv);
+ freeUTF8argvs(argc, argv);
return status;
}
+#else
+int main(int argc, const char *argv[])
+{
+ return tryMain(argc, argv);
+}
+#endif
/***********************************
@@ -1682,7 +1692,7 @@ void getenv_setargv(const char *envvar, size_t *pargc, const char** *pargv)
int slash;
char c;
- char *env = getenv(envvar);
+ char *env = dgetenv(envvar);
if (!env)
return;
diff --git a/src/root/file.c b/src/root/file.c
index 1fa7ea27ebe0..b76b9ebd1087 100644
--- a/src/root/file.c
+++ b/src/root/file.c
@@ -37,6 +37,7 @@
#include "array.h"
#include "port.h"
#include "rmem.h"
+#include "utils.h"
/****************************** File ********************************/
@@ -146,9 +147,10 @@ bool File::read()
DWORD size;
DWORD numread;
- char *name = this->name->toChars();
- HANDLE h = CreateFileA(name,GENERIC_READ,FILE_SHARE_READ,NULL,OPEN_EXISTING,
+ LPCWSTR wname = UTF8toWide(this->name->toChars());
+ HANDLE h = CreateFileW(wname, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL);
+ free((void *)wname);
if (h == INVALID_HANDLE_VALUE)
goto err1;
@@ -224,8 +226,8 @@ bool File::write()
#elif _WIN32
DWORD numwritten;
- char *name = this->name->toChars();
- HANDLE h = CreateFileA(name,GENERIC_WRITE,0,NULL,CREATE_ALWAYS,
+ LPCWSTR wname = UTF8toWide(this->name->toChars());
+ HANDLE h = CreateFileW(wname, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS,
FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN,NULL);
if (h == INVALID_HANDLE_VALUE)
goto err;
@@ -238,12 +240,15 @@ bool File::write()
if (!CloseHandle(h))
goto err;
+
+ free((void *)wname);
return false;
err2:
CloseHandle(h);
- DeleteFileA(name);
+ DeleteFileW(wname);
err:
+ free((void *)wname);
return true;
#else
assert(0);
@@ -255,7 +260,9 @@ void File::remove()
#if POSIX
int dummy = ::remove(this->name->toChars());
#elif _WIN32
- DeleteFileA(this->name->toChars());
+ LPCWSTR wname = UTF8toWide(this->name->toChars());
+ DeleteFileW(wname);
+ free((void *)wname);
#else
assert(0);
#endif
diff --git a/src/root/filename.c b/src/root/filename.c
index f27a1b383817..04dd01627a69 100644
--- a/src/root/filename.c
+++ b/src/root/filename.c
@@ -16,6 +16,7 @@
#include "array.h"
#include "file.h"
#include "rmem.h"
+#include "utils.h"
#if defined (__sun)
#include
@@ -26,12 +27,6 @@
#include
#endif
-#if _WIN32
-#include
-#include
-#include
-#endif
-
#if POSIX
#include
#include
@@ -555,10 +550,20 @@ int FileName::exists(const char *name)
return 2;
return 1;
#elif _WIN32
- DWORD dw;
- int result;
+ LPCWSTR wname = UTF8toWide(name);
+ int result = exists(wname);
+ ::free((void *)wname);
+ return result;
+#else
+ assert(0);
+#endif
+}
- dw = GetFileAttributesA(name);
+#if _WIN32
+int FileName::exists(LPCWSTR name)
+{
+ int result;
+ DWORD dw = GetFileAttributesW(name);
if (dw == -1L)
result = 0;
else if (dw & FILE_ATTRIBUTE_DIRECTORY)
@@ -566,10 +571,8 @@ int FileName::exists(const char *name)
else
result = 1;
return result;
-#else
- assert(0);
-#endif
}
+#endif
bool FileName::ensurePathExists(const char *path)
{
@@ -602,12 +605,7 @@ bool FileName::ensurePathExists(const char *path)
if (path[strlen(path) - 1] != sep)
{
//printf("mkdir(%s)\n", path);
-#if _WIN32
- int r = _mkdir(path);
-#endif
-#if POSIX
- int r = mkdir(path, (7 << 6) | (7 << 3) | 7);
-#endif
+ int r = dmkdir(path);
if (r)
{
/* Don't error out if another instance of dmd just created
@@ -635,16 +633,20 @@ const char *FileName::canonicalName(const char *name)
/* Apparently, there is no good way to do this on Windows.
* GetFullPathName isn't it, but use it anyway.
*/
- DWORD result = GetFullPathNameA(name, 0, NULL, NULL);
+ LPCWSTR wname = UTF8toWide(name);
+ DWORD result = GetFullPathNameW(wname, 0, NULL, NULL);
if (result)
{
- char *buf = (char *)malloc(result);
- result = GetFullPathNameA(name, result, buf, NULL);
+ LPWSTR wbuf = (LPWSTR)malloc(result * sizeof(WCHAR));
+ result = GetFullPathNameW(wname, result, wbuf, NULL);
if (result == 0)
{
- ::free(buf);
+ ::free((void *)wname);
+ ::free(wbuf);
return NULL;
}
+ char *buf = wideToUTF8(wbuf);
+ ::free(wbuf);
return buf;
}
return NULL;
diff --git a/src/root/filename.h b/src/root/filename.h
index 9416ce0a2e7f..f3eeb2d7bab5 100644
--- a/src/root/filename.h
+++ b/src/root/filename.h
@@ -49,6 +49,10 @@ struct FileName
static const char *searchPath(Strings *path, const char *name, bool cwd);
static const char *safeSearchPath(Strings *path, const char *name);
static int exists(const char *name);
+#if _WIN32
+ typedef const wchar_t *LPCWSTR;
+ static int exists(LPCWSTR name);
+#endif
static bool ensurePathExists(const char *path);
static const char *canonicalName(const char *name);
diff --git a/src/root/response.c b/src/root/response.c
index 70f0fd5b81bf..b9d2b5fda076 100644
--- a/src/root/response.c
+++ b/src/root/response.c
@@ -18,6 +18,7 @@
#if _WIN32
#include
#include
+#include
#endif
#if __linux__ || __APPLE__ || __FreeBSD__ || __OpenBSD__ || __sun
@@ -37,6 +38,7 @@
#endif
#include "file.h"
+#include "utils.h"
/*********************************
* #include
@@ -117,7 +119,7 @@ bool response_expand(size_t *pargc, const char ***pargv)
char *bufend;
cp++;
- char *p = getenv(cp);
+ char *p = dgetenv(cp);
if (p)
{
buffer = strdup(p);
diff --git a/src/root/utils.c b/src/root/utils.c
new file mode 100644
index 000000000000..40469abb049b
--- /dev/null
+++ b/src/root/utils.c
@@ -0,0 +1,201 @@
+#include "utils.h"
+
+#if _WIN32
+
+// Encode Unicode/Wide string to UTF-8 string
+char *wideToUTF8(const LPCWSTR wstr)
+{
+ if (!wstr) return NULL;
+ int reqchars = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
+ char *str = (char *)malloc(reqchars * sizeof(char));
+ WideCharToMultiByte(CP_UTF8, 0, wstr, -1, (LPSTR)str, reqchars, NULL, NULL);
+ return str;
+}
+
+// Encode UTF-8 string to Unicode/Wide string
+LPCWSTR UTF8toWide(const char *str)
+{
+ if (!str) return NULL;
+ int reqchars = MultiByteToWideChar(CP_UTF8, 0, str, -1, NULL, 0);
+ LPCWSTR wstr = (LPCWSTR)malloc(reqchars * sizeof(WCHAR));
+ MultiByteToWideChar(CP_UTF8, 0, str, -1, (LPWSTR)wstr, reqchars);
+ return wstr;
+}
+
+// get argvs in UTF-8
+const char **getUTF8argvs(int argc, const wchar_t *wargv[])
+{
+ if (wargv != NULL && argc > 0) {
+ const char **argv = (const char **)malloc(argc * sizeof(char *));
+ for (size_t i = 0; i < argc; i++)
+ {
+ argv[i] = wideToUTF8(wargv[i]);
+ }
+ return argv;
+ };
+ return NULL;
+}
+
+void freeUTF8argvs(int argc, const char *argv[])
+{
+ for (size_t i = 0; i < argc; i++) {
+ free((void *)argv[i]);
+ };
+ free(argv);
+}
+
+// get ENV variable in UTF-8
+char* dgetenv(const char *name) {
+ LPCWSTR wname = UTF8toWide(name);
+ char *var = NULL;
+#if defined(_MSC_VER) && _MSC_VER >= 1400
+ size_t reqsz = 0;
+ if (_wgetenv_s(&reqsz, NULL, 0, wname) == 0 && reqsz > 0) {
+ LPWSTR wvar = (LPWSTR)malloc(reqsz * sizeof(WCHAR));
+ _wgetenv_s(&reqsz, wvar, reqsz, wname);
+ var = wideToUTF8(wvar);
+ free((void *)wvar);
+ }
+#else
+ LPWSTR wvar =_wgetenv(wname);
+ if (wvar) var = wideToUTF8(wvar);
+#endif
+ free((void *)wname);
+ return var;
+}
+
+int dputenv(const char *env) {
+ LPCWSTR wenv = UTF8toWide(env);
+ int s = _wputenv(wenv);
+ free((void *)wenv);
+ return s;
+}
+
+int dmkdir(const char *name) {
+ LPCWSTR wname = UTF8toWide(name);
+ int r = _wmkdir(wname);
+ free((void *)wname);
+ return r;
+}
+
+// Quote and escape argument if needed
+LPCWSTR escape_arg(LPCWSTR wstr) {
+ if (!wstr) return NULL;
+ bool need_escape = false;
+ int extra = 0;
+ LPWSTR p = (LPWSTR)wstr;
+ WCHAR c;
+ // count how many extra chars will
+ // be needed for backslashes
+ while (*p != 0) {
+ c = *p;
+ if (c == '\\') {
+ extra++;
+ }
+ else if (c == '"') {
+ extra++;
+ need_escape = true;
+ }
+ else if (iswspace(c)) {
+ need_escape = true;
+ }
+ p++;
+ };
+ if (!need_escape) return wstr;
+ size_t len = p - wstr;
+ extra += 3; // for quotes and null
+ LPWSTR quoted_str = (LPWSTR)malloc((len + extra) * sizeof(WCHAR));
+ *quoted_str = '"';
+ p = quoted_str + 1;
+ for (size_t i = 0; i < len; i++) {
+ c = wstr[i];
+ // escape
+ if (c == '"' || c == '\\') {
+ *p = '\\';
+ p++;
+ };
+ *p = c;
+ p++;
+ };
+ *p = '"';
+ p++;
+ *p = 0;
+ return quoted_str;
+}
+
+int dspawnlp(int mode, const char *file, const char *arg0, const char *arg1, const char *arg2) {
+ LPCWSTR wfile = UTF8toWide(file);
+ LPCWSTR warg0 = UTF8toWide(arg0);
+ LPCWSTR warg1 = UTF8toWide(arg1);
+ LPCWSTR warg2 = UTF8toWide(arg2);
+ LPCWSTR escaped_warg0 = escape_arg(warg0);
+ intptr_t h = _wspawnlp(mode, wfile, escaped_warg0, warg1, warg2);
+ if (escaped_warg0 != warg0) free((void *)escaped_warg0);
+ free((void *)wfile);
+ free((void *)warg0);
+ free((void *)warg1);
+ free((void *)warg2);
+ return h;
+}
+
+int dspawnl(int mode, const char *file, const char *arg0, const char *arg1, const char *arg2) {
+ LPCWSTR wfile = UTF8toWide(file);
+ LPCWSTR warg0 = UTF8toWide(arg0);
+ LPCWSTR warg1 = UTF8toWide(arg1);
+ LPCWSTR warg2 = UTF8toWide(arg2);
+ LPCWSTR escaped_warg0 = escape_arg(warg0);
+ intptr_t h = _wspawnl(mode, wfile, escaped_warg0, warg1, warg2);
+ if (escaped_warg0 != warg0) free((void *)escaped_warg0);
+ free((void *)wfile);
+ free((void *)warg0);
+ free((void *)warg1);
+ free((void *)warg2);
+ return h;
+}
+
+int dspawnv(int mode, const char *file, const char *const *argv) {
+ LPCWSTR wfile = UTF8toWide(file);
+ int argc = 0;
+ while (argv[argc] != NULL) { argc++; };
+ LPCWSTR *wargv = (LPCWSTR *)malloc((argc + 1) * sizeof(LPCWSTR));
+ LPCWSTR warg;
+ for (size_t i = 0; i < argc; i++)
+ {
+ warg = UTF8toWide(argv[i]);
+ wargv[i] = escape_arg(warg);
+ if (wargv[i] != warg) free((void *)warg);
+ };
+ wargv[argc] = NULL;
+ intptr_t h = _wspawnv(mode, wfile, wargv);
+ free((void *)wfile);
+ for (size_t i = 0; i < argc; i++)
+ {
+ free((void *)wargv[i]);
+ }
+ free((void *)wargv);
+ return h;
+}
+
+#else
+
+char *dgetenv(const char *name) {
+ return getenv(name);
+}
+
+int dputenv(const char *env) {
+ return putenv(env);
+}
+
+int dmkdir(const char *name) {
+ return mkdir(name, (7 << 6) | (7 << 3) | 7);
+}
+
+int dspawnlp(int mode, const char *file, const char *arg0, const char *arg1, const char *arg2) {
+ return spawnlp(mode, file, arg0, arg1, arg2);
+}
+
+int dspawnl(int mode, const char *file, const char *arg0, const char *arg1, const char *arg2) {
+ return dspawnl(mode, file, arg0, arg1, arg2);
+}
+
+#endif
diff --git a/src/root/utils.h b/src/root/utils.h
new file mode 100644
index 000000000000..820f5e5a8581
--- /dev/null
+++ b/src/root/utils.h
@@ -0,0 +1,51 @@
+#ifndef UTILS_H
+#define UTILS_H
+
+#if __DMC__
+#pragma once
+#endif
+
+#if __linux__ || __APPLE__
+#define HAS_POSIX_SPAWN 1
+#include
+#if __APPLE__
+#include
+#endif
+#else
+#define HAS_POSIX_SPAWN 0
+#endif
+
+#if _WIN32
+
+#define WIN32_LEAN_AND_MEAN
+#include
+#include
+#include
+#include
+#include
+#include
+
+#ifndef _INTPTR_T_DEFINED
+#ifdef _WIN64
+typedef int64_t intptr_t;
+#else
+typedef int intptr_t;
+#endif
+#define _INTPTR_T_DEFINED
+#endif
+
+char *wideToUTF8(const LPCWSTR wstr);
+LPCWSTR UTF8toWide(const char *str);
+const char **getUTF8argvs(int argc, const wchar_t *wargv[]);
+void freeUTF8argvs(int argc, const char *argv[]);
+int dspawnv(int mode, const char *file, const char *const *argv);
+
+#endif
+
+char* dgetenv(const char *name);
+int dputenv(const char *env);
+int dmkdir(const char *name);
+int dspawnlp(int mode, const char *file, const char *arg0, const char *arg1, const char *arg2);
+int dspawnl(int mode, const char *file, const char *arg0, const char *arg1, const char *arg2);
+
+#endif
diff --git a/src/win32.mak b/src/win32.mak
index 00d9ea9a88cd..e1360355438c 100644
--- a/src/win32.mak
+++ b/src/win32.mak
@@ -175,7 +175,7 @@ BACKOBJ= go.obj gdag.obj gother.obj gflow.obj gloop.obj var.obj el.obj \
# Root package
ROOTOBJS= man.obj port.obj checkedint.obj \
stringtable.obj response.obj async.obj speller.obj aav.obj outbuffer.obj \
- object.obj filename.obj file.obj \
+ object.obj filename.obj file.obj utils.obj \
rmem.obj newdelete.obj
# D front end
@@ -236,7 +236,8 @@ ROOTSRCC=$(ROOT)\rmem.c $(ROOT)\stringtable.c \
$(ROOT)\man.c $(ROOT)\port.c $(ROOT)\async.c $(ROOT)\response.c \
$(ROOT)\speller.c $(ROOT)\aav.c $(ROOT)\longdouble.c \
$(ROOT)\checkedint.c $(ROOT)\newdelete.c \
- $(ROOT)\outbuffer.c $(ROOT)\object.c $(ROOT)\filename.c $(ROOT)\file.c
+ $(ROOT)\outbuffer.c $(ROOT)\object.c $(ROOT)\filename.c \
+ $(ROOT)\file.c $(ROOT)\utils.c
ROOTSRC= $(ROOT)\root.h \
$(ROOT)\rmem.h $(ROOT)\port.h \
$(ROOT)\stringtable.h \
@@ -250,6 +251,7 @@ ROOTSRC= $(ROOT)\root.h \
$(ROOT)\filename.h \
$(ROOT)\file.h \
$(ROOT)\array.h \
+ $(ROOT)\utils.h \
$(ROOTSRCC)
# Removed garbage collector bits (look in history)
# $(ROOT)\gc\bits.c $(ROOT)\gc\gc.c $(ROOT)\gc\gc.h $(ROOT)\gc\mscbitops.h \
@@ -347,7 +349,7 @@ GENSRC=access.d aggregate.d aliasthis.d apply.d \
globals.d escape.d \
$(ROOT)\aav.d $(ROOT)\outbuffer.d $(ROOT)\stringtable.d \
$(ROOT)\file.d $(ROOT)\filename.d $(ROOT)\speller.d \
- $(ROOT)\man.d $(ROOT)\response.d
+ $(ROOT)\man.d $(ROOT)\response.d $(ROOT)\utils.d
MANUALSRC= \
intrange.d complex.d \
@@ -729,6 +731,9 @@ filename.obj : $(ROOT)\filename.c
file.obj : $(ROOT)\file.c
$(CC) -c $(CFLAGS) $(ROOT)\file.c
+utils.obj : $(ROOT)\utils.c
+ $(CC) -c $(CFLAGS) $(ROOT)\utils.c
+
# Root/GC -- Removed (look in history)
#
#bits.obj : $(ROOT)\gc\bits.h $(ROOT)\gc\bits.c
diff --git "a/test/runnable/extra-files/\340\244\257\340\245\202\340\244\250\340\244\277\340\244\225\340\245\213\340\244\241.d" "b/test/runnable/extra-files/\340\244\257\340\245\202\340\244\250\340\244\277\340\244\225\340\245\213\340\244\241.d"
new file mode 100644
index 000000000000..8f8edd94f41d
--- /dev/null
+++ "b/test/runnable/extra-files/\340\244\257\340\245\202\340\244\250\340\244\277\340\244\225\340\245\213\340\244\241.d"
@@ -0,0 +1,2 @@
+module unicode;
+void main() { }
diff --git a/test/runnable/test_utf8_cmdfile.sh b/test/runnable/test_utf8_cmdfile.sh
new file mode 100644
index 000000000000..070023cfeaa7
--- /dev/null
+++ b/test/runnable/test_utf8_cmdfile.sh
@@ -0,0 +1,15 @@
+#!/usr/bin/env bash
+src=runnable${SEP}extra-files
+dir=${RESULTS_DIR}${SEP}runnable
+output_file=${dir}${SEP}test_utf8_cmdfile.sh.out
+
+rm -f ${output_file}
+
+echo "-of${dir}${SEP}test_utf8_cmdfile${EXE}" > ${dir}${SEP}cmdfile
+echo "${src}${SEP}यूनिकोड.d" >> ${dir}${SEP}cmdfile
+
+$DMD @${dir}${SEP}cmdfile || exit 1
+
+rm ${dir}${SEP}{cmdfile,test_utf8_cmdfile${OBJ},test_utf8_cmdfile${EXE}}
+
+echo Success > ${output_file}