Mercurial > repo
diff src/ploki/IO.c @ 4223:ac0403686959
<oerjan> rm -rf src/ploki; mv ploki src
author | HackBot |
---|---|
date | Fri, 20 Dec 2013 22:18:50 +0000 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ploki/IO.c Fri Dec 20 22:18:50 2013 +0000 @@ -0,0 +1,515 @@ +#include "config.h" +#include "IO.h" +#include "Str.h" +#include "main.h" +#include "main_io.h" +#include "xmalloc.h" +#include "zz.h" + +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> + +struct IO { + struct IO *prev, *next; + enum io_flags mode; + FILE *fp; + char *name; + size_t refs; + String *buf; + long told; + enum { + DI_NONE, + DI_RD, + DI_WR + } dirct; +}; + +static IO *Root; + +static void sanitycheck(enum io_flags m) { + #if !DEBUG_P + (void)m; + #endif + assert( + ( + m & IO_READ || + m & IO_WRITE || + m & IO_APPEND + ) && + !( + m & IO_WRITE && + m & IO_APPEND + ) && + ( + !(m & IO_BUFFERED) || m & IO_READ + ) && + ( + !(m & IO_AUTOFLUSH) || + ( + m & IO_WRITE || + m & IO_APPEND + ) + ) && + ( + !(m & IO_WRITE) || (m & IO_TRUNCATE || m & IO_READ) + ) && + ( + !(m & IO_TRUNCATE) || m & IO_WRITE + ) + ); +} + +void io_init(void) { +} + +static void io_delete(IO *io) { + if (io->mode & IO_BUFFERED) { + St_clear(io->buf); + xfree(io->buf); + } + if (io->fp && io->fp != stderr) { + if (fclose(io->fp)) { + fprintf(io_fp(Err), "%s: %s: %s\n", Prog, io->name, strerror(errno)); + } + } + xfree(io->name); + if (io->prev) { + io->prev->next = io->next; + } else { + assert(io == Root); + Root = io->next; + } + if (io->next) { + io->next->prev = io->prev; + } + xfree(io); +} + +void io_end(void) { + while (Root) { + io_delete(Root); + } +} + +static char *xstrdup(const char *s) { + const size_t len = strlen(s) + 1; + char *const tmp = xmalloc(len, sizeof *tmp); + memcpy(tmp, s, len); + return tmp; +} + +IO *io_enter(const char *name, FILE *fp, enum io_flags mode) { + IO *io; + sanitycheck(mode); + io = xmalloc(1, sizeof *io); + io->fp = fp; + io->mode = mode; + if (mode & IO_BUFFERED) { + io->buf = xmalloc(1, sizeof *io->buf); + St_init(io->buf); + io->told = -1; + } + io->name = xstrdup(name); + io->refs = 1; + + io->dirct = DI_NONE; + + io->prev = NULL; + io->next = Root; + if (Root) { + Root->prev = io; + } + Root = io; + return io; +} + +const char *io_name(const IO *io, String *s) { + if (s) { + St_cpy_s(s, io->name); + } + return io->name; +} + +IO *io_open(const char *name, enum io_flags mode) { + FILE *fp; + char mbuf[4], *p = mbuf; + sanitycheck(mode); + + if (mode & IO_APPEND) { + *p++ = 'a'; + if (mode & IO_READ) { + *p++ = '+'; + } + } else if (mode & IO_WRITE) { + if (mode & IO_TRUNCATE) { + *p++ = 'w'; + if (mode & IO_READ) { + *p++ = '+'; + } + } else { + assert(mode & IO_READ); + *p++ = 'r'; + *p++ = '+'; + } + } else { + assert(mode & IO_READ); + *p++ = 'r'; + } + + if (mode & IO_BINARY) { + *p++ = 'b'; + } + *p = '\0'; + + if (!(fp = fopen(name, mbuf))) { + return NULL; + } + return io_enter(name, fp, mode); +} + +IO *io_incr(IO *io) { + ++io->refs; + return io; +} + +void io_decr(IO *io) { + if (!--io->refs) { + io_delete(io); + } +} + +int io_close(IO *io) { + int ret; + assert(io->fp != NULL); + ret = fclose(io->fp); + io->fp = NULL; + if (io->mode & IO_BUFFERED) { + St_clear(io->buf); + xfree(io->buf); + io->mode &= ~IO_BUFFERED; + } + return ret; +} + +int io_bufred(const IO *io) { + return !!(io->mode & IO_BUFFERED); +} + +void io_unbuffer(IO *io) { + assert(io->mode & IO_BUFFERED); + if (St_len(io->buf) && io->told != -1) { + io_seek(io, io->told, SEEK_SET); + } + St_clear(io->buf); + xfree(io->buf); + io->mode &= ~IO_BUFFERED; +} + +FILE *io_fp(const IO *io) { + return io->fp; +} + +static void bufk(IO *f, size_t n) { + String tmp; + assert(f->mode & IO_BUFFERED); + + if (St_len(f->buf) >= n || feof(f->fp) || ferror(f->fp)) { + return; + } + + assert(f->dirct != DI_WR); + #if 0 + if (f->dirct == DI_WR) { + io_seek(f, 0, SEEK_CUR); + } + f->dirct = DI_RD; + #endif + + if (!(St_len(f->buf) || f->mode & IO_BINARY)) { + f->told = ftell(f->fp); + } + + St_init(&tmp); + while ( + St_len(f->buf) < n && + !feof(f->fp) && !ferror(f->fp) && + St_read(&tmp, f->fp, n - St_len(f->buf)) + ) { + St_cat(f->buf, &tmp); + } + St_clear(&tmp); +} + +#ifdef EBADF + #define BADF ((void)(errno = EBADF)) +#else + #define BADF ((void)0) +#endif + +#define XMODE(c, x) \ +do { \ + if (!(c)) { \ + BADF; \ + return (x); \ + } \ +} while (0) + +#define WMODE(f, x) XMODE((f)->mode & IO_WRITE || (f)->mode & IO_APPEND, (x)) +#define PMODE(f, x) XMODE((f)->mode & IO_BUFFERED, (x)) +#define RMODE(f, x) XMODE((f)->mode & IO_READ, (x)) + +const char *io_bufptr(IO *io) { + PMODE(io, NULL); + return St_ptr(io->buf); +} + +int io_flush(IO *f) { + WMODE(f, EOF); + return fflush(f->fp); +} + +int io_err(const IO *f) { + return ferror(f->fp); +} + +int io_eof(const IO *f) { + return feof(f->fp); +} + +int io_peek(IO *f, size_t pos) { + PMODE(f, EOF); + bufk(f, pos + 1); + if (St_len(f->buf) <= pos) { + return EOF; + } + return ST_INDEX(f->buf, pos); +} + +int io_cmppeek(IO *f, size_t o, const void *p, size_t n) { + size_t i; + PMODE(f, -1); + + for (i = 0; i < n; ++i) { + bufk(f, o + i + 1u); + if (ST_INDEX(f->buf, o + i) != i[(const unsigned char *)p]) { + return 1; + } + } + return 0; +} + +int io_xcmp(IO *f, size_t a, size_t b, size_t n) { + const size_t max = a > b ? a : b; + PMODE(f, -1); + bufk(f, max + n); + if (St_len(f->buf) < max + n) { + return 1; + } + return memcmp(St_ptr(f->buf) + a, St_ptr(f->buf) + b, n) != 0; +} + +size_t io_read(IO *f, String *s, size_t n) { + RMODE(f, -1); + + if (f->mode & IO_BUFFERED) { + String null; + size_t old; + + bufk(f, n); + old = St_len(f->buf); + St_init(&null); + St_substr(s, f->buf, 0, n, &null); + St_clear(&null); + old -= St_len(f->buf); + if (St_len(f->buf) && old && !(f->mode & IO_BINARY) && f->told != -1) { + const long keep = ftell(f->fp); + if (fseek(f->fp, f->told, SEEK_SET) != -1) { + size_t i; + for (i = 0; i < old; ++i) { + getc(f->fp); + } + f->told = ftell(f->fp); + f->dirct = DI_RD; + fseek(f->fp, keep, SEEK_SET); + } + } + return old; + } else { + if (f->dirct == DI_WR) { + fseek(f->fp, 0, SEEK_CUR); + } + f->dirct = DI_RD; + return St_read(s, f->fp, n); + } +} + +int io_getc(IO *f) { + RMODE(f, EOF); + + if (f->mode & IO_BUFFERED) { + int c; + bufk(f, 1); + c = St_shift(f->buf); + if (St_len(f->buf) && c != EOF && !(f->mode & IO_BINARY) && f->told != -1) { + const long keep = ftell(f->fp); + if (fseek(f->fp, f->told, SEEK_SET) != -1) { + getc(f->fp); + f->told = ftell(f->fp); + f->dirct = DI_RD; + fseek(f->fp, keep, SEEK_SET); + } + } + return c; + } + + if (f->dirct == DI_WR) { + fseek(f->fp, 0, SEEK_CUR); + } + f->dirct = DI_RD; + return getc(f->fp); +} + +size_t io_getline(IO *f, String *s) { + RMODE(f, -1); + + if (f->mode & IO_BUFFERED) { + size_t p; + size_t old; + + p = St_chr(f->buf, '\n') + 1u; + if (p) { + old = St_len(f->buf); + if (s) { + St_cpy_m(s, St_ptr(f->buf), p); + } + St_del(f->buf, 0, p); + } else { + for (p = St_len(f->buf); io_peek(f, p) != EOF; ++p) { + if (ST_LASTCHAR(f->buf) == '\n') { + break; + } + } + old = St_len(f->buf); + if (s) { + St_cpy(s, f->buf); + } + St_zero(f->buf); + } + old -= St_len(f->buf); + if (St_len(f->buf) && old && !(f->mode & IO_BINARY) && f->told != -1) { + const long keep = ftell(f->fp); + if (fseek(f->fp, f->told, SEEK_SET) != -1) { + size_t i; + for (i = 0; i < old; ++i) { + getc(f->fp); + } + f->dirct = DI_RD; + f->told = ftell(f->fp); + fseek(f->fp, keep, SEEK_SET); + } + } + return old; + } else { + int c; + size_t n; + + if (f->dirct == DI_WR) { + fseek(f->fp, 0, SEEK_CUR); + } + f->dirct = DI_RD; + + if (s) { + St_zero(s); + } + n = 0; + while ((c = getc(f->fp)) != EOF) { + if (s) { + St_cat_c(s, c); + } + ++n; + if (c == '\n') { + break; + } + } + if (!n && ferror(f->fp)) { + return -1; + } + return n; + } +} + +size_t io_write(IO *f, const String *s) { + size_t ret; + WMODE(f, -1); + if (f->dirct == DI_RD) { + fseek(f->fp, 0, SEEK_CUR); + } + f->dirct = DI_WR; + ret = ST_WRITE(s, f->fp); + if (f->mode & IO_AUTOFLUSH) { + fflush(f->fp); + } + return ret; +} + +size_t io_write_m(IO *f, const void *p, size_t n) { + size_t ret; + WMODE(f, -1); + if (f->dirct == DI_RD) { + fseek(f->fp, 0, SEEK_CUR); + } + f->dirct = DI_WR; + ret = fwrite(p, 1, n, f->fp); + if (f->mode & IO_AUTOFLUSH) { + fflush(f->fp); + } + return ret; +} + +size_t io_write_s(IO *f, const char *s) { + return io_write_m(f, s, strlen(s)); +} + +int io_putc(IO *f, int c) { + int ret; + WMODE(f, EOF); + if (f->dirct == DI_RD) { + fseek(f->fp, 0, SEEK_CUR); + } + f->dirct = DI_WR; + ret = putc(c, f->fp); + if (f->mode & IO_AUTOFLUSH) { + fflush(f->fp); + } + return ret; +} + +long io_tell(IO *f) { + if (f->mode & IO_BUFFERED) { + if (f->mode & IO_BINARY) { + const long ret = ftell(f->fp); + if (ret == -1) { + return ret; + } + return ret - St_len(f->buf); + } + if (St_len(f->buf)) { + return f->told; + } + } + return ftell(f->fp); +} + +int io_seek(IO *f, long off, enum io_whence w) { + if (f->mode & IO_BUFFERED) { + St_zero(f->buf); + } + f->dirct = DI_NONE; + return fseek(f->fp, off, w); +} + +void io_clearerr(IO *f) { + clearerr(f->fp); +}