summaryrefslogtreecommitdiff
path: root/src/mc.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/mc.c')
-rw-r--r--src/mc.c237
1 files changed, 237 insertions, 0 deletions
diff --git a/src/mc.c b/src/mc.c
new file mode 100644
index 0000000..33500e7
--- /dev/null
+++ b/src/mc.c
@@ -0,0 +1,237 @@
+/*
+ * Auto-sizing memory containers
+ * Copyright Jan Engelhardt, 2002-2011
+ *
+ * This file is part of libHX. libHX is free software; you can
+ * redistribute it and/or modify it under the terms of the GNU Lesser
+ * General Public License as published by the Free Software Foundation;
+ * either version 2.1 or (at your option) any later version.
+ */
+#include <stddef.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libHX/string.h>
+#include "internal.h"
+
+static __inline__ size_t __HXmc_request(size_t len)
+{
+ /* The container, data portion, and a trailing \0 */
+ return sizeof(struct memcont) + len + 1;
+}
+
+static __inline__ void HXmc_check(const struct memcont *c)
+{
+ if (c->id != HXMC_IDENT)
+ fprintf(stderr, "libHX-mc error: not a hxmc object!\n");
+}
+
+static __inline__ struct memcont *HXmc_base(const hxmc_t *p)
+{
+ return containerof(p, struct memcont, data);
+}
+
+EXPORT_SYMBOL hxmc_t *HXmc_strinit(const char *s)
+{
+ hxmc_t *t = NULL;
+ size_t z = strlen(s);
+ if (z < 23 && HXmc_memcpy(&t, NULL, 23) == NULL)
+ return NULL;
+ return HXmc_memcpy(&t, s, z);
+}
+
+EXPORT_SYMBOL hxmc_t *HXmc_meminit(const void *ptr, size_t len)
+{
+ hxmc_t *t = NULL;
+ return HXmc_memcpy(&t, ptr, len);
+}
+
+EXPORT_SYMBOL hxmc_t *HXmc_strcpy(hxmc_t **vp, const char *s)
+{
+ if (s == NULL) {
+ HXmc_free(*vp);
+ *vp = NULL;
+ return NULL;
+ }
+ return HXmc_memcpy(vp, s, strlen(s));
+}
+
+EXPORT_SYMBOL hxmc_t *HXmc_memcpy(hxmc_t **vp, const void *ptr, size_t len)
+{
+ struct memcont *ctx;
+ if (*vp != NULL) {
+ ctx = HXmc_base(*vp);
+ HXmc_check(ctx);
+ if (ctx->alloc < len) {
+ ctx = realloc(ctx, __HXmc_request(len));
+ if (ctx == NULL)
+ return NULL;
+ ctx->alloc = len;
+ }
+ } else {
+ ctx = malloc(__HXmc_request(len));
+ if (ctx == NULL)
+ return NULL;
+ ctx->id = HXMC_IDENT;
+ ctx->alloc = len;
+ }
+
+ if (ptr == NULL) {
+ ctx->length = 0;
+ ctx->data[0] = '\0';
+ return *vp = ctx->data;
+ }
+
+ memcpy(ctx->data, ptr, ctx->length = len);
+ ctx->data[len] = '\0';
+ return *vp = ctx->data;
+}
+
+EXPORT_SYMBOL size_t HXmc_length(const hxmc_t *vp)
+{
+ const struct memcont *ctx;
+
+ if (vp == NULL)
+ return 0;
+ ctx = HXmc_base(vp);
+ HXmc_check(ctx);
+ return ctx->length;
+}
+
+EXPORT_SYMBOL hxmc_t *HXmc_setlen(hxmc_t **vp, size_t len)
+{
+ struct memcont *ctx;
+ if (HXmc_trunc(vp, len) == NULL)
+ return NULL;
+
+ ctx = HXmc_base(*vp);
+ ctx->length = len;
+ return *vp;
+}
+
+EXPORT_SYMBOL hxmc_t *HXmc_trunc(hxmc_t **vp, size_t len)
+{
+ struct memcont *ctx = HXmc_base(*vp);
+
+ HXmc_check(ctx);
+ if (len > ctx->alloc) {
+ ctx = realloc(ctx, __HXmc_request(len));
+ if (ctx == NULL)
+ return NULL;
+ ctx->alloc = len;
+ } else {
+ ctx->data[len] = '\0';
+ ctx->length = len;
+ }
+ return *vp = ctx->data;
+}
+
+EXPORT_SYMBOL hxmc_t *HXmc_strcat(hxmc_t **vp, const char *s)
+{
+ if (s == NULL)
+ return *vp;
+ return HXmc_memcat(vp, s, strlen(s));
+}
+
+EXPORT_SYMBOL hxmc_t *HXmc_memcat(hxmc_t **vp, const void *ptr, size_t len)
+{
+ struct memcont *ctx = HXmc_base(*vp);
+ size_t nl = ctx->length + len;
+
+ HXmc_check(ctx);
+ if (nl > ctx->alloc) {
+ ctx = realloc(ctx, __HXmc_request(nl));
+ if (ctx == NULL)
+ return NULL;
+ ctx->alloc = nl;
+ }
+ if (ptr == NULL)
+ return *vp = ctx->data;
+
+ memcpy(ctx->data + ctx->length, ptr, len);
+ ctx->length = nl;
+ ctx->data[nl] = '\0';
+ return *vp = ctx->data;
+}
+
+EXPORT_SYMBOL hxmc_t *HXmc_strpcat(hxmc_t **vp, const char *s)
+{
+ /* Prepend string @s to @*vp */
+ if (s == NULL)
+ return *vp;
+ return HXmc_memins(vp, 0, s, strlen(s));
+}
+
+EXPORT_SYMBOL hxmc_t *HXmc_mempcat(hxmc_t **vp, const void *ptr, size_t len)
+{
+ /* Prepend memory @ptr (of length @len) to @*vp */
+ return HXmc_memins(vp, 0, ptr, len);
+}
+
+EXPORT_SYMBOL hxmc_t *HXmc_strins(hxmc_t **vp, size_t pos, const char *s)
+{
+ if (s == NULL)
+ return *vp;
+ return HXmc_memins(vp, pos, s, strlen(s));
+}
+
+/*
+ * We naturally do not support negative positions like some
+ * scripting languages do, hence @pos is unsigned.
+ */
+
+EXPORT_SYMBOL hxmc_t *HXmc_memins(hxmc_t **vp, size_t pos, const void *ptr,
+ size_t len)
+{
+ struct memcont *ctx = HXmc_base(*vp);
+ size_t nl = ctx->length + len;
+
+ HXmc_check(ctx);
+ if (ctx->alloc < nl) {
+ ctx = realloc(ctx, __HXmc_request(nl));
+ if (ctx == NULL)
+ return NULL;
+ ctx->alloc = nl;
+ }
+ if (ptr == NULL)
+ return *vp = ctx->data;
+
+ memmove(ctx->data + pos + len, ctx->data + pos, ctx->length - pos);
+ memcpy(ctx->data + pos, ptr, len);
+ ctx->length += len;
+ ctx->data[ctx->length] = '\0';
+ return *vp = ctx->data;
+}
+
+EXPORT_SYMBOL hxmc_t *HXmc_memdel(hxmc_t *vp, size_t pos, size_t len)
+{
+ struct memcont *ctx = HXmc_base(vp);
+ HXmc_check(ctx);
+
+ if (pos + len > ctx->length)
+ len = ctx->length - pos;
+
+ memmove(ctx->data + pos, ctx->data + pos + len,
+ ctx->length - pos - len);
+ ctx->length -= len;
+ ctx->data[ctx->length] = '\0';
+ return ctx->data;
+}
+
+EXPORT_SYMBOL void HXmc_free(hxmc_t *vp)
+{
+ struct memcont *ctx;
+ if (vp == NULL)
+ return;
+ ctx = HXmc_base(vp);
+ HXmc_check(ctx);
+ free(ctx);
+}
+
+EXPORT_SYMBOL void HXmc_zvecfree(hxmc_t **args)
+{
+ hxmc_t **travp;
+ for (travp = args; *travp != NULL; ++travp)
+ HXmc_free(*travp);
+ free(args);
+}