Revert "Windows Unicode I/O "

This reverts commit 3e005074a3.
pull/1260/head
Alexander Medvednikov 2019-07-21 17:29:40 +02:00
parent 9c9fe7029e
commit 23c5f88f3e
6 changed files with 68 additions and 197 deletions

View File

@ -200,11 +200,7 @@ fn (v mut V) compile() {
#ifdef _WIN32 #ifdef _WIN32
#define WIN32_LEAN_AND_MEAN
#include <windows.h> #include <windows.h>
#include <io.h> // _waccess
#include <fcntl.h> // _O_U8TEXT
#include <direct.h> // _wgetcwd
//#include <WinSock2.h> //#include <WinSock2.h>
#endif #endif
@ -364,7 +360,7 @@ string _STR_TMP(const char *fmt, ...) {
// It can be skipped in single file programs // It can be skipped in single file programs
if v.pref.is_script { if v.pref.is_script {
//println('Generating main()...') //println('Generating main()...')
cgen.genln('int main() { \n#ifdef _WIN32\n _setmode(_fileno(stdout), _O_U8TEXT); \n#endif\n init_consts(); $cgen.fn_main; return 0; }') cgen.genln('int main() { init_consts(); $cgen.fn_main; return 0; }')
} }
else { else {
println('panic: function `main` is undeclared in the main module') println('panic: function `main` is undeclared in the main module')
@ -373,7 +369,7 @@ string _STR_TMP(const char *fmt, ...) {
} }
// Generate `main` which calls every single test function // Generate `main` which calls every single test function
else if v.pref.is_test { else if v.pref.is_test {
cgen.genln('int main() { \n#ifdef _WIN32\n _setmode(_fileno(stdout), _O_U8TEXT); \n#endif\n init_consts();') cgen.genln('int main() { init_consts();')
for key, f in v.table.fns { for key, f in v.table.fns {
if f.name.starts_with('test_') { if f.name.starts_with('test_') {
cgen.genln('$f.name();') cgen.genln('$f.name();')
@ -504,7 +500,7 @@ fn (c &V) cc_windows_cross() {
obj_name = obj_name.replace('.exe', '') obj_name = obj_name.replace('.exe', '')
obj_name = obj_name.replace('.o.o', '.o') obj_name = obj_name.replace('.o.o', '.o')
mut include := '-I $winroot/include ' mut include := '-I $winroot/include '
cmd := 'clang -o $obj_name -w $include -DUNICODE -D_UNICODE -m32 -c -target x86_64-win32 $ModPath/$c.out_name_c' cmd := 'clang -o $obj_name -w $include -m32 -c -target x86_64-win32 $ModPath/$c.out_name_c'
if c.pref.show_c_cmd { if c.pref.show_c_cmd {
println(cmd) println(cmd)
} }
@ -635,9 +631,6 @@ mut args := ''
a << ' -ldl ' a << ' -ldl '
} }
} }
if v.os == .windows {
a << '-DUNICODE -D_UNICODE'
}
// Find clang executable // Find clang executable
//fast_clang := '/usr/local/Cellar/llvm/8.0.0/bin/clang' //fast_clang := '/usr/local/Cellar/llvm/8.0.0/bin/clang'
args := a.join(' ') args := a.join(' ')

View File

@ -37,11 +37,7 @@ pub fn println(s string) {
if isnil(s.str) { if isnil(s.str) {
panic('println(NIL)') panic('println(NIL)')
} }
$if windows { C.printf('%.*s\n', s.len, s.str)
C._putws(s.to_wide())
} $else {
C.printf('%.*s\n', s.len, s.str)
}
} }
pub fn eprintln(s string) { pub fn eprintln(s string) {
@ -58,11 +54,7 @@ pub fn eprintln(s string) {
} }
pub fn print(s string) { pub fn print(s string) {
$if windows { C.printf('%.*s', s.len, s.str)
C.wprintf(s.to_wide())
} $else {
C.printf('%.*s', s.len, s.str)
}
} }
__global total_m i64 = 0 __global total_m i64 = 0

View File

@ -91,43 +91,3 @@ pub fn (_rune string) utf32_code() int {
return res return res
} }
const (
CP_UTF8 = 65001
)
pub fn (_str string) to_wide() &u16 {
$if windows {
num_chars := int(C.MultiByteToWideChar(CP_UTF8, 0, _str.str, _str.len, 0, 0))
mut wstr := &u16(malloc((num_chars + 1) * 2)) // sizeof(wchar_t)
if wstr > 0 {
C.MultiByteToWideChar(CP_UTF8, 0, _str.str, _str.len, wstr, num_chars)
C.memset(&byte(wstr) + num_chars * 2, 0, 2)
}
return wstr
} $else {
return 0
}
}
pub fn string_from_wide(_wstr &u16) string {
$if windows {
wstr_len := int(C.wcslen(_wstr))
return string_from_wide2(_wstr, wstr_len)
} $else {
return ''
}
}
pub fn string_from_wide2(_wstr &u16, len int) string {
$if windows {
num_chars := int(C.WideCharToMultiByte(CP_UTF8, 0, _wstr, len, 0, 0, 0, 0))
mut str_to := &byte(malloc(num_chars + 1))
if str_to > 0 {
C.WideCharToMultiByte(CP_UTF8, 0, _wstr, len, str_to, num_chars, 0, 0)
C.memset(&byte(str_to) + num_chars, 0, 1)
}
return tos2(str_to)
} $else {
return ''
}
}

View File

@ -4,7 +4,6 @@
module math module math
#include <math.h>
// NOTE // NOTE
// When adding a new function, please make sure it's in the right place. // When adding a new function, please make sure it's in the right place.

View File

@ -35,8 +35,7 @@ import const (
INVALID_FILE_ATTRIBUTES INVALID_FILE_ATTRIBUTES
) )
struct C.FILE { struct FILE {
} }
struct File { struct File {
@ -106,14 +105,9 @@ fn parse_windows_cmd_line(cmd byteptr) []string {
// read_file reads the file in `path` and returns the contents. // read_file reads the file in `path` and returns the contents.
pub fn read_file(path string) ?string { pub fn read_file(path string) ?string {
mode := 'rb' mut mode := 'rb'
mut fp := &C.FILE{} cpath := path.cstr()
$if windows { fp := C.fopen(cpath, mode.cstr())
fp = C._wfopen(path.to_wide(), mode.to_wide())
} $else {
cpath := path.cstr()
fp = C.fopen(cpath, mode.cstr())
}
if isnil(fp) { if isnil(fp) {
return error('failed to open file "$path"') return error('failed to open file "$path"')
} }
@ -130,21 +124,13 @@ pub fn read_file(path string) ?string {
// file_size returns the size of the file located in `path`. // file_size returns the size of the file located in `path`.
pub fn file_size(path string) int { pub fn file_size(path string) int {
mut s := C.stat{} s := C.stat{}
$if windows { C.stat(path.str, &s)
C._wstat(path.to_wide(), &s)
} $else {
C.stat(path.str, &s)
}
return s.st_size return s.st_size
} }
pub fn mv(old, new string) { pub fn mv(old, new string) {
$if windows { C.rename(old.cstr(), new.cstr())
C._wrename(old.to_wide(), new.to_wide())
} $else {
C.rename(old.cstr(), new.cstr())
}
} }
// read_lines reads the file in `path` into an array of lines. // read_lines reads the file in `path` into an array of lines.
@ -152,14 +138,8 @@ pub fn mv(old, new string) {
pub fn read_lines(path string) []string { pub fn read_lines(path string) []string {
mut res := []string mut res := []string
mut buf := [1000]byte mut buf := [1000]byte
mode := 'rb' cpath := path.cstr()
mut fp := &C.FILE{} fp := C.fopen(cpath, 'rb')
$if windows {
fp = C._wfopen(path.to_wide(), mode.to_wide())
} $else {
cpath := path.cstr()
fp = C.fopen(cpath, mode.cstr())
}
if isnil(fp) { if isnil(fp) {
// TODO // TODO
// return error('failed to open file "$path"') // return error('failed to open file "$path"')
@ -191,18 +171,9 @@ fn read_ulines(path string) []ustring {
} }
pub fn open(path string) ?File { pub fn open(path string) ?File {
mut file := File{} cpath := path.cstr()
$if windows { file := File {
wpath := path.to_wide() cfile: C.fopen(cpath, 'rb')
mode := 'rb'
file = File {
cfile: C._wfopen(wpath, mode.to_wide())
}
} $else {
cpath := path.cstr()
file = File {
cfile: C.fopen(cpath, 'rb')
}
} }
if isnil(file.cfile) { if isnil(file.cfile) {
return error('failed to open file "$path"') return error('failed to open file "$path"')
@ -212,18 +183,9 @@ pub fn open(path string) ?File {
// create creates a file at a specified location and returns a writable `File` object. // create creates a file at a specified location and returns a writable `File` object.
pub fn create(path string) ?File { pub fn create(path string) ?File {
mut file := File{} cpath := path.cstr()
$if windows { file := File {
wpath := path.replace('/', '\\').to_wide() cfile: C.fopen(cpath, 'wb')
mode := 'wb'
file = File {
cfile: C._wfopen(wpath, mode.to_wide())
}
} $else {
cpath := path.cstr()
file = File {
cfile: C.fopen(cpath, 'wb')
}
} }
if isnil(file.cfile) { if isnil(file.cfile) {
return error('failed to create file "$path"') return error('failed to create file "$path"')
@ -232,21 +194,12 @@ pub fn create(path string) ?File {
} }
pub fn open_append(path string) ?File { pub fn open_append(path string) ?File {
mut file := File{} cpath := path.cstr()
$if windows { file := File {
wpath := path.replace('/', '\\').to_wide() cfile: C.fopen(cpath, 'ab')
mode := 'ab'
file = File {
cfile: C._wfopen(wpath, mode.to_wide())
}
} $else {
cpath := path.cstr()
file = File {
cfile: C.fopen(cpath, 'ab')
}
} }
if isnil(file.cfile) { if isnil(file.cfile) {
return error('failed to create(append) file "$path"') return error('failed to create file "$path"')
} }
return file return file
} }
@ -290,12 +243,7 @@ pub fn (f File) close() {
// system starts the specified command, waits for it to complete, and returns its code. // system starts the specified command, waits for it to complete, and returns its code.
pub fn system(cmd string) int { pub fn system(cmd string) int {
mut ret := int(0) ret := C.system(cmd.cstr())
$if windows {
ret = C._wsystem(cmd.to_wide())
} $else {
ret = C.system(cmd.cstr())
}
if ret == -1 { if ret == -1 {
os.print_c_errno() os.print_c_errno()
} }
@ -303,13 +251,11 @@ pub fn system(cmd string) int {
} }
fn popen(path string) *FILE { fn popen(path string) *FILE {
cpath := path.cstr()
$if windows { $if windows {
mode := 'rb' return C._popen(cpath, 'r')
wpath := path.to_wide()
return C._wpopen(wpath, mode.to_wide())
} }
$else { $else {
cpath := path.cstr()
return C.popen(cpath, 'r') return C.popen(cpath, 'r')
} }
} }
@ -333,19 +279,11 @@ pub fn exec(cmd string) string {
// `getenv` returns the value of the environment variable named by the key. // `getenv` returns the value of the environment variable named by the key.
pub fn getenv(key string) string { pub fn getenv(key string) string {
$if windows { s := C.getenv(key.cstr())
s := C._wgetenv(key.to_wide()) if isnil(s) {
if isnil(s) { return ''
return ''
}
return string_from_wide(s)
} $else {
s := C.getenv(key.cstr())
if isnil(s) {
return ''
}
return string(s)
} }
return string(s)
} }
pub fn setenv(name string, value string, overwrite bool) int { pub fn setenv(name string, value string, overwrite bool) int {
@ -377,17 +315,14 @@ pub fn unsetenv(name string) int {
// `file_exists` returns true if `path` exists. // `file_exists` returns true if `path` exists.
pub fn file_exists(path string) bool { pub fn file_exists(path string) bool {
$if windows { $if windows {
path = path.replace('/', '\\') return C._access( path.str, 0 ) != -1
return C._waccess( path.to_wide(), 0 ) != -1
} $else {
return C.access( path.str, 0 ) != -1
} }
return C.access( path.str, 0 ) != -1
} }
pub fn dir_exists(path string) bool { pub fn dir_exists(path string) bool {
$if windows { $if windows {
path = path.replace('/', '\\') attr := int(C.GetFileAttributes(path.cstr()))
attr := int(C.GetFileAttributes(path.to_wide()))
if attr == INVALID_FILE_ATTRIBUTES { if attr == INVALID_FILE_ATTRIBUTES {
return false return false
} }
@ -410,7 +345,7 @@ pub fn dir_exists(path string) bool {
pub fn mkdir(path string) { pub fn mkdir(path string) {
$if windows { $if windows {
path = path.replace('/', '\\') path = path.replace('/', '\\')
C._wmkdir(path.to_wide()) C.CreateDirectory(path.cstr(), 0)
} }
$else { $else {
C.mkdir(path.cstr(), 511)// S_IRWXU | S_IRWXG | S_IRWXO C.mkdir(path.cstr(), 511)// S_IRWXU | S_IRWXG | S_IRWXO
@ -419,12 +354,7 @@ pub fn mkdir(path string) {
// rm removes file in `path`. // rm removes file in `path`.
pub fn rm(path string) { pub fn rm(path string) {
$if windows { C.remove(path.cstr())
C._wremove(path.to_wide())
}
$else {
C.remove(path.cstr())
}
// C.unlink(path.cstr()) // C.unlink(path.cstr())
} }
@ -435,7 +365,7 @@ pub fn rmdir(path string) {
C.rmdir(path.cstr()) C.rmdir(path.cstr())
} }
$else { $else {
C.RemoveDirectoryW(path.to_wide()) C.RemoveDirectoryA(path.cstr())
} }
} }
@ -505,18 +435,20 @@ pub fn get_line() string {
// get_raw_line returns a one-line string from stdin along with '\n' if there is any // get_raw_line returns a one-line string from stdin along with '\n' if there is any
pub fn get_raw_line() string { pub fn get_raw_line() string {
$if windows { $if windows {
max := 512 // MAX_PATH * sizeof(wchar_t) max := 256
buf := &u16(malloc(max)) buf := malloc(max)
h_input := C.GetStdHandle(STD_INPUT_HANDLE) h_input := C.GetStdHandle(STD_INPUT_HANDLE)
if h_input == INVALID_HANDLE_VALUE { if h_input == INVALID_HANDLE_VALUE {
panic('get_raw_line() error getting input handle.') panic('get_raw_line() error getting input handle.')
} }
mut nr_chars := 0 nr_chars := 0
// NOTE: Once we have UTF8 encode function to
// convert utf16 to utf8, change to ReadConsoleW
C.ReadConsole(h_input, buf, max, &nr_chars, 0) C.ReadConsole(h_input, buf, max, &nr_chars, 0)
if nr_chars == 0 { if nr_chars == 0 {
return '' return ''
} }
return string_from_wide2(buf, nr_chars) return tos(buf, nr_chars)
} }
$else { $else {
//u64 is used because C.getline needs a size_t as second argument //u64 is used because C.getline needs a size_t as second argument
@ -604,8 +536,8 @@ fn on_segfault(f voidptr) {
} }
pub fn executable() string { pub fn executable() string {
mut result := malloc(MAX_PATH)
$if linux { $if linux {
mut result := malloc(MAX_PATH)
count := int(C.readlink('/proc/self/exe', result, MAX_PATH )) count := int(C.readlink('/proc/self/exe', result, MAX_PATH ))
if count < 0 { if count < 0 {
panic('error reading /proc/self/exe to get exe path') panic('error reading /proc/self/exe to get exe path')
@ -613,12 +545,10 @@ pub fn executable() string {
return string(result, count) return string(result, count)
} }
$if windows { $if windows {
mut result := &u16(malloc(512)) // MAX_PATH * sizeof(wchar_t) ret := int(C.GetModuleFileName( 0, result, MAX_PATH ))
len := int(C.GetModuleFileName( 0, result, MAX_PATH )) return string( result, ret)
return string_from_wide2(result, len)
} }
$if mac { $if mac {
mut result := malloc(MAX_PATH)
pid := C.getpid() pid := C.getpid()
ret := C.proc_pidpath (pid, result, MAX_PATH) ret := C.proc_pidpath (pid, result, MAX_PATH)
if ret <= 0 { if ret <= 0 {
@ -628,7 +558,6 @@ pub fn executable() string {
return string(result) return string(result)
} }
$if freebsd { $if freebsd {
mut result := malloc(MAX_PATH)
mut mib := [1 /* CTL_KERN */, 14 /* KERN_PROC */, 12 /* KERN_PROC_PATHNAME */, -1]!! mut mib := [1 /* CTL_KERN */, 14 /* KERN_PROC */, 12 /* KERN_PROC_PATHNAME */, -1]!!
size := MAX_PATH size := MAX_PATH
C.sysctl(mib, 4, result, &size, 0, 0) C.sysctl(mib, 4, result, &size, 0, 0)
@ -640,7 +569,6 @@ pub fn executable() string {
return os.args[0] return os.args[0]
} }
$if netbsd { $if netbsd {
mut result := malloc(MAX_PATH)
count := int(C.readlink('/proc/curproc/exe', result, MAX_PATH )) count := int(C.readlink('/proc/curproc/exe', result, MAX_PATH ))
if count < 0 { if count < 0 {
panic('error reading /proc/curproc/exe to get exe path') panic('error reading /proc/curproc/exe to get exe path')
@ -648,7 +576,6 @@ pub fn executable() string {
return string(result, count) return string(result, count)
} }
$if dragonfly { $if dragonfly {
mut result := malloc(MAX_PATH)
count := int(C.readlink('/proc/curproc/file', result, MAX_PATH )) count := int(C.readlink('/proc/curproc/file', result, MAX_PATH ))
if count < 0 { if count < 0 {
panic('error reading /proc/curproc/file to get exe path') panic('error reading /proc/curproc/file to get exe path')
@ -677,7 +604,7 @@ pub fn is_dir(path string) bool {
pub fn chdir(path string) { pub fn chdir(path string) {
$if windows { $if windows {
C._wchdir(path.to_wide()) C._chdir(path.cstr())
} }
$else { $else {
C.chdir(path.cstr()) C.chdir(path.cstr())
@ -685,21 +612,18 @@ pub fn chdir(path string) {
} }
pub fn getwd() string { pub fn getwd() string {
buf := malloc(512)
$if windows { $if windows {
max := 512 // MAX_PATH * sizeof(wchar_t) if C._getcwd(buf, 512) == 0 {
buf := &u16(malloc(max))
if C._wgetcwd(buf, max) == 0 {
return '' return ''
} }
return string_from_wide(buf)
} }
$else { $else {
buf := malloc(512)
if C.getcwd(buf, 512) == 0 { if C.getcwd(buf, 512) == 0 {
return '' return ''
} }
return string(buf)
} }
return string(buf)
} }
// win: FILETIME // win: FILETIME
@ -710,7 +634,7 @@ struct filetime {
} }
// win: WIN32_FIND_DATA // win: WIN32_FIND_DATA
// https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-_win32_find_dataw // https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-_win32_find_dataa
struct win32finddata { struct win32finddata {
mut: mut:
dwFileAttributes u32 dwFileAttributes u32
@ -747,13 +671,13 @@ pub fn ls(path string) []string {
path_files := '$path\\*' path_files := '$path\\*'
// NOTE:TODO: once we have a way to convert utf16 wide character to utf8 // NOTE:TODO: once we have a way to convert utf16 wide character to utf8
// we should use FindFirstFileW and FindNextFileW // we should use FindFirstFileW and FindNextFileW
h_find_files := C.FindFirstFile(path_files.to_wide(), &find_file_data) h_find_files := C.FindFirstFile(path_files.cstr(), &find_file_data)
first_filename := string_from_wide(&u16(find_file_data.cFileName)) first_filename := tos(&find_file_data.cFileName, strlen(find_file_data.cFileName))
if first_filename != '.' && first_filename != '..' { if first_filename != '.' && first_filename != '..' {
dir_files << first_filename dir_files << first_filename
} }
for C.FindNextFile(h_find_files, &find_file_data) { for C.FindNextFile(h_find_files, &find_file_data) {
filename := string_from_wide(&u16(find_file_data.cFileName)) filename := tos(&find_file_data.cFileName, strlen(find_file_data.cFileName))
if filename != '.' && filename != '..' { if filename != '.' && filename != '..' {
dir_files << filename.clone() dir_files << filename.clone()
} }

View File

@ -15,7 +15,7 @@ type HANDLE voidptr
// get_file_handle retrieves the operating-system file handle that is associated with the specified file descriptor. // get_file_handle retrieves the operating-system file handle that is associated with the specified file descriptor.
pub fn get_file_handle(path string) HANDLE { pub fn get_file_handle(path string) HANDLE {
mode := 'rb' mode := 'rb'
_fd := C._wfopen(path.to_wide(), mode.cstr()) _fd := C.fopen(path.cstr(), mode.cstr())
if _fd == 0 { if _fd == 0 {
return HANDLE(INVALID_HANDLE_VALUE) return HANDLE(INVALID_HANDLE_VALUE)
} }
@ -27,14 +27,17 @@ pub fn get_file_handle(path string) HANDLE {
// get_module_filename retrieves the fully qualified path for the file that contains the specified module. // get_module_filename retrieves the fully qualified path for the file that contains the specified module.
// The module must have been loaded by the current process. // The module must have been loaded by the current process.
pub fn get_module_filename(handle HANDLE) ?string { pub fn get_module_filename(handle HANDLE) ?string {
mut sz := int(4096) // Optimized length mut sz := int(1024) // Optimized length
mut buf := &u16(malloc(4096)) mut buf := [byte(0); sz] // Not work for GetModuleFileNameW :(
for { for {
status := C.GetModuleFileName(handle, &buf, sz) status := C.GetModuleFileName(handle, &buf, sz)
switch status { switch status {
case SUCCESS: case SUCCESS:
_filename := string_from_wide2(buf, sz) _filename := tos(buf.data, sz)
return _filename return _filename
case ERROR_INSUFFICIENT_BUFFER:
sz += 1024 // increment buffer cluster by 1024
buf = [byte(0); sz] // clear buffer
default: default:
// Must handled with GetLastError and converted by FormatMessage // Must handled with GetLastError and converted by FormatMessage
return error('Cannot get file name from handle.') return error('Cannot get file name from handle.')