diff options
| author | Cliff Click <cliffc@acm.org> | 2026-08-10 11:11:18 -0700 |
|---|---|---|
| committer | Cliff Click <cliffc@acm.org> | 2026-11-12 23:28:58 -0800 |
| commit | 2cb35c65bde63f90d7afc3d7a8a985b0c6ea15d7 (patch) | |
| tree | 50646613e551b1d4e523639d2973299c9d3bd5cd /src/main/smp/sys/io.smp | |
| parent | 772e3a1036d571de55b178ebd6d11ee5140d4e36 (diff) | |
| download | Simple-2cb35c65bde63f90d7afc3d7a8a985b0c6ea15d7.tar.gz Simple-2cb35c65bde63f90d7afc3d7a8a985b0c6ea15d7.zip | |
Chapter 30: Text Formatting and Diagnostics
Co-authored-by: Hsiang-Ying Fu <66062782+fuhsnn@users.noreply.github.com>
Co-authored-by: fuhsnn <66062782+fuhsnn@users.noreply.github.com>
Co-authored-by: Symious <14933944+symious@users.noreply.github.com>
Co-authored-by: Jun Kawasaki <jun784@gmail.com>
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Diffstat (limited to 'src/main/smp/sys/io.smp')
| -rw-r--r-- | src/main/smp/sys/io.smp | 75 |
1 files changed, 53 insertions, 22 deletions
diff --git a/src/main/smp/sys/io.smp b/src/main/smp/sys/io.smp index d6263ffe..14993429 100644 --- a/src/main/smp/sys/io.smp +++ b/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); |
