#include "inc/priv.h"#include "inc/str.h"#include "inc/time.h" #define MOST_OF(x) ((x) - ((x)>>4)) ios *ios_stdin = nil;ios *ios_stdout = nil;ios *ios_stderr = nil; /* OS-level primitive wrappers */ void *sl_memrchr(const void *s, int c, usize n){ const u8int *src = (const u8int*)s + n; u8int uc = c; while(--src >= (const u8int*)s) if(*src == uc) return (void *)src; return nil;} sl_fd_wr(1) sl_rd(2, 3) sl_wr(4) sl_nonnull(2, 4)static intwrite_all(int fd, const u8int *buf, usize n, usize *nwritten){ usize wrote; *nwritten = 0; while(n > 0){ wrote = 0; int err = sys_write(fd, buf, n, &wrote); n -= wrote; *nwritten += wrote; buf += wrote; if(err) return err; } return 0;} /* internal utility functions */ sl_nonnull(1)static u8int *buf_realloc(ios *s, usize sz){ u8int *temp; if((s->buf == nil || s->buf == &s->local[0]) && sz <= IOS_INLSIZE){ /* TODO: if we want to allow shrinking, see if the buffer shrank down to this size, in which case we need to copy. */ s->buf = &s->local[0]; s->maxsize = IOS_INLSIZE; s->flags |= IOS_FL_OWNBUF; return s->buf; } if(sz <= s->maxsize) return s->buf; if((s->flags & IOS_FL_OWNBUF) != 0 && s->buf != &s->local[0]){ // if we own the buffer we're free to resize it // always allocate 1 bigger in case user wants to add a NUL // terminator after taking over the buffer temp = MEM_REALLOC(s->buf, sz); if(temp == nil) return nil; }else{ temp = MEM_ALLOC(sz); if(temp == nil) return nil; s->flags |= IOS_FL_OWNBUF; if(s->buf != nil) memcpy(temp, s->buf, s->size); } s->buf = temp; s->maxsize = sz; return s->buf;} // write a block of data into the buffer at the current position, resizing// if necessary. returns # written.sl_nonnull(1, 2) sl_rd(2, 3)static usizewrite_grow(ios *s, const void *data, usize n){ usize amt; usize newsize; if(sl_unlikely(n == 0)) return 0; if(sl_likely(s->bpos + n > s->size)){ if(sl_unlikely(s->bpos + n > s->maxsize)){ /* TODO: here you might want to add a mechanism for limiting the growth of the io. */ newsize = s->maxsize ? s->maxsize * 2 : 8; while(s->bpos + n > newsize) newsize *= 2; if(buf_realloc(s, newsize) == nil){ /* no more space; write as much as we can */ amt = s->maxsize - s->bpos; if(amt > 0) memcpy(&s->buf[s->bpos], data, amt); s->bpos += amt; s->size = s->maxsize; return amt; } } s->size = s->bpos + n; } memcpy(s->buf + s->bpos, data, n); s->bpos += n; return n;} /* interface functions, low level */ usizeios_read(ios *s, void *dest, usize n){ usize tot = 0; usize got, avail; if(s->state == IOS_STATE_CLOSED || (s->flags & IOS_FL_WRONLY) != 0) return 0; while(n > 0){ avail = s->size - s->bpos; if(avail > 0){ usize ncopy = avail >= n ? n : avail; memcpy(dest, s->buf + s->bpos, ncopy); s->bpos += ncopy; if(ncopy >= n){ s->state = IOS_STATE_RD; return tot+ncopy; } } if(s->bm == IOS_BUF_MEM || s->fd == -1){ // can't get any more data s->state = IOS_STATE_RD; if(avail == 0) s->flags |= IOS_FL_EOF; return avail; } dest = (u8int*)dest + avail; n -= avail; tot += avail; ios_flush(s); s->bpos = s->size = 0; s->state = IOS_STATE_RD; got = 0; if(n > MOST_OF(s->maxsize)){ // doesn't fit comfortably in buffer; go direct sys_read(s->fd, dest, n, &got); tot += got; if(got == 0) s->flags |= IOS_FL_EOF; return tot; } // refill buffer if(sys_read(s->fd, s->buf, s->maxsize, &got) != 0 || got == 0){ s->flags |= IOS_FL_EOF; return tot; } s->size = got; } return tot;} // ensure at least n bytes are buffered if possible. returns # available.usizeios_readprep(ios *s, usize n){ if((s->flags & IOS_FL_WRONLY) != 0) return 0; if(s->state == IOS_STATE_WR && s->bm != IOS_BUF_MEM){ ios_flush(s); s->bpos = s->size = 0; } usize space = s->size - s->bpos; s->state = IOS_STATE_RD; if(space >= n || s->bm == IOS_BUF_MEM || s->fd == -1) return space; if(s->maxsize < s->bpos+n){ // it won't fit. grow buffer or move data back. if(n <= s->maxsize && space <= ((s->maxsize)>>2)){ if(space) memmove(s->buf, s->buf+s->bpos, space); s->size -= s->bpos; s->bpos = 0; } else { if(buf_realloc(s, s->bpos + n) == nil) return space; } } usize got; int result = sys_read(s->fd, s->buf+s->size, s->maxsize - s->size, &got); if(result != 0) return space; s->size += got; return s->size - s->bpos;} sl_nonnull(1)static voidwrite_update_pos(ios *s){ if(sl_likely(s->bpos > s->ndirty)) s->ndirty = s->bpos; if(s->bpos > s->size) s->size = s->bpos;} usizeios_write(ios *s, const void *data, usize n){ if(sl_unlikely((s->flags & IOS_FL_RDONLY) != 0 || s->state == IOS_STATE_CLOSED || n == 0)) return 0; usize space, wrote = 0; if(sl_unlikely(s->state == IOS_STATE_NONE)) s->state = IOS_STATE_WR; if(sl_unlikely(s->state == IOS_STATE_RD)){ if((s->flags & IOS_FL_REREADABLE) == 0){ s->size = 0; s->bpos = 0; } space = s->size - s->bpos; }else{ space = s->maxsize - s->bpos; } if(sl_likely(s->bm == IOS_BUF_MEM)){ wrote = write_grow(s, data, n); }else if(sl_unlikely(s->bm == IOS_BUF_NONE)){ write_all(s->fd, data, n, &wrote); return wrote; }else if(sl_likely(n <= space)){ if(s->bm == IOS_BUF_LINE){ const char *nl; if(sl_unlikely((nl = sl_memrchr(data, '\n', n)) != nil)){ usize linesz = nl-(const char*)data+1; s->bm = IOS_BUF_BLOCK; wrote += ios_write(s, data, linesz); ios_flush(s); s->bm = IOS_BUF_LINE; n -= linesz; data = (const char*)data + linesz; } } memcpy(s->buf + s->bpos, data, n); s->bpos += n; wrote += n; }else{ s->state = IOS_STATE_WR; ios_flush(s); if(n > MOST_OF(s->maxsize)){ write_all(s->fd, data, n, &wrote); return wrote; } return ios_write(s, data, n); } write_update_pos(s); return wrote;} soffsetios_seek(ios *s, soffset pos){ if(sl_unlikely(s->state == IOS_STATE_CLOSED || pos < 0)) return -1; s->flags &= ~IOS_FL_EOF; if(sl_likely(s->bm == IOS_BUF_MEM)){ if((usize)pos >= s->size) pos = s->size; s->bpos = pos; }else{ ios_flush(s); s->bpos = s->size = 0; soffset fdpos = sys_seek(s->fd, pos, SEEK_SET); if(fdpos < 0) return -1; pos = fdpos; } s->loc.lineno = 1; s->loc.colno = 0; return pos;} soffsetios_seek_end(ios *s){ if(sl_unlikely(s->state == IOS_STATE_CLOSED)) return -1; s->flags |= IOS_FL_EOF; if(s->bm == IOS_BUF_MEM) s->bpos = s->size; else{ ios_flush(s); soffset fdpos = sys_seek(s->fd, 0, SEEK_END); if(fdpos == (soffset)-1) return fdpos; s->bpos = s->size = 0; } s->loc.lineno = 1; s->loc.colno = 0; return 0;} soffsetios_skip(ios *s, soffset offs, bool end){ if(sl_unlikely(s->state == IOS_STATE_CLOSED)) return -1; if(sl_unlikely(end && ios_seek_end(s) < 0)) return -1; s->flags &= ~IOS_FL_EOF; if(s->bm == IOS_BUF_MEM){ if(offs > 0){ if(offs <= (soffset)(s->size-s->bpos)) s->bpos += offs; else s->bpos = s->size; }else if(offs < 0){ if((soffset)s->bpos+offs >= 0) s->bpos += offs; else s->bpos = 0; } return s->bpos; } ios_flush(s); s->bpos = s->size = 0; return sys_seek(s->fd, offs, SEEK_CUR);} intios_trunc(ios *s, soffset size){ if(sl_unlikely(s->state == IOS_STATE_CLOSED || (s->flags & IOS_FL_RDONLY) != 0 || size < 0)) return -1; if(s->bm == IOS_BUF_MEM){ if(sl_unlikely((usize)size == s->size)) return 0; if(sl_likely((usize)size < s->size)){ if(s->bpos > (usize)size) s->bpos = size; }else if(sl_unlikely(buf_realloc(s, size) == nil)) return -1; s->size = size; return 0; } return sl_likely(ios_flush(s) == 0) ? ftruncate(s->fd, size) : -1;} intios_flush(ios *s){ if(s->ndirty == 0 || s->bm == IOS_BUF_MEM || s->buf == nil) return 0; if(sl_unlikely(s->fd == -1)) return -1; if(sl_unlikely(s->state == IOS_STATE_RD)){ if(sys_seek(s->fd, -(soffset)s->size, SEEK_CUR) == (soffset)-1){ // FIXME eh? } return -1; } usize nw, ntowrite = s->ndirty; int err = write_all(s->fd, s->buf, ntowrite, &nw); // todo: try recovering from some kinds of errors (e.g. retry) if(sl_unlikely(s->state == IOS_STATE_RD)){ if(sys_seek(s->fd, s->size - nw, SEEK_CUR) == (soffset)-1){ // FIXME eh? } return -1; }else if(s->state == IOS_STATE_WR){ if(s->bpos != nw && sys_seek(s->fd, (soffset)s->bpos - (soffset)nw, SEEK_CUR) == (soffset)-1){ // FIXME eh? } // now preserve the invariant that data to write // begins at the beginning of the buffer, and s->size refers // to how much valid file data is stored in the buffer. if(sl_unlikely(s->size > s->ndirty)){ usize delta = s->size - s->ndirty; memmove(s->buf, s->buf + s->ndirty, delta); } s->size -= s->ndirty; s->bpos = 0; } s->ndirty = 0; if(sl_unlikely(err)) return err; if(sl_unlikely(nw < ntowrite)) return -1; return 0;} voidios_close(ios *s){ if(sl_unlikely(s->state == IOS_STATE_CLOSED)) return; ios_flush(s); if(sl_unlikely(s->fd != -1 && (s->flags & IOS_FL_OWNFD) != 0)) sys_close(s->fd); s->fd = -1; s->data = sl_nil; if((s->flags & IOS_FL_OWNBUF) != 0 && s->buf != &s->local[0]) MEM_FREE(s->buf); s->buf = nil; s->size = s->maxsize = s->bpos = 0; s->state = IOS_STATE_CLOSED;} voidios_free(ios *s){ MEM_FREE(s->filename); s->filename = nil;} sl_nonnull(1)static voidbuf_init(ios *s, ios_buf_mode bm){ s->bm = bm; if(s->bm == IOS_BUF_MEM || s->bm == IOS_BUF_NONE){ s->buf = &s->local[0]; s->maxsize = IOS_INLSIZE; }else{ s->buf = nil; buf_realloc(s, IOS_BUFSIZE); } s->size = s->bpos = 0;} u8int *ios_takebuf(ios *s, usize *psize){ u8int *buf; ios_flush(s); if(sl_unlikely(s->buf == &s->local[0] || s->buf == nil || ((s->flags & IOS_FL_OWNBUF) == 0 && s->size == s->maxsize))){ buf = MEM_ALLOC(s->size+1); if(buf == nil) return nil; if(s->buf != nil) memcpy(buf, s->buf, s->size); }else if(sl_unlikely(s->size == s->maxsize)){ buf = MEM_REALLOC(s->buf, s->size + 1); if(sl_unlikely(buf == nil)) return nil; }else{ buf = s->buf; } buf[s->size] = '\0'; *psize = s->size + 1; /* empty io and reinitialize */ buf_init(s, s->bm); return buf;} intios_setbuf(ios *s, u8int *buf, usize size, bool own){ ios_flush(s); usize nvalid = size < s->size ? size : s->size; if(nvalid > 0) memcpy(buf, s->buf, nvalid); if(s->bpos > nvalid){ // truncated s->bpos = nvalid; } s->size = nvalid; if((s->flags & IOS_FL_OWNBUF) != 0 && s->buf != &s->local[0]) MEM_FREE(s->buf); s->buf = buf; s->maxsize = size;Lines 1–500 of 898. Load more
#include "inc/priv.h" #include "inc/str.h" #include "inc/time.h" #define MOST_OF(x) ((x) - ((x)>>4)) ios *ios_stdin = nil; ios *ios_stdout = nil; ios *ios_stderr = nil; /* OS-level primitive wrappers */ void * sl_memrchr(const void *s, int c, usize n) { const u8int *src = (const u8int*)s + n; u8int uc = c; while(--src >= (const u8int*)s) if(*src == uc) return (void *)src; return nil; } sl_fd_wr(1) sl_rd(2, 3) sl_wr(4) sl_nonnull(2, 4) static int write_all(int fd, const u8int *buf, usize n, usize *nwritten) { usize wrote; *nwritten = 0; while(n > 0){ wrote = 0; int err = sys_write(fd, buf, n, &wrote); n -= wrote; *nwritten += wrote; buf += wrote; if(err) return err; } return 0; } /* internal utility functions */ sl_nonnull(1) static u8int * buf_realloc(ios *s, usize sz) { u8int *temp; if((s->buf == nil || s->buf == &s->local[0]) && sz <= IOS_INLSIZE){ /* TODO: if we want to allow shrinking, see if the buffer shrank down to this size, in which case we need to copy. */ s->buf = &s->local[0]; s->maxsize = IOS_INLSIZE; s->flags |= IOS_FL_OWNBUF; return s->buf; } if(sz <= s->maxsize) return s->buf; if((s->flags & IOS_FL_OWNBUF) != 0 && s->buf != &s->local[0]){ // if we own the buffer we're free to resize it // always allocate 1 bigger in case user wants to add a NUL // terminator after taking over the buffer temp = MEM_REALLOC(s->buf, sz); if(temp == nil) return nil; }else{ temp = MEM_ALLOC(sz); if(temp == nil) return nil; s->flags |= IOS_FL_OWNBUF; if(s->buf != nil) memcpy(temp, s->buf, s->size); } s->buf = temp; s->maxsize = sz; return s->buf; } // write a block of data into the buffer at the current position, resizing // if necessary. returns # written. sl_nonnull(1, 2) sl_rd(2, 3) static usize write_grow(ios *s, const void *data, usize n) { usize amt; usize newsize; if(sl_unlikely(n == 0)) return 0; if(sl_likely(s->bpos + n > s->size)){ if(sl_unlikely(s->bpos + n > s->maxsize)){ /* TODO: here you might want to add a mechanism for limiting the growth of the io. */ newsize = s->maxsize ? s->maxsize * 2 : 8; while(s->bpos + n > newsize) newsize *= 2; if(buf_realloc(s, newsize) == nil){ /* no more space; write as much as we can */ amt = s->maxsize - s->bpos; if(amt > 0) memcpy(&s->buf[s->bpos], data, amt); s->bpos += amt; s->size = s->maxsize; return amt; } } s->size = s->bpos + n; } memcpy(s->buf + s->bpos, data, n); s->bpos += n; return n; } /* interface functions, low level */ usize ios_read(ios *s, void *dest, usize n) { usize tot = 0; usize got, avail; if(s->state == IOS_STATE_CLOSED || (s->flags & IOS_FL_WRONLY) != 0) return 0; while(n > 0){ avail = s->size - s->bpos; if(avail > 0){ usize ncopy = avail >= n ? n : avail; memcpy(dest, s->buf + s->bpos, ncopy); s->bpos += ncopy; if(ncopy >= n){ s->state = IOS_STATE_RD; return tot+ncopy; } } if(s->bm == IOS_BUF_MEM || s->fd == -1){ // can't get any more data s->state = IOS_STATE_RD; if(avail == 0) s->flags |= IOS_FL_EOF; return avail; } dest = (u8int*)dest + avail; n -= avail; tot += avail; ios_flush(s); s->bpos = s->size = 0; s->state = IOS_STATE_RD; got = 0; if(n > MOST_OF(s->maxsize)){ // doesn't fit comfortably in buffer; go direct sys_read(s->fd, dest, n, &got); tot += got; if(got == 0) s->flags |= IOS_FL_EOF; return tot; } // refill buffer if(sys_read(s->fd, s->buf, s->maxsize, &got) != 0 || got == 0){ s->flags |= IOS_FL_EOF; return tot; } s->size = got; } return tot; } // ensure at least n bytes are buffered if possible. returns # available. usize ios_readprep(ios *s, usize n) { if((s->flags & IOS_FL_WRONLY) != 0) return 0; if(s->state == IOS_STATE_WR && s->bm != IOS_BUF_MEM){ ios_flush(s); s->bpos = s->size = 0; } usize space = s->size - s->bpos; s->state = IOS_STATE_RD; if(space >= n || s->bm == IOS_BUF_MEM || s->fd == -1) return space; if(s->maxsize < s->bpos+n){ // it won't fit. grow buffer or move data back. if(n <= s->maxsize && space <= ((s->maxsize)>>2)){ if(space) memmove(s->buf, s->buf+s->bpos, space); s->size -= s->bpos; s->bpos = 0; } else { if(buf_realloc(s, s->bpos + n) == nil) return space; } } usize got; int result = sys_read(s->fd, s->buf+s->size, s->maxsize - s->size, &got); if(result != 0) return space; s->size += got; return s->size - s->bpos; } sl_nonnull(1) static void write_update_pos(ios *s) { if(sl_likely(s->bpos > s->ndirty)) s->ndirty = s->bpos; if(s->bpos > s->size) s->size = s->bpos; } usize ios_write(ios *s, const void *data, usize n) { if(sl_unlikely((s->flags & IOS_FL_RDONLY) != 0 || s->state == IOS_STATE_CLOSED || n == 0)) return 0; usize space, wrote = 0; if(sl_unlikely(s->state == IOS_STATE_NONE)) s->state = IOS_STATE_WR; if(sl_unlikely(s->state == IOS_STATE_RD)){ if((s->flags & IOS_FL_REREADABLE) == 0){ s->size = 0; s->bpos = 0; } space = s->size - s->bpos; }else{ space = s->maxsize - s->bpos; } if(sl_likely(s->bm == IOS_BUF_MEM)){ wrote = write_grow(s, data, n); }else if(sl_unlikely(s->bm == IOS_BUF_NONE)){ write_all(s->fd, data, n, &wrote); return wrote; }else if(sl_likely(n <= space)){ if(s->bm == IOS_BUF_LINE){ const char *nl; if(sl_unlikely((nl = sl_memrchr(data, '\n', n)) != nil)){ usize linesz = nl-(const char*)data+1; s->bm = IOS_BUF_BLOCK; wrote += ios_write(s, data, linesz); ios_flush(s); s->bm = IOS_BUF_LINE; n -= linesz; data = (const char*)data + linesz; } } memcpy(s->buf + s->bpos, data, n); s->bpos += n; wrote += n; }else{ s->state = IOS_STATE_WR; ios_flush(s); if(n > MOST_OF(s->maxsize)){ write_all(s->fd, data, n, &wrote); return wrote; } return ios_write(s, data, n); } write_update_pos(s); return wrote; } soffset ios_seek(ios *s, soffset pos) { if(sl_unlikely(s->state == IOS_STATE_CLOSED || pos < 0)) return -1; s->flags &= ~IOS_FL_EOF; if(sl_likely(s->bm == IOS_BUF_MEM)){ if((usize)pos >= s->size) pos = s->size; s->bpos = pos; }else{ ios_flush(s); s->bpos = s->size = 0; soffset fdpos = sys_seek(s->fd, pos, SEEK_SET); if(fdpos < 0) return -1; pos = fdpos; } s->loc.lineno = 1; s->loc.colno = 0; return pos; } soffset ios_seek_end(ios *s) { if(sl_unlikely(s->state == IOS_STATE_CLOSED)) return -1; s->flags |= IOS_FL_EOF; if(s->bm == IOS_BUF_MEM) s->bpos = s->size; else{ ios_flush(s); soffset fdpos = sys_seek(s->fd, 0, SEEK_END); if(fdpos == (soffset)-1) return fdpos; s->bpos = s->size = 0; } s->loc.lineno = 1; s->loc.colno = 0; return 0; } soffset ios_skip(ios *s, soffset offs, bool end) { if(sl_unlikely(s->state == IOS_STATE_CLOSED)) return -1; if(sl_unlikely(end && ios_seek_end(s) < 0)) return -1; s->flags &= ~IOS_FL_EOF; if(s->bm == IOS_BUF_MEM){ if(offs > 0){ if(offs <= (soffset)(s->size-s->bpos)) s->bpos += offs; else s->bpos = s->size; }else if(offs < 0){ if((soffset)s->bpos+offs >= 0) s->bpos += offs; else s->bpos = 0; } return s->bpos; } ios_flush(s); s->bpos = s->size = 0; return sys_seek(s->fd, offs, SEEK_CUR); } int ios_trunc(ios *s, soffset size) { if(sl_unlikely(s->state == IOS_STATE_CLOSED || (s->flags & IOS_FL_RDONLY) != 0 || size < 0)) return -1; if(s->bm == IOS_BUF_MEM){ if(sl_unlikely((usize)size == s->size)) return 0; if(sl_likely((usize)size < s->size)){ if(s->bpos > (usize)size) s->bpos = size; }else if(sl_unlikely(buf_realloc(s, size) == nil)) return -1; s->size = size; return 0; } return sl_likely(ios_flush(s) == 0) ? ftruncate(s->fd, size) : -1; } int ios_flush(ios *s) { if(s->ndirty == 0 || s->bm == IOS_BUF_MEM || s->buf == nil) return 0; if(sl_unlikely(s->fd == -1)) return -1; if(sl_unlikely(s->state == IOS_STATE_RD)){ if(sys_seek(s->fd, -(soffset)s->size, SEEK_CUR) == (soffset)-1){ // FIXME eh? } return -1; } usize nw, ntowrite = s->ndirty; int err = write_all(s->fd, s->buf, ntowrite, &nw); // todo: try recovering from some kinds of errors (e.g. retry) if(sl_unlikely(s->state == IOS_STATE_RD)){ if(sys_seek(s->fd, s->size - nw, SEEK_CUR) == (soffset)-1){ // FIXME eh? } return -1; }else if(s->state == IOS_STATE_WR){ if(s->bpos != nw && sys_seek(s->fd, (soffset)s->bpos - (soffset)nw, SEEK_CUR) == (soffset)-1){ // FIXME eh? } // now preserve the invariant that data to write // begins at the beginning of the buffer, and s->size refers // to how much valid file data is stored in the buffer. if(sl_unlikely(s->size > s->ndirty)){ usize delta = s->size - s->ndirty; memmove(s->buf, s->buf + s->ndirty, delta); } s->size -= s->ndirty; s->bpos = 0; } s->ndirty = 0; if(sl_unlikely(err)) return err; if(sl_unlikely(nw < ntowrite)) return -1; return 0; } void ios_close(ios *s) { if(sl_unlikely(s->state == IOS_STATE_CLOSED)) return; ios_flush(s); if(sl_unlikely(s->fd != -1 && (s->flags & IOS_FL_OWNFD) != 0)) sys_close(s->fd); s->fd = -1; s->data = sl_nil; if((s->flags & IOS_FL_OWNBUF) != 0 && s->buf != &s->local[0]) MEM_FREE(s->buf); s->buf = nil; s->size = s->maxsize = s->bpos = 0; s->state = IOS_STATE_CLOSED; } void ios_free(ios *s) { MEM_FREE(s->filename); s->filename = nil; } sl_nonnull(1) static void buf_init(ios *s, ios_buf_mode bm) { s->bm = bm; if(s->bm == IOS_BUF_MEM || s->bm == IOS_BUF_NONE){ s->buf = &s->local[0]; s->maxsize = IOS_INLSIZE; }else{ s->buf = nil; buf_realloc(s, IOS_BUFSIZE); } s->size = s->bpos = 0; } u8int * ios_takebuf(ios *s, usize *psize) { u8int *buf; ios_flush(s); if(sl_unlikely(s->buf == &s->local[0] || s->buf == nil || ((s->flags & IOS_FL_OWNBUF) == 0 && s->size == s->maxsize))){ buf = MEM_ALLOC(s->size+1); if(buf == nil) return nil; if(s->buf != nil) memcpy(buf, s->buf, s->size); }else if(sl_unlikely(s->size == s->maxsize)){ buf = MEM_REALLOC(s->buf, s->size + 1); if(sl_unlikely(buf == nil)) return nil; }else{ buf = s->buf; } buf[s->size] = '\0'; *psize = s->size + 1; /* empty io and reinitialize */ buf_init(s, s->bm); return buf; } int ios_setbuf(ios *s, u8int *buf, usize size, bool own) { ios_flush(s); usize nvalid = size < s->size ? size : s->size; if(nvalid > 0) memcpy(buf, s->buf, nvalid); if(s->bpos > nvalid){ // truncated s->bpos = nvalid; } s->size = nvalid; if((s->flags & IOS_FL_OWNBUF) != 0 && s->buf != &s->local[0]) MEM_FREE(s->buf); s->buf = buf; s->maxsize = size;