os.odin 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232
  1. package os
  2. import "core:mem"
  3. import "core:strconv"
  4. import "core:unicode/utf8"
  5. OS :: ODIN_OS
  6. ARCH :: ODIN_ARCH
  7. ENDIAN :: ODIN_ENDIAN
  8. write_string :: proc(fd: Handle, str: string) -> (int, Errno) {
  9. return write(fd, transmute([]byte)str)
  10. }
  11. write_byte :: proc(fd: Handle, b: byte) -> (int, Errno) {
  12. return write(fd, []byte{b})
  13. }
  14. write_rune :: proc(fd: Handle, r: rune) -> (int, Errno) {
  15. if r < utf8.RUNE_SELF {
  16. return write_byte(fd, byte(r))
  17. }
  18. b, n := utf8.encode_rune(r)
  19. return write(fd, b[:n])
  20. }
  21. write_encoded_rune :: proc(fd: Handle, r: rune) {
  22. write_byte(fd, '\'')
  23. switch r {
  24. case '\a': write_string(fd, "\\a")
  25. case '\b': write_string(fd, "\\b")
  26. case '\e': write_string(fd, "\\e")
  27. case '\f': write_string(fd, "\\f")
  28. case '\n': write_string(fd, "\\n")
  29. case '\r': write_string(fd, "\\r")
  30. case '\t': write_string(fd, "\\t")
  31. case '\v': write_string(fd, "\\v")
  32. case:
  33. if r < 32 {
  34. write_string(fd, "\\x")
  35. b: [2]byte
  36. s := strconv.append_bits(b[:], u64(r), 16, true, 64, strconv.digits, nil)
  37. switch len(s) {
  38. case 0: write_string(fd, "00")
  39. case 1: write_rune(fd, '0')
  40. case 2: write_string(fd, s)
  41. }
  42. } else {
  43. write_rune(fd, r)
  44. }
  45. }
  46. write_byte(fd, '\'')
  47. }
  48. file_size_from_path :: proc(path: string) -> i64 {
  49. fd, err := open(path, O_RDONLY, 0)
  50. if err != 0 {
  51. return -1
  52. }
  53. defer close(fd)
  54. length: i64
  55. if length, err = file_size(fd); err != 0 {
  56. return -1
  57. }
  58. return length
  59. }
  60. read_entire_file_from_filename :: proc(name: string, allocator := context.allocator) -> (data: []byte, success: bool) {
  61. context.allocator = allocator
  62. fd, err := open(name, O_RDONLY, 0)
  63. if err != 0 {
  64. return nil, false
  65. }
  66. defer close(fd)
  67. return read_entire_file_from_handle(fd, allocator)
  68. }
  69. read_entire_file_from_handle :: proc(fd: Handle, allocator := context.allocator) -> (data: []byte, success: bool) {
  70. context.allocator = allocator
  71. length: i64
  72. err: Errno
  73. if length, err = file_size(fd); err != 0 {
  74. return nil, false
  75. }
  76. if length <= 0 {
  77. return nil, true
  78. }
  79. data = make([]byte, int(length), allocator)
  80. if data == nil {
  81. return nil, false
  82. }
  83. bytes_read, read_err := read(fd, data)
  84. if read_err != ERROR_NONE {
  85. delete(data)
  86. return nil, false
  87. }
  88. return data[:bytes_read], true
  89. }
  90. read_entire_file :: proc {
  91. read_entire_file_from_filename,
  92. read_entire_file_from_handle,
  93. }
  94. write_entire_file :: proc(name: string, data: []byte, truncate := true) -> (success: bool) {
  95. flags: int = O_WRONLY|O_CREATE
  96. if truncate {
  97. flags |= O_TRUNC
  98. }
  99. mode: int = 0
  100. when OS == "linux" || OS == "darwin" {
  101. // NOTE(justasd): 644 (owner read, write; group read; others read)
  102. mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH
  103. }
  104. fd, err := open(name, flags, mode)
  105. if err != 0 {
  106. return false
  107. }
  108. defer close(fd)
  109. _, write_err := write(fd, data)
  110. return write_err == 0
  111. }
  112. write_ptr :: proc(fd: Handle, data: rawptr, len: int) -> (int, Errno) {
  113. s := transmute([]byte)mem.Raw_Slice{data, len}
  114. return write(fd, s)
  115. }
  116. read_ptr :: proc(fd: Handle, data: rawptr, len: int) -> (int, Errno) {
  117. s := transmute([]byte)mem.Raw_Slice{data, len}
  118. return read(fd, s)
  119. }
  120. heap_allocator_proc :: proc(allocator_data: rawptr, mode: mem.Allocator_Mode,
  121. size, alignment: int,
  122. old_memory: rawptr, old_size: int, loc := #caller_location) -> ([]byte, mem.Allocator_Error) {
  123. //
  124. // NOTE(tetra, 2020-01-14): The heap doesn't respect alignment.
  125. // Instead, we overallocate by `alignment + size_of(rawptr) - 1`, and insert
  126. // padding. We also store the original pointer returned by heap_alloc right before
  127. // the pointer we return to the user.
  128. //
  129. aligned_alloc :: proc(size, alignment: int, old_ptr: rawptr = nil) -> ([]byte, mem.Allocator_Error) {
  130. a := max(alignment, align_of(rawptr))
  131. space := size + a - 1
  132. allocated_mem: rawptr
  133. if old_ptr != nil {
  134. original_old_ptr := mem.ptr_offset((^rawptr)(old_ptr), -1)^
  135. allocated_mem = heap_resize(original_old_ptr, space+size_of(rawptr))
  136. } else {
  137. allocated_mem = heap_alloc(space+size_of(rawptr))
  138. }
  139. aligned_mem := rawptr(mem.ptr_offset((^u8)(allocated_mem), size_of(rawptr)))
  140. ptr := uintptr(aligned_mem)
  141. aligned_ptr := (ptr - 1 + uintptr(a)) & -uintptr(a)
  142. diff := int(aligned_ptr - ptr)
  143. if (size + diff) > space {
  144. return nil, .Out_Of_Memory
  145. }
  146. aligned_mem = rawptr(aligned_ptr)
  147. mem.ptr_offset((^rawptr)(aligned_mem), -1)^ = allocated_mem
  148. return mem.byte_slice(aligned_mem, size), nil
  149. }
  150. aligned_free :: proc(p: rawptr) {
  151. if p != nil {
  152. heap_free(mem.ptr_offset((^rawptr)(p), -1)^)
  153. }
  154. }
  155. aligned_resize :: proc(p: rawptr, old_size: int, new_size: int, new_alignment: int) -> ([]byte, mem.Allocator_Error) {
  156. if p == nil {
  157. return nil, nil
  158. }
  159. return aligned_alloc(new_size, new_alignment, p)
  160. }
  161. switch mode {
  162. case .Alloc:
  163. return aligned_alloc(size, alignment)
  164. case .Free:
  165. aligned_free(old_memory)
  166. case .Free_All:
  167. return nil, .Mode_Not_Implemented
  168. case .Resize:
  169. if old_memory == nil {
  170. return aligned_alloc(size, alignment)
  171. }
  172. return aligned_resize(old_memory, old_size, size, alignment)
  173. case .Query_Features:
  174. set := (^mem.Allocator_Mode_Set)(old_memory)
  175. if set != nil {
  176. set^ = {.Alloc, .Free, .Resize, .Query_Features}
  177. }
  178. return nil, nil
  179. case .Query_Info:
  180. return nil, .Mode_Not_Implemented
  181. }
  182. return nil, nil
  183. }
  184. heap_allocator :: proc() -> mem.Allocator {
  185. return mem.Allocator{
  186. procedure = heap_allocator_proc,
  187. data = nil,
  188. }
  189. }