authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-08-31 20:23:47-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-08-31 20:23:47-07:00
log320e26590a31351301992dc7067eb287e4f565f4
treef42869f9dc94e00f01d4adaa81eb974a2d15db08
parent289bfa890b758cdc408b33f4dd601410bebd0a9b

fix std io input to work for non seekable fds


5 files changed, 149 insertions(+), 72 deletions(-)

example/guess_number/main.zig+4-2
......@@ -1,6 +1,6 @@
11const std = @import("std");
22const io = std.io;
3const Rand = std.Rand;
3const Rand = std.rand.Rand;
44const os = std.os;
55
66pub fn main(args: [][]u8) -> %void {
......@@ -18,7 +18,9 @@ pub fn main(args: [][]u8) -> %void {
1818 var line_buf : [20]u8 = undefined;
1919
2020 const line_len = io.stdin.read(line_buf) %% |err| {
21 %%io.stdout.printf("Unable to read from stdin.\n");
21 %%io.stdout.printf("Unable to read from stdin: ");
22 %%io.stdout.printf(@errName(err));
23 %%io.stdout.printf("\n");
2224 return err;
2325 };
2426
std/debug.zig+1-1
......@@ -119,7 +119,7 @@ fn arangesOffset(st: &ElfStackTrace, target_address: usize) -> %?u64 {
119119 unit_index += 1;
120120
121121 const align = segment_size + 2 * address_size;
122 const padding = st.self_exe_stream.offset % align;
122 const padding = (%return st.self_exe_stream.getPos()) % align;
123123 %return st.self_exe_stream.seekForward(padding);
124124 unit_index += padding;
125125
std/elf.zig+1-1
......@@ -170,7 +170,7 @@ pub struct Elf {
170170 const ph_byte_count = u64(ph_entry_size) * u64(ph_entry_count);
171171 const end_ph = %return math.addOverflow(u64, elf.program_header_offset, ph_byte_count);
172172
173 const stream_end = %return elf.in_stream.endPos();
173 const stream_end = %return elf.in_stream.getEndPos();
174174 if (stream_end < end_sh || stream_end < end_ph) {
175175 return error.InvalidFormat;
176176 }
std/index.zig+1-1
......@@ -1,4 +1,4 @@
1pub const Rand = @import("rand.zig").Rand;
1pub const rand = @import("rand.zig");
22pub const io = @import("io.zig");
33pub const os = @import("os.zig");
44pub const math = @import("math.zig");
std/io.zig+142-67
......@@ -11,7 +11,6 @@ pub const stderr_fileno = 2;
1111
1212pub var stdin = InStream {
1313 .fd = stdin_fileno,
14 .offset = 0,
1514};
1615
1716pub var stdout = OutStream {
......@@ -37,9 +36,6 @@ pub error Unexpected;
3736
3837pub error DiskQuota;
3938pub error FileTooBig;
40// TODO hide interrupts at this layer by retrying. Users can use the linux specific APIs if they
41// want to handle interrupts.
42pub error SigInterrupt;
4339pub error Io;
4440pub error NoSpaceLeft;
4541pub error BadPerm;
......@@ -113,34 +109,42 @@ pub struct OutStream {
113109 }
114110
115111 pub fn flush(os: &OutStream) -> %void {
116 const write_ret = linux.write(os.fd, &os.buffer[0], os.index);
117 const write_err = linux.getErrno(write_ret);
118 if (write_err > 0) {
119 return switch (write_err) {
120 errno.EINVAL => unreachable{},
121 errno.EDQUOT => error.DiskQuota,
122 errno.EFBIG => error.FileTooBig,
123 errno.EINTR => error.SigInterrupt,
124 errno.EIO => error.Io,
125 errno.ENOSPC => error.NoSpaceLeft,
126 errno.EPERM => error.BadPerm,
127 errno.EPIPE => error.PipeFail,
128 else => error.Unexpected,
112 while (true) {
113 const write_ret = linux.write(os.fd, &os.buffer[0], os.index);
114 const write_err = linux.getErrno(write_ret);
115 if (write_err > 0) {
116 return switch (write_err) {
117 errno.EINTR => continue,
118
119 errno.EINVAL => unreachable{},
120 errno.EDQUOT => error.DiskQuota,
121 errno.EFBIG => error.FileTooBig,
122 errno.EIO => error.Io,
123 errno.ENOSPC => error.NoSpaceLeft,
124 errno.EPERM => error.BadPerm,
125 errno.EPIPE => error.PipeFail,
126 else => error.Unexpected,
127 }
129128 }
129 os.index = 0;
130 return;
130131 }
131 os.index = 0;
132132 }
133133
134134 pub fn close(os: &OutStream) -> %void {
135 const close_ret = linux.close(os.fd);
136 const close_err = linux.getErrno(close_ret);
137 if (close_err > 0) {
138 return switch (close_err) {
139 errno.EIO => error.Io,
140 errno.EBADF => error.BadFd,
141 errno.EINTR => error.SigInterrupt,
142 else => error.Unexpected,
135 while (true) {
136 const close_ret = linux.close(os.fd);
137 const close_err = linux.getErrno(close_ret);
138 if (close_err > 0) {
139 return switch (close_err) {
140 errno.EINTR => continue,
141
142 errno.EIO => error.Io,
143 errno.EBADF => error.BadFd,
144 else => error.Unexpected,
145 }
143146 }
147 return;
144148 }
145149 }
146150}
......@@ -149,47 +153,62 @@ pub struct OutStream {
149153// BufferedInStream API goes on top of minimal InStream API.
150154pub struct InStream {
151155 fd: i32,
152 offset: usize,
153156
154157 /// Call close to clean up.
155158 pub fn open(is: &InStream, path: []const u8) -> %void {
156 const result = linux.open(path, linux.O_LARGEFILE|linux.O_RDONLY, 0);
157 const err = linux.getErrno(result);
158 if (err > 0) {
159 return switch (err) {
160 errno.EFAULT => unreachable{},
161 errno.EINVAL => unreachable{},
162 errno.EACCES => error.BadPerm,
163 errno.EFBIG, errno.EOVERFLOW => error.FileTooBig,
164 errno.EINTR => error.SigInterrupt,
165 errno.EISDIR => error.IsDir,
166 errno.ELOOP => error.SymLinkLoop,
167 errno.EMFILE => error.ProcessFdQuotaExceeded,
168 errno.ENAMETOOLONG => error.NameTooLong,
169 errno.ENFILE => error.SystemFdQuotaExceeded,
170 errno.ENODEV => error.NoDevice,
171 errno.ENOENT => error.PathNotFound,
172 errno.ENOMEM => error.NoMem,
173 errno.ENOSPC => error.NoSpaceLeft,
174 errno.ENOTDIR => error.NotDir,
175 errno.EPERM => error.BadPerm,
176 else => error.Unexpected,
177 }
159 switch (@compileVar("os")) {
160 linux => {
161 while (true) {
162 const result = linux.open(path, linux.O_LARGEFILE|linux.O_RDONLY, 0);
163 const err = linux.getErrno(result);
164 if (err > 0) {
165 return switch (err) {
166 errno.EINTR => continue,
167
168 errno.EFAULT => unreachable{},
169 errno.EINVAL => unreachable{},
170 errno.EACCES => error.BadPerm,
171 errno.EFBIG, errno.EOVERFLOW => error.FileTooBig,
172 errno.EISDIR => error.IsDir,
173 errno.ELOOP => error.SymLinkLoop,
174 errno.EMFILE => error.ProcessFdQuotaExceeded,
175 errno.ENAMETOOLONG => error.NameTooLong,
176 errno.ENFILE => error.SystemFdQuotaExceeded,
177 errno.ENODEV => error.NoDevice,
178 errno.ENOENT => error.PathNotFound,
179 errno.ENOMEM => error.NoMem,
180 errno.ENOSPC => error.NoSpaceLeft,
181 errno.ENOTDIR => error.NotDir,
182 errno.EPERM => error.BadPerm,
183 else => error.Unexpected,
184 }
185 }
186 is.fd = i32(result);
187 return;
188 }
189 },
190 else => @compileErr("unsupported OS"),
178191 }
179 is.fd = i32(result);
180 is.offset = 0;
181192 }
182193
183194 pub fn close(is: &InStream) -> %void {
184 const close_ret = linux.close(is.fd);
185 const close_err = linux.getErrno(close_ret);
186 if (close_err > 0) {
187 return switch (close_err) {
188 errno.EIO => error.Io,
189 errno.EBADF => error.BadFd,
190 errno.EINTR => error.SigInterrupt,
191 else => error.Unexpected,
192 }
195 switch (@compileVar("os")) {
196 linux => {
197 while (true) {
198 const close_ret = linux.close(is.fd);
199 const close_err = linux.getErrno(close_ret);
200 if (close_err > 0) {
201 return switch (close_err) {
202 errno.EINTR => continue,
203
204 errno.EIO => error.Io,
205 errno.EBADF => error.BadFd,
206 else => error.Unexpected,
207 }
208 }
209 }
210 },
211 else => @compileErr("unsupported OS"),
193212 }
194213 }
195214
......@@ -198,12 +217,14 @@ pub struct InStream {
198217 pub fn read(is: &InStream, buf: []u8) -> %usize {
199218 switch (@compileVar("os")) {
200219 linux => {
201 while (true) {
202 const amt_read = linux.pread(is.fd, buf.ptr, buf.len, is.offset);
220 var index: usize = 0;
221 while (index < buf.len) {
222 const amt_read = linux.read(is.fd, &buf[index], buf.len - index);
203223 const read_err = linux.getErrno(amt_read);
204224 if (read_err > 0) {
205225 switch (read_err) {
206226 errno.EINTR => continue,
227
207228 errno.EINVAL => unreachable{},
208229 errno.EFAULT => unreachable{},
209230 errno.EBADF => return error.BadFd,
......@@ -211,9 +232,10 @@ pub struct InStream {
211232 else => return error.Unexpected,
212233 }
213234 }
214 is.offset += amt_read;
215 return amt_read;
235 if (amt_read == 0) return index;
236 index += amt_read;
216237 }
238 return index;
217239 },
218240 else => @compileErr("unsupported OS"),
219241 }
......@@ -261,14 +283,67 @@ pub struct InStream {
261283 }
262284
263285 pub fn seekForward(is: &InStream, amount: usize) -> %void {
264 is.offset += amount;
286 switch (@compileVar("os")) {
287 linux => {
288 const result = linux.lseek(is.fd, amount, linux.SEEK_CUR);
289 const err = linux.getErrno(result);
290 if (err > 0) {
291 return switch (err) {
292 errno.EBADF => error.BadFd,
293 errno.EINVAL => error.Unseekable,
294 errno.EOVERFLOW => error.Unseekable,
295 errno.ESPIPE => error.Unseekable,
296 errno.ENXIO => error.Unseekable,
297 else => error.Unexpected,
298 };
299 }
300 },
301 else => @compileErr("unsupported OS"),
302 }
265303 }
266304
267305 pub fn seekTo(is: &InStream, pos: usize) -> %void {
268 is.offset = pos;
306 switch (@compileVar("os")) {
307 linux => {
308 const result = linux.lseek(is.fd, pos, linux.SEEK_SET);
309 const err = linux.getErrno(result);
310 if (err > 0) {
311 return switch (err) {
312 errno.EBADF => error.BadFd,
313 errno.EINVAL => error.Unseekable,
314 errno.EOVERFLOW => error.Unseekable,
315 errno.ESPIPE => error.Unseekable,
316 errno.ENXIO => error.Unseekable,
317 else => error.Unexpected,
318 };
319 }
320 },
321 else => @compileErr("unsupported OS"),
322 }
323 }
324
325 pub fn getPos(is: &InStream) -> %usize {
326 switch (@compileVar("os")) {
327 linux => {
328 const result = linux.lseek(is.fd, 0, linux.SEEK_CUR);
329 const err = linux.getErrno(result);
330 if (err > 0) {
331 return switch (err) {
332 errno.EBADF => error.BadFd,
333 errno.EINVAL => error.Unseekable,
334 errno.EOVERFLOW => error.Unseekable,
335 errno.ESPIPE => error.Unseekable,
336 errno.ENXIO => error.Unseekable,
337 else => error.Unexpected,
338 };
339 }
340 return result;
341 },
342 else => @compileErr("unsupported OS"),
343 }
269344 }
270345
271 pub fn endPos(is: &InStream) -> %usize {
346 pub fn getEndPos(is: &InStream) -> %usize {
272347 var stat: linux.stat = undefined;
273348 const err = linux.getErrno(linux.fstat(is.fd, &stat));
274349 if (err > 0) {