commit 89596b21383f11e9939ae97fbcfee92b99b03130
parent b13471343e63a9c034bde2a7d7f9476f07e28f42
Author: gearsix <gearsix@tuta.io>
Date: Wed, 20 Jul 2022 11:50:33 +0100
final cleanup
Diffstat:
M | Makefile | | | 12 | ++++++------ |
A | buf.c | | | 245 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
A | buf.h | | | 67 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
D | buffer.c | | | 245 | ------------------------------------------------------------------------------- |
D | buffer.h | | | 67 | ------------------------------------------------------------------- |
M | test.c | | | 230 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-- |
D | test.h | | | 2 | -- |
D | test_buffer.c | | | 233 | ------------------------------------------------------------------------------- |
8 files changed, 544 insertions(+), 557 deletions(-)
diff --git a/Makefile b/Makefile
@@ -1,12 +1,12 @@
CC := gcc
-SRC := buffer.c
-OUT := ec
-OPTS := -g -Wall -Wpedantic -std=c89
+SRC := buf.c
+OUT := piecetable
+OPTS := -g -Wall -Wpedantic
+
+all: $(static)
-all:
- ${CC} $(OPTS) $(SRC) main.c -o $(OUT)
static:
${CC} $(OPTS) -c $(SRC) -o $(OUT).o
ar rcs lib$(OUT).a $(OUT).o
test:
- ${CC} $(OPTS) $(SRC) test*c -o $(OUT)-test
+ ${CC} $(OPTS) $(SRC) test.c -o $(OUT)-test
diff --git a/buf.c b/buf.c
@@ -0,0 +1,245 @@
+#include "buf.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+
+#define CATCH(condition, msg, action) \
+ if (condition) { perror(msg); action; }
+
+static Piece *pieceblk = NULL;
+static Piece **freeblk = NULL;
+
+static void pclean()
+{
+ if (freeblk) free(freeblk);
+ if (pieceblk) 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, blksiz = 0;
+ static const size_t allocsiz = BUFSIZ/sizeof(Piece *);
+
+ if (!p) return (nfree == 0) ? NULL : freeblk[--nfree];
+
+ if (nfree + 1 > allocsiz * nblk) {
+ blksiz = (++nblk * allocsiz) * sizeof(Piece *);
+ freeblk = realloc(freeblk, blksiz);
+ }
+ CATCH(!freeblk, "failed to allocate freeblk",
+ exit(EXIT_FAILURE));
+
+ 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. */
+static Piece *palloc()
+{
+ Piece *p;
+
+ static size_t nblk = 0, nalloc = 0, blksiz = 0;
+ static const size_t allocsiz = BUFSIZ/sizeof(Piece);
+
+ static int hook = 0;
+
+ if ( !(p = pfree(NULL)) ) {
+ if (nalloc + 1 > allocsiz * nblk) {
+ blksiz = (++nblk * allocsiz) * sizeof(Piece);
+ pieceblk = realloc(pieceblk, blksiz);
+ }
+ CATCH(!pieceblk, "failed to allocate pieceblk",
+ exit(EXIT_FAILURE));
+ if (hook == 0) hook = !atexit(pclean);
+
+ p = &pieceblk[nalloc++];
+ }
+
+ 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` values of these & associated `Piece`
+ items will be updated to reflect the split.
+ `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 = p;
+ if (offset > 0 && offset <= (int)p->len) {
+ q = palloc();
+ memcpy(q, p, sizeof(Piece));
+ q->off += offset;
+ q->len -= p->len = offset;
+ q->next = p->next;
+ q->prev = p;
+ p->next = q;
+ if (q->next) q->next->prev = q;
+ } else if (offset == 0) {
+ q = palloc();
+ q->next = p;
+ p->prev = q;
+ }
+ return q;
+}
+
+/* pfind will find the `Piece` which contains index `pos`.
+ The search starts from `p`, where the index is `idx`.
+ `p` will be set to the found `Piece`.
+ The new index will be returned. */
+static size_t pfind(Piece **ptr, size_t idx, size_t pos)
+{
+ Piece *p = *ptr;
+ if (pos >= idx) {
+ while (pos >= idx + p->len && p->next) {
+ idx += p->len;
+ p = p->next;
+ }
+ } else {
+ do {
+ p = p->prev;
+ idx -= p->len;
+ } while (pos < idx && p->prev);
+ }
+ *ptr = p;
+ return idx;
+}
+
+struct Buf *bufinit(FILE *read, FILE *append)
+{
+ Buf *b = calloc(1, sizeof(Buf));
+
+ if (!append) return NULL;
+
+ b->read = read;
+ b->append = append;
+
+ b->tail = b->pos = b->head = palloc();
+ b->pos->f = b->read;
+ fseek(b->read, 0, SEEK_END);
+ b->size = b->pos->len = ftell(b->read);
+
+ return b;
+}
+
+void buffree(Buf *b)
+{
+ Piece *p = b->tail->next;
+ while (p) {
+ pfree(p->prev);
+ p = p->next;
+ }
+ free(b);
+}
+
+Piece *bufidx(Buf *b, size_t pos)
+{
+ size_t offset, idx = pfind(&b->pos, b->idx, pos);
+
+ if (idx != pos || idx == 0) {
+ offset = (idx >= pos) ? idx - pos : pos - idx;
+ b->pos = psplit(b->pos, offset);
+ if (!b->pos->prev) b->tail = b->pos;
+ if (!b->pos->next) b->head = b->pos;
+ }
+
+ b->idx = pos;
+ return b->pos;
+}
+
+size_t bufins(Buf *b, size_t pos, const char *s)
+{
+ const size_t slen = strlen(s);
+ Piece *p;
+
+ b->pos = bufidx(b, pos)->prev;
+ if (!b->pos) b->pos = b->tail;
+
+ p = palloc();
+ p->f = b->append;
+ p->off = ftell(b->append);
+ p->len = slen;
+ p->prev = b->pos;
+ p->next = b->pos->next;
+
+ b->pos->next = b->pos->next->prev = p;
+
+ fprintf(b->append, "%s", s);
+ CATCH(ferror(b->append), "bufins: write to append",
+ { pfree(p); p = 0; });
+
+ if (p != 0) {
+ b->idx += slen;
+ b->size += slen;
+ b->pos = p->next;
+ }
+
+ return b->size;
+}
+
+size_t bufdel(Buf *b, size_t pos, int num)
+{
+ size_t tmp;
+ Piece *pre, *post;
+
+ if (num < 0) {
+ if ((int)pos-num < 0)
+ num = pos;
+ else {
+ tmp = abs(num);
+ num = pos;
+ pos = (tmp > pos) ? 0 : tmp;
+ }
+ }
+
+ if (pos+num > b->size) num = b->size - pos;
+
+ pre = bufidx(b, pos)->prev;
+ if (!pre) pre = b->tail;
+ post = bufidx(b, pos+num);
+
+ pre->next = post;
+ post->prev = pre;
+
+ b->idx = pos;
+ return (b->size -= num);
+}
+
+size_t bufout(Buf *b, FILE *f)
+{
+ size_t n, fsiz = 0;
+ char buf[BUFSIZ];
+ Piece *p = b->tail;
+
+ do {
+ if (p->len > 0 && p->f) {
+ if ((size_t)ftell(p->f) != p->off)
+ fseek(p->f, p->off, SEEK_SET);
+
+ n = 0;
+ do {
+ buf[0] = '\0';
+ fread(buf, 1, p->len, p->f);
+ CATCH(ferror(p->f), "bufout: fread failed", break);
+ fsiz += fwrite(buf, 1, p->len, f);
+ CATCH(ferror(f), "bufout: fwrite failed", break);
+ } while (p->len - (BUFSIZ*n++) > BUFSIZ);
+ }
+ p = p->next;
+ } while(p);
+
+ return fsiz;
+}
diff --git a/buf.h b/buf.h
@@ -0,0 +1,67 @@
+/* A piece chain implementation.
+ gearsix, 2022 */
+#ifndef PIECETABLE
+#define PIECETABLE
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+#include <stdio.h>
+
+/* Points to a file (`f`), which contains a string that starts at
+ `off`, with length of `len`. `prev` and `next` point to the
+ previous and next items in the table. */
+typedef struct Piece {
+ FILE *f;
+ size_t off, len;
+ struct Piece *prev, *next;
+} Piece;
+
+/* Holds a doubly-linked `Piece` list, starting at `tail`, ending at
+ `head`. `pos` points to the last addressed `Piece`. `size` is the
+ sum length of all `len` values of all `Piece` items in the list.
+ `idx` is the last addressed index in the chain. `read` and `append`
+ point to the original file and any data to be added. */
+typedef struct Buf {
+ FILE *read, *append;
+ size_t size, idx;
+ 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, int num);
+
+/* writes all data in `b` to `f`. */
+size_t
+bufout(Buf *b, FILE *f);
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* PIECETABLE */
diff --git a/buffer.c b/buffer.c
@@ -1,245 +0,0 @@
-#include "buffer.h"
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <errno.h>
-
-#define CATCH(condition, msg, action) \
- if (condition) { perror(msg); action; }
-
-static Piece *pieceblk = NULL;
-static Piece **freeblk = NULL;
-
-static void pclean()
-{
- if (freeblk) free(freeblk);
- if (pieceblk) 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, blksiz = 0;
- static const size_t allocsiz = BUFSIZ/sizeof(Piece *);
-
- if (!p) return (nfree == 0) ? NULL : freeblk[--nfree];
-
- if (nfree + 1 > allocsiz * nblk) {
- blksiz = (++nblk * allocsiz) * sizeof(Piece *);
- freeblk = realloc(freeblk, blksiz);
- }
- CATCH(!freeblk, "failed to allocate freeblk",
- exit(EXIT_FAILURE));
-
- 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. */
-static Piece *palloc()
-{
- Piece *p;
-
- static size_t nblk = 0, nalloc = 0, blksiz = 0;
- static const size_t allocsiz = BUFSIZ/sizeof(Piece);
-
- static int hook = 0;
-
- if ( !(p = pfree(NULL)) ) {
- if (nalloc + 1 > allocsiz * nblk) {
- blksiz = (++nblk * allocsiz) * sizeof(Piece);
- pieceblk = realloc(pieceblk, blksiz);
- }
- CATCH(!pieceblk, "failed to allocate pieceblk",
- exit(EXIT_FAILURE));
- if (hook == 0) hook = !atexit(pclean);
-
- p = &pieceblk[nalloc++];
- }
-
- 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` values of these & associated `Piece`
- items will be updated to reflect the split.
- `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 = p;
- if (offset > 0 && offset <= (int)p->len) {
- q = palloc();
- memcpy(q, p, sizeof(Piece));
- q->off += offset;
- q->len -= p->len = offset;
- q->next = p->next;
- q->prev = p;
- p->next = q;
- if (q->next) q->next->prev = q;
- } else if (offset == 0) {
- q = palloc();
- q->next = p;
- p->prev = q;
- }
- return q;
-}
-
-/* pfind will find the `Piece` which contains index `pos`.
- The search starts from `p`, where the index is `idx`.
- `p` will be set to the found `Piece`.
- The new index will be returned. */
-static size_t pfind(Piece **ptr, size_t idx, size_t pos)
-{
- Piece *p = *ptr;
- if (pos >= idx) {
- while (pos >= idx + p->len && p->next) {
- idx += p->len;
- p = p->next;
- }
- } else {
- do {
- p = p->prev;
- idx -= p->len;
- } while (pos < idx && p->prev);
- }
- *ptr = p;
- return idx;
-}
-
-struct Buffer *bufinit(FILE *read, FILE *append)
-{
- Buffer *b = calloc(1, sizeof(Buffer));
-
- if (!append) return NULL;
-
- b->read = read;
- b->append = append;
-
- b->tail = b->pos = b->head = palloc();
- b->pos->f = b->read;
- fseek(b->read, 0, SEEK_END);
- b->size = b->pos->len = ftell(b->read);
-
- return b;
-}
-
-void buffree(Buffer *b)
-{
- Piece *p = b->tail->next;
- while (p) {
- pfree(p->prev);
- p = p->next;
- }
- free(b);
-}
-
-Piece *bufidx(Buffer *b, size_t pos)
-{
- size_t offset, idx = pfind(&b->pos, b->idx, pos);
-
- if (idx != pos || idx == 0) {
- offset = (idx >= pos) ? idx - pos : pos - idx;
- b->pos = psplit(b->pos, offset);
- if (!b->pos->prev) b->tail = b->pos;
- if (!b->pos->next) b->head = b->pos;
- }
-
- b->idx = pos;
- return b->pos;
-}
-
-size_t bufins(Buffer *b, size_t pos, const char *s)
-{
- const size_t slen = strlen(s);
- Piece *p;
-
- b->pos = bufidx(b, pos)->prev;
- if (!b->pos) b->pos = b->tail;
-
- p = palloc();
- p->f = b->append;
- p->off = ftell(b->append);
- p->len = slen;
- p->prev = b->pos;
- p->next = b->pos->next;
-
- b->pos->next = b->pos->next->prev = p;
-
- fprintf(b->append, "%s", s);
- CATCH(ferror(b->append), "bufins: write to append",
- { pfree(p); p = 0; });
-
- if (p != 0) {
- b->idx += slen;
- b->size += slen;
- b->pos = p->next;
- }
-
- return b->size;
-}
-
-size_t bufdel(Buffer *b, size_t pos, int num)
-{
- size_t tmp;
- Piece *pre, *post;
-
- if (num < 0) {
- if ((int)pos-num < 0)
- num = pos;
- else {
- tmp = abs(num);
- num = pos;
- pos = (tmp > pos) ? 0 : tmp;
- }
- }
-
- if (pos+num > b->size) num = b->size - pos;
-
- pre = bufidx(b, pos)->prev;
- if (!pre) pre = b->tail;
- post = bufidx(b, pos+num);
-
- pre->next = post;
- post->prev = pre;
-
- b->idx = pos;
- return (b->size -= num);
-}
-
-int bufout(Buffer *b, FILE *f)
-{
- size_t n, fsiz = 0;
- char buf[BUFSIZ];
- Piece *p = b->tail;
-
- do {
- if (p->len > 0 && p->f) {
- if ((size_t)ftell(p->f) != p->off)
- fseek(p->f, p->off, SEEK_SET);
-
- n = 0;
- do {
- buf[0] = '\0';
- fread(buf, 1, p->len, p->f);
- CATCH(ferror(p->f), "bufout: fread failed", break);
- fsiz += fwrite(buf, 1, p->len, f);
- CATCH(ferror(f), "bufout: fwrite failed", break);
- } while (p->len - (BUFSIZ*n++) > BUFSIZ);
- }
- p = p->next;
- } while(p);
-
- return fsiz;
-}
diff --git a/buffer.h b/buffer.h
@@ -1,67 +0,0 @@
-/* A piece chain implementation.
- gearsix, 2022 */
-#ifndef ECBUF
-#define ECBUF
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#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 doubly-linked list. */
-typedef struct Piece {
- FILE *f;
- size_t off, len;
- struct Piece *prev, *next;
-} Piece;
-
-/* Holds a doubly-linked `Piece` list, starting at `tail` and ending
- at `head`. `pos` points to the last addressed `Piece`.
- `size` is the sum length of all `Piece` `len` values in the
- chain. `idx` is the last addressed index in the chain.
- `read` and `append` point to the original file (`read`) and
- any data to be added `append`. */
-typedef struct Buffer {
- FILE *read, *append;
- size_t size, idx;
- struct Piece *tail, *pos, *head;
-} Buffer;
-
-/* Allocates & initialises a `Buffer`. If `append` is NULL, nothing is
- allocated or initialised and NULL is returned. */
-Buffer *
-bufinit(FILE *read, FILE *append);
-
-/* Frees `b` and all `Piece` items associated with it. */
-void
-buffree(Buffer *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(Buffer *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(Buffer *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(Buffer *b, size_t pos, int num);
-
-/* writes all data in `b` to `f`. */
-int
-bufout(Buffer *b, FILE *f);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* ECBUF */
diff --git a/test.c b/test.c
@@ -1,11 +1,233 @@
-#include "test.h"
+
+#include "buf.h"
#include <stdio.h>
+#include <signal.h>
+#include <string.h>
+#include <assert.h>
+
+static Buf *B;
+
+static FILE *in_f;
+static const char *in_p = "in.txt", *in_buf = "hello world";
+static FILE *out_f;
+static const char *out_p = "out.txt", *out_buf = "Hey buddy!";
+static FILE *tmp_f;
+static const char *tmp_p = "tmp.txt";
+
+
+static void setup();
+static void setdown();
+static void test_bufinit();
+static void test_bufidx();
+static void test_bufins();
+static void test_bufdel();
+static void test_bufins1();
+static void test_bufdel1();
+static void test_bufins2();
+static void test_bufout();
int main()
{
- test_buffer();
- puts("no assertions failed");
- return 0;
+ printf("test: ");
+ setup();
+ signal(SIGABRT, setdown);
+ test_bufinit();
+ test_bufidx();
+ test_bufins();
+ test_bufdel();
+ test_bufins1();
+ test_bufdel1();
+ test_bufins2();
+ test_bufout();
+ setdown(0);
+ puts("success");
+}
+
+static void debugprint()
+{
+ Piece *p = B->tail;
+
+ printf("\nBuf: %p\n", (void *)B);
+ printf("size: %d, index: %d\n", (int)B->size, (int)B->idx);
+ do {
+ printf("%p", (void *)p);
+ if (p == B->tail) printf("<-tail");
+ if (p == B->head) printf("<-head");
+ if (p == B->pos) printf("<-pos");
+ printf("\n\toff: %d, len %d, f: %s\n", (int)p->off, (int)p->len,
+ (!p->f) ? "0" : (p->f == B->read) ? "read" : "append");
+ } while ((p = p->next));
+ printf("\n");
+}
+
+static void setup()
+{
+ in_f = fopen(in_p, "w+b");
+ if (ferror(in_f)) perror("fopen in");
+ fputs(in_buf, in_f);
+
+ out_f = fopen(out_p, "w+b");
+ if (ferror(out_f)) perror("fopen out");
+
+ tmp_f = fopen(tmp_p, "w+b");
+ if (ferror(tmp_f)) perror("fopen tmp");
+}
+
+static void setdown(int n)
+{
+ buffree(B);
+ fclose(out_f);
+ fclose(in_f);
+ fclose(tmp_f);
+ if (n != SIGABRT) {
+ remove(in_p);
+ remove(out_p);
+ remove(tmp_p);
+ }
+}
+
+static void test_bufinit()
+{
+ Piece *p;
+
+ B = bufinit(in_f, tmp_f);
+
+ assert(B->read);
+ assert(B->append);
+ assert(B->pos == B->tail);
+ assert(B->pos == B->head);
+
+ assert((p = B->pos));
+ assert(p->f == B->read);
+ assert(p->off == 0);
+ assert(p->len == strlen(in_buf));
+ assert(p->prev == NULL);
+ assert(p->next == NULL);
+}
+
+static void test_bufidx()
+{
+ Piece *p; size_t idx = 5;
+
+ p = bufidx(B, idx);
+
+ assert(p == B->pos);
+ assert(p == B->head);
+ assert(p->prev == B->tail);
+ assert(p->f == B->read);
+ assert(p->off == idx);
+ assert(p->len == strlen(in_buf) - idx);
+}
+
+static void test_bufins()
+{
+ const char *buf = "y"; size_t idx = 2;
+ const size_t len = strlen(buf);
+
+ bufins(B, idx, buf);
+
+ assert(B->size == strlen(in_buf) + len);
+ assert(B->idx == idx + len);
+ assert(B->pos == B->tail->next->next);
+
+ assert(B->pos->f == B->read);
+ assert(B->pos->off == 2);
+ assert(B->pos->len == 3);
+ assert(B->pos->prev == B->tail->next);
+ assert(B->pos->next == B->head);
+}
+
+static void test_bufdel()
+{
+ size_t idx = 3; int len = B->size+1;
+ const size_t bsiz = B->size;
+
+ bufdel(B, idx, len);
+
+ assert(B->size == bsiz-(bsiz-idx));
+ assert(B->idx == idx);
+ assert(B->pos == B->head);
+ assert(B->tail->next->next == B->pos);
+
+ assert(B->pos->f == B->read);
+ assert(B->pos->off == 11);
+ assert(B->pos->len == 0);
+ assert(B->pos->prev == B->tail->next);
+ assert(B->pos->next == NULL);
+}
+
+static void test_bufins1()
+{
+ size_t idx = 3; const char *buf = " buddy!";
+ const size_t len = strlen(buf), bsiz = B->size;
+
+ bufins(B, idx, buf);
+
+ assert(B->size == bsiz + len);
+ assert(B->idx == idx + len);
+ assert(B->pos == B->head);
+ assert(B->pos == B->tail->next->next->next);
+
+ assert(B->pos->prev->f == B->append);
+ assert(B->pos->prev->off == 1);
+ assert(B->pos->prev->len == len);
+ assert(B->pos->prev == B->tail->next->next);
+ assert(B->pos->next == NULL);
+}
+
+static void test_bufdel1()
+{
+ size_t idx = 0; int len = 1;
+ const size_t bsiz = B->size;
+
+ bufdel(B, idx, len);
+
+ assert(B->size == bsiz - len);
+ assert(B->idx == idx);
+
+ assert(B->pos->prev == B->tail);
+ assert(B->pos->prev->f == 0);
+ assert(B->pos->prev->off == 0);
+ assert(B->pos->prev->len == 0);
+ assert(B->pos->prev->prev == 0);
+ assert(B->pos->prev->next == B->pos);
+
+ assert(B->pos->f == B->read);
+ assert(B->pos->off == 1);
+ assert(B->pos->len == (size_t)len);
+ assert(B->pos->prev == B->tail);
+ assert(B->pos->next->next->next == B->head);
+}
+
+static void test_bufins2()
+{
+ const char *buf = "H"; const size_t idx = 0;
+ size_t len = strlen(buf), bsiz = B->size;
+
+ bufins(B, idx, buf);
+
+ assert(B->size == bsiz + len);
+ assert(B->idx == idx + len);
+ assert(B->pos == B->tail->next->next);
+
+ assert(B->pos->prev == B->tail->next);
+ assert(B->pos->prev->f == B->append);
+ assert(B->pos->prev->off == 8);
+ assert(B->pos->prev->len == 1);
+ assert(B->pos->prev->prev == B->tail);
+ assert(B->pos->prev->next == B->pos);
+}
+
+static void test_bufout()
+{
+ size_t n = 0;
+ char buf[BUFSIZ] = {0};
+
+ bufout(B, out_f);
+ rewind(out_f);
+ n = fread(buf, 1, BUFSIZ, out_f);
+ assert(n > 0);
+ assert(strcmp(buf, out_buf) == 0);
}
diff --git a/test.h b/test.h
@@ -1,2 +0,0 @@
-
-void test_buffer();
diff --git a/test_buffer.c b/test_buffer.c
@@ -1,233 +0,0 @@
-#include "test.h"
-#include "buffer.h"
-
-#include <stdio.h>
-#include <signal.h>
-#include <string.h>
-#include <assert.h>
-
-static Buffer *B;
-
-static FILE *in_f;
-static const char *in_p = "in.txt", *in_buf = "hello world";
-static FILE *out_f;
-static const char *out_p = "out.txt", *out_buf = "Hey buddy!";
-static FILE *tmp_f;
-static const char *tmp_p = "tmp.txt";
-
-
-static void setup();
-static void setdown();
-static void test_bufinit();
-static void test_bufidx();
-static void test_bufins();
-static void test_bufdel();
-static void test_bufins1();
-static void test_bufdel1();
-static void test_bufins2();
-static void test_bufout();
-
-
-void test_buffer()
-{
- printf("test_buffer: ");
- setup();
- signal(SIGABRT, setdown);
- test_bufinit();
- test_bufidx();
- test_bufins();
- test_bufdel();
- test_bufins1();
- test_bufdel1();
- test_bufins2();
- test_bufout();
- setdown(0);
- puts("success");
-}
-
-static void debugprint()
-{
- Piece *p = B->tail;
-
- printf("\nBuf: %p\n", (void *)B);
- printf("size: %d, index: %d\n", (int)B->size, (int)B->idx);
- do {
- printf("%p", (void *)p);
- if (p == B->tail) printf("<-tail");
- if (p == B->head) printf("<-head");
- if (p == B->pos) printf("<-pos");
- printf("\n\toff: %d, len %d, f: %s\n", (int)p->off, (int)p->len,
- (!p->f) ? "0" : (p->f == B->read) ? "read" : "append");
- } while ((p = p->next));
- printf("\n");
-}
-
-static void setup()
-{
- in_f = fopen(in_p, "w+b");
- if (ferror(in_f)) perror("fopen in");
- fputs(in_buf, in_f);
-
- out_f = fopen(out_p, "w+b");
- if (ferror(out_f)) perror("fopen out");
-
- tmp_f = fopen(tmp_p, "w+b");
- if (ferror(tmp_f)) perror("fopen tmp");
-}
-
-static void setdown(int n)
-{
- buffree(B);
- fclose(out_f);
- fclose(in_f);
- fclose(tmp_f);
- if (n != SIGABRT) {
- remove(in_p);
- remove(out_p);
- remove(tmp_p);
- }
-}
-
-static void test_bufinit()
-{
- Piece *p;
-
- B = bufinit(in_f, tmp_f);
-
- assert(B->read);
- assert(B->append);
- assert(B->pos == B->tail);
- assert(B->pos == B->head);
-
- assert((p = B->pos));
- assert(p->f == B->read);
- assert(p->off == 0);
- assert(p->len == strlen(in_buf));
- assert(p->prev == NULL);
- assert(p->next == NULL);
-}
-
-static void test_bufidx()
-{
- Piece *p; size_t idx = 5;
-
- p = bufidx(B, idx);
-
- assert(p == B->pos);
- assert(p == B->head);
- assert(p->prev == B->tail);
- assert(p->f == B->read);
- assert(p->off == idx);
- assert(p->len == strlen(in_buf) - idx);
-}
-
-static void test_bufins()
-{
- const char *buf = "y"; size_t idx = 2;
- const size_t len = strlen(buf);
-
- bufins(B, idx, buf);
-
- assert(B->size == strlen(in_buf) + len);
- assert(B->idx == idx + len);
- assert(B->pos == B->tail->next->next);
-
- assert(B->pos->f == B->read);
- assert(B->pos->off == 2);
- assert(B->pos->len == 3);
- assert(B->pos->prev == B->tail->next);
- assert(B->pos->next == B->head);
-}
-
-static void test_bufdel()
-{
- size_t idx = 3; int len = B->size+1;
- const size_t bsiz = B->size;
-
- bufdel(B, idx, len);
-
- assert(B->size == bsiz-(bsiz-idx));
- assert(B->idx == idx);
- assert(B->pos == B->head);
- assert(B->tail->next->next == B->pos);
-
- assert(B->pos->f == B->read);
- assert(B->pos->off == 11);
- assert(B->pos->len == 0);
- assert(B->pos->prev == B->tail->next);
- assert(B->pos->next == NULL);
-}
-
-static void test_bufins1()
-{
- size_t idx = 3; const char *buf = " buddy!";
- const size_t len = strlen(buf), bsiz = B->size;
-
- bufins(B, idx, buf);
-
- assert(B->size == bsiz + len);
- assert(B->idx == idx + len);
- assert(B->pos == B->head);
- assert(B->pos == B->tail->next->next->next);
-
- assert(B->pos->prev->f == B->append);
- assert(B->pos->prev->off == 1);
- assert(B->pos->prev->len == len);
- assert(B->pos->prev == B->tail->next->next);
- assert(B->pos->next == NULL);
-}
-
-static void test_bufdel1()
-{
- size_t idx = 0; int len = 1;
- const size_t bsiz = B->size;
-
- bufdel(B, idx, len);
-
- assert(B->size == bsiz - len);
- assert(B->idx == idx);
-
- assert(B->pos->prev == B->tail);
- assert(B->pos->prev->f == 0);
- assert(B->pos->prev->off == 0);
- assert(B->pos->prev->len == 0);
- assert(B->pos->prev->prev == 0);
- assert(B->pos->prev->next == B->pos);
-
- assert(B->pos->f == B->read);
- assert(B->pos->off == 1);
- assert(B->pos->len == (size_t)len);
- assert(B->pos->prev == B->tail);
- assert(B->pos->next->next->next == B->head);
-}
-
-static void test_bufins2()
-{
- const char *buf = "H"; const size_t idx = 0;
- size_t len = strlen(buf), bsiz = B->size;
-
- bufins(B, idx, buf);
-
- assert(B->size == bsiz + len);
- assert(B->idx == idx + len);
- assert(B->pos == B->tail->next->next);
-
- assert(B->pos->prev == B->tail->next);
- assert(B->pos->prev->f == B->append);
- assert(B->pos->prev->off == 8);
- assert(B->pos->prev->len == 1);
- assert(B->pos->prev->prev == B->tail);
- assert(B->pos->prev->next == B->pos);
-}
-
-static void test_bufout()
-{
- size_t n = 0;
- char buf[BUFSIZ] = {0};
-
- bufout(B, out_f);
- rewind(out_f);
- n = fread(buf, 1, BUFSIZ, out_f);
- assert(n > 0);
- assert(strcmp(buf, out_buf) == 0);
-}