os.odin 5.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221
  1. package os
  2. import "core:mem"
  3. import "core:strconv"
  4. import "core:unicode/utf8"
  5. write_string :: proc(fd: Handle, str: string) -> (int, Errno) {
  6. return write(fd, transmute([]byte)str);
  7. }
  8. write_byte :: proc(fd: Handle, b: byte) -> (int, Errno) {
  9. return write(fd, []byte{b});
  10. }
  11. write_rune :: proc(fd: Handle, r: rune) -> (int, Errno) {
  12. if r < utf8.RUNE_SELF {
  13. return write_byte(fd, byte(r));
  14. }
  15. b, n := utf8.encode_rune(r);
  16. return write(fd, b[:n]);
  17. }
  18. write_encoded_rune :: proc(fd: Handle, r: rune) {
  19. write_byte(fd, '\'');
  20. switch r {
  21. case '\a': write_string(fd, "\\a");
  22. case '\b': write_string(fd, "\\b");
  23. case '\e': write_string(fd, "\\e");
  24. case '\f': write_string(fd, "\\f");
  25. case '\n': write_string(fd, "\\n");
  26. case '\r': write_string(fd, "\\r");
  27. case '\t': write_string(fd, "\\t");
  28. case '\v': write_string(fd, "\\v");
  29. case:
  30. if r < 32 {
  31. write_string(fd, "\\x");
  32. b: [2]byte;
  33. s := strconv.append_bits(b[:], u64(r), 16, true, 64, strconv.digits, nil);
  34. switch len(s) {
  35. case 0: write_string(fd, "00");
  36. case 1: write_rune(fd, '0');
  37. case 2: write_string(fd, s);
  38. }
  39. } else {
  40. write_rune(fd, r);
  41. }
  42. }
  43. write_byte(fd, '\'');
  44. }
  45. file_size_from_path :: proc(path: string) -> i64 {
  46. fd, err := open(path, O_RDONLY, 0);
  47. if err != 0 {
  48. return -1;
  49. }
  50. defer close(fd);
  51. length: i64;
  52. if length, err = file_size(fd); err != 0 {
  53. return -1;
  54. }
  55. return length;
  56. }
  57. read_entire_file :: proc(name: string) -> (data: []byte, success: bool) {
  58. fd, err := open(name, O_RDONLY, 0);
  59. if err != 0 {
  60. return nil, false;
  61. }
  62. defer close(fd);
  63. length: i64;
  64. if length, err = file_size(fd); err != 0 {
  65. return nil, false;
  66. }
  67. if length <= 0 {
  68. return nil, true;
  69. }
  70. data = make([]byte, int(length));
  71. if data == nil {
  72. return nil, false;
  73. }
  74. bytes_read, read_err := read(fd, data);
  75. if read_err != 0 {
  76. delete(data);
  77. return nil, false;
  78. }
  79. return data[0:bytes_read], true;
  80. }
  81. write_entire_file :: proc(name: string, data: []byte, truncate := true) -> (success: bool) {
  82. flags: int = O_WRONLY|O_CREATE;
  83. if truncate {
  84. flags |= O_TRUNC;
  85. }
  86. mode: int = 0;
  87. when OS == "linux" {
  88. // NOTE(justasd): 644 (owner read, write; group read; others read)
  89. mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
  90. }
  91. fd, err := open(name, flags, mode);
  92. if err != 0 {
  93. return false;
  94. }
  95. defer close(fd);
  96. _, write_err := write(fd, data);
  97. return write_err == 0;
  98. }
  99. write_ptr :: proc(fd: Handle, data: rawptr, len: int) -> (int, Errno) {
  100. s := transmute([]byte)mem.Raw_Slice{data, len};
  101. return write(fd, s);
  102. }
  103. read_ptr :: proc(fd: Handle, data: rawptr, len: int) -> (int, Errno) {
  104. s := transmute([]byte)mem.Raw_Slice{data, len};
  105. return read(fd, s);
  106. }
  107. heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
  108. size, alignment: int,
  109. old_memory: rawptr, old_size: int, flags: u64 = 0, loc := #caller_location) -> rawptr {
  110. /*
  111. //
  112. // NOTE(tetra, 2019-11-10): The heap doesn't respect alignment.
  113. // HACK: Overallocate, align forwards, and then use the two bytes immediately before
  114. // the address we return, to store the padding we inserted.
  115. // This allows us to pass the original pointer we got back from the heap to `free` later.
  116. //
  117. align_and_store_padding :: proc(ptr: rawptr, alignment: int) -> rawptr {
  118. ptr := mem.ptr_offset(cast(^u8) ptr, 2);
  119. new_ptr := cast(^u8) mem.align_forward(ptr, uintptr(alignment));
  120. offset := mem.ptr_sub(new_ptr, cast(^u8) ptr) + 2;
  121. assert(offset < int(max(u16)));
  122. (^[2]u8)(mem.ptr_offset(new_ptr, -2))^ = transmute([2]u8) u16(offset);
  123. return new_ptr;
  124. }
  125. recover_original_pointer :: proc(ptr: rawptr) -> rawptr {
  126. ptr := cast(^u8) ptr;
  127. offset := transmute(u16) (^[2]u8)(mem.ptr_offset(ptr, -2))^;
  128. ptr = mem.ptr_offset(ptr, -int(offset));
  129. return ptr;
  130. }
  131. aligned_heap_alloc :: proc(size: int, alignment: int) -> rawptr {
  132. // NOTE(tetra): Alignment 1 will mean we only have one extra byte.
  133. // This is not enough for a u16 - so we ensure there is at least two bytes extra.
  134. // This also means that the pointer is always aligned to at least 2.
  135. extra := alignment;
  136. if extra <= 1 do extra = 2;
  137. orig := cast(^u8) heap_alloc(size + extra);
  138. if orig == nil do return nil;
  139. ptr := align_and_store_padding(orig, alignment);
  140. assert(recover_original_pointer(ptr) == orig);
  141. return ptr;
  142. }
  143. switch mode {
  144. case .Alloc:
  145. return aligned_heap_alloc(size, alignment);
  146. case .Free:
  147. if old_memory != nil {
  148. ptr := recover_original_pointer(old_memory);
  149. heap_free(ptr);
  150. }
  151. return nil;
  152. case .Free_All:
  153. // NOTE(bill): Does nothing
  154. case .Resize:
  155. if old_memory == nil {
  156. return aligned_heap_alloc(size, alignment);
  157. }
  158. ptr := recover_original_pointer(old_memory);
  159. ptr = heap_resize(ptr, size);
  160. assert(ptr != nil);
  161. return align_and_store_padding(ptr, alignment);
  162. }
  163. return nil;
  164. */
  165. switch mode {
  166. case .Alloc:
  167. return heap_alloc(size);
  168. case .Free:
  169. if old_memory != nil {
  170. heap_free(old_memory);
  171. }
  172. return nil;
  173. case .Free_All:
  174. // NOTE(bill): Does nothing
  175. case .Resize:
  176. return heap_resize(old_memory, size);
  177. }
  178. return nil;
  179. }
  180. heap_allocator :: proc() -> mem.Allocator {
  181. return mem.Allocator{
  182. procedure = heap_allocator_proc,
  183. data = nil,
  184. };
  185. }