summary refs log tree commit diff
path: root/bin/edi
diff options
context:
space:
mode:
Diffstat (limited to 'bin/edi')
-rw-r--r--bin/edi/edi.c34
-rw-r--r--bin/edi/edi.h8
-rw-r--r--bin/edi/file.c65
-rw-r--r--bin/edi/log.c15
4 files changed, 58 insertions, 64 deletions
diff --git a/bin/edi/edi.c b/bin/edi/edi.c
index a0231785..d234df5e 100644
--- a/bin/edi/edi.c
+++ b/bin/edi/edi.c
@@ -23,24 +23,27 @@
 
 #include "edi.h"
 
+static void errorExit(enum Error error, const char *prefix) {
+	if (error > Errno) errc(EX_IOERR, error - Errno, "%s", prefix);
+	else errx(EX_DATAERR, "%s: %d", prefix, error);
+}
+
 int main(int argc, char *argv[]) {
 	setlocale(LC_CTYPE, "");
 
 	if (argc < 2) return EX_USAGE;
 
+	enum Error error;
+
 	struct File file = fileAlloc(strdup(argv[1]));
-	fileRead(&file);
-	
-	struct Edit edit = { file.buf, file.log };
+	error = fileRead(&file);
+	if (error) errorExit(error, file.path);
 
 	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);
-	}
+	error = storeWrite(store, &file.edit);
+	if (error) errorExit(error, "store.edi");
 
 	fclose(store);
 	if (ferror(store)) err(EX_IOERR, "store.edi");
@@ -48,21 +51,16 @@ int main(int argc, char *argv[]) {
 	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;
+	error = storeRead(store, &file.edit);
+	if (error) errorExit(error, "store.edi");
 
-	const struct Table *table = logTable(&file.log);
+	const struct Table *table = logTable(&file.edit.log);
 	for (struct Iter it = iter(table, 0); it.ch != WEOF; it = iterNext(it)) {
 		printf("%lc", it.ch);
 	}
 
-	fileWrite(&file);
+	error = fileWrite(&file);
+	if (error) errorExit(error, file.path);
 
 	fileFree(&file);
 }
diff --git a/bin/edi/edi.h b/bin/edi/edi.h
index bdcc6496..46cb4249 100644
--- a/bin/edi/edi.h
+++ b/bin/edi/edi.h
@@ -98,6 +98,7 @@ enum Error {
 	StoreMagic,
 	StoreVersion,
 	StoreEOF,
+	FileNoPath,
 	Errno,
 };
 
@@ -106,11 +107,10 @@ enum Error storeRead(FILE *stream, struct Edit *edit);
 
 struct File {
 	char *path;
-	struct Buffer buf;
-	struct Log log;
 	size_t clean;
+	struct Edit edit;
 };
 struct File fileAlloc(char *path);
 void fileFree(struct File *file);
-void fileRead(struct File *file);
-void fileWrite(struct File *file);
+enum Error fileRead(struct File *file);
+enum Error fileWrite(struct File *file);
diff --git a/bin/edi/file.c b/bin/edi/file.c
index 91479ee6..59d648d2 100644
--- a/bin/edi/file.c
+++ b/bin/edi/file.c
@@ -14,11 +14,10 @@
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
-#include <err.h>
+#include <assert.h>
 #include <errno.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <sysexits.h>
 #include <wchar.h>
 
 #include "edi.h"
