piece-chain

Research & implementation of a Piece Chain
git clone git://src.gearsix.net/piece-chain.git
Log | Files | Refs | Atom | README

commit 2f3ea34be6b3b10dcf43e89941a6a35394c3c2af
parent 003fd961221b10fd75960257c508b107e252bb27
Author: gearsix <gearsix@tuta.io>
Date:   Sat,  9 Jul 2022 15:42:05 +0100

added comment doc to buf.{h,c}; removed unused undo, redo in Piece.

Diffstat:
Mbuf.c | 33++++++++++++++++++++++++++-------
Mbuf.h | 18+++++++++++++++++-
Mtest.c | 6------
3 files changed, 43 insertions(+), 14 deletions(-)

diff --git a/buf.c b/buf.c @@ -4,9 +4,10 @@ #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <errno.h> -static Piece *pieceblk = NULL; /* block of all pieces */ -static Piece **freeblk = NULL; /* ptr block to all free'd `pieceblk` items */ +static Piece *pieceblk = NULL; +static Piece **freeblk = NULL; static void pclean() { @@ -14,6 +15,10 @@ static void pclean() free(pieceblk); } +/* adds `p` to `freeblk` and returns the last added `freeblk` item. + If `p` is NULL, the last added `freeblk` item will be returned, + or NULL if `freeblk` is empty. + `freeblk` is dynamically allocated. */ static Piece *pfree(Piece *p) { static size_t nblk = 0, nfree = 0; @@ -28,6 +33,12 @@ static Piece *pfree(Piece *p) return freeblk[nfree++] = p; } +/* returns the next available `Piece` item in `pieceblk`. + If `freeblk` is not empty, it's last item pointed to by it will be + returned (recycling `pieceblk` items). The returned `Piece` will + always have it's values set to 0. `pieceblk` is dynamically + allocated. + `atexit(pclean)` is called the first time the function is called. */ static Piece *palloc() { Piece *p; @@ -36,7 +47,7 @@ static Piece *palloc() static const size_t blksiz = BUFSIZ/sizeof(Piece); static int hook = 0; - if (hook == 0) { atexit(pclean); hook = 1; } + if (!hook) { atexit(pclean); hook = 1; } if ( !(p = pfree(NULL)) ) { if (nalloc + 1 > blksiz * nblk) @@ -48,10 +59,18 @@ static Piece *palloc() return memset(p, 0, sizeof(Piece)); } +/* splits `p` into two `Piece` items. The values of `p` will be + modified to fit the first `Piece`; a new `Piece` will be allocated + for the second. + The `prev` and `next` items of these & associated `Piece` items will + be updated to reflect the new `Piece`. + `offset` should be the offset within `p->len` to split at. If offset + is not within the boundry of `p->len`, then `p` will be returned. + The *first* `Piece` in the split is returned. */ static Piece *psplit(Piece *p, long int offset) { Piece *q = palloc(); - if (offset > 0) { + if (offset > 0 && offset <= (int)p->len) { memcpy(q, p, sizeof(Piece)); q->off += offset; @@ -70,7 +89,7 @@ struct Buf *bufinit(FILE *read, FILE *append) { Buf *b = calloc(1, sizeof(Buf)); - if (!read || !append) return NULL; + if (!append) return NULL; b->read = read; b->append = append; @@ -133,8 +152,6 @@ size_t bufins(Buf *b, size_t pos, const char *s) p->f = b->append; p->off = ftell(b->append); p->len = slen; - p->undo = NULL; - p->redo = NULL; p->prev = b->pos; p->next = b->pos->next; @@ -183,7 +200,9 @@ int bufout(Buf *b, FILE *f) do { buf[0] = '\0'; fread(buf, 1, p->len, p->f); + if (ferror(p->f)) { perror("bufout: fread failed"); break; } fsiz += fwrite(buf, 1, p->len, f); + if (ferror(f)) { perror("bufout: fwrite failed"); break; } } while (p->len - (BUFSIZ*n++) > BUFSIZ); p = p->next; diff --git a/buf.h b/buf.h @@ -1,11 +1,14 @@ /* TODO */ #include <stdio.h> +/* Points to a file (`f`), which contains a string which + starts within `f` at `off` and has a length of `len`. + `prev` and `next` point to the previous and next + `Piece` elements in the intended double-linked list. */ typedef struct Piece { FILE *f; size_t off, len; - struct Piece *undo, *redo; struct Piece *prev, *next; } Piece; @@ -15,14 +18,27 @@ typedef struct Buf { struct Piece *tail, *pos, *head; } Buf; +/* Allocates & initialises a `Buf`. If `append` is NULL, + nothing is allocated or initialised and NULL is + returned. */ Buf *bufinit(FILE *read, FILE *append); +/* Frees `b` and all `Piece` items associated with it. */ void buffree(Buf *b); +/* Set `b->idx` to `pos` and `b->pos` to the `Piece` + in the chain, where the start of `b->pos->next` + is `pos`. */ Piece *bufidx(Buf *b, size_t pos); +/* Adds a new `Piece` to the chain, at `pos` (found + using `bufidx`). `s` will be appended to `b->append` + and the new `Piece` will reflect the appended data. */ size_t bufins(Buf *b, size_t pos, const char *s); +/* Removed all pieces from index `pos` to `pos+num`. + `pos` and `pos+num` are found using `bufidx`. */ size_t bufdel(Buf *b, size_t pos, size_t num); +/* writes all data in `b` to `f`. */ int bufout(Buf *b, FILE *f); diff --git a/test.c b/test.c @@ -100,8 +100,6 @@ void test_bufins() assert(b->pos->f == b->read); assert(b->pos->off == 2); assert(b->pos->len == 3); - assert(b->pos->undo == NULL); - assert(b->pos->redo == NULL); assert(b->pos->prev == b->tail->next); assert(b->pos->next == b->head); } @@ -120,8 +118,6 @@ void test_bufdel() assert(b->pos->f == b->read); assert(b->pos->off == 11); assert(b->pos->len == 0); - assert(b->pos->undo == NULL); - assert(b->pos->redo == NULL); assert(b->pos->prev == b->tail->next); assert(b->pos->next == NULL); } @@ -141,8 +137,6 @@ void test_bufins1() assert(b->pos->prev->f == b->append); assert(b->pos->prev->off == 1); assert(b->pos->prev->len == len); - assert(b->pos->undo == NULL); - assert(b->pos->redo == NULL); assert(b->pos->prev == b->tail->next->next); assert(b->pos->next == NULL); }