summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--bin/edi/edi.c28
-rw-r--r--bin/edi/edi.h13
-rw-r--r--bin/edi/store.c193
3 files changed, 194 insertions, 40 deletions
diff --git a/bin/edi/edi.c b/bin/edi/edi.c
index e8024073..a0231785 100644
--- a/bin/edi/edi.c
+++ b/bin/edi/edi.c
@@ -14,7 +14,9 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
+#include <err.h>
 #include <locale.h>
+#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sysexits.h>
@@ -28,6 +30,32 @@ int main(int argc, char *argv[]) {
 
 	struct File file = fileAlloc(strdup(argv[1]));
 	fileRead(&file);
+	
+	struct Edit edit = { file.buf, file.log };
+
+	FILE *store = fopen("store.edi", "w");
+	if (!store) err(EX_CANTCREAT, "store.edi");
+
+	enum Error error = storeWrite(store, &edit);
+	if (error) {
+		if (error > Errno) errc(EX_IOERR, error - Errno, "store.edi");
+		else errx(EX_IOERR, "store.edi: %d", error);
+	}
+
+	fclose(store);
+	if (ferror(store)) err(EX_IOERR, "store.edi");
+
+	store = fopen("store.edi", "r");
+	if (!store) err(EX_CANTCREAT, "store.edi");
+
+	error = storeRead(store, &edit);
+	if (error) {
+		if (error > Errno) errc(EX_IOERR, error - Errno, "store.edi");
+		else errx(EX_DATAERR, "store.edi: %d", error);
+	}
+
+	file.buf = edit.buf;
+	file.log = edit.log;
 
 	const struct Table *table = logTable(&file.log);
 	for (struct Iter it = iter(table, 0); it.ch != WEOF; it = iterNext(it)) {
diff --git a/bin/edi/edi.h b/bin/edi/edi.h
index f335d1bd..bdcc6496 100644
--- a/bin/edi/edi.h
+++ b/bin/edi/edi.h
@@ -14,7 +14,6 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <wchar.h>
@@ -94,8 +93,16 @@ struct Edit {
 	struct Log log;
 };
 
-bool storeWrite(FILE *stream, const struct Edit *edit);
-bool storeRead(FILE *stream, struct Edit *edit);
+enum Error {
+	Ok,
+	StoreMagic,
+	StoreVersion,
+	StoreEOF,
+	Errno,
+};
+
+enum Error storeWrite(FILE *stream, const struct Edit *edit);
+enum Error storeRead(FILE *stream, struct Edit *edit);
 
 struct File {
 	char *path;
diff --git a/bin/edi/store.c b/bin/edi/store.c
index f116600a..5012eb3e 100644
--- a/bin/edi/store.c
+++ b/bin/edi/store.c
@@ -15,7 +15,7 @@
  */
 
 #include <assert.h>
-#include <stdbool.h>
+#include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <wchar.h>
@@ -25,68 +25,187 @@
 static const char Magic[3] = "EDI";
 static const char Version  = 1;
 
-static bool writeBuffer(FILE *stream, const struct Buffer *buf) {
+static enum Error
+write(FILE *stream, const void *ptr, size_t size, size_t nitems) {
+	size_t n = fwrite(ptr, size, nitems, stream);
+	return (n < nitems ? Errno + errno : Ok);
+}
+
+static enum Error writeBuffer(FILE *stream, const struct Buffer *buf) {
 	size_t len = 0;
 	const struct Block *block;
 	for (block = buf->block; block; block = block->prev) {
 		len += block->len;
 	}
-	if (!fwrite(&len, sizeof(len), 1, stream)) return false;
+	enum Error error = write(stream, &len, sizeof(len), 1);
+	if (error) return error;
 	for (block = buf->block; block; block = block->prev) {
-		fwrite(block->chars, sizeof(wchar_t), block->len, stream);
-		if (ferror(stream)) return false;
+		error = write(stream, block->chars, sizeof(wchar_t), block->len);
+		if (error) return error;
 	}
-	return true;
+	return Ok;
 }
 
-static bool writeSlice(
-	FILE *stream, const struct Buffer *buf, struct Slice slice
-) {
+static enum Error
+writeSlice(FILE *stream, const struct Buffer *buf, struct Slice slice) {
 	size_t offset = 0;
-	const struct Block *block;
-	for (block = buf->block; block; offset += block->len, block = block->prev) {
+	const struct Block *block = buf->block;
+	while (block) {
 		if (
 			slice.ptr >= block->chars && slice.ptr < &block->chars[block->len]
 		) break;
+		offset += block->len;
+		block = block->prev;
 	}
 	assert(block);
 	size_t ptr = offset + (size_t)(slice.ptr - block->chars);
-	return fwrite(&ptr, sizeof(ptr), 1, stream)
-		&& fwrite(&slice.len, sizeof(slice.len), 1, stream);
+	enum Error error = write(stream, &ptr, sizeof(ptr), 1);
+	if (error) return error;
+	return write(stream, &slice.len, sizeof(slice.len), 1);
 }
 
-static bool writeTable(
-	FILE *stream, const struct Buffer *buf, const struct Table *table
-) {
-	if (!fwrite(&table->len, sizeof(table->len), 1, stream)) return false;
+static enum Error
+writeTable(FILE *stream, const struct Buffer *buf, const struct Table *table) {
+	enum Error error = write(stream, &table->len, sizeof(table->len), 1);
 	for (size_t i = 0; i < table->len; ++i) {
-		if (!writeSlice(stream, buf, table->slices[i])) return false;
+		error = writeSlice(stream, buf, table->slices[i]);
+		if (error) return error;
 	}
-	return true;
+	return Ok;
 }
 
-static bool writeState(
-	FILE *stream, const struct Buffer *buf, const struct State *state
-) {
-	return fwrite(&state->prev, sizeof(state->prev), 1, stream)
-		&& fwrite(&state->next, sizeof(state->next), 1, stream)
-		&& writeTable(stream, buf, &state->table);
+static enum Error
+writeState(FILE *stream, const struct Buffer *buf, const struct State *state) {
+	enum Error error;
+	error = write(stream, &state->prev, sizeof(state->prev), 1);
+	if (error) return error;
+	error = write(stream, &state->next, sizeof(state->next), 1);
+	if (error) return error;
+	return writeTable(stream, buf, &state->table);
 }
 
-static bool writeLog(
-	FILE *stream, const struct Buffer *buf, const struct Log *log
-) {
-	if (!fwrite(&log->state, sizeof(log->state), 1, stream)) return false;
-	if (!fwrite(&log->len, sizeof(log->len), 1, stream)) return false;
+static enum Error
+writeLog(FILE *stream, const struct Buffer *buf, const struct Log *log) {
+	enum Error error;
+	error = write(stream, &log->state, sizeof(log->state), 1);
+	if (error) return error;
+	error = write(stream, &log->len, sizeof(log->len), 1);
+	if (error) return error;
 	for (size_t i = 0; i < log->len; ++i) {
-		if (!writeState(stream, buf, &log->states[i])) return false;
+		error = writeState(stream, buf, &log->states[i]);
+		if (error) return error;
+	}
+	return Ok;
+}
+
+enum Error storeWrite(FILE *stream, const struct Edit *edit) {
+	enum Error error;
+	error = write(stream, Magic, sizeof(Magic), 1);
+	if (error) return error;
+	error = write(stream, &Version, sizeof(Version), 1);
+	if (error) return error;
+	error = writeBuffer(stream, &edit->buf);
+	if (error) return error;
+	return writeLog(stream, &edit->buf, &edit->log);
+}
+
+static enum Error read(FILE *stream, void *ptr, size_t size, size_t nitems) {
+	size_t n = fread(ptr, size, nitems, stream);
+	if (ferror(stream)) return Errno + errno;
+	return (n < nitems ? StoreEOF : Ok);
+}
+
+static enum Error readMagic(FILE *stream) {
+	char magic[3];
+	enum Error error = read(stream, magic, sizeof(magic), 1);
+	if (error) return error;
+	return (
+		magic[0] != Magic[0] || magic[1] != Magic[1] || magic[2] != Magic[2]
+		? StoreMagic
+		: Ok
+	);
+}
+
+static enum Error readVersion(FILE *stream) {
+	char version;
+	enum Error error = read(stream, &version, sizeof(version), 1);
+	if (error) return error;
+	return (version != Version ? StoreVersion : Ok);
+}
+
+static enum Error readBuffer(FILE *stream, struct Buffer *buf) {
+	size_t len;
+	enum Error error = read(stream, &len, sizeof(len), 1);
+	if (error) return error;
+	wchar_t *dest = bufferDest(buf, len);
+	return read(stream, dest, sizeof(wchar_t), len);
+}
+
+static enum Error
+readSlice(FILE *stream, struct Buffer *buf, struct Table *table) {
+	enum Error error;
+	size_t ptr, len;
+	error = read(stream, &ptr, sizeof(ptr), 1);
+	if (error) return error;
+	error = read(stream, &len, sizeof(len), 1);
+	if (error) return error;
+	tablePush(table, (struct Slice) { &buf->slice.ptr[ptr], len });
+	return Ok;
+}
+
+static enum Error
+readTable(FILE *stream, struct Buffer *buf, struct Table *table) {
+	size_t len;
+	enum Error error = read(stream, &len, sizeof(len), 1);
+	if (error) return error;
+	*table = tableAlloc(len);
+	for (size_t i = 0; i < len; ++i) {
+		error = readSlice(stream, buf, table);
+		if (error) return error;
+	}
+	return Ok;
+}
+
+static enum Error
+readState(FILE *stream, struct Buffer *buf, size_t offset, struct Log *log) {
+	enum Error error;
+	size_t prev, next;
+	struct Table table;
+	error = read(stream, &prev, sizeof(prev), 1);
+	if (error) return error;
+	error = read(stream, &next, sizeof(next), 1);
+	if (error) return error;
+	error = readTable(stream, buf, &table);
+	if (error) return error;
+	logPush(log, table);
+	log->states[log->state].prev = offset + prev;
+	log->states[log->state].next = offset + next;
+	return Ok;
+}
+
+static enum Error readLog(FILE *stream, struct Buffer *buf, struct Log *log) {
+	enum Error error;
+	size_t state, len;
+	error = read(stream, &state, sizeof(state), 1);
+	if (error) return error;
+	error = read(stream, &len, sizeof(len), 1);
+	if (error) return error;
+	size_t offset = log->len;
+	for (size_t i = 0; i < len; ++i) {
+		error = readState(stream, buf, offset, log);
+		if (error) return error;
 	}
-	return true;
+	log->state = offset + state;
+	return Ok;
 }
 
-bool storeWrite(FILE *stream, const struct Edit *edit) {
-	return fwrite(Magic, sizeof(Magic), 1, stream)
-		&& fwrite(&Version, sizeof(Version), 1, stream)
-		&& writeBuffer(stream, &edit->buf)
-		&& writeLog(stream, &edit->buf, &edit->log);
+enum Error storeRead(FILE *stream, struct Edit *edit) {
+	enum Error error;
+	error = readMagic(stream);
+	if (error) return error;
+	error = readVersion(stream);
+	if (error) return error;
+	error = readBuffer(stream, &edit->buf);
+	if (error) return error;
+	return readLog(stream, &edit->buf, &edit->log);
 }