@@ -32,31 +31,32 @@ enum {
 struct File fileAlloc(char *path) {
 	struct File file = {
 		.path = path,
-		.buf = bufferAlloc(BufferCap),
-		.log = logAlloc(LogCap),
+		.edit = {
+			.buf = bufferAlloc(BufferCap),
+			.log = logAlloc(LogCap),
+		},
 	};
-	if (!path) logPush(&file.log, TableEmpty);
+	if (!path) logPush(&file.edit.log, TableEmpty);
 	return file;
 }
 
 void fileFree(struct File *file) {
-	logFree(&file->log);
-	bufferFree(&file->buf);
+	logFree(&file->edit.log);
+	bufferFree(&file->edit.buf);
 	free(file->path);
 }
 
 static const mbstate_t StateInit;
 
-// TODO: Error handling.
-void fileRead(struct File *file) {
-	if (!file->path) return;
+enum Error fileRead(struct File *file) {
+	if (!file->path) return FileNoPath;
 
 	FILE *stream = fopen(file->path, "r");
 	if (!stream) {
-		if (errno != ENOENT) err(EX_NOINPUT, "%s", file->path);
-		logPush(&file->log, TableEmpty);
-		file->clean = file->log.state;
-		return;
+		if (errno != ENOENT) return Errno + errno;
+		logPush(&file->edit.log, TableEmpty);
+		file->clean = file->edit.log.state;
+		return Ok;
 	}
 
 	struct Table table = tableAlloc(TableCap);
@@ -64,49 +64,52 @@ void fileRead(struct File *file) {
 	mbstate_t state = StateInit;
 	while (!feof(stream)) {
 		size_t mbsLen = fread(buf, 1, sizeof(buf), stream);
-		if (ferror(stream)) err(EX_IOERR, "%s", file->path);
+		if (ferror(stream)) return Errno + errno;
 
+		// FIXME: Handle null bytes specially.
 		const char *mbs = buf;
-		wchar_t *wcs = bufferDest(&file->buf, mbsLen);
+		wchar_t *wcs = bufferDest(&file->edit.buf, mbsLen);
 		size_t wcsLen = mbsnrtowcs(wcs, &mbs, mbsLen, mbsLen, &state);
-		if (wcsLen == (size_t)-1) err(EX_DATAERR, "%s", file->path);
+		if (wcsLen == (size_t)-1) return Errno + errno;
 
-		bufferTruncate(&file->buf, wcsLen);
-		tablePush(&table, file->buf.slice);
+		bufferTruncate(&file->edit.buf, wcsLen);
+		tablePush(&table, file->edit.buf.slice);
 	}
-	logPush(&file->log, table);
-	file->clean = file->log.state;
+	logPush(&file->edit.log, table);
+	file->clean = file->edit.log.state;
 
 	fclose(stream);
+	return Ok;
 }
 
-// TODO: Error handling.
-void fileWrite(struct File *file) {
-	if (!file->path) return;
+enum Error fileWrite(struct File *file) {
+	if (!file->path) return FileNoPath;
 
 	FILE *stream = fopen(file->path, "w");
-	if (!stream) err(EX_CANTCREAT, "%s", file->path);
+	if (!stream) return Errno + errno;
 
-	const struct Table *table = logTable(&file->log);
-	if (!table) errx(EX_SOFTWARE, "fileWrite: no table");
+	const struct Table *table = logTable(&file->edit.log);
+	assert(table);
 
 	char buf[BufferCap];
 	mbstate_t state = StateInit;
 	for (size_t i = 0; i < table->len; ++i) {
 		struct Slice slice = table->slices[i];
 		while (slice.len) {
+			// FIXME: Handle null bytes specially.
 			size_t mbsLen = wcsnrtombs(
 				buf, &slice.ptr, slice.len, sizeof(buf), &state
 			);
-			if (mbsLen == (size_t)-1) err(EX_DATAERR, "%s", file->path);
+			if (mbsLen == (size_t)-1) return Errno + errno;
+			// FIXME: This only works once.
 			slice.len -= slice.ptr - table->slices[i].ptr;
 
 			fwrite(buf, 1, mbsLen, stream);
-			if (ferror(stream)) err(EX_IOERR, "%s", file->path);
+			if (ferror(stream)) return Errno + errno;
 		}
 	}
-	file->clean = file->log.state;
+	file->clean = file->edit.log.state;
 
 	fclose(stream);
-	if (ferror(stream)) err(EX_IOERR, "%s", file->path);
+	return (ferror(stream) ? Errno + errno : Ok);
 }
diff --git a/bin/edi/log.c b/bin/edi/log.c
index 82cd7ff3..c391bdba 100644
--- a/bin/edi/log.c
+++ b/bin/edi/log.c
@@ -25,12 +25,7 @@
 struct Log logAlloc(size_t cap) {
 	struct State *states = malloc(sizeof(*states) * cap);
 	if (!states) err(EX_OSERR, "malloc");
-	return (struct Log) {
-		.cap = cap,
-		.len = 0,
-		.state = 0,
-		.states = states,
-	};
+	return (struct Log) { .cap = cap, .states = states };
 }
 
 void logFree(struct Log *log) {
@@ -47,11 +42,9 @@ void logPush(struct Log *log, struct Table table) {
 		if (!log->states) err(EX_OSERR, "realloc");
 	}
 	size_t next = log->len++;
-	log->states[next] = (struct State) {
-		.table = table,
-		.prev = log->state,
-		.next = next,
-	};
+	log->states[next].table = table;
+	log->states[next].prev = log->state;
+	log->states[next].next = next;
 	log->states[log->state].next = next;
 	log->state = next;
 }