os_windows.odin 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314
  1. import win32 "core:sys/windows.odin"
  2. import "core:mem.odin"
  3. Handle :: distinct uintptr;
  4. File_Time :: distinct u64;
  5. Errno :: distinct int;
  6. INVALID_HANDLE :: ~Handle(0);
  7. O_RDONLY :: 0x00000;
  8. O_WRONLY :: 0x00001;
  9. O_RDWR :: 0x00002;
  10. O_CREATE :: 0x00040;
  11. O_EXCL :: 0x00080;
  12. O_NOCTTY :: 0x00100;
  13. O_TRUNC :: 0x00200;
  14. O_NONBLOCK :: 0x00800;
  15. O_APPEND :: 0x00400;
  16. O_SYNC :: 0x01000;
  17. O_ASYNC :: 0x02000;
  18. O_CLOEXEC :: 0x80000;
  19. ERROR_NONE: Errno : 0;
  20. ERROR_FILE_NOT_FOUND: Errno : 2;
  21. ERROR_PATH_NOT_FOUND: Errno : 3;
  22. ERROR_ACCESS_DENIED: Errno : 5;
  23. ERROR_NO_MORE_FILES: Errno : 18;
  24. ERROR_HANDLE_EOF: Errno : 38;
  25. ERROR_NETNAME_DELETED: Errno : 64;
  26. ERROR_FILE_EXISTS: Errno : 80;
  27. ERROR_BROKEN_PIPE: Errno : 109;
  28. ERROR_BUFFER_OVERFLOW: Errno : 111;
  29. ERROR_INSUFFICIENT_BUFFER: Errno : 122;
  30. ERROR_MOD_NOT_FOUND: Errno : 126;
  31. ERROR_PROC_NOT_FOUND: Errno : 127;
  32. ERROR_DIR_NOT_EMPTY: Errno : 145;
  33. ERROR_ALREADY_EXISTS: Errno : 183;
  34. ERROR_ENVVAR_NOT_FOUND: Errno : 203;
  35. ERROR_MORE_DATA: Errno : 234;
  36. ERROR_OPERATION_ABORTED: Errno : 995;
  37. ERROR_IO_PENDING: Errno : 997;
  38. ERROR_NOT_FOUND: Errno : 1168;
  39. ERROR_PRIVILEGE_NOT_HELD: Errno : 1314;
  40. WSAEACCES: Errno : 10013;
  41. WSAECONNRESET: Errno : 10054;
  42. // Windows reserves errors >= 1<<29 for application use
  43. ERROR_FILE_IS_PIPE: Errno : 1<<29 + 0;
  44. // "Argv" arguments converted to Odin strings
  45. args := _alloc_command_line_arguments();
  46. open :: proc(path: string, mode: int = O_RDONLY, perm: u32 = 0) -> (Handle, Errno) {
  47. if len(path) == 0 do return INVALID_HANDLE, ERROR_FILE_NOT_FOUND;
  48. access: u32;
  49. switch mode & (O_RDONLY|O_WRONLY|O_RDWR) {
  50. case O_RDONLY: access = win32.FILE_GENERIC_READ;
  51. case O_WRONLY: access = win32.FILE_GENERIC_WRITE;
  52. case O_RDWR: access = win32.FILE_GENERIC_READ | win32.FILE_GENERIC_WRITE;
  53. }
  54. if mode&O_CREATE != 0 {
  55. access |= win32.FILE_GENERIC_WRITE;
  56. }
  57. if mode&O_APPEND != 0 {
  58. access &~= win32.FILE_GENERIC_WRITE;
  59. access |= win32.FILE_APPEND_DATA;
  60. }
  61. share_mode := u32(win32.FILE_SHARE_READ|win32.FILE_SHARE_WRITE);
  62. sa: ^win32.Security_Attributes = nil;
  63. sa_inherit := win32.Security_Attributes{length = size_of(win32.Security_Attributes), inherit_handle = true};
  64. if mode&O_CLOEXEC == 0 {
  65. sa = &sa_inherit;
  66. }
  67. create_mode: u32;
  68. switch {
  69. case mode&(O_CREATE|O_EXCL) == (O_CREATE | O_EXCL):
  70. create_mode = win32.CREATE_NEW;
  71. case mode&(O_CREATE|O_TRUNC) == (O_CREATE | O_TRUNC):
  72. create_mode = win32.CREATE_ALWAYS;
  73. case mode&O_CREATE == O_CREATE:
  74. create_mode = win32.OPEN_ALWAYS;
  75. case mode&O_TRUNC == O_TRUNC:
  76. create_mode = win32.TRUNCATE_EXISTING;
  77. case:
  78. create_mode = win32.OPEN_EXISTING;
  79. }
  80. buf: [300]byte;
  81. copy(buf[..], cast([]byte)path);
  82. handle := Handle(win32.create_file_a(&buf[0], access, share_mode, sa, create_mode, win32.FILE_ATTRIBUTE_NORMAL, nil));
  83. if handle != INVALID_HANDLE do return handle, ERROR_NONE;
  84. err := Errno(win32.get_last_error());
  85. return INVALID_HANDLE, err;
  86. }
  87. close :: proc(fd: Handle) {
  88. win32.close_handle(win32.Handle(fd));
  89. }
  90. write :: proc(fd: Handle, data: []byte) -> (int, Errno) {
  91. if len(data) == 0 do return 0, ERROR_NONE;
  92. single_write_length: i32;
  93. total_write: i64;
  94. length := i64(len(data));
  95. for total_write < length {
  96. remaining := length - total_write;
  97. MAX :: 1<<31-1;
  98. to_write: i32 = min(i32(remaining), MAX);
  99. e := win32.write_file(win32.Handle(fd), &data[total_write], to_write, &single_write_length, nil);
  100. if single_write_length <= 0 || !e {
  101. err := Errno(win32.get_last_error());
  102. return int(total_write), err;
  103. }
  104. total_write += i64(single_write_length);
  105. }
  106. return int(total_write), ERROR_NONE;
  107. }
  108. read :: proc(fd: Handle, data: []byte) -> (int, Errno) {
  109. if len(data) == 0 do return 0, ERROR_NONE;
  110. single_read_length: i32;
  111. total_read: i64;
  112. length := i64(len(data));
  113. for total_read < length {
  114. remaining := length - total_read;
  115. MAX :: 1<<32-1;
  116. to_read: u32 = min(u32(remaining), MAX);
  117. e := win32.read_file(win32.Handle(fd), &data[total_read], to_read, &single_read_length, nil);
  118. if single_read_length <= 0 || !e {
  119. err := Errno(win32.get_last_error());
  120. return int(total_read), err;
  121. }
  122. total_read += i64(single_read_length);
  123. }
  124. return int(total_read), ERROR_NONE;
  125. }
  126. seek :: proc(fd: Handle, offset: i64, whence: int) -> (i64, Errno) {
  127. w: u32;
  128. switch whence {
  129. case 0: w = win32.FILE_BEGIN;
  130. case 1: w = win32.FILE_CURRENT;
  131. case 2: w = win32.FILE_END;
  132. }
  133. hi := i32(offset>>32);
  134. lo := i32(offset);
  135. ft := win32.get_file_type(win32.Handle(fd));
  136. if ft == win32.FILE_TYPE_PIPE do return 0, ERROR_FILE_IS_PIPE;
  137. dw_ptr := win32.set_file_pointer(win32.Handle(fd), lo, &hi, w);
  138. if dw_ptr == win32.INVALID_SET_FILE_POINTER {
  139. err := Errno(win32.get_last_error());
  140. return 0, err;
  141. }
  142. return i64(hi)<<32 + i64(dw_ptr), ERROR_NONE;
  143. }
  144. file_size :: proc(fd: Handle) -> (i64, Errno) {
  145. length: i64;
  146. err: Errno;
  147. if !win32.get_file_size_ex(win32.Handle(fd), &length) {
  148. err = Errno(win32.get_last_error());
  149. }
  150. return length, err;
  151. }
  152. // NOTE(bill): Uses startup to initialize it
  153. stdin := get_std_handle(win32.STD_INPUT_HANDLE);
  154. stdout := get_std_handle(win32.STD_OUTPUT_HANDLE);
  155. stderr := get_std_handle(win32.STD_ERROR_HANDLE);
  156. get_std_handle :: proc(h: int) -> Handle {
  157. fd := win32.get_std_handle(i32(h));
  158. win32.set_handle_information(fd, win32.HANDLE_FLAG_INHERIT, 0);
  159. return Handle(fd);
  160. }
  161. last_write_time :: proc(fd: Handle) -> File_Time {
  162. file_info: win32.By_Handle_File_Information;
  163. win32.get_file_information_by_handle(win32.Handle(fd), &file_info);
  164. lo := File_Time(file_info.last_write_time.lo);
  165. hi := File_Time(file_info.last_write_time.hi);
  166. return lo | hi << 32;
  167. }
  168. last_write_time_by_name :: proc(name: string) -> File_Time {
  169. last_write_time: win32.Filetime;
  170. data: win32.File_Attribute_Data;
  171. buf: [1024]byte;
  172. assert(len(buf) > len(name));
  173. copy(buf[..], cast([]byte)name);
  174. if win32.get_file_attributes_ex_a(&buf[0], win32.GetFileExInfoStandard, &data) {
  175. last_write_time = data.last_write_time;
  176. }
  177. l := File_Time(last_write_time.lo);
  178. h := File_Time(last_write_time.hi);
  179. return l | h << 32;
  180. }
  181. heap_alloc :: proc(size: int) -> rawptr {
  182. return win32.heap_alloc(win32.get_process_heap(), win32.HEAP_ZERO_MEMORY, size);
  183. }
  184. heap_resize :: proc(ptr: rawptr, new_size: int) -> rawptr {
  185. if new_size == 0 {
  186. heap_free(ptr);
  187. return nil;
  188. }
  189. if ptr == nil do return heap_alloc(new_size);
  190. return win32.heap_realloc(win32.get_process_heap(), win32.HEAP_ZERO_MEMORY, ptr, new_size);
  191. }
  192. heap_free :: proc(ptr: rawptr) {
  193. if ptr == nil do return;
  194. win32.heap_free(win32.get_process_heap(), 0, ptr);
  195. }
  196. exit :: proc(code: int) {
  197. win32.exit_process(u32(code));
  198. }
  199. current_thread_id :: proc() -> int {
  200. return int(win32.get_current_thread_id());
  201. }
  202. _alloc_command_line_arguments :: proc() -> []string {
  203. alloc_ucs2_to_utf8 :: proc(wstr: ^u16) -> string {
  204. wstr_len := 0;
  205. for (wstr+wstr_len)^ != 0 do wstr_len += 1;
  206. len := 2*wstr_len-1;
  207. buf := make([]byte, len+1);
  208. str := mem.slice_ptr(wstr, wstr_len+1);
  209. i, j := 0, 0;
  210. for str[j] != 0 {
  211. switch {
  212. case str[j] < 0x80:
  213. if i+1 > len do return "";
  214. buf[i] = byte(str[j]); i += 1;
  215. j += 1;
  216. case str[j] < 0x800:
  217. if i+2 > len do return "";
  218. buf[i] = byte(0xc0 + (str[j]>>6)); i += 1;
  219. buf[i] = byte(0x80 + (str[j]&0x3f)); i += 1;
  220. j += 1;
  221. case 0xd800 <= str[j] && str[j] < 0xdc00:
  222. if i+4 > len do return "";
  223. c := rune((str[j] - 0xd800) << 10) + rune((str[j+1]) - 0xdc00) + 0x10000;
  224. buf[i] = byte(0xf0 + (c >> 18)); i += 1;
  225. buf[i] = byte(0x80 + ((c >> 12) & 0x3f)); i += 1;
  226. buf[i] = byte(0x80 + ((c >> 6) & 0x3f)); i += 1;
  227. buf[i] = byte(0x80 + ((c ) & 0x3f)); i += 1;
  228. j += 2;
  229. case 0xdc00 <= str[j] && str[j] < 0xe000:
  230. return "";
  231. case:
  232. if i+3 > len do return "";
  233. buf[i] = 0xe0 + byte (str[j] >> 12); i += 1;
  234. buf[i] = 0x80 + byte((str[j] >> 6) & 0x3f); i += 1;
  235. buf[i] = 0x80 + byte((str[j] ) & 0x3f); i += 1;
  236. j += 1;
  237. }
  238. }
  239. return string(buf[..i]);
  240. }
  241. arg_count: i32;
  242. arg_list_ptr := win32.command_line_to_argv_w(win32.get_command_line_w(), &arg_count);
  243. arg_list := make([]string, int(arg_count));
  244. for _, i in arg_list do arg_list[i] = alloc_ucs2_to_utf8((arg_list_ptr+i)^);
  245. return arg_list;
  246. }