some fixes to ios

This commit is contained in:
JeffBezanson 2012-01-17 04:31:08 +00:00
parent 3d25a1a672
commit 21dd640454
2 changed files with 110 additions and 90 deletions

176
llt/ios.c
View File

@ -45,20 +45,6 @@ void *memrchr(const void *s, int c, size_t n)
extern void *memrchr(const void *s, int c, size_t n);
#endif
static int _fd_available(long fd)
{
#ifndef WIN32
fd_set set;
struct timeval tv = {0, 0};
FD_ZERO(&set);
FD_SET(fd, &set);
return (select(fd+1, &set, NULL, NULL, &tv)!=0);
#else
return 1;
#endif
}
// poll for read, unless forwrite!=0
static void _fd_poll(long fd, int forwrite)
{
@ -115,10 +101,8 @@ static int _os_read_all(long fd, void *buf, size_t n, size_t *nread)
n -= got;
*nread += got;
buf += got;
if (err)
if (err || got==0)
return err;
if (got == 0)
_fd_poll(fd, 0);
}
return 0;
}
@ -155,8 +139,6 @@ static int _os_write_all(long fd, void *buf, size_t n, size_t *nwritten)
buf += wrote;
if (err)
return err;
if (wrote == 0)
_fd_poll(fd, 1);
}
return 0;
}
@ -274,6 +256,7 @@ static size_t _ios_read(ios_t *s, char *dest, size_t n, int all)
s->bpos = s->size = 0;
s->state = bst_rd;
s->fpos = -1;
if (n > MOST_OF(s->maxsize)) {
// doesn't fit comfortably in buffer; go direct
if (all)
@ -281,7 +264,7 @@ static size_t _ios_read(ios_t *s, char *dest, size_t n, int all)
else
result = _os_read(s->fd, dest, n, &got);
tot += got;
if (got < n)
if (got == 0)
s->_eof = 1;
return tot;
}
@ -292,14 +275,9 @@ static size_t _ios_read(ios_t *s, char *dest, size_t n, int all)
return tot;
}
if (got == 0) {
if (all) {
_fd_poll(s->fd, 0);
}
else {
s->_eof = 1;
return tot;
}
}
s->size = got;
}
}
@ -377,6 +355,7 @@ size_t ios_write(ios_t *s, char *data, size_t n)
wrote = _write_grow(s, data, n);
}
else if (s->bm == bm_none) {
s->fpos = -1;
_os_write_all(s->fd, data, n, &wrote);
return wrote;
}
@ -417,24 +396,67 @@ off_t ios_seek(ios_t *s, off_t pos)
if ((size_t)pos > s->size)
return -1;
s->bpos = pos;
return s->bpos;
}
// TODO
else {
ios_flush(s);
off_t fdpos = lseek(s->fd, pos, SEEK_SET);
if (fdpos == (off_t)-1)
return fdpos;
s->bpos = s->size = 0;
}
return 0;
}
off_t ios_seek_end(ios_t *s)
{
s->_eof = 1;
// TODO
if (s->bm == bm_mem) {
s->bpos = s->size;
}
else {
ios_flush(s);
off_t fdpos = lseek(s->fd, 0, SEEK_END);
if (fdpos == (off_t)-1)
return fdpos;
s->bpos = s->size = 0;
}
return 0;
}
off_t ios_skip(ios_t *s, off_t offs)
{
if (offs < 0)
if (offs != 0) {
if (offs > 0) {
if (offs <= (off_t)(s->size-s->bpos)) {
s->bpos += offs;
return 0;
}
else if (s->bm == bm_mem) {
// TODO: maybe grow buffer
return -1;
}
}
else if (offs < 0) {
if (-offs <= (off_t)s->bpos) {
s->bpos += offs;
s->_eof = 0;
// TODO
return 0;
}
else if (s->bm == bm_mem) {
return -1;
}
}
ios_flush(s);
if (s->state == bst_wr)
offs += s->bpos;
else if (s->state == bst_rd)
offs -= (s->size - s->bpos);
off_t fdpos = lseek(s->fd, offs, SEEK_CUR);
if (fdpos == (off_t)-1)
return fdpos;
s->bpos = s->size = 0;
s->_eof = 0;
}
return 0;
}
@ -443,9 +465,13 @@ off_t ios_pos(ios_t *s)
if (s->bm == bm_mem)
return (off_t)s->bpos;
off_t fdpos = lseek(s->fd, 0, SEEK_CUR);
off_t fdpos = s->fpos;
if (fdpos == (off_t)-1) {
fdpos = lseek(s->fd, 0, SEEK_CUR);
if (fdpos == (off_t)-1)
return fdpos;
s->fpos = fdpos;
}
if (s->state == bst_wr)
fdpos += s->bpos;
@ -483,30 +509,6 @@ int ios_eof(ios_t *s)
if (s->_eof)
return 1;
return 0;
/*
if (_fd_available(s->fd))
return 0;
s->_eof = 1;
return 1;
*/
}
static void _discard_partial_buffer(ios_t *s)
{
// this function preserves 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.
// this needs to be called when normal operation is interrupted in
// the middle of the buffer. "normal operation" is reading or
// writing to the end of the buffer. this happens e.g. when flushing.
size_t delta = 0;
if (s->ndirty && s->size > s->ndirty) {
delta = s->size - s->ndirty;
memmove(s->buf, s->buf + s->ndirty, delta);
}
s->size -= s->ndirty;
s->bpos -= s->ndirty;
}
int ios_flush(ios_t *s)
@ -522,6 +524,7 @@ int ios_flush(ios_t *s)
}
size_t nw, ntowrite=s->ndirty;
s->fpos = -1;
int err = _os_write_all(s->fd, s->buf, ntowrite, &nw);
// todo: try recovering from some kinds of errors (e.g. retry)
@ -533,12 +536,17 @@ int ios_flush(ios_t *s)
if (s->bpos != nw &&
lseek(s->fd, (off_t)s->bpos - (off_t)nw, SEEK_CUR) == (off_t)-1) {
}
// 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 (s->size > s->ndirty) {
size_t delta = s->size - s->ndirty;
memmove(s->buf, s->buf + s->ndirty, delta);
}
s->size -= s->ndirty;
s->bpos = 0;
}
if (s->ndirty <= s->bpos) {
// in this case assume we're done with the first part of the buffer
_discard_partial_buffer(s);
}
s->ndirty = 0;
if (err)
@ -639,11 +647,6 @@ void ios_set_readonly(ios_t *s)
s->readonly = 1;
}
void ios_bswap(ios_t *s, int bswap)
{
s->byteswap = !!bswap;
}
static size_t ios_copy_(ios_t *to, ios_t *from, size_t nbytes, bool_t all)
{
size_t total = 0, avail;
@ -686,16 +689,21 @@ size_t ios_copyall(ios_t *to, ios_t *from)
size_t ios_copyuntil(ios_t *to, ios_t *from, char delim)
{
size_t total = 0, avail;
size_t total = 0, avail=from->size - from->bpos;
int first = 1;
if (!ios_eof(from)) {
do {
if (avail == 0) {
first = 0;
avail = ios_readprep(from, LINE_CHUNK_SIZE);
}
size_t written;
char *pd = (char*)memchr(from->buf+from->bpos, delim, avail);
if (pd == NULL) {
written = ios_write(to, from->buf+from->bpos, avail);
from->bpos += avail;
total += written;
avail = 0;
}
else {
size_t ntowrite = pd - (from->buf+from->bpos) + 1;
@ -704,7 +712,7 @@ size_t ios_copyuntil(ios_t *to, ios_t *from, char delim)
total += written;
return total;
}
} while (!ios_eof(from) && avail >= LINE_CHUNK_SIZE);
} while (!ios_eof(from) && (first || avail >= LINE_CHUNK_SIZE));
}
from->_eof = 1;
return total;
@ -721,9 +729,9 @@ static void _ios_init(ios_t *s)
s->size = 0;
s->bpos = 0;
s->ndirty = 0;
s->tally = 0;
s->fpos = -1;
s->lineno = 1;
s->fd = -1;
s->byteswap = 0;
s->ownbuf = 1;
s->ownfd = 0;
s->_eof = 0;
@ -745,8 +753,7 @@ ios_t *ios_file(ios_t *s, char *fname, int rd, int wr, int create, int trunc)
fd = open(fname, flags, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH/*644*/);
if (fd == -1)
goto open_file_err;
s = ios_fd(s, fd, 1);
s->ownfd = 1;
s = ios_fd(s, fd, 1, 1);
if (!wr)
s->readonly = 1;
return s;
@ -781,13 +788,15 @@ ios_t *ios_static_buffer(ios_t *s, char *buf, size_t sz)
return s;
}
ios_t *ios_fd(ios_t *s, long fd, int isfile)
ios_t *ios_fd(ios_t *s, long fd, int isfile, int own)
{
_ios_init(s);
s->fd = fd;
if (isfile) s->rereadable = 1;
_buf_init(s, bm_block);
s->ownfd = 0;
s->ownfd = own;
if (fd == STDERR_FILENO)
s->bm = bm_none;
return s;
}
@ -798,14 +807,14 @@ ios_t *ios_stderr = NULL;
void ios_init_stdstreams()
{
ios_stdin = LLT_ALLOC(sizeof(ios_t));
ios_fd(ios_stdin, STDIN_FILENO, 0);
ios_fd(ios_stdin, STDIN_FILENO, 0, 0);
ios_stdout = LLT_ALLOC(sizeof(ios_t));
ios_fd(ios_stdout, STDOUT_FILENO, 0);
ios_fd(ios_stdout, STDOUT_FILENO, 0, 0);
ios_stdout->bm = bm_line;
ios_stderr = LLT_ALLOC(sizeof(ios_t));
ios_fd(ios_stderr, STDERR_FILENO, 0);
ios_fd(ios_stderr, STDERR_FILENO, 0, 0);
ios_stderr->bm = bm_none;
}
@ -836,6 +845,7 @@ int ios_getc(ios_t *s)
if (ios_read(s, &ch, 1) < 1)
return IOS_EOF;
}
if (ch == '\n') s->lineno++;
return (unsigned char)ch;
}
@ -935,18 +945,30 @@ void ios_purge(ios_t *s)
}
}
char *ios_readline(ios_t *s)
{
ios_t dest;
ios_mem(&dest, 0);
ios_copyuntil(&dest, s, '\n');
size_t n;
return ios_takebuf(&dest, &n);
}
int vasprintf(char **strp, const char *fmt, va_list ap);
int ios_vprintf(ios_t *s, const char *format, va_list args)
{
char *str=NULL;
int c;
va_list al;
va_copy(al, args);
if (s->state == bst_wr && s->bpos < s->maxsize && s->bm != bm_none) {
size_t avail = s->maxsize - s->bpos;
char *start = s->buf + s->bpos;
c = vsnprintf(start, avail, format, args);
if (c < 0) {
va_end(al);
return c;
}
if (c < avail) {
@ -955,16 +977,18 @@ int ios_vprintf(ios_t *s, const char *format, va_list args)
// TODO: only works right if newline is at end
if (s->bm == bm_line && memrchr(start, '\n', (size_t)c))
ios_flush(s);
va_end(al);
return c;
}
}
c = vasprintf(&str, format, args);
c = vasprintf(&str, format, al);
if (c >= 0) {
ios_write(s, str, c);
LLT_FREE(str);
}
va_end(al);
return c;
}

