size_t col;
} Sel;
-/* gap buffer main data structure */
typedef struct {
- enum {
- NORMAL = 0, MODIFIED, OUTDATED, ERRORED
- } status;
- char* path; /* the path to the open file */
- uint64_t modtime; /* modification time of the opened file */
size_t bufsize; /* size of the buffer in runes */
char* bufstart; /* start of the data buffer */
char* bufend; /* end of the data buffer */
char* gapstart; /* start of the gap */
char* gapend; /* end of the gap */
+} GapBuf;
+
+/* gap buffer main data structure */
+typedef struct {
+ enum {
+ NORMAL = 0, MODIFIED, OUTDATED, ERRORED
+ } status;
+ char* path; /* the path to the open file */
+ GapBuf contents; /* underlying sequence data structure */
Log* undo; /* undo list */
Log* redo; /* redo list */
Log* save; /* pointer to last save position */
Sel selection; /* the currently selected text */
} Buf;
+void gapbuf_init(GapBuf* buf);
+size_t gapbuf_end(GapBuf* buf);
+long gapbuf_save(GapBuf* buf, char* path);
+void gapbuf_load(GapBuf* buf, char* path);
+char gapbuf_getb(GapBuf* buf, size_t off);
+void gapbuf_putb(GapBuf* buf, char b, Sel* p_sel);
+void gapbuf_del(GapBuf* buf, size_t off, size_t len);
+
void buf_init(Buf* buf);
void buf_setpath(Buf* buf, char* path);
void buf_load(Buf* buf, char* path);
#include <sys/stat.h>
#include "config.h"
-extern void gapbuf_init(Buf* buf);
-extern long gapbuf_save(Buf* buf, char* path);
-extern void gapbuf_load(Buf* buf, char* path);
-extern char gapbuf_getb(Buf* buf, size_t off);
-extern void gapbuf_putb(Buf* buf, char b, Sel* p_sel);
-extern void gapbuf_del(Buf* buf, size_t off, size_t len);
-
#ifndef NDEBUG
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->contents.bufsize > 0)
+ && (buf->contents.bufstart != NULL)
+ && (buf->contents.bufend != NULL)
+ && (buf->contents.gapstart != NULL)
+ && (buf->contents.gapend != NULL)
+ && (buf->contents.bufstart < buf->contents.bufend)
+ && (buf->contents.gapstart <= buf->contents.gapend)
+ && (buf->contents.gapstart >= buf->contents.bufstart)
+ && (buf->contents.gapend >= buf->contents.bufstart)
+ && (buf->contents.gapstart <= buf->contents.bufend)
+ && (buf->contents.gapend <= buf->contents.bufend)
);
}
#endif
{
if (b == '\n' && DosLineFeed)
{
- gapbuf_putb(buf, '\r', p_sel);
- gapbuf_putb(buf, '\n', p_sel);
+ gapbuf_putb(&buf->contents, '\r', p_sel);
+ gapbuf_putb(&buf->contents, '\n', p_sel);
}
else
{
- gapbuf_putb(buf, b, p_sel);
+ gapbuf_putb(&buf->contents, b, p_sel);
}
+ buf->status = MODIFIED;
}
}
{
require(buf != NULL);
- /* cleanup old data if there is any */
- if (buf->bufstart)
- {
- free(buf->bufstart);
- buf->bufstart = NULL;
- free(buf->path);
- buf->path = NULL;
- buf_logclear(buf);
- }
-
/* reset the state to defaults */
- gapbuf_init(buf);
+ gapbuf_init(&buf->contents);
buf->status = NORMAL;
buf->undo = NULL;
buf->redo = NULL;
path += 2;
}
buf->path = strdup(path);
- gapbuf_load(buf, buf->path);
+ gapbuf_load(&buf->contents, buf->path);
/* reset buffer state */
buf->status = NORMAL;
buf_logclear(buf);
/* use the EOL style of the first line to determine EOL style */
- DosLineFeed = (gapbuf_getb(buf, buf_eol(buf, 0)) == '\r');
+ DosLineFeed = (gapbuf_getb(&buf->contents, buf_eol(buf, 0)) == '\r');
}
ensure(buf_valid(buf));
}
buf_logstart(buf);
while (prev != buf->selection.end)
{
- int r = gapbuf_getb(buf, buf->selection.end);
+ int r = gapbuf_getb(&buf->contents, buf->selection.end);
/* If we reached a newline, then delete whatever we have selected */
if (r == '\r' || r == '\n')
{
trim_whitespace(buf);
}
- long nwrite = gapbuf_save(buf, buf->path);
+ long nwrite = gapbuf_save(&buf->contents, buf->path);
buf->status = (nwrite >= 0 ? NORMAL : ERRORED);
if (buf->status == NORMAL)
/* reinsert deleted bytes */
for (char* s = item->data; s && *s; s++, item->end++)
{
- gapbuf_putb(buf, *s, &(buf->selection));
+ gapbuf_putb(&buf->contents, *s, &(buf->selection));
+ buf->status = MODIFIED;
}
free(item->data);
item->data = NULL;
/* delete the added bytes */
Sel sel = selget(buf);
item->data = buf_gets(buf);
- gapbuf_del(buf, sel.beg, (item->end - item->beg));
+ gapbuf_del(&buf->contents, sel.beg, (item->end - item->beg));
sel.end = sel.beg;
buf->selection = sel;
item->beg = sel.beg;
******************************************************************************/
size_t buf_end(Buf* buf)
{
- require(buf != NULL);
- size_t bufsz = buf->bufend - buf->bufstart;
- size_t gapsz = buf->gapend - buf->gapstart;
- return (bufsz - gapsz);
+ return gapbuf_end(&buf->contents);
}
int buf_getrat(Buf* buf, size_t off)
require(buf != NULL);
size_t rlen = 0;
Rune rune = 0;
- if (gapbuf_getb(buf, off) == '\r' && gapbuf_getb(buf, off+1) == '\n')
+ if (gapbuf_getb(&buf->contents, off) == '\r' && gapbuf_getb(&buf->contents, off+1) == '\n')
{
rune = '\n';
}
else
{
- while ( !utf8decode(&rune, &rlen, gapbuf_getb(buf, off++)) )
+ while ( !utf8decode(&rune, &rlen, gapbuf_getb(&buf->contents, off++)) )
{
}
}
char* str = malloc(nbytes+1);
for (size_t i = 0; i < nbytes; i++)
{
- str[i] = gapbuf_getb(buf, sel.beg + i);
+ str[i] = gapbuf_getb(&buf->contents, sel.beg + i);
}
str[nbytes] = '\0';
return str;
{
buf->status = MODIFIED;
char* str = buf_gets(buf);
- gapbuf_del(buf, sel.beg, nbytes);
+ gapbuf_del(&buf->contents, sel.beg, nbytes);
sel.end = sel.beg = (sel.beg < sel.end ? sel.beg : sel.end);
buf->selection = sel;
log_add(buf, sel.beg, sel.end, str);
int ret = 0;
for (; *str && mbeg < mend; str++, mbeg++)
{
- int cmp = *str - gapbuf_getb(buf, mbeg);
+ int cmp = *str - gapbuf_getb(&buf->contents, mbeg);
if (cmp != 0)
{
ret = cmp;
{
if (pos > 0 && move < 0)
{
- if (gapbuf_getb(buf, pos-2) == '\r' && gapbuf_getb(buf, pos-1) == '\n')
+ if (gapbuf_getb(&buf->contents, pos-2) == '\r' && gapbuf_getb(&buf->contents, pos-1) == '\n')
{
pos -= 2;
}
}
else if (pos < buf_end(buf) && move > 0)
{
- if (gapbuf_getb(buf, pos) == '\r' && gapbuf_getb(buf, pos+1) == '\n')
+ if (gapbuf_getb(&buf->contents, pos) == '\r' && gapbuf_getb(&buf->contents, pos+1) == '\n')
{
pos += 2;
}
size_t nleft = buf_end(buf);
for (; (mbeg != start) && nleft; nleft--)
{
- if ((gapbuf_getb(buf, mbeg) == str[0]) &&
- (gapbuf_getb(buf, mend-1) == str[len-1]) &&
+ if ((gapbuf_getb(&buf->contents, mbeg) == str[0]) &&
+ (gapbuf_getb(&buf->contents, mend-1) == str[len-1]) &&
(0 == bytes_match(buf, mbeg, mend, str)))
{
buf->selection.beg = mbeg, buf->selection.end = mend;
#include <sys/stat.h>
#include "config.h"
+size_t gapbuf_end(GapBuf* buf)
+{
+ require(buf != NULL);
+ size_t bufsz = buf->bufend - buf->bufstart;
+ size_t gapsz = buf->gapend - buf->gapstart;
+ return (bufsz - gapsz);
+}
+
static size_t pagealign(size_t sz)
{
size_t pgsize = sysconf(_SC_PAGE_SIZE);
return sz;
}
-static void resize(Buf* buf, size_t sz)
+static void resize(GapBuf* buf, size_t sz)
{
/* allocate the new buffer and gap */
- Buf copy = *buf;
+ GapBuf copy = *buf;
copy.bufsize = sz;
copy.bufstart = (char*)malloc(copy.bufsize);
copy.bufend = copy.bufstart + copy.bufsize;
/* free the buffer and commit the changes */
free(buf->bufstart);
- memcpy(buf, ©, sizeof(Buf));
+ memcpy(buf, ©, sizeof(GapBuf));
}
-static void syncgap(Buf* buf, size_t off)
+static void syncgap(GapBuf* buf, size_t off)
{
- assert(off <= buf_end(buf));
+ assert(off <= gapbuf_end(buf));
/* If the buffer is full, resize it before syncing */
if (0 == (buf->gapend - buf->gapstart))
{
}
}
-void gapbuf_init(Buf* buf)
+void gapbuf_init(GapBuf* buf)
{
buf->bufsize = 8192;
buf->bufstart = malloc(buf->bufsize);
buf->gapend = buf->bufend;
}
-long gapbuf_save(Buf* buf, char* path)
+long gapbuf_save(GapBuf* buf, char* path)
{
char* wptr;
long fd, nwrite = 0, towrite = 0;
while (towrite && ((nwrite = write(fd, wptr, towrite)) > 0))
wptr += nwrite, towrite -= nwrite;
close(fd);
- /* report success or failure */
- buf->status = (nwrite >= 0 ? NORMAL : ERRORED);
}
else
{
return nwrite;
}
-void gapbuf_load(Buf* buf, char* path)
+void gapbuf_load(GapBuf* buf, char* path)
{
/* load the contents from the file */
int fd, nread;
}
}
-char gapbuf_getb(Buf* buf, size_t off)
+char gapbuf_getb(GapBuf* buf, size_t off)
{
int c = '\n'; // TODO: get rid of this hack
- if (off < buf_end(buf))
+ if (off < gapbuf_end(buf))
{
size_t bsz = (buf->gapstart - buf->bufstart);
if (off < bsz)
return c;
}
-void gapbuf_putb(Buf* buf, char b, Sel* p_sel)
+void gapbuf_putb(GapBuf* buf, char b, Sel* p_sel)
{
syncgap(buf, p_sel->end);
*(buf->gapstart++) = b;
p_sel->end = p_sel->end + 1u;
p_sel->beg = p_sel->end;
- buf->status = MODIFIED;
}
-void gapbuf_del(Buf* buf, size_t off, size_t len)
+void gapbuf_del(GapBuf* buf, size_t off, size_t len)
{
syncgap(buf, off);
buf->gapend += len;
fprintf(f, "\t.rows:\t\t%p\n", (void*)Regions[i].rows);
fprintf(f, "\t.buffer:\n");
fprintf(f, "\t\t.status:\t%d\n", Regions[i].buffer.status);
- fprintf(f, "\t\t.modtime:\t%lu\n", (unsigned long)Regions[i].buffer.modtime);
- fprintf(f, "\t\t.bufsize:\t%zu\n", Regions[i].buffer.bufsize);
- fprintf(f, "\t\t.bufstart:\t%p\n", (void*)Regions[i].buffer.bufstart);
- fprintf(f, "\t\t.bufend:\t%p\n", (void*)Regions[i].buffer.bufend);
- fprintf(f, "\t\t.gapstart:\t%p\n", (void*)Regions[i].buffer.gapstart);
- fprintf(f, "\t\t.gapend:\t%p\n", (void*)Regions[i].buffer.gapend);
+ fprintf(f, "\t\t.bufsize:\t%zu\n", Regions[i].buffer.contents.bufsize);
+ fprintf(f, "\t\t.bufstart:\t%p\n", (void*)Regions[i].buffer.contents.bufstart);
+ fprintf(f, "\t\t.bufend:\t%p\n", (void*)Regions[i].buffer.contents.bufend);
+ fprintf(f, "\t\t.gapstart:\t%p\n", (void*)Regions[i].buffer.contents.gapstart);
+ fprintf(f, "\t\t.gapend:\t%p\n", (void*)Regions[i].buffer.contents.gapend);
fprintf(f, "\t\t.undo:\t\t%p\n", (void*)Regions[i].buffer.undo);
fprintf(f, "\t\t.redo:\t\t%p\n", (void*)Regions[i].buffer.redo);
fprintf(f, "\t\t.save:\t\t%p\n", (void*)Regions[i].buffer.save);
static void set_buffer_text(char* str)
{
+ /* cleanup old data if there is any */
+ if (TestBuf.contents.bufstart)
+ {
+ free(TestBuf.contents.bufstart);
+ TestBuf.contents.bufstart = NULL;
+ free(TestBuf.path);
+ TestBuf.path = NULL;
+ buf_logclear(&TestBuf);
+ }
buf_init(&TestBuf);
buf_puts(&TestBuf, str);
}
{
buf_init(&TestBuf);
CHECK(TestBuf.status != MODIFIED);
- CHECK(TestBuf.bufsize == 8192);
- CHECK(TestBuf.bufstart != NULL);
- CHECK(TestBuf.bufend == TestBuf.bufstart + TestBuf.bufsize);
- CHECK(TestBuf.gapstart == TestBuf.bufstart);
- CHECK(TestBuf.gapend == TestBuf.bufend);
+ CHECK(TestBuf.contents.bufsize == 8192);
+ CHECK(TestBuf.contents.bufstart != NULL);
+ CHECK(TestBuf.contents.bufend == TestBuf.contents.bufstart + TestBuf.contents.bufsize);
+ CHECK(TestBuf.contents.gapstart == TestBuf.contents.bufstart);
+ CHECK(TestBuf.contents.gapend == TestBuf.contents.bufend);
CHECK(TestBuf.undo == NULL);
CHECK(TestBuf.redo == NULL);
}
buf_putc(&TestBuf, 'a');
buf_init(&TestBuf);
CHECK(TestBuf.status != MODIFIED);
- CHECK(TestBuf.bufsize == 8192);
- CHECK(TestBuf.bufstart != NULL);
- CHECK(TestBuf.bufend == TestBuf.bufstart + TestBuf.bufsize);
- CHECK(TestBuf.gapstart == TestBuf.bufstart);
- CHECK(TestBuf.gapend == TestBuf.bufend);
+ CHECK(TestBuf.contents.bufsize == 8192);
+ CHECK(TestBuf.contents.bufstart != NULL);
+ CHECK(TestBuf.contents.bufend == TestBuf.contents.bufstart + TestBuf.contents.bufsize);
+ CHECK(TestBuf.contents.gapstart == TestBuf.contents.bufstart);
+ CHECK(TestBuf.contents.gapend == TestBuf.contents.bufend);
CHECK(TestBuf.undo == NULL);
CHECK(TestBuf.redo == NULL);
}
buf_init(&TestBuf);
buf_load(&TestBuf, "testdocs/lorem.txt");
CHECK(TestBuf.status != MODIFIED);
- CHECK(TestBuf.bufsize == 61440);
+ CHECK(TestBuf.contents.bufsize == 61440);
CHECK(TestBuf.undo == NULL);
CHECK(TestBuf.redo == NULL);
CHECK(!strcmp(TestBuf.path, "testdocs/lorem.txt"));
buf_init(&TestBuf);
buf_load(&TestBuf, "testdocs/waf");
CHECK(TestBuf.status != MODIFIED);
- CHECK(TestBuf.bufsize == 98304);
+ CHECK(TestBuf.contents.bufsize == 98304);
CHECK(TestBuf.undo == NULL);
CHECK(TestBuf.redo == NULL);
CHECK(!strcmp(TestBuf.path, "testdocs/waf"));
buf_init(&TestBuf);
buf_load(&TestBuf, "./testdocs/lorem.txt");
CHECK(TestBuf.status != MODIFIED);
- CHECK(TestBuf.bufsize == 61440);
+ CHECK(TestBuf.contents.bufsize == 61440);
CHECK(TestBuf.undo == NULL);
CHECK(TestBuf.redo == NULL);
CHECK(!strcmp(TestBuf.path, "testdocs/lorem.txt"));
TestBuf.path = "testdocs/lorem.txt";
buf_reload(&TestBuf);
CHECK(TestBuf.status != MODIFIED);
- CHECK(TestBuf.bufsize == 61440);
+ CHECK(TestBuf.contents.bufsize == 61440);
CHECK(TestBuf.undo == NULL);
CHECK(TestBuf.redo == NULL);
CHECK(!strcmp(TestBuf.path, "testdocs/lorem.txt"));