Commit 320e26590a

Andrew Kelley <superjoe30@gmail.com>
2016-09-01 05:23:47
fix std io input to work for non seekable fds
1 parent 289bfa8
Changed files (5)
example/guess_number/main.zig
@@ -1,6 +1,6 @@
 const std = @import("std");
 const io = std.io;
-const Rand = std.Rand;
+const Rand = std.rand.Rand;
 const os = std.os;
 
 pub fn main(args: [][]u8) -> %void {
@@ -18,7 +18,9 @@ pub fn main(args: [][]u8) -> %void {
         var line_buf : [20]u8 = undefined;
 
         const line_len = io.stdin.read(line_buf) %% |err| {
-            %%io.stdout.printf("Unable to read from stdin.\n");
+            %%io.stdout.printf("Unable to read from stdin: ");
+            %%io.stdout.printf(@errName(err));
+            %%io.stdout.printf("\n");
             return err;
         };
 
std/debug.zig
@@ -119,7 +119,7 @@ fn arangesOffset(st: &ElfStackTrace, target_address: usize) -> %?u64 {
         unit_index += 1;
 
         const align = segment_size + 2 * address_size;
-        const padding = st.self_exe_stream.offset % align;
+        const padding = (%return st.self_exe_stream.getPos()) % align;
         %return st.self_exe_stream.seekForward(padding);
         unit_index += padding;
 
std/elf.zig
@@ -170,7 +170,7 @@ pub struct Elf {
         const ph_byte_count = u64(ph_entry_size) * u64(ph_entry_count);
         const end_ph = %return math.addOverflow(u64, elf.program_header_offset, ph_byte_count);
 
-        const stream_end = %return elf.in_stream.endPos();
+        const stream_end = %return elf.in_stream.getEndPos();
         if (stream_end < end_sh || stream_end < end_ph) {
             return error.InvalidFormat;
         }
std/index.zig
@@ -1,4 +1,4 @@
-pub const Rand = @import("rand.zig").Rand;
+pub const rand = @import("rand.zig");
 pub const io = @import("io.zig");
 pub const os = @import("os.zig");
 pub const math = @import("math.zig");
std/io.zig
@@ -11,7 +11,6 @@ pub const stderr_fileno = 2;
 
 pub var stdin = InStream {
     .fd = stdin_fileno,
-    .offset = 0,
 };
 
 pub var stdout = OutStream {
@@ -37,9 +36,6 @@ pub error Unexpected;
 
 pub error DiskQuota;
 pub error FileTooBig;
-// TODO hide interrupts at this layer by retrying. Users can use the linux specific APIs if they
-// want to handle interrupts.
-pub error SigInterrupt;
 pub error Io;
 pub error NoSpaceLeft;
 pub error BadPerm;
@@ -113,34 +109,42 @@ pub struct OutStream {
     }
 
     pub fn flush(os: &OutStream) -> %void {
-        const write_ret = linux.write(os.fd, &os.buffer[0], os.index);
-        const write_err = linux.getErrno(write_ret);
-        if (write_err > 0) {
-            return switch (write_err) {
-                errno.EINVAL => unreachable{},
-                errno.EDQUOT => error.DiskQuota,
-                errno.EFBIG  => error.FileTooBig,
-                errno.EINTR  => error.SigInterrupt,
-                errno.EIO    => error.Io,
-                errno.ENOSPC => error.NoSpaceLeft,
-                errno.EPERM  => error.BadPerm,
-                errno.EPIPE  => error.PipeFail,
-                else         => error.Unexpected,
+        while (true) {
+            const write_ret = linux.write(os.fd, &os.buffer[0], os.index);
+            const write_err = linux.getErrno(write_ret);
+            if (write_err > 0) {
+                return switch (write_err) {
+                    errno.EINTR  => continue,
+
+                    errno.EINVAL => unreachable{},
+                    errno.EDQUOT => error.DiskQuota,
+                    errno.EFBIG  => error.FileTooBig,
+                    errno.EIO    => error.Io,
+                    errno.ENOSPC => error.NoSpaceLeft,
+                    errno.EPERM  => error.BadPerm,
+                    errno.EPIPE  => error.PipeFail,
+                    else         => error.Unexpected,
+                }
             }
+            os.index = 0;
+            return;
         }
-        os.index = 0;
     }
 
     pub fn close(os: &OutStream) -> %void {
-        const close_ret = linux.close(os.fd);
-        const close_err = linux.getErrno(close_ret);
-        if (close_err > 0) {
-            return switch (close_err) {
-                errno.EIO   => error.Io,
-                errno.EBADF => error.BadFd,
-                errno.EINTR => error.SigInterrupt,
-                else        => error.Unexpected,
+        while (true) {
+            const close_ret = linux.close(os.fd);
+            const close_err = linux.getErrno(close_ret);
+            if (close_err > 0) {
+                return switch (close_err) {
+                    errno.EINTR => continue,
+
+                    errno.EIO   => error.Io,
+                    errno.EBADF => error.BadFd,
+                    else        => error.Unexpected,
+                }
             }
+            return;
         }
     }
 }
@@ -149,47 +153,62 @@ pub struct OutStream {
 // BufferedInStream API goes on top of minimal InStream API.
 pub struct InStream {
     fd: i32,
-    offset: usize,
 
     /// Call close to clean up.
     pub fn open(is: &InStream, path: []const u8) -> %void {
-        const result = linux.open(path, linux.O_LARGEFILE|linux.O_RDONLY, 0);
-        const err = linux.getErrno(result);
-        if (err > 0) {
-            return switch (err) {
-                errno.EFAULT => unreachable{},
-                errno.EINVAL => unreachable{},
-                errno.EACCES => error.BadPerm,
-                errno.EFBIG, errno.EOVERFLOW => error.FileTooBig,
-                errno.EINTR => error.SigInterrupt,
-                errno.EISDIR => error.IsDir,
-                errno.ELOOP => error.SymLinkLoop,
-                errno.EMFILE => error.ProcessFdQuotaExceeded,
-                errno.ENAMETOOLONG => error.NameTooLong,
-                errno.ENFILE => error.SystemFdQuotaExceeded,
-                errno.ENODEV => error.NoDevice,
-                errno.ENOENT => error.PathNotFound,
-                errno.ENOMEM => error.NoMem,
-                errno.ENOSPC => error.NoSpaceLeft,
-                errno.ENOTDIR => error.NotDir,
-                errno.EPERM => error.BadPerm,
-                else => error.Unexpected,
-            }
+        switch (@compileVar("os")) {
+            linux => {
+                while (true) {
+                    const result = linux.open(path, linux.O_LARGEFILE|linux.O_RDONLY, 0);
+                    const err = linux.getErrno(result);
+                    if (err > 0) {
+                        return switch (err) {
+                            errno.EINTR => continue,
+
+                            errno.EFAULT => unreachable{},
+                            errno.EINVAL => unreachable{},
+                            errno.EACCES => error.BadPerm,
+                            errno.EFBIG, errno.EOVERFLOW => error.FileTooBig,
+                            errno.EISDIR => error.IsDir,
+                            errno.ELOOP => error.SymLinkLoop,
+                            errno.EMFILE => error.ProcessFdQuotaExceeded,
+                            errno.ENAMETOOLONG => error.NameTooLong,
+                            errno.ENFILE => error.SystemFdQuotaExceeded,
+                            errno.ENODEV => error.NoDevice,
+                            errno.ENOENT => error.PathNotFound,
+                            errno.ENOMEM => error.NoMem,
+                            errno.ENOSPC => error.NoSpaceLeft,
+                            errno.ENOTDIR => error.NotDir,
+                            errno.EPERM => error.BadPerm,
+                            else => error.Unexpected,
+                        }
+                    }
+                    is.fd = i32(result);
+                    return;
+                }
+            },
+            else => @compileErr("unsupported OS"),
         }
-        is.fd = i32(result);
-        is.offset = 0;
     }
 
     pub fn close(is: &InStream) -> %void {
-        const close_ret = linux.close(is.fd);
-        const close_err = linux.getErrno(close_ret);
-        if (close_err > 0) {
-            return switch (close_err) {
-                errno.EIO => error.Io,
-                errno.EBADF => error.BadFd,
-                errno.EINTR => error.SigInterrupt,
-                else => error.Unexpected,
-            }
+        switch (@compileVar("os")) {
+            linux => {
+                while (true) {
+                    const close_ret = linux.close(is.fd);
+                    const close_err = linux.getErrno(close_ret);
+                    if (close_err > 0) {
+                        return switch (close_err) {
+                            errno.EINTR => continue,
+
+                            errno.EIO => error.Io,
+                            errno.EBADF => error.BadFd,
+                            else => error.Unexpected,
+                        }
+                    }
+                }
+            },
+            else => @compileErr("unsupported OS"),
         }
     }
 
@@ -198,12 +217,14 @@ pub struct InStream {
     pub fn read(is: &InStream, buf: []u8) -> %usize {
         switch (@compileVar("os")) {
             linux => {
-                while (true) {
-                    const amt_read = linux.pread(is.fd, buf.ptr, buf.len, is.offset);
+                var index: usize = 0;
+                while (index < buf.len) {
+                    const amt_read = linux.read(is.fd, &buf[index], buf.len - index);
                     const read_err = linux.getErrno(amt_read);
                     if (read_err > 0) {
                         switch (read_err) {
                             errno.EINTR  => continue,
+
                             errno.EINVAL => unreachable{},
                             errno.EFAULT => unreachable{},
                             errno.EBADF  => return error.BadFd,
@@ -211,9 +232,10 @@ pub struct InStream {
                             else         => return error.Unexpected,
                         }
                     }
-                    is.offset += amt_read;
-                    return amt_read;
+                    if (amt_read == 0) return index;
+                    index += amt_read;
                 }
+                return index;
             },
             else => @compileErr("unsupported OS"),
         }
@@ -261,14 +283,67 @@ pub struct InStream {
     }
 
     pub fn seekForward(is: &InStream, amount: usize) -> %void {
-        is.offset += amount;
+        switch (@compileVar("os")) {
+            linux => {
+                const result = linux.lseek(is.fd, amount, linux.SEEK_CUR);
+                const err = linux.getErrno(result);
+                if (err > 0) {
+                    return switch (err) {
+                        errno.EBADF => error.BadFd,
+                        errno.EINVAL => error.Unseekable,
+                        errno.EOVERFLOW => error.Unseekable,
+                        errno.ESPIPE => error.Unseekable,
+                        errno.ENXIO => error.Unseekable,
+                        else => error.Unexpected,
+                    };
+                }
+            },
+            else => @compileErr("unsupported OS"),
+        }
     }
 
     pub fn seekTo(is: &InStream, pos: usize) -> %void {
-        is.offset = pos;
+        switch (@compileVar("os")) {
+            linux => {
+                const result = linux.lseek(is.fd, pos, linux.SEEK_SET);
+                const err = linux.getErrno(result);
+                if (err > 0) {
+                    return switch (err) {
+                        errno.EBADF => error.BadFd,
+                        errno.EINVAL => error.Unseekable,
+                        errno.EOVERFLOW => error.Unseekable,
+                        errno.ESPIPE => error.Unseekable,
+                        errno.ENXIO => error.Unseekable,
+                        else => error.Unexpected,
+                    };
+                }
+            },
+            else => @compileErr("unsupported OS"),
+        }
+    }
+
+    pub fn getPos(is: &InStream) -> %usize {
+        switch (@compileVar("os")) {
+            linux => {
+                const result = linux.lseek(is.fd, 0, linux.SEEK_CUR);
+                const err = linux.getErrno(result);
+                if (err > 0) {
+                    return switch (err) {
+                        errno.EBADF => error.BadFd,
+                        errno.EINVAL => error.Unseekable,
+                        errno.EOVERFLOW => error.Unseekable,
+                        errno.ESPIPE => error.Unseekable,
+                        errno.ENXIO => error.Unseekable,
+                        else => error.Unexpected,
+                    };
+                }
+                return result;
+            },
+            else => @compileErr("unsupported OS"),
+        }
     }
 
-    pub fn endPos(is: &InStream) -> %usize {
+    pub fn getEndPos(is: &InStream) -> %usize {
         var stat: linux.stat = undefined;
         const err = linux.getErrno(linux.fstat(is.fd, &stat));
         if (err > 0) {