Mercurial > repo
view src/ploki/IO.c @ 7072:53e47c85558e
<oerjan> learn optional.
author | HackBot |
---|---|
date | Thu, 03 Mar 2016 00:05:00 +0000 |
parents | ac0403686959 |
children |
line wrap: on
line source
#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); }