util.odin 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405
  1. package io
  2. import "core:strconv"
  3. import "core:unicode/utf8"
  4. read_ptr :: proc(r: Reader, p: rawptr, byte_size: int, n_read: ^int = nil) -> (n: int, err: Error) {
  5. return read(r, ([^]byte)(p)[:byte_size], n_read)
  6. }
  7. write_ptr :: proc(w: Writer, p: rawptr, byte_size: int, n_written: ^int = nil) -> (n: int, err: Error) {
  8. return write(w, ([^]byte)(p)[:byte_size], n_written)
  9. }
  10. read_ptr_at :: proc(r: Reader_At, p: rawptr, byte_size: int, offset: i64, n_read: ^int = nil) -> (n: int, err: Error) {
  11. return read_at(r, ([^]byte)(p)[:byte_size], offset, n_read)
  12. }
  13. write_ptr_at :: proc(w: Writer_At, p: rawptr, byte_size: int, offset: i64, n_written: ^int = nil) -> (n: int, err: Error) {
  14. return write_at(w, ([^]byte)(p)[:byte_size], offset, n_written)
  15. }
  16. write_u64 :: proc(w: Writer, i: u64, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) {
  17. buf: [32]byte
  18. s := strconv.append_bits(buf[:], i, base, false, 64, strconv.digits, nil)
  19. return write_string(w, s, n_written)
  20. }
  21. write_i64 :: proc(w: Writer, i: i64, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) {
  22. buf: [32]byte
  23. s := strconv.append_bits(buf[:], u64(i), base, true, 64, strconv.digits, nil)
  24. return write_string(w, s, n_written)
  25. }
  26. write_uint :: proc(w: Writer, i: uint, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) {
  27. return write_u64(w, u64(i), base, n_written)
  28. }
  29. write_int :: proc(w: Writer, i: int, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) {
  30. return write_i64(w, i64(i), base, n_written)
  31. }
  32. write_u128 :: proc(w: Writer, i: u128, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) {
  33. buf: [32]byte
  34. s := strconv.append_bits_128(buf[:], i, base, false, 128, strconv.digits, nil)
  35. return write_string(w, s, n_written)
  36. }
  37. write_i128 :: proc(w: Writer, i: i128, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) {
  38. buf: [32]byte
  39. s := strconv.append_bits_128(buf[:], u128(i), base, true, 128, strconv.digits, nil)
  40. return write_string(w, s, n_written)
  41. }
  42. write_f16 :: proc(w: Writer, val: f16, n_written: ^int = nil) -> (n: int, err: Error) {
  43. buf: [386]byte
  44. str := strconv.append_float(buf[1:], f64(val), 'f', 2*size_of(val), 8*size_of(val))
  45. s := buf[:len(str)+1]
  46. if s[1] == '+' || s[1] == '-' {
  47. s = s[1:]
  48. } else {
  49. s[0] = '+'
  50. }
  51. if s[0] == '+' {
  52. s = s[1:]
  53. }
  54. return write_string(w, string(s), n_written)
  55. }
  56. write_f32 :: proc(w: Writer, val: f32, n_written: ^int = nil) -> (n: int, err: Error) {
  57. buf: [386]byte
  58. str := strconv.append_float(buf[1:], f64(val), 'f', 2*size_of(val), 8*size_of(val))
  59. s := buf[:len(str)+1]
  60. if s[1] == '+' || s[1] == '-' {
  61. s = s[1:]
  62. } else {
  63. s[0] = '+'
  64. }
  65. if s[0] == '+' {
  66. s = s[1:]
  67. }
  68. return write_string(w, string(s), n_written)
  69. }
  70. write_f64 :: proc(w: Writer, val: f64, n_written: ^int = nil) -> (n: int, err: Error) {
  71. buf: [386]byte
  72. str := strconv.append_float(buf[1:], val, 'f', 2*size_of(val), 8*size_of(val))
  73. s := buf[:len(str)+1]
  74. if s[1] == '+' || s[1] == '-' {
  75. s = s[1:]
  76. } else {
  77. s[0] = '+'
  78. }
  79. if s[0] == '+' {
  80. s = s[1:]
  81. }
  82. return write_string(w, string(s), n_written)
  83. }
  84. @(private="file")
  85. DIGITS_LOWER := "0123456789abcdefx"
  86. n_wrapper :: proc(n: int, err: Error, bytes_processed: ^int) -> Error {
  87. bytes_processed^ += n
  88. return err
  89. }
  90. write_encoded_rune :: proc(w: Writer, r: rune, write_quote := true, n_written: ^int = nil) -> (n: int, err: Error) {
  91. defer if n_written != nil {
  92. n_written^ += n
  93. }
  94. if write_quote {
  95. write_byte(w, '\'', &n) or_return
  96. }
  97. switch r {
  98. case '\a': write_string(w, `\a`, &n) or_return
  99. case '\b': write_string(w, `\b`, &n) or_return
  100. case '\e': write_string(w, `\e`, &n) or_return
  101. case '\f': write_string(w, `\f`, &n) or_return
  102. case '\n': write_string(w, `\n`, &n) or_return
  103. case '\r': write_string(w, `\r`, &n) or_return
  104. case '\t': write_string(w, `\t`, &n) or_return
  105. case '\v': write_string(w, `\v`, &n) or_return
  106. case:
  107. if r < 32 {
  108. write_string(w, `\x`, &n) or_return
  109. buf: [2]byte
  110. s := strconv.append_bits(buf[:], u64(r), 16, true, 64, strconv.digits, nil)
  111. switch len(s) {
  112. case 0: write_string(w, "00", &n) or_return
  113. case 1: write_byte(w, '0', &n) or_return
  114. case 2: write_string(w, s, &n) or_return
  115. }
  116. } else {
  117. write_rune(w, r, &n) or_return
  118. }
  119. }
  120. if write_quote {
  121. write_byte(w, '\'', &n) or_return
  122. }
  123. return
  124. }
  125. write_escaped_rune :: proc(w: Writer, r: rune, quote: byte, html_safe := false, n_written: ^int = nil) -> (n: int, err: Error) {
  126. is_printable :: proc(r: rune) -> bool {
  127. if r <= 0xff {
  128. switch r {
  129. case 0x20..=0x7e:
  130. return true
  131. case 0xa1..=0xff: // ¡ through ÿ except for the soft hyphen
  132. return r != 0xad //
  133. }
  134. }
  135. // TODO(bill): A proper unicode library will be needed!
  136. return false
  137. }
  138. defer if n_written != nil {
  139. n_written^ += n
  140. }
  141. if html_safe {
  142. switch r {
  143. case '<', '>', '&':
  144. write_byte(w, '\\', &n) or_return
  145. write_byte(w, 'u', &n) or_return
  146. for s := 12; s >= 0; s -= 4 {
  147. write_byte(w, DIGITS_LOWER[r>>uint(s) & 0xf], &n) or_return
  148. }
  149. return
  150. }
  151. }
  152. if r == rune(quote) || r == '\\' {
  153. write_byte(w, '\\', &n) or_return
  154. write_byte(w, byte(r), &n) or_return
  155. return
  156. } else if is_printable(r) {
  157. write_encoded_rune(w, r, false, &n) or_return
  158. return
  159. }
  160. switch r {
  161. case '\a': write_string(w, `\a`, &n) or_return
  162. case '\b': write_string(w, `\b`, &n) or_return
  163. case '\e': write_string(w, `\e`, &n) or_return
  164. case '\f': write_string(w, `\f`, &n) or_return
  165. case '\n': write_string(w, `\n`, &n) or_return
  166. case '\r': write_string(w, `\r`, &n) or_return
  167. case '\t': write_string(w, `\t`, &n) or_return
  168. case '\v': write_string(w, `\v`, &n) or_return
  169. case:
  170. switch c := r; {
  171. case c < ' ':
  172. write_byte(w, '\\', &n) or_return
  173. write_byte(w, 'x', &n) or_return
  174. write_byte(w, DIGITS_LOWER[byte(c)>>4], &n) or_return
  175. write_byte(w, DIGITS_LOWER[byte(c)&0xf], &n) or_return
  176. case c > utf8.MAX_RUNE:
  177. c = 0xfffd
  178. fallthrough
  179. case c < 0x10000:
  180. write_byte(w, '\\', &n) or_return
  181. write_byte(w, 'u', &n) or_return
  182. for s := 12; s >= 0; s -= 4 {
  183. write_byte(w, DIGITS_LOWER[c>>uint(s) & 0xf], &n) or_return
  184. }
  185. case:
  186. write_byte(w, '\\', &n) or_return
  187. write_byte(w, 'U', &n) or_return
  188. for s := 28; s >= 0; s -= 4 {
  189. write_byte(w, DIGITS_LOWER[c>>uint(s) & 0xf], &n) or_return
  190. }
  191. }
  192. }
  193. return
  194. }
  195. write_quoted_string :: proc(w: Writer, str: string, quote: byte = '"', n_written: ^int = nil) -> (n: int, err: Error) {
  196. defer if n_written != nil {
  197. n_written^ += n
  198. }
  199. write_byte(w, quote, &n) or_return
  200. for width, s := 0, str; len(s) > 0; s = s[width:] {
  201. r := rune(s[0])
  202. width = 1
  203. if r >= utf8.RUNE_SELF {
  204. r, width = utf8.decode_rune_in_string(s)
  205. }
  206. if width == 1 && r == utf8.RUNE_ERROR {
  207. write_byte(w, '\\', &n) or_return
  208. write_byte(w, 'x', &n) or_return
  209. write_byte(w, DIGITS_LOWER[s[0]>>4], &n) or_return
  210. write_byte(w, DIGITS_LOWER[s[0]&0xf], &n) or_return
  211. continue
  212. }
  213. n_wrapper(write_escaped_rune(w, r, quote), &n) or_return
  214. }
  215. write_byte(w, quote, &n) or_return
  216. return
  217. }
  218. Tee_Reader :: struct {
  219. r: Reader,
  220. w: Writer,
  221. }
  222. @(private)
  223. _tee_reader_vtable := &Stream_VTable{
  224. impl_read = proc(s: Stream, p: []byte) -> (n: int, err: Error) {
  225. t := (^Tee_Reader)(s.stream_data)
  226. n, err = read(t.r, p)
  227. if n > 0 {
  228. if wn, werr := write(t.w, p[:n]); werr != nil {
  229. return wn, werr
  230. }
  231. }
  232. return
  233. },
  234. }
  235. // tee_reader_init returns a Reader that writes to 'w' what it reads from 'r'
  236. // All reads from 'r' performed through it are matched with a corresponding write to 'w'
  237. // There is no internal buffering done
  238. // The write must complete before th read completes
  239. // Any error encountered whilst writing is reported as a 'read' error
  240. // tee_reader_init must call io.destroy when done with
  241. tee_reader_init :: proc(t: ^Tee_Reader, r: Reader, w: Writer, allocator := context.allocator) -> Reader {
  242. t.r, t.w = r, w
  243. return tee_reader_to_reader(t)
  244. }
  245. tee_reader_to_reader :: proc(t: ^Tee_Reader) -> (r: Reader) {
  246. r.stream_data = t
  247. r.stream_vtable = _tee_reader_vtable
  248. return
  249. }
  250. // A Limited_Reader reads from r but limits the amount of data returned to just n bytes.
  251. // Each call to read updates n to reflect the new amount remaining.
  252. // read returns EOF when n <= 0 or when the underlying r returns EOF.
  253. Limited_Reader :: struct {
  254. r: Reader, // underlying reader
  255. n: i64, // max_bytes
  256. }
  257. @(private)
  258. _limited_reader_vtable := &Stream_VTable{
  259. impl_read = proc(s: Stream, p: []byte) -> (n: int, err: Error) {
  260. l := (^Limited_Reader)(s.stream_data)
  261. if l.n <= 0 {
  262. return 0, .EOF
  263. }
  264. p := p
  265. if i64(len(p)) > l.n {
  266. p = p[0:l.n]
  267. }
  268. n, err = read(l.r, p)
  269. l.n -= i64(n)
  270. return
  271. },
  272. }
  273. limited_reader_init :: proc(l: ^Limited_Reader, r: Reader, n: i64) -> Reader {
  274. l.r = r
  275. l.n = n
  276. return limited_reader_to_reader(l)
  277. }
  278. limited_reader_to_reader :: proc(l: ^Limited_Reader) -> (r: Reader) {
  279. r.stream_vtable = _limited_reader_vtable
  280. r.stream_data = l
  281. return
  282. }
  283. // Section_Reader implements read, seek, and read_at on a section of an underlying Reader_At
  284. Section_Reader :: struct {
  285. r: Reader_At,
  286. base: i64,
  287. off: i64,
  288. limit: i64,
  289. }
  290. section_reader_init :: proc(s: ^Section_Reader, r: Reader_At, off: i64, n: i64) {
  291. s.r = r
  292. s.off = off
  293. s.limit = off + n
  294. return
  295. }
  296. section_reader_to_stream :: proc(s: ^Section_Reader) -> (out: Stream) {
  297. out.stream_data = s
  298. out.stream_vtable = _section_reader_vtable
  299. return
  300. }
  301. @(private)
  302. _section_reader_vtable := &Stream_VTable{
  303. impl_read = proc(stream: Stream, p: []byte) -> (n: int, err: Error) {
  304. s := (^Section_Reader)(stream.stream_data)
  305. if s.off >= s.limit {
  306. return 0, .EOF
  307. }
  308. p := p
  309. if max := s.limit - s.off; i64(len(p)) > max {
  310. p = p[0:max]
  311. }
  312. n, err = read_at(s.r, p, s.off)
  313. s.off += i64(n)
  314. return
  315. },
  316. impl_read_at = proc(stream: Stream, p: []byte, off: i64) -> (n: int, err: Error) {
  317. s := (^Section_Reader)(stream.stream_data)
  318. p, off := p, off
  319. if off < 0 || off >= s.limit - s.base {
  320. return 0, .EOF
  321. }
  322. off += s.base
  323. if max := s.limit - off; i64(len(p)) > max {
  324. p = p[0:max]
  325. n, err = read_at(s.r, p, off)
  326. if err == nil {
  327. err = .EOF
  328. }
  329. return
  330. }
  331. return read_at(s.r, p, off)
  332. },
  333. impl_seek = proc(stream: Stream, offset: i64, whence: Seek_From) -> (n: i64, err: Error) {
  334. s := (^Section_Reader)(stream.stream_data)
  335. offset := offset
  336. switch whence {
  337. case:
  338. return 0, .Invalid_Whence
  339. case .Start:
  340. offset += s.base
  341. case .Current:
  342. offset += s.off
  343. case .End:
  344. offset += s.limit
  345. }
  346. if offset < s.base {
  347. return 0, .Invalid_Offset
  348. }
  349. s.off = offset
  350. n = offset - s.base
  351. return
  352. },
  353. impl_size = proc(stream: Stream) -> i64 {
  354. s := (^Section_Reader)(stream.stream_data)
  355. return s.limit - s.base
  356. },
  357. }