]> git.mdlowis.com Git - projs/tide.git/commitdiff
added simple design by contract module and use it from view and buf
authorMichael D. Lowis <mike@mdlowis.com>
Tue, 24 Sep 2019 14:48:11 +0000 (10:48 -0400)
committerMichael D. Lowis <mike@mdlowis.com>
Tue, 24 Sep 2019 14:48:11 +0000 (10:48 -0400)
inc/dbc.h [new file with mode: 0644]
src/lib/buf.c
src/lib/dbc.c [new file with mode: 0644]
src/lib/view.c
src/tide.c

diff --git a/inc/dbc.h b/inc/dbc.h
new file mode 100644 (file)
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);
index 4a2a3089fa98b03ced61fab3942085413e5a67a1..4166407da1aff26b09d81372ace5bb0f6c6bc045 100644 (file)
@@ -1,4 +1,5 @@
 #include <stdc.h>
+#include <dbc.h>
 #include <utf.h>
 #include <edit.h>
 #include <ctype.h>
@@ -7,6 +8,42 @@
 #include <sys/stat.h>
 #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 (file)
index 0000000..d35676e
--- /dev/null
@@ -0,0 +1,38 @@
+#include <dbc.h>
+#include <stdio.h>
+
+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
+}
index 16933b6b96fc12c49dc4fffef0392eefa690b9e1..3f7ac694315fab146fd8ec476fbfef371d77c88a 100644 (file)
@@ -1,9 +1,21 @@
 #include <stdc.h>
+#include <dbc.h>
 #include <utf.h>
 #include <edit.h>
 #include <ctype.h>
 #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));
 }
index 41349bfbcf741a66b9a02a9d908aac7b831c64ce..75adb2bad596c8e1d2cbf283673e3dde37988e37 100644 (file)
@@ -1,4 +1,5 @@
 #include <stdc.h>
+#include <dbc.h>
 #include <utf.h>
 #include <edit.h>
 #include <win.h>
@@ -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);