summaryrefslogtreecommitdiff
path: root/chapter30/src/main/smp/sys/io.smp
diff options
context:
space:
mode:
Diffstat (limited to 'chapter30/src/main/smp/sys/io.smp')
-rw-r--r--chapter30/src/main/smp/sys/io.smp75
1 files changed, 53 insertions, 22 deletions
diff --git a/chapter30/src/main/smp/sys/io.smp b/chapter30/src/main/smp/sys/io.smp
index d6263ffe..14993429 100644
--- a/chapter30/src/main/smp/sys/io.smp
+++ b/chapter30/src/main/smp/sys/io.smp
@@ -4,43 +4,74 @@
// Write byte array to stdout
val p = { u8[~] str -> write(1,str); };
val p_noInline = { u8[~] str -> write(1,str); };
+// Write to stderr
+val err = { u8[~] str -> write(libc.STDERR,str); };
-// Return fd contents as a u8[].
+
+// Read until EOF, including after short reads. Return an empty array for an
+// empty stream, or null on error with errno preserved (partial data discarded).
val read = { i32 fd ->
- var buf = new u8[8*1024];
- i64 ptr = buf;
- int len = 0;
+ val chunk = new u8[8*1024];
+ i64 ptr = chunk;
+ val buf = new aryu8();
while( true ) {
- i32 rez = libc.read(fd,ptr,buf#);
- if( rez > buf# ) libc._exit(libc.errno());
- len += rez;
- if( rez < buf# )
- break;
- libc._exit(-2); // Need to implement for more than 8K input
+ i64 rez = libc.read(fd,ptr,chunk#);
+ if( rez < 0 ) {
+ if( libc.errno() == libc.EINTR ) continue;
+ return null;
+ }
+ if( rez == 0 ) break;
+ if( buf.len+rez > 4294967295 ) {
+ libc.set_errno(libc.EOVERFLOW);
+ return null;
+ }
+ u32 count = rez;
+ buf._grow(count);
+ ary.copy(buf.buf,buf.len,chunk,0,count);
+ buf.len += count;
}
- var out = new u8[len];
- ary.copy(out,0,buf,0,len);
+ val out = new u8[buf.len];
+ return ary.copy(out,0,buf.buf,0,buf.len);
};
-// Write all of str to fd.
+// Write all bytes, returning the count or -1 with errno set. An error can
+// follow a successfully written prefix; it does not undo that prefix.
val write = { i32 fd, u8[~] str ->
- i64 ptr = str; // Convert array pointer to a i64 for the native call
- libc.write(fd,ptr,str#);
+ writeOff(fd,str,0,str#);
};
-// Write all of str to fd.
+// Write a slice, capping len at the remaining bytes. An offset past the end
+// is invalid, including for an empty write. A valid empty slice returns zero.
+// Invalid arguments return -1;
val writeOff = { i32 fd, u8[~] str, u32 off, u32 len ->
- i64 ptr = str; // Convert array pointer to a i64 for the native call
- ptr += off; // Skip offset
- // Cap at available length
- if( len > str# - off ) len = str# - off;
- // Do the write
- libc.write(fd,ptr,len);
+ if( off > str# ) return libc.set_errno(libc.EINVAL);
+ if( len > str# - off ) len = str# - off;
+ i64 ptr = str;
+ ptr += off;
+ i64 done = 0;
+ while( done < len ) {
+ i64 rez = libc.write(fd,ptr+done,len-done);
+ if( rez < 0 ) {
+ if( libc.errno() == libc.EINTR ) continue;
+ return -1;
+ }
+ if( rez == 0 ) {
+ libc.set_errno(libc.EIO);
+ return -1;
+ }
+ done += rez;
+ }
+ return done;
};
// Return stdin as a u8[].
val stdin = { -> read(0); };
+// One byte, without Enter or echo. Restores the previous terminal mode before
+// returning. Files/pipes also work. Returns 0..255, or -1 with libc.errno() set
+// to libc.EOF or an OS error. Ctrl-C is byte 3; escape/UTF-8 sequences are multiple bytes.
+val getch = { -> libc.simple_getch(); };
+
// Create file for writing. Return fd, or -1 and errno has the error code
val create = { u8[~] str ->
i64 ptr = sys.aryu8.str0(str);