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}