More UTF-16 wrapping on win32. Close #1927.

This commit is contained in:
Graydon Hoare 2012-03-06 18:49:08 -08:00
parent cf8f5b7606
commit 04e7bd6758
2 changed files with 122 additions and 86 deletions

View File

@ -493,6 +493,9 @@ mod consts {
const O_TEXT : int = 16384; const O_TEXT : int = 16384;
const O_BINARY : int = 32768; const O_BINARY : int = 32768;
const O_NOINHERIT: int = 128; const O_NOINHERIT: int = 128;
const ERROR_SUCCESS : int = 0;
const ERROR_INSUFFICIENT_BUFFER : int = 122;
} }
} }
@ -1105,15 +1108,17 @@ mod funcs {
nsize: DWORD) -> DWORD; nsize: DWORD) -> DWORD;
fn SetEnvironmentVariableW(n: LPCWSTR, v: LPCWSTR) -> BOOL; fn SetEnvironmentVariableW(n: LPCWSTR, v: LPCWSTR) -> BOOL;
fn GetModuleFileNameA(hModule: HMODULE, fn GetModuleFileNameW(hModule: HMODULE,
lpFilename: LPSTR, lpFilename: LPWSTR,
nSize: DWORD) -> DWORD; nSize: DWORD) -> DWORD;
fn CreateDirectoryA(lpPathName: LPCSTR, fn CreateDirectoryW(lpPathName: LPCWSTR,
lpSecurityAttributes: lpSecurityAttributes:
LPSECURITY_ATTRIBUTES) -> BOOL; LPSECURITY_ATTRIBUTES) -> BOOL;
fn DeleteFileA(lpPathName: LPCSTR) -> BOOL; fn DeleteFileW(lpPathName: LPCWSTR) -> BOOL;
fn RemoveDirectoryA(lpPathName: LPCSTR) -> BOOL; fn RemoveDirectoryW(lpPathName: LPCWSTR) -> BOOL;
fn SetCurrentDirectoryA(lpPathName: LPCSTR) -> BOOL; fn SetCurrentDirectoryW(lpPathName: LPCWSTR) -> BOOL;
fn GetLastError() -> DWORD;
} }
#[abi = "cdecl"] #[abi = "cdecl"]

View File

