From 065792b3b0968bb38add192976418f1ba1fb40cc Mon Sep 17 00:00:00 2001 From: Curtis McEnroe Date: Sun, 25 Nov 2018 20:53:34 -0500 Subject: Return enum Error from file functions in edi --- bin/edi/edi.c | 34 +++++++++++++++--------------- bin/edi/edi.h | 8 ++++---- bin/edi/file.c | 65 ++++++++++++++++++++++++++++++---------------------------- bin/edi/log.c | 15 ++++---------- 4 files changed, 58 insertions(+), 64 deletions(-) (limited to 'bin') 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 . */ -#include +#include #include #include #include -#include #include #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; } -- cgit 1.4.1 r> Also separate the options and fileName buffers in gfxx. 2018-02-06Require 4 bit counts on gfxx command lineJune McEnroe 2018-02-06Add gfxx controls for custom bitsJune McEnroe 2018-02-06Add gfxx palette loading and dumpingJune McEnroe 2018-02-06Add tags targetJune McEnroe This seems a bit out of character for me, but this is basically free: ctags(1) is part of FreeBSD and Darwin, and vim automatically uses tags. Also the format of tags files is cute. 2018-02-06Replace gfxx SCALE macro with interp functionJune McEnroe Short-circuits for b = 8. 2018-02-05Rename gfxx space indexed and add palette samplingJune McEnroe 2018-02-05Take scale into account for when to stop drawing in gfxxJune McEnroe 2018-02-05Always skip most significant bits in gfxxJune McEnroe This works for CARDS.DLL but might not for other things. We'll see. 2018-02-05Set title in gfcocoaJune McEnroe 2018-02-05Double-buffer gfb frontendJune McEnroe Still not vsync (seems like a newer DRM-fbdev implementation handles FBIO_WAITFORVSYNC but my kernel doesn't), but avoids flicker from clearing to black for each frame. 2018-02-05Rewrite gfxx bit handlingJune McEnroe Specifies how many bits for each of "alpha" (ignored), red, green, blue. Separates byte-order and bit-order. Much more flexible, but now won't render CARDS.DLL graphics properly due to the skip bit being not where it expects. Also mmaps the file instead of reading it all in. And the default palette and sampling got removed again for now, since it's too awkward to use. 2018-02-05Add flip option to gfxxJune McEnroe This handles upside-down graphics much better than reverse did. 2018-02-05Remove gfxx reverse optionJune McEnroe 2018-02-04Fix gfxx draw stop conditionJune McEnroe Would not draw the last partially visible column when mirrored. 2018-02-04Reuse CGColorSpace and CGDataProvider in gfcocoaJune McEnroe 2018-02-04Mark mac target phonyJune McEnroe 2018-02-04Set up Makefile for gfxx-cocoa or gfxx-fbJune McEnroe 2018-02-04Avoid doing excessive work in gfxxJune McEnroe By stopping when the next column would be off the edge of the buffer. 2018-02-04Handle window resizing in gfcocoaJune McEnroe 2018-02-04Set cinoptionsJune McEnroe 2018-02-04Tweak colorscheme moreJune McEnroe 2018-02-04Color MatchParen DarkYellowJune McEnroe White is not obvious enough. 2018-02-04Add palette sampling to gfxxJune McEnroe 2018-02-04Add 4-bit RGB to gfxxJune McEnroe Replace default palette with alternating black and white. 2018-02-04Add Quit menu item to gfcocoaJune McEnroe 2018-02-04Switch back to sane Objective-C styleJune McEnroe 2018-02-04Quit gfcocoa when window closesJune McEnroe 2018-02-03Apparently this is how people write Objective-CJune McEnroe