View File

@ -11,7 +11,7 @@ typedef enum { bm_none, bm_line, bm_block, bm_mem } bufmode_t;
typedef enum { bst_none, bst_rd, bst_wr } bufstate_t;
#define IOS_INLSIZE 54
#define IOS_BUFSIZE 8191
#define IOS_BUFSIZE 131072
typedef struct {
bufmode_t bm;
@ -29,17 +29,13 @@ typedef struct {
size_t bpos; // current position in buffer
size_t ndirty; // # bytes at &buf[0] that need to be written
// this is a public field that keeps a running count of bytes
// read or written. you can freely use and change it. this is
// intended for keeping track of relative positions in streams
// that don't have absolute positions (like sockets).
size_t tally;
off_t fpos; // cached file pos
size_t lineno; // current line number
// pointer-size integer to support platforms where it might have
// to be a pointer
long fd;
unsigned char byteswap:1;
unsigned char readonly:1;
unsigned char ownbuf:1;
unsigned char ownfd:1;
@ -79,7 +75,6 @@ char *ios_takebuf(ios_t *s, size_t *psize); // release buffer to caller
int ios_setbuf(ios_t *s, char *buf, size_t size, int own);
int ios_bufmode(ios_t *s, bufmode_t mode);
void ios_set_readonly(ios_t *s);
void ios_bswap(ios_t *s, int bswap);
size_t ios_copy(ios_t *to, ios_t *from, size_t nbytes);
size_t ios_copyall(ios_t *to, ios_t *from);
size_t ios_copyuntil(ios_t *to, ios_t *from, char delim);
@ -94,7 +89,7 @@ ios_t *ios_file(ios_t *s, char *fname, int rd, int wr, int create, int trunc);
ios_t *ios_mem(ios_t *s, size_t initsize);
ios_t *ios_str(ios_t *s, char *str);
ios_t *ios_static_buffer(ios_t *s, char *buf, size_t sz);
ios_t *ios_fd(ios_t *s, long fd, int isfile);
ios_t *ios_fd(ios_t *s, long fd, int isfile, int own);
// todo: ios_socket
extern ios_t *ios_stdin;
extern ios_t *ios_stdout;
@ -119,6 +114,7 @@ int ios_ungetutf8(ios_t *s, uint32_t wc);
int ios_getstringz(ios_t *dest, ios_t *src);
int ios_getstringn(ios_t *dest, ios_t *src, size_t nchars);
int ios_getline(ios_t *s, char **pbuf, size_t *psz);
char *ios_readline(ios_t *s);
// discard data buffered for reading
void ios_purge(ios_t *s);