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);
+}