diff options
Diffstat (limited to 'bin')
-rw-r--r-- | bin/edi/Makefile | 2 | ||||
-rw-r--r-- | bin/edi/edi.c | 40 | ||||
-rw-r--r-- | bin/edi/edi.h | 61 | ||||
-rw-r--r-- | bin/edi/file.c | 85 | ||||
-rw-r--r-- | bin/edi/log.c | 18 | ||||
-rw-r--r-- | bin/edi/table.c | 179 |
6 files changed, 249 insertions, 136 deletions
diff --git a/bin/edi/Makefile b/bin/edi/Makefile index 2d9128c0..8ad154c6 100644 --- a/bin/edi/Makefile +++ b/bin/edi/Makefile @@ -2,6 +2,8 @@ CFLAGS += -Wall -Wextra -Wpedantic LDLIBS = -lcursesw OBJS += buffer.o +OBJS += edi.o +OBJS += file.o OBJS += log.o OBJS += table.o diff --git a/bin/edi/edi.c b/bin/edi/edi.c new file mode 100644 index 00000000..c8cd2a44 --- /dev/null +++ b/bin/edi/edi.c @@ -0,0 +1,40 @@ +/* Copyright (C) 2018 June McEnroe <june@causal.agency> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <locale.h> +#include <stdlib.h> +#include <string.h> +#include <sysexits.h> + +#include "edi.h" + +int main(int argc, char *argv[]) { + setlocale(LC_CTYPE, ""); + + if (argc < 2) return EX_USAGE; + + struct File file = fileAlloc(strdup(argv[1])); + fileRead(&file); + + const struct Table *table = &file.log.states[file.log.state].table; + for (size_t i = 0; i < table->len; ++i) { + for (size_t j = 0; j < table->slices[i].len; ++j) { + printf("%lc", table->slices[i].ptr[j]); + } + } + + fileFree(&file); +} diff --git a/bin/edi/edi.h b/bin/edi/edi.h index f37ad5ab..3425b235 100644 --- a/bin/edi/edi.h +++ b/bin/edi/edi.h @@ -17,11 +17,9 @@ #include <stdlib.h> #include <wchar.h> -struct Span { +static inline struct Span { size_t at, to; -}; - -static inline struct Span spanNext(struct Span span, size_t len) { +} spanNext(struct Span span, size_t len) { return (struct Span) { span.to, span.to + len }; } @@ -31,15 +29,13 @@ struct Slice { }; struct Buffer { - size_t cap; - size_t len; + size_t cap, len; struct Slice slice; struct Block { struct Block *prev; wchar_t chars[]; } *block; }; - struct Buffer bufferAlloc(size_t cap); void bufferFree(struct Buffer *buf); void bufferInsert(struct Buffer *buf); @@ -47,43 +43,36 @@ void bufferAppend(struct Buffer *buf, wchar_t ch); void bufferDelete(struct Buffer *buf); wchar_t *bufferDest(struct Buffer *buf, size_t len); -struct Table { - size_t len; - size_t hot; +static const struct Table { + size_t cap, len; + size_t ins; struct Slice *slices; -}; -static const struct Table TableEmpty = { 0, 0, NULL }; - -struct Table tableInsert(struct Table prev, size_t at, struct Slice ins); -struct Table tableDelete(struct Table prev, struct Span del); +} TableEmpty; +struct Table tableAlloc(size_t cap); +void tableFree(struct Table *table); +void tablePush(struct Table *table, struct Slice slice); +struct Table tableInsert(const struct Table *prev, size_t at, struct Slice ins); +struct Table tableDelete(const struct Table *prev, struct Span del); +void tableUpdate(struct Table *table, struct Slice ins); struct Log { - size_t cap; - size_t len; - size_t idx; + size_t cap, len; + size_t state; struct State { struct Table table; - size_t prev; - size_t next; + size_t prev, next; } *states; }; - struct Log logAlloc(size_t cap); void logFree(struct Log *log); void logPush(struct Log *log, struct Table table); -static inline struct Table logTable(struct Log log) { - return log.states[log.idx].table; -} -static inline void logPrev(struct Log *log) { - log->idx = log->states[log->idx].prev; -} -static inline void logNext(struct Log *log) { - log->idx = log->states[log->idx].next; -} -static inline void logBack(struct Log *log) { - if (log->idx) log->idx--; -} -static inline void logFore(struct Log *log) { - if (log->idx + 1 < log->len) log->idx++; -} +struct File { + char *path; + struct Buffer buf; + struct Log log; + size_t clean; +}; +struct File fileAlloc(char *path); +void fileFree(struct File *file); +void fileRead(struct File *file); diff --git a/bin/edi/file.c b/bin/edi/file.c new file mode 100644 index 00000000..9f85d1da --- /dev/null +++ b/bin/edi/file.c @@ -0,0 +1,85 @@ +/* Copyright (C) 2018 June McEnroe <june@causal.agency> + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +#include <assert.h> +#include <err.h> +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <sysexits.h> +#include <wchar.h> + +#include "edi.h" + +enum { + BufCap = 8192, + LogCap = 8, +}; + +struct File fileAlloc(char *path) { + struct File file = { + .path = path, + .buf = bufferAlloc(BufCap), + .log = logAlloc(LogCap), + .clean = 0, + }; + if (!path) logPush(&file.log, TableEmpty); + return file; +} + +void fileFree(struct File *file) { + logFree(&file->log); + bufferFree(&file->buf); + free(file->path); +} + +static const mbstate_t MBStateInit; + +// TODO: Error handling. +void fileRead(struct File *file) { + if (!file->path) return; + + 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; + } + + struct Table table = tableAlloc(1); + + char buf[BufCap]; + mbstate_t mbState = MBStateInit; + while (!feof(stream)) { + size_t mbsLen = fread(buf, 1, sizeof(buf), stream); + if (ferror(stream)) err(EX_IOERR, "%s", file->path); + + const char *mbs = buf; + mbstate_t mbLenState = mbState; + size_t wcsLen = mbsnrtowcs(NULL, &mbs, mbsLen, 0, &mbLenState); + if (wcsLen == (size_t)-1) err(EX_DATAERR, "%s", file->path); + + wchar_t *wcs = bufferDest(&file->buf, wcsLen); + assert(wcsLen == mbsnrtowcs(wcs, &mbs, mbsLen, wcsLen, &mbState)); + + tablePush(&table, file->buf.slice); + } + logPush(&file->log, table); + file->clean = file->log.state; + + fclose(stream); +} diff --git a/bin/edi/log.c b/bin/edi/log.c index c91f5fd9..267833ec 100644 --- a/bin/edi/log.c +++ b/bin/edi/log.c @@ -23,25 +23,19 @@ #include "edi.h" struct Log logAlloc(size_t cap) { - assert(cap); struct State *states = malloc(sizeof(*states) * cap); if (!states) err(EX_OSERR, "malloc"); - states[0] = (struct State) { - .table = TableEmpty, - .prev = 0, - .next = 0, - }; return (struct Log) { .cap = cap, - .len = 1, - .idx = 0, + .len = 0, + .state = 0, .states = states, }; } void logFree(struct Log *log) { for (size_t i = 0; i < log->len; ++i) { - free(log->states[i].table.slices); + tableFree(&log->states[i].table); } free(log->states); } @@ -55,9 +49,9 @@ void logPush(struct Log *log, struct Table table) { size_t next = log->len++; log->states[next] = (struct State) { .table = table, - .prev = log->idx, + .prev = log->state, .next = next, }; - log->states[log->idx].next = next; - log->idx = next; + log->states[log->state].next = next; + log->state = next; } diff --git a/bin/edi/table.c b/bin/edi/table.c index a5383d56..593766a4 100644 --- a/bin/edi/table.c +++ b/bin/edi/table.c @@ -21,79 +21,96 @@ #include "edi.h" -static struct Table alloc(size_t cap) { +struct Table tableAlloc(size_t cap) { struct Slice *slices = malloc(sizeof(*slices) * cap); if (!slices) err(EX_OSERR, "malloc"); - return (struct Table) { 0, 0, slices }; + return (struct Table) { + .cap = cap, + .len = 0, + .ins = 0, + .slices = slices, + }; } -struct Table tableInsert(struct Table prev, size_t at, struct Slice ins) { - if (!prev.len) { - struct Table next = alloc(1); - next.slices[next.hot = next.len++] = ins; - return next; +void tableFree(struct Table *table) { + free(table->slices); +} + +void tablePush(struct Table *table, struct Slice slice) { + if (table->len == table->cap) { + table->cap *= 2; + table->slices = realloc( + table->slices, + sizeof(*table->slices) * table->cap + ); + if (!table->slices) err(EX_OSERR, "malloc"); } + table->slices[table->len++] = slice; +} - struct Table next = alloc(prev.len + 2); +struct Table tableInsert(const struct Table *prev, size_t at, struct Slice ins) { + struct Table next = tableAlloc(prev->len + 2); struct Span span = { 0, 0 }; - for (size_t i = 0; i < prev.len; ++i) { - span = spanNext(span, prev.slices[i].len); + for (size_t i = 0; i < prev->len; ++i) { + span = spanNext(span, prev->slices[i].len); if (span.at == at) { - next.slices[next.hot = next.len++] = ins; - next.slices[next.len++] = prev.slices[i]; + next.slices[next.ins = next.len++] = ins; + next.slices[next.len++] = prev->slices[i]; } else if (span.at < at && span.to > at) { next.slices[next.len++] = (struct Slice) { - prev.slices[i].ptr, + prev->slices[i].ptr, at - span.at, }; - next.slices[next.hot = next.len++] = ins; + next.slices[next.ins = next.len++] = ins; next.slices[next.len++] = (struct Slice) { - &prev.slices[i].ptr[at - span.at], - prev.slices[i].len - (at - span.at), + &prev->slices[i].ptr[at - span.at], + prev->slices[i].len - (at - span.at), }; } else { - next.slices[next.len++] = prev.slices[i]; + next.slices[next.len++] = prev->slices[i]; } } if (span.to == at) { - next.slices[next.hot = next.len++] = ins; + next.slices[next.ins = next.len++] = ins; } return next; } -struct Table tableDelete(struct Table prev, struct Span del) { - if (!prev.len) return TableEmpty; - struct Table next = alloc(prev.len + 1); +void tableUpdate(struct Table *table, struct Slice ins) { + if (table->ins < table->len) table->slices[table->ins] = ins; +} + +struct Table tableDelete(const struct Table *prev, struct Span del) { + struct Table next = tableAlloc(prev->len + 1); struct Span span = { 0, 0 }; - for (size_t i = 0; i < prev.len; ++i) { - span = spanNext(span, prev.slices[i].len); + for (size_t i = 0; i < prev->len; ++i) { + span = spanNext(span, prev->slices[i].len); if (span.at >= del.at && span.to <= del.to) { - (void)prev.slices[i]; - next.hot = next.len; + (void)prev->slices[i]; } else if (span.at < del.at && span.to > del.to) { next.slices[next.len++] = (struct Slice) { - prev.slices[i].ptr, + prev->slices[i].ptr, del.at - span.at, }; - next.slices[next.hot = next.len++] = (struct Slice) { - &prev.slices[i].ptr[del.to - span.at], - prev.slices[i].len - (del.to - span.at), + next.slices[next.len++] = (struct Slice) { + &prev->slices[i].ptr[del.to - span.at], + prev->slices[i].len - (del.to - span.at), }; } else if (span.at < del.at && span.to > del.at) { next.slices[next.len++] = (struct Slice) { - prev.slices[i].ptr, + prev->slices[i].ptr, del.at - span.at, }; - next.hot = next.len; } else if (span.at < del.to && span.to > del.to) { - next.slices[next.hot = next.len++] = (struct Slice) { - &prev.slices[i].ptr[del.to - span.at], - prev.slices[i].len - (del.to - span.at), + next.slices[next.len++] = (struct Slice) { + &prev->slices[i].ptr[del.to - span.at], + prev->slices[i].len - (del.to - span.at), }; } else { - next.slices[next.len++] = prev.slices[i]; + next.slices[next.len++] = prev->slices[i]; } } + next.ins = next.len; return next; } @@ -108,66 +125,52 @@ static struct Span span(size_t at, size_t to) { return (struct Span) { at, to }; } -static int eq(const wchar_t *str, struct Table table) { - for (size_t i = 0; i < table.len; ++i) { - if (wcsncmp(str, table.slices[i].ptr, table.slices[i].len)) { +static int eq(const wchar_t *str, const struct Table *table) { + for (size_t i = 0; i < table->len; ++i) { + if (wcsncmp(str, table->slices[i].ptr, table->slices[i].len)) { return 0; } - str = &str[table.slices[i].len]; + str = &str[table->slices[i].len]; } return !str[0]; } -static int hot(wint_t ch, struct Table table) { - if (table.hot == table.len) { - return ch == WEOF; - } else { - return ch == table.slices[table.hot].ptr[0]; - } -} - int main() { - struct Table abc = tableInsert(TableEmpty, 0, slice(L"ABC")); - assert(eq(L"ABC", abc)); - assert(hot(L'A', abc)); - - struct Table dabc = tableInsert(abc, 0, slice(L"D")); - struct Table abcd = tableInsert(abc, 3, slice(L"D")); - struct Table adbc = tableInsert(abc, 1, slice(L"D")); - - assert(eq(L"DABC", dabc)); - assert(eq(L"ABCD", abcd)); - assert(eq(L"ADBC", adbc)); - - assert(hot(L'D', dabc)); - assert(hot(L'D', abcd)); - assert(hot(L'D', adbc)); - - free(dabc.slices); - free(abcd.slices); - free(adbc.slices); - - struct Table bc = tableDelete(abc, span(0, 1)); - struct Table ab = tableDelete(abc, span(2, 3)); - struct Table ac = tableDelete(abc, span(1, 2)); - struct Table __ = tableDelete(abc, span(0, 3)); - - assert(eq(L"BC", bc)); - assert(eq(L"AB", ab)); - assert(eq(L"AC", ac)); - assert(eq(L"", __)); - - assert(hot(L'B', bc)); - assert(hot(WEOF, ab)); - assert(hot(L'C', ac)); - assert(hot(WEOF, __)); - - free(bc.slices); - free(ab.slices); - free(ac.slices); - free(__.slices); - - free(abc.slices); + struct Table abc = tableInsert(&TableEmpty, 0, slice(L"ABC")); + assert(eq(L"ABC", &abc)); + + struct Table dabc = tableInsert(&abc, 0, slice(L"D")); + struct Table abcd = tableInsert(&abc, 3, slice(L"D")); + struct Table adbc = tableInsert(&abc, 1, slice(L"D")); + + assert(eq(L"DABC", &dabc)); + assert(eq(L"ABCD", &abcd)); + assert(eq(L"ADBC", &adbc)); + + assert(L'D' == dabc.slices[dabc.ins].ptr[0]); + assert(L'D' == abcd.slices[abcd.ins].ptr[0]); + assert(L'D' == adbc.slices[adbc.ins].ptr[0]); + + tableFree(&dabc); + tableFree(&abcd); + tableFree(&adbc); + + struct Table bc = tableDelete(&abc, span(0, 1)); + struct Table ab = tableDelete(&abc, span(2, 3)); + struct Table ac = tableDelete(&abc, span(1, 2)); + struct Table __ = tableDelete(&abc, span(0, 3)); + + assert(eq(L"BC", &bc)); + assert(eq(L"AB", &ab)); + assert(eq(L"AC", &ac)); + assert(eq(L"", &__)); + + tableFree(&bc); + tableFree(&ab); + tableFree(&ac); + tableFree(&__); + + tableFree(&abc); } #endif |