Windows Unicode I/O
							parent
							
								
									6e6f6bc387
								
							
						
					
					
						commit
						3e005074a3
					
				|  | @ -200,7 +200,11 @@ 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  | ||||||
| 
 | 
 | ||||||
|  | @ -360,7 +364,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() { init_consts(); $cgen.fn_main; return 0; }') | 				cgen.genln('int main() { \n#ifdef _WIN32\n _setmode(_fileno(stdout), _O_U8TEXT); \n#endif\n 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') | ||||||
|  | @ -369,7 +373,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() { init_consts();') | 			cgen.genln('int main() { \n#ifdef _WIN32\n _setmode(_fileno(stdout), _O_U8TEXT); \n#endif\n 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();') | ||||||
|  | @ -500,7 +504,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 -m32 -c -target x86_64-win32 $ModPath/$c.out_name_c' |                cmd := 'clang -o $obj_name -w $include -DUNICODE -D_UNICODE -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) | ||||||
|                } |                } | ||||||
|  | @ -631,6 +635,9 @@ 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(' ') | ||||||
|  |  | ||||||
|  | @ -37,8 +37,12 @@ pub fn println(s string) { | ||||||
| 	if isnil(s.str) { | 	if isnil(s.str) { | ||||||
| 		panic('println(NIL)') | 		panic('println(NIL)') | ||||||
| 	} | 	} | ||||||
|  | 	$if windows { | ||||||
|  | 		C._putws(s.to_wide()) | ||||||
|  | 	} $else { | ||||||
| 		C.printf('%.*s\n', s.len, s.str) | 		C.printf('%.*s\n', s.len, s.str) | ||||||
| 	} | 	} | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| pub fn eprintln(s string) { | pub fn eprintln(s string) { | ||||||
| 	if isnil(s.str) { | 	if isnil(s.str) { | ||||||
|  | @ -54,8 +58,12 @@ pub fn eprintln(s string) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn print(s string) { | pub fn print(s string) { | ||||||
|  | 	$if windows { | ||||||
|  | 		C.wprintf(s.to_wide()) | ||||||
|  | 	} $else { | ||||||
| 		C.printf('%.*s', s.len, s.str) | 		C.printf('%.*s', s.len, s.str) | ||||||
| 	} | 	} | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
| __global total_m i64 = 0 | __global total_m i64 = 0 | ||||||
| pub fn malloc(n int) byteptr { | pub fn malloc(n int) byteptr { | ||||||
|  |  | ||||||
|  | @ -91,3 +91,43 @@ 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 '' | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
|  | @ -4,6 +4,7 @@ | ||||||
| 
 | 
 | ||||||
| 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.
 | ||||||
|  |  | ||||||
							
								
								
									
										148
									
								
								vlib/os/os.v
								
								
								
								
							
							
						
						
									
										148
									
								
								vlib/os/os.v
								
								
								
								
							|  | @ -35,7 +35,8 @@ import const ( | ||||||
| 	INVALID_FILE_ATTRIBUTES | 	INVALID_FILE_ATTRIBUTES | ||||||
| ) | ) | ||||||
| 
 | 
 | ||||||
| struct FILE { | struct C.FILE { | ||||||
|  | 	 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| struct File { | struct File { | ||||||
|  | @ -105,9 +106,14 @@ 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 {  | ||||||
| 	mut mode := 'rb'  | 	mode := 'rb' | ||||||
|  | 	mut fp := &C.FILE{} | ||||||
|  | 	$if windows { | ||||||
|  | 		fp = C._wfopen(path.to_wide(), mode.to_wide()) | ||||||
|  | 	} $else { | ||||||
| 		cpath := path.cstr() | 		cpath := path.cstr() | ||||||
| 	fp := C.fopen(cpath, mode.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"') | ||||||
| 	} | 	} | ||||||
|  | @ -124,22 +130,36 @@ 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 { | ||||||
| 	s := C.stat{} | 	mut s := C.stat{} | ||||||
|  | 	$if windows { | ||||||
|  | 		C._wstat(path.to_wide(), &s) | ||||||
|  | 	} $else { | ||||||
| 		C.stat(path.str, &s) | 		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._wrename(old.to_wide(), new.to_wide()) | ||||||
|  | 	} $else { | ||||||
| 		C.rename(old.cstr(), new.cstr()) | 		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.
 | ||||||
| // TODO return `?[]string` TODO implement `?[]` support
 | // TODO return `?[]string` TODO implement `?[]` support
 | ||||||
| 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' | ||||||
|  | 	mut fp := &C.FILE{} | ||||||
|  | 	$if windows { | ||||||
|  | 		fp = C._wfopen(path.to_wide(), mode.to_wide()) | ||||||
|  | 	} $else { | ||||||
| 		cpath := path.cstr() | 		cpath := path.cstr() | ||||||
| 	fp := C.fopen(cpath, 'rb') | 		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"')
 | ||||||
|  | @ -171,10 +191,19 @@ fn read_ulines(path string) []ustring { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn open(path string) ?File { | pub fn open(path string) ?File { | ||||||
|  | 	mut file := File{} | ||||||
|  | 	$if windows { | ||||||
|  | 		wpath := path.to_wide() | ||||||
|  | 		mode := 'rb' | ||||||
|  | 		file = File {			 | ||||||
|  | 			cfile: C._wfopen(wpath, mode.to_wide()) | ||||||
|  | 		} | ||||||
|  | 	} $else { | ||||||
| 		cpath := path.cstr()  | 		cpath := path.cstr()  | ||||||
| 	file := File { | 		file = File { | ||||||
| 			cfile: C.fopen(cpath, 'rb')  | 			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"') | ||||||
| 	} | 	} | ||||||
|  | @ -183,10 +212,19 @@ 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{} | ||||||
|  | 	$if windows { | ||||||
|  | 		wpath := path.replace('/', '\\').to_wide() | ||||||
|  | 		mode := 'wb' | ||||||
|  | 		file = File {			 | ||||||
|  | 			cfile: C._wfopen(wpath, mode.to_wide()) | ||||||
|  | 		} | ||||||
|  | 	} $else { | ||||||
| 		cpath := path.cstr()  | 		cpath := path.cstr()  | ||||||
| 	file := File { | 		file = File { | ||||||
| 			cfile: C.fopen(cpath, 'wb')  | 			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"') | ||||||
| 	} | 	} | ||||||
|  | @ -194,12 +232,21 @@ pub fn create(path string) ?File { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn open_append(path string) ?File { | pub fn open_append(path string) ?File { | ||||||
|  | 	mut file := File{} | ||||||
|  | 	$if windows { | ||||||
|  | 		wpath := path.replace('/', '\\').to_wide() | ||||||
|  | 		mode := 'ab' | ||||||
|  | 		file = File {			 | ||||||
|  | 			cfile: C._wfopen(wpath, mode.to_wide()) | ||||||
|  | 		} | ||||||
|  | 	} $else { | ||||||
| 		cpath := path.cstr()  | 		cpath := path.cstr()  | ||||||
| 	file := File { | 		file = File { | ||||||
| 			cfile: C.fopen(cpath, 'ab')  | 			cfile: C.fopen(cpath, 'ab')  | ||||||
| 		} | 		} | ||||||
|  | 	} | ||||||
| 	if isnil(file.cfile) { | 	if isnil(file.cfile) { | ||||||
| 		return error('failed to create file "$path"') | 		return error('failed to create(append) file "$path"') | ||||||
| 	} | 	} | ||||||
| 	return file  | 	return file  | ||||||
| } | } | ||||||
|  | @ -243,7 +290,12 @@ 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 { | ||||||
| 	ret := C.system(cmd.cstr())  | 	mut ret := int(0) | ||||||
|  | 	$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() | ||||||
| 	} | 	} | ||||||
|  | @ -251,11 +303,13 @@ pub fn system(cmd string) int { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| fn popen(path string) *FILE { | fn popen(path string) *FILE { | ||||||
| 	cpath := path.cstr() |  | ||||||
| 	$if windows { | 	$if windows { | ||||||
| 		return C._popen(cpath, 'r') | 		mode := string('rb') | ||||||
|  | 		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') | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
|  | @ -279,12 +333,20 @@ 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._wgetenv(key.to_wide()) | ||||||
|  | 		if isnil(s) { | ||||||
|  | 			return '' | ||||||
|  | 		} | ||||||
|  | 		return string_from_wide(s) | ||||||
|  | 	} $else { | ||||||
| 		s := C.getenv(key.cstr())		 | 		s := C.getenv(key.cstr())		 | ||||||
| 		if isnil(s) { | 		if isnil(s) { | ||||||
| 			return '' | 			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 { | ||||||
| 	$if windows { | 	$if windows { | ||||||
|  | @ -315,14 +377,17 @@ 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 { | ||||||
| 		return C._access( path.str, 0 ) != -1 | 		path = path.replace('/', '\\') | ||||||
| 	} | 		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 { | ||||||
| 		attr := int(C.GetFileAttributes(path.cstr()))  | 		path = path.replace('/', '\\') | ||||||
|  | 		attr := int(C.GetFileAttributes(path.to_wide())) | ||||||
| 		if attr == INVALID_FILE_ATTRIBUTES { | 		if attr == INVALID_FILE_ATTRIBUTES { | ||||||
| 			return false | 			return false | ||||||
| 		} | 		} | ||||||
|  | @ -345,7 +410,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.CreateDirectory(path.cstr(), 0) | 		C._wmkdir(path.to_wide()) | ||||||
| 	} | 	} | ||||||
| 	$else { | 	$else { | ||||||
| 		C.mkdir(path.cstr(), 511)// S_IRWXU | S_IRWXG | S_IRWXO
 | 		C.mkdir(path.cstr(), 511)// S_IRWXU | S_IRWXG | S_IRWXO
 | ||||||
|  | @ -354,7 +419,12 @@ 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._wremove(path.to_wide()) | ||||||
|  | 	} | ||||||
|  | 	$else { | ||||||
| 		C.remove(path.cstr()) | 		C.remove(path.cstr()) | ||||||
|  | 	} | ||||||
| 	// C.unlink(path.cstr())
 | 	// C.unlink(path.cstr())
 | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -365,7 +435,7 @@ pub fn rmdir(path string) { | ||||||
| 		C.rmdir(path.cstr())		 | 		C.rmdir(path.cstr())		 | ||||||
| 	} | 	} | ||||||
| 	$else { | 	$else { | ||||||
| 		C.RemoveDirectoryA(path.cstr()) | 		C.RemoveDirectoryW(path.to_wide()) | ||||||
| 	} | 	} | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -435,20 +505,18 @@ 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 := 256 | 		max := 512 // MAX_PATH * sizeof(wchar_t)
 | ||||||
| 		buf := malloc(max) | 		buf := &u16(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.') | ||||||
| 		} | 		} | ||||||
| 		nr_chars := 0 | 		mut 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 tos(buf, nr_chars) | 		return string_from_wide2(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
 | ||||||
|  | @ -536,8 +604,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') | ||||||
|  | @ -545,10 +613,12 @@ pub fn executable() string { | ||||||
| 		return string(result, count) | 		return string(result, count) | ||||||
| 	} | 	} | ||||||
| 	$if windows { | 	$if windows { | ||||||
| 		ret := int(C.GetModuleFileName( 0, result, MAX_PATH )) | 		mut result := &u16(malloc(512)) // MAX_PATH * sizeof(wchar_t)
 | ||||||
| 		return string( result, ret) | 		len := int(C.GetModuleFileName( 0, result, MAX_PATH )) | ||||||
|  | 		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  { | ||||||
|  | @ -558,6 +628,7 @@ 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)  | ||||||
|  | @ -569,6 +640,7 @@ 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') | ||||||
|  | @ -576,6 +648,7 @@ 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') | ||||||
|  | @ -587,9 +660,9 @@ pub fn executable() string { | ||||||
| 
 | 
 | ||||||
| pub fn is_dir(path string) bool { | pub fn is_dir(path string) bool { | ||||||
| 	$if windows { | 	$if windows { | ||||||
| 		val := int(C.GetFileAttributes(path.cstr())) | 		val := int(C.GetFileAttributes(path.to_wide())) | ||||||
| 		// Note: this return is broke (wrong). we have dir_exists already how will this differ?
 | 		// Note: this return is broke (wrong). we have dir_exists already how will this differ?
 | ||||||
| 		return val &FILE_ATTRIBUTE_DIRECTORY > 0 | 		return (val &FILE_ATTRIBUTE_DIRECTORY) > 0 | ||||||
| 	}  | 	}  | ||||||
| 	$else {  | 	$else {  | ||||||
| 		statbuf := C.stat{} | 		statbuf := C.stat{} | ||||||
|  | @ -603,7 +676,7 @@ pub fn is_dir(path string) bool { | ||||||
| 
 | 
 | ||||||
| pub fn chdir(path string) { | pub fn chdir(path string) { | ||||||
| 	$if windows { | 	$if windows { | ||||||
| 		C._chdir(path.cstr()) | 		C._wchdir(path.to_wide()) | ||||||
| 	} | 	} | ||||||
| 	$else {  | 	$else {  | ||||||
| 		C.chdir(path.cstr()) | 		C.chdir(path.cstr()) | ||||||
|  | @ -611,19 +684,22 @@ pub fn chdir(path string) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn getwd() string {	 | pub fn getwd() string {	 | ||||||
| 	buf := malloc(512) |  | ||||||
| 	$if windows { | 	$if windows { | ||||||
| 		if C._getcwd(buf, 512) == 0 { | 		max := 512 // MAX_PATH * sizeof(wchar_t)
 | ||||||
|  | 		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
 | ||||||
| // https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
 | // https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-filetime
 | ||||||
|  | @ -633,7 +709,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_dataa
 | // https://docs.microsoft.com/en-us/windows/win32/api/minwinbase/ns-minwinbase-_win32_find_dataw
 | ||||||
| struct win32finddata { | struct win32finddata { | ||||||
| mut: | mut: | ||||||
|     dwFileAttributes u32 |     dwFileAttributes u32 | ||||||
|  | @ -670,13 +746,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.cstr(), &find_file_data) | 		h_find_files := C.FindFirstFile(path_files.to_wide(), &find_file_data) | ||||||
| 		first_filename := tos(&find_file_data.cFileName, strlen(find_file_data.cFileName)) | 		first_filename := string_from_wide(&u16(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 := tos(&find_file_data.cFileName, strlen(find_file_data.cFileName)) | 			filename := string_from_wide(&u16(find_file_data.cFileName)) | ||||||
| 			if filename != '.' && filename != '..' { | 			if filename != '.' && filename != '..' { | ||||||
| 				dir_files << filename.clone() | 				dir_files << filename.clone() | ||||||
| 			} | 			} | ||||||
|  |  | ||||||
|  | @ -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.fopen(path.cstr(), mode.cstr()) |     _fd := C._wfopen(path.to_wide(), mode.cstr()) | ||||||
|     if _fd == 0 { |     if _fd == 0 { | ||||||
| 	    return HANDLE(INVALID_HANDLE_VALUE) | 	    return HANDLE(INVALID_HANDLE_VALUE) | ||||||
|     } |     } | ||||||
|  | @ -27,17 +27,14 @@ 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(1024) // Optimized length 
 |     mut sz := int(4096) // Optimized length 
 | ||||||
|     mut buf := [byte(0); sz] // Not work for GetModuleFileNameW :(
 |     mut buf := &u16(malloc(4096)) | ||||||
|     for { |     for { | ||||||
|         status := C.GetModuleFileName(handle, &buf, sz) |         status := C.GetModuleFileName(handle, &buf, sz) | ||||||
|         switch status { |         switch status { | ||||||
|         case SUCCESS: |         case SUCCESS: | ||||||
|             _filename := tos(buf.data, sz) |             _filename := string_from_wide2(buf, 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.') | ||||||
|  |  | ||||||
		Loading…
	
		Reference in New Issue