@ -14,9 +14,13 @@
// facts of which OS the user is on -- they should be given the opportunity // facts of which OS the user is on -- they should be given the opportunity
// to write OS-ignorant code by default. // to write OS-ignorant code by default.
import libc::{c_char, c_void, c_int, c_uint, size_t, mode_t, pid_t, FILE}; import libc::{c_char, c_void, c_int, c_uint, size_t, ssize_t,
mode_t, pid_t, FILE};
import libc::{close, fclose}; import libc::{close, fclose};
import option::{some, none};
import option = option::t;
import getcwd = rustrt::rust_getcwd; import getcwd = rustrt::rust_getcwd;
import consts::*; import consts::*;
@ -46,15 +50,48 @@ fn env() -> [(str,str)] {
ret pairs; ret pairs;
} }
const tmpbuf_sz : uint = 1000u;
fn as_c_charp<T>(s: str, f: fn(*c_char) -> T) -> T { fn as_c_charp<T>(s: str, f: fn(*c_char) -> T) -> T {
str::as_buf(s) {|b| f(b as *c_char) } str::as_buf(s) {|b| f(b as *c_char) }
} }
fn as_utf16_p<T>(s: str, f: fn(*u16) -> T) -> T { fn fill_charp_buf(f: fn(*mutable c_char, size_t) -> bool)
let t = str::to_utf16(s); -> option<str> {
// "null terminate" let buf = vec::to_mut(vec::init_elt(tmpbuf_sz, 0u8 as c_char));
t += [0u16]; vec::as_mut_buf(buf) { |b|
vec::as_buf(t, f) if f(b, tmpbuf_sz as size_t) {
some(str::from_cstr(b as str::sbuf))
} else {
none
}
}
}
#[cfg(target_os = "win32")]
mod win32 {
import dword = libc::types::os::arch::extra::DWORD;
fn fill_utf16_buf_and_decode(f: fn(*mutable u16, dword) -> dword)
-> option<str> {
let buf = vec::to_mut(vec::init_elt(tmpbuf_sz, 0u16));
vec::as_mut_buf(buf) {|b|
let k : dword = f(b, tmpbuf_sz as dword);
if k == (0 as dword) {
none
} else {
let sub = vec::slice(buf, 0u, k as uint);
option::some::<str>(str::from_utf16(sub))
}
}
}
fn as_utf16_p<T>(s: str, f: fn(*u16) -> T) -> T {
let t = str::to_utf16(s);
// Null terminate before passing on.
t += [0u16];
vec::as_buf(t, f)
}
} }
@ -74,19 +111,11 @@ fn getenv(n: str) -> option<str> unsafe {
#[cfg(target_os = "win32")] #[cfg(target_os = "win32")]
fn getenv(n: str) -> option<str> unsafe { fn getenv(n: str) -> option<str> unsafe {
import libc::types::os::arch::extra::*; import libc::types::os::arch::extra::*;
import libc::funcs::extra::kernel32; import libc::funcs::extra::kernel32::*;
import win32::*;
as_utf16_p(n) {|u| as_utf16_p(n) {|u|
let bufsize = 1023u; fill_utf16_buf_and_decode() {|buf, sz|
let buf = vec::to_mut(vec::init_elt(bufsize, 0u16)); GetEnvironmentVariableW(u, buf, sz)
vec::as_mut_buf(buf) {|b|
let k = kernel32::GetEnvironmentVariableW(u, b,
bufsize as DWORD);
if k != (0 as DWORD) {
let sub = vec::slice(buf, 0u, k as uint);
option::some::<str>(str::from_utf16(sub))
} else {
option::none::<str>
}
} }
} }
} }
@ -99,7 +128,6 @@ fn setenv(n: str, v: str) {
// FIXME: remove this when export globs work properly. // FIXME: remove this when export globs work properly.
import libc::funcs::posix01::unistd::setenv; import libc::funcs::posix01::unistd::setenv;
as_c_charp(n) {|nbuf| as_c_charp(n) {|nbuf|
as_c_charp(v) {|vbuf| as_c_charp(v) {|vbuf|
setenv(nbuf, vbuf, 1i32); setenv(nbuf, vbuf, 1i32);
@ -111,10 +139,11 @@ fn setenv(n: str, v: str) {
#[cfg(target_os = "win32")] #[cfg(target_os = "win32")]
fn setenv(n: str, v: str) { fn setenv(n: str, v: str) {
// FIXME: remove imports when export globs work properly. // FIXME: remove imports when export globs work properly.
import libc::funcs::extra::kernel32; import libc::funcs::extra::kernel32::*;
import win32::*;
as_utf16_p(n) {|nbuf| as_utf16_p(n) {|nbuf|
as_utf16_p(v) {|vbuf| as_utf16_p(v) {|vbuf|
kernel32::SetEnvironmentVariableW(nbuf, vbuf); SetEnvironmentVariableW(nbuf, vbuf);
} }
} }
} }
@ -244,59 +273,57 @@ fn dll_filename(base: str) -> str {
fn pre() -> str { "" } fn pre() -> str { "" }
} }
fn self_exe_path() -> option<path> unsafe {
let bufsize = 1023u; fn self_exe_path() -> option<path> {
let buf = vec::to_mut(vec::init_elt(bufsize, 0u8 as c_char));
// FIXME: This does not handle the case where the buffer is too small
ret vec::as_mut_buf(buf) {|pbuf|
if load_self(pbuf as *mutable c_char, bufsize as c_uint) {
let path = str::from_cstr(pbuf as str::sbuf);
option::some(path::dirname(path) + path::path_sep())
} else {
option::none
}
};
#[cfg(target_os = "freebsd")] #[cfg(target_os = "freebsd")]
unsafe fn load_self(pth: *mutable c_char, plen: c_uint) -> bool { fn load_self() -> option<path> unsafe {
// FIXME: remove imports when export globs work properly.
import libc::funcs::bsd44::*; import libc::funcs::bsd44::*;
import libc::consts::os::extra::*; import libc::consts::os::extra::*;
let mib = [CTL_KERN as c_int, fill_charp_buf() {|buf, sz|
KERN_PROC as c_int, let mib = [CTL_KERN as c_int,
KERN_PROC_PATHNAME as c_int, -1 as c_int]; KERN_PROC as c_int,
ret sysctl(vec::unsafe::to_ptr(mib), vec::len(mib) as c_uint, KERN_PROC_PATHNAME as c_int, -1 as c_int];
pth as *mutable c_void, ptr::mut_addr_of(plen as size_t), sysctl(vec::unsafe::to_ptr(mib), vec::len(mib) as c_uint,
ptr::null(), 0u as size_t) buf as *mutable c_void, ptr::mut_addr_of(sz),
== (0 as c_int); ptr::null(), 0u as size_t) != (0 as c_int)
}
} }
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
unsafe fn load_self(pth: *mutable c_char, plen: c_uint) -> bool { fn load_self() -> option<path> unsafe {
// FIXME: remove imports when export globs work properly.
import libc::funcs::posix01::unistd::readlink; import libc::funcs::posix01::unistd::readlink;
as_c_charp("/proc/self/exe") { |proc_self_buf| fill_charp_buf() {|buf, sz|
ret readlink(proc_self_buf, pth, plen as size_t) != -1; as_c_charp("/proc/self/exe") { |proc_self_buf|
readlink(proc_self_buf, buf, sz) != (-1 as ssize_t)
}
}
}
#[cfg(target_os = "macos")]
fn load_self() -> option<path> unsafe {
// FIXME: remove imports when export globs work properly.
import libc::funcs::extra::*;
fill_charp_buf() {|buf, sz|
_NSGetExecutablePath(buf, ptr::mut_addr_of(sz as u32))
== (0 as c_int)
} }
} }
#[cfg(target_os = "win32")] #[cfg(target_os = "win32")]
unsafe fn load_self(pth: *mutable c_char, plen: c_uint) -> bool { fn load_self() -> option<path> unsafe {
// FIXME: remove imports when export globs work properly. // FIXME: remove imports when export globs work properly.
import libc::types::os::arch::extra::*; import libc::types::os::arch::extra::*;
import libc::funcs::extra::kernel32; import libc::funcs::extra::kernel32::*;
ret kernel32::GetModuleFileNameA(0u, pth, plen) != (0 as DWORD); import win32::*;
fill_utf16_buf_and_decode() {|buf, sz|
GetModuleFileNameW(0u, buf, sz)
}
} }
#[cfg(target_os = "macos")] option::map(load_self()) {|pth|
unsafe fn load_self(pth: *mutable c_char, plen: c_uint) -> bool { path::dirname(pth) + path::path_sep()
// FIXME: remove imports when export globs work properly.
import libc::funcs::extra::*;
let mplen = plen;
ret _NSGetExecutablePath(pth, ptr::mut_addr_of(mplen))
== (0 as c_int);
} }
} }
@ -356,9 +383,9 @@ Function: path_is_dir
Indicates whether a path represents a directory. Indicates whether a path represents a directory.
*/ */
fn path_is_dir(p: path) -> bool { fn path_is_dir(p: path) -> bool {
ret str::as_buf(p, {|buf| str::as_buf(p) {|buf|
rustrt::rust_path_is_dir(buf) != 0 as c_int rustrt::rust_path_is_dir(buf) != 0 as c_int
}); }
} }
/* /*
@ -367,9 +394,9 @@ Function: path_exists
Indicates whether a path exists. Indicates whether a path exists.
*/ */
fn path_exists(p: path) -> bool { fn path_exists(p: path) -> bool {
ret str::as_buf(p, {|buf| str::as_buf(p) {|buf|
rustrt::rust_path_exists(buf) != 0 as c_int rustrt::rust_path_exists(buf) != 0 as c_int
}); }
} }
// FIXME: under Windows, we should prepend the current drive letter to paths // 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 {
ret mkdir(p, mode); ret mkdir(p, mode);
#[cfg(target_os = "win32")] #[cfg(target_os = "win32")]
fn mkdir(_p: path, _mode: c_int) -> bool unsafe { fn mkdir(p: path, _mode: c_int) -> bool unsafe {
// FIXME: remove imports when export globs work properly.
import libc::types::os::arch::extra::*;
import libc::funcs::extra::kernel32::*;
import win32::*;
// FIXME: turn mode into something useful? // FIXME: turn mode into something useful?
ret as_c_charp(_p, {|buf| as_utf16_p(p) {|buf|
// FIXME: remove imports when export globs work properly. CreateDirectoryW(buf, unsafe::reinterpret_cast(0))
import libc::types::os::arch::extra::*; != (0 as BOOL)
import libc::funcs::extra::kernel32; }
kernel32::CreateDirectoryA(
buf, unsafe::reinterpret_cast(0)) != (0 as BOOL)
});
} }
#[cfg(target_os = "linux")] #[cfg(target_os = "linux")]
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
#[cfg(target_os = "freebsd")] #[cfg(target_os = "freebsd")]
fn mkdir(p: path, mode: c_int) -> bool { fn mkdir(p: path, mode: c_int) -> bool {
ret as_c_charp(p) {|c| as_c_charp(p) {|c|
libc::mkdir(c, mode as mode_t) == (0 as c_int) libc::mkdir(c, mode as mode_t) == (0 as c_int)
}; }
} }
} }
@ -468,10 +496,11 @@ fn remove_dir(p: path) -> bool {
#[cfg(target_os = "win32")] #[cfg(target_os = "win32")]
fn rmdir(p: path) -> bool { fn rmdir(p: path) -> bool {
// FIXME: remove imports when export globs work properly. // FIXME: remove imports when export globs work properly.
import libc::funcs::extra::kernel32; import libc::funcs::extra::kernel32::*;
import libc::types::os::arch::extra::*; import libc::types::os::arch::extra::*;
ret as_c_charp(p) {|buf| import win32::*;
kernel32::RemoveDirectoryA(buf) != (0 as BOOL) ret as_utf16_p(p) {|buf|
RemoveDirectoryW(buf) != (0 as BOOL)
}; };
} }
@ -491,10 +520,11 @@ fn change_dir(p: path) -> bool {
#[cfg(target_os = "win32")] #[cfg(target_os = "win32")]
fn chdir(p: path) -> bool { fn chdir(p: path) -> bool {
// FIXME: remove imports when export globs work properly. // FIXME: remove imports when export globs work properly.
import libc::funcs::extra::kernel32; import libc::funcs::extra::kernel32::*;
import libc::types::os::arch::extra::*; import libc::types::os::arch::extra::*;
ret as_c_charp(p) {|buf| import win32::*;
kernel32::SetCurrentDirectoryA(buf) != (0 as BOOL) ret as_utf16_p(p) {|buf|
SetCurrentDirectoryW(buf) != (0 as BOOL)
}; };
} }
@ -519,10 +549,11 @@ fn remove_file(p: path) -> bool {
#[cfg(target_os = "win32")] #[cfg(target_os = "win32")]
fn unlink(p: path) -> bool { fn unlink(p: path) -> bool {
// FIXME: remove imports when export globs work properly. // FIXME: remove imports when export globs work properly.
import libc::funcs::extra::kernel32; import libc::funcs::extra::kernel32::*;
import libc::types::os::arch::extra::*; import libc::types::os::arch::extra::*;
ret as_c_charp(p) {|buf| import win32::*;
kernel32::DeleteFileA(buf) != (0 as BOOL) ret as_utf16_p(p) {|buf|
DeleteFileW(buf) != (0 as BOOL)
}; };
} }