file_util.odin 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179
  1. package os2
  2. import "base:runtime"
  3. import "core:strconv"
  4. import "core:unicode/utf8"
  5. write_string :: proc(f: ^File, s: string) -> (n: int, err: Error) {
  6. return write(f, transmute([]byte)s)
  7. }
  8. write_strings :: proc(f: ^File, strings: ..string) -> (n: int, err: Error) {
  9. for s in strings {
  10. m: int
  11. m, err = write_string(f, s)
  12. n += m
  13. if err != nil {
  14. return
  15. }
  16. }
  17. return
  18. }
  19. write_byte :: proc(f: ^File, b: byte) -> (n: int, err: Error) {
  20. return write(f, []byte{b})
  21. }
  22. write_rune :: proc(f: ^File, r: rune) -> (n: int, err: Error) {
  23. if r < utf8.RUNE_SELF {
  24. return write_byte(f, byte(r))
  25. }
  26. b: [4]byte
  27. b, n = utf8.encode_rune(r)
  28. return write(f, b[:n])
  29. }
  30. write_encoded_rune :: proc(f: ^File, r: rune) -> (n: int, err: Error) {
  31. wrap :: proc(m: int, merr: Error, n: ^int, err: ^Error) -> bool {
  32. n^ += m
  33. if merr != nil {
  34. err^ = merr
  35. return true
  36. }
  37. return false
  38. }
  39. if wrap(write_byte(f, '\''), &n, &err) { return }
  40. switch r {
  41. case '\a': if wrap(write_string(f, "\\a"), &n, &err) { return }
  42. case '\b': if wrap(write_string(f, "\\b"), &n, &err) { return }
  43. case '\e': if wrap(write_string(f, "\\e"), &n, &err) { return }
  44. case '\f': if wrap(write_string(f, "\\f"), &n, &err) { return }
  45. case '\n': if wrap(write_string(f, "\\n"), &n, &err) { return }
  46. case '\r': if wrap(write_string(f, "\\r"), &n, &err) { return }
  47. case '\t': if wrap(write_string(f, "\\t"), &n, &err) { return }
  48. case '\v': if wrap(write_string(f, "\\v"), &n, &err) { return }
  49. case:
  50. if r < 32 {
  51. if wrap(write_string(f, "\\x"), &n, &err) { return }
  52. b: [2]byte
  53. s := strconv.append_bits(b[:], u64(r), 16, true, 64, strconv.digits, nil)
  54. switch len(s) {
  55. case 0: if wrap(write_string(f, "00"), &n, &err) { return }
  56. case 1: if wrap(write_rune(f, '0'), &n, &err) { return }
  57. case 2: if wrap(write_string(f, s), &n, &err) { return }
  58. }
  59. } else {
  60. if wrap(write_rune(f, r), &n, &err) { return }
  61. }
  62. }
  63. _ = wrap(write_byte(f, '\''), &n, &err)
  64. return
  65. }
  66. read_at_least :: proc(f: ^File, buf: []byte, min: int) -> (n: int, err: Error) {
  67. if len(buf) < min {
  68. return 0, .Short_Buffer
  69. }
  70. nn := max(int)
  71. for nn > 0 && n < min && err == nil {
  72. nn, err = read(f, buf[n:])
  73. n += nn
  74. }
  75. if n >= min {
  76. err = nil
  77. }
  78. return
  79. }
  80. read_full :: proc(f: ^File, buf: []byte) -> (n: int, err: Error) {
  81. return read_at_least(f, buf, len(buf))
  82. }
  83. write_ptr :: proc(f: ^File, data: rawptr, len: int) -> (n: int, err: Error) {
  84. return write(f, ([^]byte)(data)[:len])
  85. }
  86. read_ptr :: proc(f: ^File, data: rawptr, len: int) -> (n: int, err: Error) {
  87. return read(f, ([^]byte)(data)[:len])
  88. }
  89. read_entire_file :: proc{
  90. read_entire_file_from_path,
  91. read_entire_file_from_file,
  92. }
  93. @(require_results)
  94. read_entire_file_from_path :: proc(name: string, allocator: runtime.Allocator) -> (data: []byte, err: Error) {
  95. f, ferr := open(name)
  96. if ferr != nil {
  97. return nil, ferr
  98. }
  99. defer close(f)
  100. return read_entire_file_from_file(f, allocator)
  101. }
  102. @(require_results)
  103. read_entire_file_from_file :: proc(f: ^File, allocator: runtime.Allocator) -> (data: []byte, err: Error) {
  104. size: int
  105. has_size := false
  106. if size64, serr := file_size(f); serr == nil {
  107. if i64(int(size64)) == size64 {
  108. has_size = true
  109. size = int(size64)
  110. }
  111. }
  112. if has_size && size > 0 {
  113. total: int
  114. data = make([]byte, size, allocator) or_return
  115. for total < len(data) {
  116. n: int
  117. n, err = read(f, data[total:])
  118. total += n
  119. if err != nil {
  120. if err == .EOF {
  121. err = nil
  122. }
  123. data = data[:total]
  124. break
  125. }
  126. }
  127. return
  128. } else {
  129. buffer: [1024]u8
  130. out_buffer := make([dynamic]u8, 0, 0, allocator)
  131. total := 0
  132. for {
  133. n: int
  134. n, err = read(f, buffer[:])
  135. total += n
  136. append_elems(&out_buffer, ..buffer[:n])
  137. if err != nil {
  138. if err == .EOF || err == .Broken_Pipe {
  139. err = nil
  140. }
  141. data = out_buffer[:total]
  142. return
  143. }
  144. }
  145. }
  146. }
  147. @(require_results)
  148. write_entire_file :: proc(name: string, data: []byte, perm: int, truncate := true) -> Error {
  149. flags := O_WRONLY|O_CREATE
  150. if truncate {
  151. flags |= O_TRUNC
  152. }
  153. f := open(name, flags, perm) or_return
  154. _, err := write(f, data)
  155. if cerr := close(f); cerr != nil && err == nil {
  156. err = cerr
  157. }
  158. return err
  159. }