-
-
Notifications
You must be signed in to change notification settings - Fork 637
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
dmd.vsoptions: Prepare for LDC & use *latest* VS version found via COM #11089
Merged
Merged
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -40,7 +40,7 @@ version (Windows) | |
extern (C) char* getcwd(char* buffer, size_t maxlen) nothrow; | ||
|
||
// assume filenames encoded in system default Windows ANSI code page | ||
private enum codepage = CP_ACP; | ||
private enum CodePage = CP_ACP; | ||
} | ||
|
||
version (CRuntime_Glibc) | ||
|
@@ -357,55 +357,67 @@ nothrow: | |
/// Ditto | ||
extern(D) static const(char)[] combine(const(char)[] path, const(char)[] name) | ||
{ | ||
if (!path.length) | ||
return name; | ||
return !path.length ? name : buildPath(path, name); | ||
} | ||
|
||
char* f = cast(char*)mem.xmalloc(path.length + 1 + name.length + 1); | ||
memcpy(f, path.ptr, path.length); | ||
bool trailingSlash = false; | ||
version (Posix) | ||
unittest | ||
{ | ||
version (Windows) | ||
assert(combine("foo"[], "bar"[]) == "foo\\bar"); | ||
else | ||
assert(combine("foo"[], "bar"[]) == "foo/bar"); | ||
assert(combine("foo/"[], "bar"[]) == "foo/bar"); | ||
} | ||
|
||
static const(char)[] buildPath(const(char)[][] fragments...) | ||
{ | ||
size_t size; | ||
foreach (f; fragments) | ||
size += f.length ? f.length + 1 : 0; | ||
if (size == 0) | ||
size = 1; | ||
|
||
char* p = cast(char*) mem.xmalloc_noscan(size); | ||
size_t length; | ||
foreach (f; fragments) | ||
{ | ||
if (path[$ - 1] != '/') | ||
if (!f.length) | ||
continue; | ||
|
||
p[length .. length + f.length] = f; | ||
length += f.length; | ||
|
||
const last = p[length - 1]; | ||
version (Posix) | ||
{ | ||
f[path.length] = '/'; | ||
trailingSlash = true; | ||
if (last != '/') | ||
p[length++] = '/'; | ||
} | ||
} | ||
else version (Windows) | ||
{ | ||
if (path[$ - 1] != '\\' && path[$ - 1] != '/' && path[$ - 1] != ':') | ||
else version (Windows) | ||
{ | ||
f[path.length] = '\\'; | ||
trailingSlash = true; | ||
if (last != '\\' && last != '/' && last != ':') | ||
p[length++] = '\\'; | ||
} | ||
else | ||
assert(0); | ||
} | ||
else | ||
{ | ||
assert(0); | ||
} | ||
const len = path.length + trailingSlash; | ||
memcpy(f + len, name.ptr, name.length); | ||
// Note: At the moment `const(char)*` are being transitioned to | ||
// `const(char)[]`. To avoid bugs crippling in, we `\0` terminate | ||
// slices, but don't include it in the slice so `.ptr` can be used. | ||
f[len + name.length] = '\0'; | ||
return f[0 .. len + name.length]; | ||
|
||
// overwrite last slash with null terminator | ||
p[length ? --length : 0] = 0; | ||
|
||
return p[0 .. length]; | ||
} | ||
|
||
unittest | ||
{ | ||
assert(buildPath() == ""); | ||
assert(buildPath("foo") == "foo"); | ||
assert(buildPath("foo", null) == "foo"); | ||
assert(buildPath(null, "foo") == "foo"); | ||
version (Windows) | ||
assert(combine("foo"[], "bar"[]) == "foo\\bar"); | ||
assert(buildPath("C:", r"a\", "bb/", "ccc", "d") == r"C:a\bb/ccc\d"); | ||
else | ||
assert(combine("foo"[], "bar"[]) == "foo/bar"); | ||
assert(combine("foo/"[], "bar"[]) == "foo/bar"); | ||
} | ||
|
||
static const(char)* buildPath(const(char)* path, const(char)*[] names...) | ||
{ | ||
foreach (const(char)* name; names) | ||
path = combine(path, name); | ||
return path; | ||
assert(buildPath("a/", "bb", "ccc") == "a/bb/ccc"); | ||
} | ||
|
||
// Split a path into an Array of paths | ||
|
@@ -808,7 +820,7 @@ nothrow: | |
} | ||
else version (Windows) | ||
{ | ||
return name.toCStringThen!((cstr) => cstr.toWStringzThen!((wname) | ||
return name.toWStringzThen!((wname) | ||
{ | ||
const dw = GetFileAttributesW(&wname[0]); | ||
if (dw == -1) | ||
|
@@ -817,7 +829,7 @@ nothrow: | |
return 2; | ||
else | ||
return 1; | ||
})); | ||
}); | ||
} | ||
else | ||
{ | ||
|
@@ -990,26 +1002,15 @@ nothrow: | |
// First find out how long the buffer has to be. | ||
const fullPathLength = GetFullPathNameW(&wname[0], 0, null, null); | ||
if (!fullPathLength) return null; | ||
auto fullPath = new wchar[fullPathLength]; | ||
auto fullPath = (cast(wchar*) mem.xmalloc_noscan((fullPathLength + 1) * wchar.sizeof))[0 .. fullPathLength + 1]; | ||
scope(exit) mem.xfree(fullPath.ptr); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One less leak. |
||
|
||
// Actually get the full path name | ||
const fullPathLengthNoTerminator = GetFullPathNameW( | ||
&wname[0], fullPathLength, &fullPath[0], null /*filePart*/); | ||
// Unfortunately, when the buffer is large enough the return value is the number of characters | ||
// _not_ counting the null terminator, so fullPathLengthNoTerminator should be smaller | ||
assert(fullPathLength > fullPathLengthNoTerminator); | ||
|
||
// Find out size of the converted string | ||
const retLength = WideCharToMultiByte( | ||
codepage, 0 /*flags*/, &fullPath[0], fullPathLength, null, 0, null, null); | ||
auto ret = new char[retLength]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This previously meant that the result could not be free'd via |
||
|
||
// Actually convert to char | ||
const retLength2 = WideCharToMultiByte( | ||
codepage, 0 /*flags*/, &fullPath[0], fullPathLength, &ret[0], retLength, null, null); | ||
assert(retLength == retLength2); | ||
|
||
return ret; | ||
const length = GetFullPathNameW( | ||
&wname[0], cast(DWORD) fullPath.length, &fullPath[0], null /*filePart*/); | ||
assert(length == fullPathLength); | ||
|
||
return toNarrowStringz(fullPath[0 .. length]); | ||
}); | ||
} | ||
else | ||
|
@@ -1149,6 +1150,60 @@ version(Windows) | |
}); | ||
} | ||
|
||
/********************************** | ||
* Converts a UTF-16 string to a (null-terminated) narrow string. | ||
* Returns: | ||
* If `buffer` is specified and the result fits, a slice of that buffer, | ||
* otherwise a new buffer which can be released via `mem.xfree()`. | ||
* Nulls are propagated, i.e., if `wide` is null, the returned slice is | ||
* null too. | ||
*/ | ||
char[] toNarrowStringz(const(wchar)[] wide, char[] buffer = null) nothrow | ||
{ | ||
if (wide is null) | ||
return null; | ||
|
||
const requiredLength = WideCharToMultiByte(CodePage, 0, wide.ptr, cast(int) wide.length, buffer.ptr, cast(int) buffer.length, null, null); | ||
if (requiredLength < buffer.length) | ||
{ | ||
buffer[requiredLength] = 0; | ||
return buffer[0 .. requiredLength]; | ||
} | ||
|
||
char* newBuffer = cast(char*) mem.xmalloc_noscan(requiredLength + 1); | ||
const length = WideCharToMultiByte(CodePage, 0, wide.ptr, cast(int) wide.length, newBuffer, requiredLength, null, null); | ||
assert(length == requiredLength); | ||
newBuffer[length] = 0; | ||
return newBuffer[0 .. length]; | ||
} | ||
|
||
/********************************** | ||
* Converts a narrow string to a (null-terminated) UTF-16 string. | ||
* Returns: | ||
* If `buffer` is specified and the result fits, a slice of that buffer, | ||
* otherwise a new buffer which can be released via `mem.xfree()`. | ||
* Nulls are propagated, i.e., if `narrow` is null, the returned slice is | ||
* null too. | ||
*/ | ||
wchar[] toWStringz(const(char)[] narrow, wchar[] buffer = null) nothrow | ||
{ | ||
if (narrow is null) | ||
return null; | ||
|
||
const requiredLength = MultiByteToWideChar(CodePage, 0, narrow.ptr, cast(int) narrow.length, buffer.ptr, cast(int) buffer.length); | ||
if (requiredLength < buffer.length) | ||
{ | ||
buffer[requiredLength] = 0; | ||
return buffer[0 .. requiredLength]; | ||
} | ||
|
||
wchar* newBuffer = cast(wchar*) mem.xmalloc_noscan((requiredLength + 1) * wchar.sizeof); | ||
const length = MultiByteToWideChar(CodePage, 0, narrow.ptr, cast(int) narrow.length, newBuffer, requiredLength); | ||
assert(length == requiredLength); | ||
newBuffer[length] = 0; | ||
return newBuffer[0 .. length]; | ||
} | ||
|
||
/********************************** | ||
* Converts a slice of UTF-8 characters to an array of wchar that's null | ||
* terminated so it can be passed to Win32 APIs then calls the supplied | ||
|
@@ -1164,28 +1219,10 @@ version(Windows) | |
{ | ||
if (!str.length) return F(""w.ptr); | ||
|
||
import core.stdc.stdlib: malloc, free; | ||
wchar[1024] buf = void; | ||
wchar[] wide = toWStringz(str, buf); | ||
scope(exit) wide.ptr != buf.ptr && mem.xfree(wide.ptr); | ||
|
||
// first find out how long the buffer must be to store the result | ||
const length = MultiByteToWideChar(codepage, 0 /*flags*/, &str[0], cast(int)str.length, null, 0); | ||
if (!length) return F(""w); | ||
|
||
wchar[] ret = length >= buf.length | ||
? (cast(wchar*)malloc((length + 1) * wchar.sizeof))[0 .. length + 1] | ||
: buf[0 .. length + 1]; | ||
scope (exit) | ||
{ | ||
if (&ret[0] != &buf[0]) | ||
free(&ret[0]); | ||
} | ||
// actually do the conversion | ||
const length2 = MultiByteToWideChar( | ||
codepage, 0 /*flags*/, &str[0], cast(int)str.length, &ret[0], length); | ||
assert(length == length2); // should always be true according to the API | ||
// Add terminating `\0` | ||
ret[$ - 1] = '\0'; | ||
|
||
return F(ret[0 .. $ - 1]); | ||
return F(wide); | ||
} | ||
} |
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
C null-termination was superfluous here.