file_util.odin 3.6 KB

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