From: Michael D. Lowis Date: Tue, 24 Sep 2019 14:48:11 +0000 (-0400) Subject: added simple design by contract module and use it from view and buf X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=a0d80ff1c7992a7f26f6e53b27a55f379289bde3;p=projs%2Ftide.git added simple design by contract module and use it from view and buf --- diff --git a/inc/dbc.h b/inc/dbc.h new file mode 100644 index 0000000..4e5b2e0 --- /dev/null +++ b/inc/dbc.h @@ -0,0 +1,9 @@ +#define require(cond) \ + dbc_require(cond, #cond, __FILE__, __LINE__) + +#define ensure(cond) \ + dbc_ensure(cond, #cond, __FILE__, __LINE__) + +void dbc_init(void (*)(FILE*)); +void dbc_require(bool success, char* text, char* file, int line); +void dbc_ensure(bool success, char* text, char* file, int line); diff --git a/src/lib/buf.c b/src/lib/buf.c index 4a2a308..4166407 100644 --- a/src/lib/buf.c +++ b/src/lib/buf.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -7,6 +8,42 @@ #include #include "config.h" +static bool buf_logvalid(Log* log) { + bool result = true; + for (; result && log; log = log->next) { + if (log->data) { + result = result && (log->beg == log->end); + } else { + result = result && (log->end > log->beg); + } + } + return result; +} + +static bool buf_selvalid(Buf* buf) { + (void)buf; + return true; +} + +static bool buf_valid(Buf* buf) { + return ( + (buf->bufsize > 0) + && (buf->bufstart != NULL) + && (buf->bufend != NULL) + && (buf->gapstart != NULL) + && (buf->gapend != NULL) + && (buf->bufstart < buf->bufend) + && (buf->gapstart <= buf->gapend) + && (buf->gapstart >= buf->bufstart) + && (buf->gapend >= buf->bufstart) + && (buf->gapstart <= buf->bufend) + && (buf->gapend <= buf->bufend) + && (buf_logvalid(buf->undo)) + && (buf_logvalid(buf->redo)) + && (buf_selvalid(buf)) + ); +} + /* Creation, Resizing, Loading, and Saving ******************************************************************************/ static size_t pagealign(size_t sz) { @@ -97,13 +134,14 @@ void buf_init(Buf* buf) { buf->redo = NULL; buf->transid = -1; buf->selection = (Sel){0,0,0}; - assert(buf->bufstart); + ensure(buf_valid(buf)); } void buf_setpath(Buf* buf, char* path) { if (path) { free(buf->path); buf->path = strdup(path); + ensure(buf->path != NULL); } } @@ -138,6 +176,8 @@ void buf_load(Buf* buf, char* path) { /* use the EOL style of the first line to determine EOL style */ DosLineFeed = (getb(buf, buf_eol(buf, 0)) == '\r'); + + ensure(buf_valid(buf)); } void buf_reload(Buf* buf) { @@ -225,6 +265,8 @@ int buf_save(Buf* buf, char* path) { } if (buf->status == NORMAL) buf->save = buf->undo; + + ensure(buf_valid(buf)); return buf->status; } @@ -344,10 +386,12 @@ void buf_logstop(Buf* buf) { void buf_undo(Buf* buf) { log_swap(buf, &(buf->undo), &(buf->redo)); + ensure(buf_valid(buf)); } void buf_redo(Buf* buf) { log_swap(buf, &(buf->redo), &(buf->undo)); + ensure(buf_valid(buf)); } void buf_logclear(Buf* buf) { @@ -399,6 +443,7 @@ void buf_putc(Buf* buf, int c) { char utf8buf[UTF_MAX+1] = {0}; (void)utf8encode(utf8buf, c); buf_puts(buf, utf8buf); + ensure(buf_valid(buf)); } void buf_puts(Buf* buf, char* s) { @@ -408,6 +453,7 @@ void buf_puts(Buf* buf, char* s) { while (*s) putch(buf, *(s++), &(buf->selection)); log_add(buf, beg, buf_getsel(buf).end, NULL); } + ensure(buf_valid(buf)); } int buf_getc(Buf* buf) { @@ -444,6 +490,7 @@ void buf_del(Buf* buf) { buf->selection = sel; log_add(buf, sel.beg, sel.end, str); } + ensure(buf_valid(buf)); } /* Positional and Movement Operations @@ -753,6 +800,8 @@ bool buf_insel(Buf* buf, size_t off) { } char* buf_fetch(Buf* buf, bool (*isword)(Rune), size_t off) { + require(buf != NULL); + require(isword != NULL); char* str = NULL; Sel prev = buf->selection; if (!buf_insel(buf, off)) { diff --git a/src/lib/dbc.c b/src/lib/dbc.c new file mode 100644 index 0000000..d35676e --- /dev/null +++ b/src/lib/dbc.c @@ -0,0 +1,38 @@ +#include +#include + +static void (*DumpFn)(FILE*) = NULL; + +static void dump_and_abort(char* msg) { + FILE* f = fopen("/tmp/tide.dump", "w"); + fprintf(f, "%s\n", msg); + if (DumpFn) DumpFn(f); + fclose(f); + abort(); +} + +void dbc_init(void (*dumpfn)(FILE*)) { +#ifndef NDEBUG + DumpFn = dumpfn; +#endif +} + +void dbc_require(bool success, char* text, char* file, int line) { +#ifndef NDEBUG + char buf[8192]; + if (!success) { + snprintf(buf, sizeof(buf), "%s:%d: pre-condition failed (%s)", file, line, text); + dump_and_abort(buf); + } +#endif +} + +void dbc_ensure(bool success, char* text, char* file, int line) { +#ifndef NDEBUG + char buf[8192]; + if (!success) { + snprintf(buf, sizeof(buf), "%s:%d: post-condition failed (%s)", file, line, text); + dump_and_abort(buf); + } +#endif +} diff --git a/src/lib/view.c b/src/lib/view.c index 16933b6..3f7ac69 100644 --- a/src/lib/view.c +++ b/src/lib/view.c @@ -1,9 +1,21 @@ #include +#include #include #include #include #include "config.h" +static bool view_valid(View* view) { + return ( + (view->sync_flags <= 3u) + && (!view->nrows || view->index < view->nrows) +// && (view->width > 0) +// && (view->nvisible > 0) +// && (view->nrows > 0) +// && (view->rows != NULL) + ); +} + /* Provided by x11.c */ extern size_t glyph_width(View* view, int c); @@ -77,6 +89,7 @@ static void clear_rows(View* view, size_t startidx) { } void view_init(View* view, char* file) { + require(view != NULL); clear_rows(view, 0); view->sync_flags |= (CURSOR|CENTER); view->index = 0; @@ -85,17 +98,22 @@ void view_init(View* view, char* file) { /* load the file and jump to the address returned from the load function */ buf_init(BUF); if (file) buf_load(BUF, file); + ensure(view_valid(view)); } void view_reload(View* view) { + require(view != NULL); if (view->buffer.path) { buf_reload(BUF); view->sync_flags |= (CURSOR|CENTER); } + ensure(view_valid(view)); } void view_sync(View* view) { + require(view != NULL); view->sync_flags |= (CURSOR|CENTER); + ensure(view_valid(view)); } static size_t rune_width(View* view, int c, size_t xpos, size_t width) { @@ -110,6 +128,7 @@ static size_t rune_width(View* view, int c, size_t xpos, size_t width) { } size_t view_limitrows(View* view, size_t maxrows) { + require(view != NULL); size_t nrows = 1, off = 0, xpos = 0; while (nrows < maxrows && off < buf_end(&(view->buffer))) { Rune rune = buf_getrat(&(view->buffer), off); @@ -123,6 +142,7 @@ size_t view_limitrows(View* view, size_t maxrows) { off = buf_byrune(&(view->buffer), off, RIGHT); } } + ensure(nrows >= 1); return nrows; } @@ -172,13 +192,18 @@ static void resize(View* view, size_t width, size_t nrows, size_t off) { } void view_resize(View* view, size_t width, size_t nrows) { + require(view != NULL); + require(width > 0); + require(nrows > 0); if (view->width == width && view->nvisible == nrows) return; size_t off = (view->nrows && view->index < view->nrows ? view->rows[view->index]->off : 0); resize(view, width, nrows, off); + ensure(view_valid(view)); } void view_update(View* view) { + require(view != NULL); /* refill the view contents to make sure updates are visible */ size_t off = view->rows[view->index]->off; clear_rows(view, view->index); @@ -198,6 +223,7 @@ void view_update(View* view) { } view->sync_flags = 0; } + ensure(view_valid(view)); } Row* view_getrow(View* view, size_t row) { @@ -205,15 +231,21 @@ Row* view_getrow(View* view, size_t row) { } void view_byrune(View* view, int move, bool extsel) { + require(view != NULL); move_selection(view, extsel, move, buf_byrune); + ensure(view_valid(view)); } void view_byword(View* view, int move, bool extsel) { + require(view != NULL); move_selection(view, extsel, move, buf_byword); + ensure(view_valid(view)); } void view_byline(View* view, int move, bool extsel) { + require(view != NULL); move_selection(view, extsel, move, buf_byline); + ensure(view_valid(view)); } static size_t getoffset(View* view, size_t row, size_t col) { @@ -232,12 +264,14 @@ void view_setcursor(View* view, size_t row, size_t col, bool extsel) { if (!extsel) getsel(view)->beg = getsel(view)->end; buf_getcol(BUF); + ensure(view_valid(view)); } void view_selword(View* view, size_t row, size_t col) { if (row != SIZE_MAX && col != SIZE_MAX) view_setcursor(view, row, col, false); buf_selword(BUF, risbigword); + ensure(view_valid(view)); } void view_selprev(View* view) { @@ -245,11 +279,13 @@ void view_selprev(View* view) { buf_lastins(BUF); else buf_selclr(BUF, RIGHT); + ensure(view_valid(view)); } void view_select(View* view, size_t row, size_t col) { view_setcursor(view, row, col, false); buf_selctx(BUF, risword); + ensure(view_valid(view)); } size_t view_selsize(View* view) { @@ -261,12 +297,14 @@ char* view_fetch(View* view, size_t row, size_t col, bool (*isword)(Rune)) { size_t off = getoffset(view, row, col); if (off != SIZE_MAX) str = buf_fetch(BUF, isword, off); + ensure(view_valid(view)); return str; } bool view_findstr(View* view, int dir, char* str) { bool found = buf_findstr(BUF, dir, str); view->sync_flags |= (CURSOR|CENTER); + ensure(view_valid(view)); return found; } @@ -290,6 +328,7 @@ void view_insert(View* view, Rune rune) { buf_putc(BUF, rune); } move_to(view, false, CSRPOS); + ensure(view_valid(view)); } void view_delete(View* view, int dir, bool byword) { @@ -297,10 +336,12 @@ void view_delete(View* view, int dir, bool byword) { (byword ? view_byword : view_byrune)(view, dir, true); buf_del(BUF); move_to(view, false, CSRPOS); + ensure(view_valid(view)); } void view_jumpto(View* view, bool extsel, size_t off) { move_to(view, extsel, off); + ensure(view_valid(view)); } void view_bol(View* view, bool extsel) { @@ -312,19 +353,23 @@ void view_bol(View* view, bool extsel) { unsigned pos = CSRPOS; pos = (pos == bol || pos > boi ? boi : bol); move_to(view, extsel, pos); + ensure(view_valid(view)); } void view_eol(View* view, bool extsel) { move_to(view, extsel, buf_eol(BUF, CSRPOS)); getsel(view)->col = -1; // Peg cursor to line end + ensure(view_valid(view)); } void view_bof(View* view, bool extsel) { view_jumpto(view, extsel, 0); + ensure(view_valid(view)); } void view_eof(View* view, bool extsel) { view_jumpto(view, extsel, buf_end(BUF)); + ensure(view_valid(view)); } void view_setln(View* view, size_t line) { @@ -333,18 +378,21 @@ void view_setln(View* view, size_t line) { buf_setln(BUF, line); buf_selln(BUF); } + ensure(view_valid(view)); } void view_undo(View* view) { buf_undo(BUF); view->sync_flags |= CURSOR; if (!selection_visible(view)) view->sync_flags |= CENTER; + ensure(view_valid(view)); } void view_redo(View* view) { buf_redo(BUF); view->sync_flags |= CURSOR; if (!selection_visible(view)) view->sync_flags |= CENTER; + ensure(view_valid(view)); } void view_paste(View* view, char* str) { @@ -352,10 +400,12 @@ void view_paste(View* view, char* str) { view_putstr(view, str); buf_logstop(BUF); view_selprev(view); + ensure(view_valid(view)); } void view_putstr(View* view, char* str) { buf_puts(BUF, str); + ensure(view_valid(view)); } char* view_getstr(View* view) { @@ -365,16 +415,19 @@ char* view_getstr(View* view) { char* view_getcmd(View* view) { if (!view_selsize(view)) buf_selctx(BUF, riscmd); + ensure(view_valid(view)); return view_getstr(view); } void view_selctx(View* view) { if (!view_selsize(view)) buf_selctx(BUF, risword); + ensure(view_valid(view)); } char* view_getctx(View* view) { view_selctx(view); + ensure(view_valid(view)); return view_getstr(view); } @@ -405,11 +458,13 @@ void view_scroll(View* view, int move) { else scroll_dn(view); } + ensure(view_valid(view)); } void view_scrollpage(View* view, int move) { move = (move < 0 ? -1 : 1) * view->nrows; view_scroll(view, move); + ensure(view_valid(view)); } Rune view_getrune(View* view) { @@ -422,14 +477,17 @@ void view_scrollto(View* view, size_t csr) { size_t last = lastrow->cols[lastrow->len-1].off; if (csr < first || csr > last) resize(view, view->width, view->nrows, csr); + ensure(view_valid(view)); } void view_selectall(View* view) { buf_selall(BUF); view->sync_flags |= CURSOR; + ensure(view_valid(view)); } void view_selectobj(View* view, bool (*istype)(Rune)) { buf_selword(BUF, istype); view->sync_flags |= CURSOR; + ensure(view_valid(view)); } diff --git a/src/tide.c b/src/tide.c index 41349bf..75adb2b 100644 --- a/src/tide.c +++ b/src/tide.c @@ -1,4 +1,5 @@ #include +#include #include #include #include @@ -663,10 +664,8 @@ int main(int argc, char** argv) { if (!ShellCmd[0]) ShellCmd[0] = getenv("SHELL"); if (!ShellCmd[0]) ShellCmd[0] = "/bin/sh"; - /* create the window */ + /* Initialize the window and views */ win_init(); - - /* Initialize the views */ view_init(&Regions[TAGS], NULL); view_init(&Regions[EDIT], NULL); view_putstr(win_view(TAGS), TagString);