From cb632ff51e1ed7a7367a82dd31ae84c3ecc0a934 Mon Sep 17 00:00:00 2001 From: TJ Holowaychuk Date: Sun, 16 Dec 2012 14:57:11 -0800 Subject: [PATCH] Initial commit --- .gitignore | 2 + History.md | 5 ++ Makefile | 6 ++ Readme.md | 3 + buffer.c | 175 +++++++++++++++++++++++++++++++++++++++++++++++++++ buffer.h | 62 ++++++++++++++++++ package.json | 9 +++ test.c | 136 +++++++++++++++++++++++++++++++++++++++ 8 files changed, 398 insertions(+) create mode 100644 .gitignore create mode 100644 History.md create mode 100644 Makefile create mode 100644 Readme.md create mode 100644 buffer.c create mode 100644 buffer.h create mode 100644 package.json create mode 100644 test.c diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..f4ab3d5 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +test +*.o diff --git a/History.md b/History.md new file mode 100644 index 0000000..363e1bd --- /dev/null +++ b/History.md @@ -0,0 +1,5 @@ + +0.0.2 / 2012-09-17 +================== + + * add `string_to_seconds(str)` diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e2f516c --- /dev/null +++ b/Makefile @@ -0,0 +1,6 @@ + +test: buffer.c test.c + @$(CC) $^ -std=c99 -o $@ + @./test + +.PHONY: test diff --git a/Readme.md b/Readme.md new file mode 100644 index 0000000..514cb9e --- /dev/null +++ b/Readme.md @@ -0,0 +1,3 @@ + +# buffer.c + diff --git a/buffer.c b/buffer.c new file mode 100644 index 0000000..3c9bf35 --- /dev/null +++ b/buffer.c @@ -0,0 +1,175 @@ + +// +// buffer.c +// +// Copyright (c) 2012 TJ Holowaychuk +// + +#include +#include +#include "buffer.h" + +/* + * Compute the nearest multiple of `a` from `b`. + */ + +#define nearest_multiple_of(a, b) \ + (((b) + ((a) - 1)) & ~((a) - 1)) + +/* + * Allocate a new buffer with BUFFER_DEFAULT_SIZE. + */ + +buffer_t * +buffer_new() { + return buffer_new_with_size(BUFFER_DEFAULT_SIZE); +} + +/* + * Allocate a new buffer with `n` bytes. + */ + +buffer_t * +buffer_new_with_size(size_t n) { + buffer_t *self = malloc(sizeof(buffer_t)); + if (!self) return NULL; + self->len = n; + self->data = calloc(n, 1); + return self; +} + +/* + * Allocate a new buffer with `str`. + */ + +buffer_t * +buffer_new_with_string(char *str) { + size_t len = strlen(str); + buffer_t *self = buffer_new_with_size(len); + if (!self) return NULL; + memcpy(self->data, str, len); + return self; +} + +/* + * Free the buffer. + */ + +void +buffer_free(buffer_t *self) { + free(self->data); + free(self); +} + +/* + * Return buffer size. + */ + +size_t +buffer_size(buffer_t *self) { + return self->len; +} + +/* + * Return string length. + */ + +size_t +buffer_length(buffer_t *self) { + return strlen(self->data); +} + +/* + * Resize to hold `n` bytes. + */ + +int +buffer_resize(buffer_t *self, size_t n) { + n = nearest_multiple_of(1024, n); + self->len = n; + self->data = realloc(self->data, n); + return self->data ? 0 : -1; +} + +/* + * Append `str` to `self` and return 0 on success, -1 on failure. + */ + +int +buffer_append(buffer_t *self, char *str) { + size_t len = strlen(str); + size_t prev = strlen(self->data); + size_t needed = len + prev; + + // enough space + if (self->len > needed) { + strcat(self->data, str); + return 0; + } + + // resize + int ret = buffer_resize(self, needed); + if (-1 == ret) return -1; + strcat(self->data, str); + + return 0; +} + +/* + * Prepend `str` to `self` and return 0 on success, -1 on failure. + */ + +int +buffer_prepend(buffer_t *self, char *str) { + size_t len = strlen(str); + size_t prev = strlen(self->data); + size_t needed = len + prev; + + // enough space + if (self->len > needed) goto move; + + // resize + int ret = buffer_resize(self, needed); + if (-1 == ret) return -1; + + // move + move: + memmove(self->data + len, self->data, len + 1); + memcpy(self->data, str, len); + + return 0; +} + +/* + * Return a new buffer based on the `from..to` slice of `buf`, + * or NULL on error. + */ + +buffer_t * +buffer_slice(buffer_t *buf, size_t from, ssize_t to) { + size_t len = strlen(buf->data); + + // bad range + if (to < from) return NULL; + + // relative to end + if (to < 0) to = len - ~to; + + // cap end + if (to > len) to = len; + + size_t n = to - from; + buffer_t *self = buffer_new_with_size(n + 1); + memcpy(self->data, buf->data + from, n); + return self; +} + +/* + * Return 1 if the buffers contain equivalent data. + */ + +int +buffer_equals(buffer_t *self, buffer_t *other) { + return 0 == strcmp(self->data, other->data); +} + diff --git a/buffer.h b/buffer.h new file mode 100644 index 0000000..9f8498c --- /dev/null +++ b/buffer.h @@ -0,0 +1,62 @@ + +// +// buffer.h +// +// Copyright (c) 2012 TJ Holowaychuk +// + +#ifndef BUFFER +#define BUFFER + +/* + * Default buffer size. + */ + +#ifndef BUFFER_DEFAULT_SIZE +#define BUFFER_DEFAULT_SIZE 64 +#endif + +/* + * Buffer struct. + */ + +typedef struct { + size_t len; + char *data; +} buffer_t; + +// prototypes + +buffer_t * +buffer_new(); + +buffer_t * +buffer_new_with_size(size_t n); + +buffer_t * +buffer_new_with_string(char *str); + +size_t +buffer_size(buffer_t *self); + +size_t +buffer_length(buffer_t *self); + +void +buffer_free(buffer_t *self); + +int +buffer_prepend(buffer_t *self, char *str); + +int +buffer_append(buffer_t *self, char *str); + +int +buffer_equals(buffer_t *self, buffer_t *other); + +buffer_t * +buffer_slice(buffer_t *self, size_t from, ssize_t to); + +#define buffer_string(self) (self->data) + +#endif diff --git a/package.json b/package.json new file mode 100644 index 0000000..cbb43b4 --- /dev/null +++ b/package.json @@ -0,0 +1,9 @@ +{ + "name": "buffer", + "version": "0.0.1", + "repo": "visionmedia/buffer.c", + "description": "Higher level C-string utilities", + "keywords": ["buf", "buffer", "string", "str", "util", "utils"], + "license": "MIT", + "src": ["buffer.c", "buffer.h"] +} diff --git a/test.c b/test.c new file mode 100644 index 0000000..2d2f645 --- /dev/null +++ b/test.c @@ -0,0 +1,136 @@ + +// +// test.c +// +// Copyright (c) 2012 TJ Holowaychuk +// + +#include +#include +#include +#include +#include "buffer.h" + +void +equal(char *a, char *b) { + if (strcmp(a, b)) { + printf("\n"); + printf(" expected: '%s'\n", a); + printf(" actual: '%s'\n", b); + printf("\n"); + exit(1); + } +} + +void +test_buffer_new() { + buffer_t *buf = buffer_new(); + assert(BUFFER_DEFAULT_SIZE == buffer_size(buf)); + assert(0 == buffer_length(buf)); +} + +void +test_buffer_new_with_size() { + buffer_t *buf = buffer_new_with_size(1024); + assert(1024 == buffer_size(buf)); + assert(0 == buffer_length(buf)); +} + +void +test_buffer_append() { + buffer_t *buf = buffer_new(); + assert(0 == buffer_append(buf, "Hello")); + assert(0 == buffer_append(buf, " World")); + assert(strlen("Hello World") == buffer_length(buf)); + equal("Hello World", buffer_string(buf)); +} + +void +test_buffer_append__grow() { + buffer_t *buf = buffer_new_with_size(10); + assert(0 == buffer_append(buf, "Hello")); + assert(0 == buffer_append(buf, " tobi")); + assert(0 == buffer_append(buf, " was")); + assert(0 == buffer_append(buf, " here")); + + char *str = "Hello tobi was here"; + equal(str, buffer_string(buf)); + assert(1024 == buffer_size(buf)); + assert(strlen(str) == buffer_length(buf)); +} + +void +test_buffer_prepend() { + buffer_t *buf = buffer_new(); + assert(0 == buffer_append(buf, " World")); + assert(0 == buffer_prepend(buf, "Hello")); + assert(strlen("Hello World") == buffer_length(buf)); + equal("Hello World", buffer_string(buf)); +} + +void +test_buffer_slice() { + buffer_t *buf = buffer_new(); + buffer_append(buf, "Tobi Ferret"); + + buffer_t *a = buffer_slice(buf, 2, 8); + equal("Tobi Ferret", buffer_string(buf)); + equal("bi Fer", buffer_string(a)); +} + +void +test_buffer_slice__range_error() { + buffer_t *buf = buffer_new_with_string("Tobi Ferret"); + buffer_t *a = buffer_slice(buf, 10, 2); + assert(NULL == a); +} + +void +test_buffer_slice__end() { + buffer_t *buf = buffer_new_with_string("Tobi Ferret"); + + buffer_t *a = buffer_slice(buf, 5, -1); + equal("Tobi Ferret", buffer_string(buf)); + equal("Ferret", buffer_string(a)); + + buffer_t *b = buffer_slice(buf, 5, -3); + equal("Ferr", buffer_string(b)); + + buffer_t *c = buffer_slice(buf, 8, -1); + equal("ret", buffer_string(c)); +} + +void +test_buffer_slice__end_overflow() { + buffer_t *buf = buffer_new_with_string("Tobi Ferret"); + buffer_t *a = buffer_slice(buf, 5, 1000); + equal("Tobi Ferret", buffer_string(buf)); + equal("Ferret", buffer_string(a)); +} + +void +test_buffer_equals() { + buffer_t *a = buffer_new_with_string("Hello"); + buffer_t *b = buffer_new_with_string("Hello"); + + assert(1 == buffer_equals(a, b)); + + buffer_append(b, " World"); + assert(0 == buffer_equals(a, b)); +} + +int +main(){ + test_buffer_new(); + test_buffer_new_with_size(); + test_buffer_append(); + test_buffer_append__grow(); + test_buffer_prepend(); + test_buffer_slice(); + test_buffer_slice__range_error(); + test_buffer_slice__end(); + test_buffer_slice__end_overflow(); + test_buffer_equals(); + printf("\n \e[32m\u2713 \e[90mok\e[0m\n\n"); + return 0; +}