Browse Source

c/libc: add `to_stream` proc

Adds the `to_stream` procedure to `core:c/libc` to improve usability of
the core collection when you have to use libc.
Laytan Laats 1 year ago
parent
commit
ce8801c37f
1 changed files with 101 additions and 0 deletions
  1. 101 0
      core/c/libc/stdio.odin

+ 101 - 0
core/c/libc/stdio.odin

@@ -1,5 +1,7 @@
 package libc
 package libc
 
 
+import "core:io"
+
 when ODIN_OS == .Windows {
 when ODIN_OS == .Windows {
 	foreign import libc {
 	foreign import libc {
 		"system:libucrt.lib",
 		"system:libucrt.lib",
@@ -218,3 +220,102 @@ foreign libc {
 	ferror    :: proc(stream: ^FILE) -> int ---
 	ferror    :: proc(stream: ^FILE) -> int ---
 	perror    :: proc(s: cstring) ---
 	perror    :: proc(s: cstring) ---
 }
 }
+
+to_stream :: proc(file: ^FILE) -> io.Stream {
+	stream_proc :: proc(stream_data: rawptr, mode: io.Stream_Mode, p: []byte, offset: i64, whence: io.Seek_From) -> (n: i64, err: io.Error) {
+		unknown_or_eof :: proc(f: ^FILE) -> io.Error {
+			switch {
+			case ferror(f) != 0:
+				return .Unknown
+			case feof(f) != 0:
+				return .EOF
+			case:
+				return nil
+			}
+		}
+
+		file := (^FILE)(stream_data)
+		switch mode {
+		case .Close:
+			if fclose(file) != 0 {
+				return 0, unknown_or_eof(file)
+			}
+
+		case .Flush:
+			if fflush(file) != 0 {
+				return 0, unknown_or_eof(file)
+			}
+
+		case .Read:
+			n = i64(fread(raw_data(p), size_of(byte), len(p), file))
+			if n == 0 { err = unknown_or_eof(file) }
+
+		case .Read_At:
+			curr := ftell(file)
+			if curr == -1 {
+				return 0, unknown_or_eof(file)
+			}
+
+			if fseek(file, long(offset), SEEK_SET) != 0 {
+				return 0, unknown_or_eof(file)
+			}
+
+			defer fseek(file, long(curr), SEEK_SET)
+
+			n = i64(fread(raw_data(p), size_of(byte), len(p), file))
+			if n == 0 { err = unknown_or_eof(file) }
+		
+		case .Write:
+			n = i64(fwrite(raw_data(p), size_of(byte), len(p), file))
+			if n == 0 { err = unknown_or_eof(file) }
+
+		case .Write_At:
+			curr := ftell(file)
+			if curr == -1 {
+				return 0, unknown_or_eof(file)
+			}
+
+			if fseek(file, long(offset), SEEK_SET) != 0 {
+				return 0, unknown_or_eof(file)
+			}
+
+			defer fseek(file, long(curr), SEEK_SET)
+
+			n = i64(fwrite(raw_data(p), size_of(byte), len(p), file))
+			if n == 0 { err = unknown_or_eof(file) }
+
+		case .Seek:
+			if fseek(file, long(offset), int(whence)) != 0 {
+				return 0, unknown_or_eof(file)
+			}
+		
+		case .Size:
+			curr := ftell(file)
+			if curr == -1 {
+				return 0, unknown_or_eof(file)
+			}
+			defer fseek(file, curr, SEEK_SET)
+
+			if fseek(file, 0, SEEK_END) != 0 {
+				return 0, unknown_or_eof(file)
+			}
+
+			n = i64(ftell(file))
+			if n == -1 {
+				return 0, unknown_or_eof(file)
+			}
+
+		case .Destroy:
+			return 0, .Empty
+		
+		case .Query:
+			return io.query_utility({ .Close, .Flush, .Read, .Read_At, .Write, .Write_At, .Seek, .Size })
+		}
+		return
+	}
+
+	return {
+		data      = file,
+		procedure = stream_proc,
+	}
+}