Skip to content

Commit 04e7bd6

Browse files
committed
More UTF-16 wrapping on win32. Close rust-lang#1927.
1 parent cf8f5b7 commit 04e7bd6

File tree

2 files changed

+122
-86
lines changed

2 files changed

+122
-86
lines changed

src/libcore/libc.rs

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -493,6 +493,9 @@ mod consts {
493493
const O_TEXT : int = 16384;
494494
const O_BINARY : int = 32768;
495495
const O_NOINHERIT: int = 128;
496+
497+
const ERROR_SUCCESS : int = 0;
498+
const ERROR_INSUFFICIENT_BUFFER : int = 122;
496499
}
497500
}
498501

@@ -1105,15 +1108,17 @@ mod funcs {
11051108
nsize: DWORD) -> DWORD;
11061109
fn SetEnvironmentVariableW(n: LPCWSTR, v: LPCWSTR) -> BOOL;
11071110

1108-
fn GetModuleFileNameA(hModule: HMODULE,
1109-
lpFilename: LPSTR,
1111+
fn GetModuleFileNameW(hModule: HMODULE,
1112+
lpFilename: LPWSTR,
11101113
nSize: DWORD) -> DWORD;
1111-
fn CreateDirectoryA(lpPathName: LPCSTR,
1114+
fn CreateDirectoryW(lpPathName: LPCWSTR,
11121115
lpSecurityAttributes:
11131116
LPSECURITY_ATTRIBUTES) -> BOOL;
1114-
fn DeleteFileA(lpPathName: LPCSTR) -> BOOL;
1115-
fn RemoveDirectoryA(lpPathName: LPCSTR) -> BOOL;
1116-
fn SetCurrentDirectoryA(lpPathName: LPCSTR) -> BOOL;
1117+
fn DeleteFileW(lpPathName: LPCWSTR) -> BOOL;
1118+
fn RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL;
1119+
fn SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL;
1120+
1121+
fn GetLastError() -> DWORD;
11171122
}
11181123

11191124
#[abi = "cdecl"]

src/libcore/os.rs

Lines changed: 111 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -14,9 +14,13 @@
1414
// facts of which OS the user is on -- they should be given the opportunity
1515
// to write OS-ignorant code by default.
1616

17-
import libc::{c_char, c_void, c_int, c_uint, size_t, mode_t, pid_t, FILE};
17+
import libc::{c_char, c_void, c_int, c_uint, size_t, ssize_t,
18+
mode_t, pid_t, FILE};
1819
import libc::{close, fclose};
1920

21+
import option::{some, none};
22+
import option = option::t;
23+
2024
import getcwd = rustrt::rust_getcwd;
2125
import consts::*;
2226

@@ -46,15 +50,48 @@ fn env() -> [(str,str)] {
4650
ret pairs;
4751
}
4852

53+
const tmpbuf_sz : uint = 1000u;
54+
4955
fn as_c_charp<T>(s: str, f: fn(*c_char) -> T) -> T {
5056
str::as_buf(s) {|b| f(b as *c_char) }
5157
}
5258

53-
fn as_utf16_p<T>(s: str, f: fn(*u16) -> T) -> T {
54-
let t = str::to_utf16(s);
55-
// "null terminate"
56-
t += [0u16];
57-
vec::as_buf(t, f)
59+
fn fill_charp_buf(f: fn(*mutable c_char, size_t) -> bool)
60+
-> option<str> {
61+
let buf = vec::to_mut(vec::init_elt(tmpbuf_sz, 0u8 as c_char));
62+
vec::as_mut_buf(buf) { |b|
63+
if f(b, tmpbuf_sz as size_t) {
64+
some(str::from_cstr(b as str::sbuf))
65+
} else {
66+
none
67+
}
68+
}
69+
}
70+
71+
#[cfg(target_os = "win32")]
72+
mod win32 {
73+
import dword = libc::types::os::arch::extra::DWORD;
74+
75+
fn fill_utf16_buf_and_decode(f: fn(*mutable u16, dword) -> dword)
76+
-> option<str> {
77+
let buf = vec::to_mut(vec::init_elt(tmpbuf_sz, 0u16));
78+
vec::as_mut_buf(buf) {|b|
79+
let k : dword = f(b, tmpbuf_sz as dword);
80+
if k == (0 as dword) {
81+
none
82+
} else {
83+
let sub = vec::slice(buf, 0u, k as uint);
84+
option::some::<str>(str::from_utf16(sub))
85+
}
86+
}
87+
}
88+
89+
fn as_utf16_p<T>(s: str, f: fn(*u16) -> T) -> T {
90+
let t = str::to_utf16(s);
91+
// Null terminate before passing on.
92+
t += [0u16];
93+
vec::as_buf(t, f)
94+
}
5895
}
5996

6097

@@ -74,19 +111,11 @@ fn getenv(n: str) -> option<str> unsafe {
74111
#[cfg(target_os = "win32")]
75112
fn getenv(n: str) -> option<str> unsafe {
76113
import libc::types::os::arch::extra::*;
77-
import libc::funcs::extra::kernel32;
114+
import libc::funcs::extra::kernel32::*;
115+
import win32::*;
78116
as_utf16_p(n) {|u|
79-
let bufsize = 1023u;
80-
let buf = vec::to_mut(vec::init_elt(bufsize, 0u16));
81-
vec::as_mut_buf(buf) {|b|
82-
let k = kernel32::GetEnvironmentVariableW(u, b,
83-
bufsize as DWORD);
84-
if k != (0 as DWORD) {
85-
let sub = vec::slice(buf, 0u, k as uint);
86-
option::some::<str>(str::from_utf16(sub))
87-
} else {
88-
option::none::<str>
89-
}
117+
fill_utf16_buf_and_decode() {|buf, sz|
118+
GetEnvironmentVariableW(u, buf, sz)
90119
}
91120
}
92121
}
@@ -99,7 +128,6 @@ fn setenv(n: str, v: str) {
99128

100129
// FIXME: remove this when export globs work properly.
101130
import libc::funcs::posix01::unistd::setenv;
102-
103131
as_c_charp(n) {|nbuf|
104132
as_c_charp(v) {|vbuf|
105133
setenv(nbuf, vbuf, 1i32);
@@ -111,10 +139,11 @@ fn setenv(n: str, v: str) {
111139
#[cfg(target_os = "win32")]
112140
fn setenv(n: str, v: str) {
113141
// FIXME: remove imports when export globs work properly.
114-
import libc::funcs::extra::kernel32;
142+
import libc::funcs::extra::kernel32::*;
143+
import win32::*;
115144
as_utf16_p(n) {|nbuf|
116145
as_utf16_p(v) {|vbuf|
117-
kernel32::SetEnvironmentVariableW(nbuf, vbuf);
146+
SetEnvironmentVariableW(nbuf, vbuf);
118147
}
119148
}
120149
}
@@ -244,59 +273,57 @@ fn dll_filename(base: str) -> str {
244273
fn pre() -> str { "" }
245274
}
246275

247-
fn self_exe_path() -> option<path> unsafe {
248-
let bufsize = 1023u;
249-
let buf = vec::to_mut(vec::init_elt(bufsize, 0u8 as c_char));
250-
// FIXME: This does not handle the case where the buffer is too small
251-
ret vec::as_mut_buf(buf) {|pbuf|
252-
if load_self(pbuf as *mutable c_char, bufsize as c_uint) {
253-
let path = str::from_cstr(pbuf as str::sbuf);
254-
option::some(path::dirname(path) + path::path_sep())
255-
} else {
256-
option::none
257-
}
258-
};
276+
277+
fn self_exe_path() -> option<path> {
259278

260279
#[cfg(target_os = "freebsd")]
261-
unsafe fn load_self(pth: *mutable c_char, plen: c_uint) -> bool {
262-
// FIXME: remove imports when export globs work properly.
280+
fn load_self() -> option<path> unsafe {
263281
import libc::funcs::bsd44::*;
264282
import libc::consts::os::extra::*;
265-
let mib = [CTL_KERN as c_int,
266-
KERN_PROC as c_int,
267-
KERN_PROC_PATHNAME as c_int, -1 as c_int];
268-
ret sysctl(vec::unsafe::to_ptr(mib), vec::len(mib) as c_uint,
269-
pth as *mutable c_void, ptr::mut_addr_of(plen as size_t),
270-
ptr::null(), 0u as size_t)
271-
== (0 as c_int);
283+
fill_charp_buf() {|buf, sz|
284+
let mib = [CTL_KERN as c_int,
285+
KERN_PROC as c_int,
286+
KERN_PROC_PATHNAME as c_int, -1 as c_int];
287+
sysctl(vec::unsafe::to_ptr(mib), vec::len(mib) as c_uint,
288+
buf as *mutable c_void, ptr::mut_addr_of(sz),
289+
ptr::null(), 0u as size_t) != (0 as c_int)
290+
}
272291
}
273292

274293
#[cfg(target_os = "linux")]
275-
unsafe fn load_self(pth: *mutable c_char, plen: c_uint) -> bool {
276-
// FIXME: remove imports when export globs work properly.
294+
fn load_self() -> option<path> unsafe {
277295
import libc::funcs::posix01::unistd::readlink;
278-
as_c_charp("/proc/self/exe") { |proc_self_buf|
279-
ret readlink(proc_self_buf, pth, plen as size_t) != -1;
296+
fill_charp_buf() {|buf, sz|
297+
as_c_charp("/proc/self/exe") { |proc_self_buf|
298+
readlink(proc_self_buf, buf, sz) != (-1 as ssize_t)
299+
}
280300
}
281301
}
282302

283-
#[cfg(target_os = "win32")]
284-
unsafe fn load_self(pth: *mutable c_char, plen: c_uint) -> bool {
303+
#[cfg(target_os = "macos")]
304+
fn load_self() -> option<path> unsafe {
285305
// FIXME: remove imports when export globs work properly.
286-
import libc::types::os::arch::extra::*;
287-
import libc::funcs::extra::kernel32;
288-
ret kernel32::GetModuleFileNameA(0u, pth, plen) != (0 as DWORD);
306+
import libc::funcs::extra::*;
307+
fill_charp_buf() {|buf, sz|
308+
_NSGetExecutablePath(buf, ptr::mut_addr_of(sz as u32))
309+
== (0 as c_int)
310+
}
289311
}
290312

291-
#[cfg(target_os = "macos")]
292-
unsafe fn load_self(pth: *mutable c_char, plen: c_uint) -> bool {
313+
#[cfg(target_os = "win32")]
314+
fn load_self() -> option<path> unsafe {
293315
// FIXME: remove imports when export globs work properly.
294-
import libc::funcs::extra::*;
295-
let mplen = plen;
296-
ret _NSGetExecutablePath(pth, ptr::mut_addr_of(mplen))
297-
== (0 as c_int);
316+
import libc::types::os::arch::extra::*;
317+
import libc::funcs::extra::kernel32::*;
318+
import win32::*;
319+
fill_utf16_buf_and_decode() {|buf, sz|
320+
GetModuleFileNameW(0u, buf, sz)
321+
}
298322
}
299323

324+
option::map(load_self()) {|pth|
325+
path::dirname(pth) + path::path_sep()
326+
}
300327
}
301328

302329

@@ -356,9 +383,9 @@ Function: path_is_dir
356383
Indicates whether a path represents a directory.
357384
*/
358385
fn path_is_dir(p: path) -> bool {
359-
ret str::as_buf(p, {|buf|
386+
str::as_buf(p) {|buf|
360387
rustrt::rust_path_is_dir(buf) != 0 as c_int
361-
});
388+
}
362389
}
363390

364391
/*
@@ -367,9 +394,9 @@ Function: path_exists
367394
Indicates whether a path exists.
368395
*/
369396
fn path_exists(p: path) -> bool {
370-
ret str::as_buf(p, {|buf|
397+
str::as_buf(p) {|buf|
371398
rustrt::rust_path_exists(buf) != 0 as c_int
372-
});
399+
}
373400
}
374401

375402
// FIXME: under Windows, we should prepend the current drive letter to paths
@@ -404,24 +431,25 @@ fn make_dir(p: path, mode: c_int) -> bool {
404431
ret mkdir(p, mode);
405432

406433
#[cfg(target_os = "win32")]
407-
fn mkdir(_p: path, _mode: c_int) -> bool unsafe {
434+
fn mkdir(p: path, _mode: c_int) -> bool unsafe {
435+
// FIXME: remove imports when export globs work properly.
436+
import libc::types::os::arch::extra::*;
437+
import libc::funcs::extra::kernel32::*;
438+
import win32::*;
408439
// FIXME: turn mode into something useful?
409-
ret as_c_charp(_p, {|buf|
410-
// FIXME: remove imports when export globs work properly.
411-
import libc::types::os::arch::extra::*;
412-
import libc::funcs::extra::kernel32;
413-
kernel32::CreateDirectoryA(
414-
buf, unsafe::reinterpret_cast(0)) != (0 as BOOL)
415-
});
440+
as_utf16_p(p) {|buf|
441+
CreateDirectoryW(buf, unsafe::reinterpret_cast(0))
442+
!= (0 as BOOL)
443+
}
416444
}
417445

418446
#[cfg(target_os = "linux")]
419447
#[cfg(target_os = "macos")]
420448
#[cfg(target_os = "freebsd")]
421449
fn mkdir(p: path, mode: c_int) -> bool {
422-
ret as_c_charp(p) {|c|
450+
as_c_charp(p) {|c|
423451
libc::mkdir(c, mode as mode_t) == (0 as c_int)
424-
};
452+
}
425453
}
426454
}
427455

@@ -468,10 +496,11 @@ fn remove_dir(p: path) -> bool {
468496
#[cfg(target_os = "win32")]
469497
fn rmdir(p: path) -> bool {
470498
// FIXME: remove imports when export globs work properly.
471-
import libc::funcs::extra::kernel32;
499+
import libc::funcs::extra::kernel32::*;
472500
import libc::types::os::arch::extra::*;
473-
ret as_c_charp(p) {|buf|
474-
kernel32::RemoveDirectoryA(buf) != (0 as BOOL)
501+
import win32::*;
502+
ret as_utf16_p(p) {|buf|
503+
RemoveDirectoryW(buf) != (0 as BOOL)
475504
};
476505
}
477506

@@ -491,10 +520,11 @@ fn change_dir(p: path) -> bool {
491520
#[cfg(target_os = "win32")]
492521
fn chdir(p: path) -> bool {
493522
// FIXME: remove imports when export globs work properly.
494-
import libc::funcs::extra::kernel32;
523+
import libc::funcs::extra::kernel32::*;
495524
import libc::types::os::arch::extra::*;
496-
ret as_c_charp(p) {|buf|
497-
kernel32::SetCurrentDirectoryA(buf) != (0 as BOOL)
525+
import win32::*;
526+
ret as_utf16_p(p) {|buf|
527+
SetCurrentDirectoryW(buf) != (0 as BOOL)
498528
};
499529
}
500530

@@ -519,10 +549,11 @@ fn remove_file(p: path) -> bool {
519549
#[cfg(target_os = "win32")]
520550
fn unlink(p: path) -> bool {
521551
// FIXME: remove imports when export globs work properly.
522-
import libc::funcs::extra::kernel32;
552+
import libc::funcs::extra::kernel32::*;
523553
import libc::types::os::arch::extra::*;
524-
ret as_c_charp(p) {|buf|
525-
kernel32::DeleteFileA(buf) != (0 as BOOL)
554+
import win32::*;
555+
ret as_utf16_p(p) {|buf|
556+
DeleteFileW(buf) != (0 as BOOL)
526557
};
527558
}
528559

0 commit comments

Comments
 (0)