aboutsummaryrefslogtreecommitdiffstats
path: root/src/ptr.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/ptr.c')
-rw-r--r--src/ptr.c586
1 files changed, 586 insertions, 0 deletions
diff --git a/src/ptr.c b/src/ptr.c
new file mode 100644
index 0000000..5878cd4
--- /dev/null
+++ b/src/ptr.c
@@ -0,0 +1,586 @@
+/*
+ * data.c -- basic data structures and functions to manipulate them
+ *
+ * Copyright (C) 1998 by Massimiliano Ghilardi
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <time.h>
+#include <sys/time.h>
+
+#include "defines.h"
+#include "main.h"
+#include "utils.h"
+#include "eval.h"
+
+/*
+ * create a new, empty ptr.
+ * return NULL if max == 0
+ */
+ptr ptrnew(int max)
+{
+ ptr p = (ptr)0;
+
+ if (max == 0)
+ ;
+ else if (limit_mem && max > limit_mem)
+ error = MEM_LIMIT_ERROR;
+ else if (max < 0 || max + sizeofptr < max) /* overflow! */
+ error = NO_MEM_ERROR;
+ else if ((p = (ptr)malloc(max + sizeofptr))) {
+ p->signature = PTR_SIG;
+ p->max = max;
+ ptrdata(p)[p->len = 0] = '\0';
+ } else
+ error = NO_MEM_ERROR;
+ return p;
+}
+
+/*
+ * create a new ptr giving an initial contents,
+ * which gets duplicated.
+ *
+ * warning: newmax could be so small that we must truncate the copied data!
+ */
+ptr ptrdup2(ptr src, int newmax)
+{
+ ptr p = (ptr)0;
+
+ if (newmax == 0)
+ ;
+ else if (newmax < 0 || newmax + sizeofptr < newmax)
+ error = NO_MEM_ERROR;
+ else if (limit_mem && newmax > limit_mem)
+ error = MEM_LIMIT_ERROR;
+ else if (!src)
+ p = ptrnew(newmax);
+ else if ((p = malloc(newmax + sizeofptr))) {
+ p->signature = PTR_SIG;
+ p->max = newmax;
+ if (newmax > ptrlen(src))
+ newmax = ptrlen(src);
+ memmove(ptrdata(p), ptrdata(src), p->len = newmax);
+ ptrdata(p)[newmax] = '\0';
+ } else
+ error = NO_MEM_ERROR;
+ return p;
+}
+
+ptr ptrdup(ptr src)
+{
+ if (!src)
+ return src;
+ return ptrdup2(src, ptrlen(src));
+}
+
+/* delete (free) a ptr */
+void _ptrdel(ptr p)
+{
+ if (p && p->signature == PTR_SIG)
+ free((void *)p);
+ //else
+ //fprintf( stderr, "Tried to free non ptr @%x\n", p );
+}
+
+/* clear a ptr */
+void ptrzero(ptr p)
+{
+ if (p) {
+ p->len = 0;
+ ptrdata(p)[0] = '\0';
+ }
+}
+
+/* truncate a ptr to len chars */
+void ptrtrunc(ptr p, int len)
+{
+ if (p) {
+ if (len < 0 || len > ptrlen(p))
+ return;
+ ptrdata(p)[p->len = len] = '\0';
+ }
+}
+
+/* shrink a ptr by len chars */
+void ptrshrink(ptr p, int len)
+{
+ if (p) {
+ if (len < 0 || len > ptrlen(p))
+ return;
+ ptrdata(p)[p->len -= len] = '\0';
+ }
+}
+
+/*
+ * concatenate two ptr (ptrcat) or a ptr and a char* (ptrmcat)
+ * result may be a _newly_allocated_ ptr if original one
+ * is too small or if it is soooo big that we are wasting tons of memory.
+ * In both cases, the original one may get deleted (freed)
+ * You have been warned! Don't use any statically created ptr for
+ * write operations, and you will be fine.
+ */
+ptr __ptrmcat(ptr dst, char *src, int len, int shrink)
+{
+ int newmax, failmax, overlap;
+ char mustalloc;
+
+ if (!src || len <= 0)
+ return dst;
+ if (len + sizeofptr < 0) {
+ /* overflow! */
+ error = NO_MEM_ERROR;
+ return dst;
+ }
+
+ if (!dst) {
+ failmax = len;
+ mustalloc = 1;
+ } else {
+ failmax = ptrlen(dst) + len;
+ mustalloc = ptrmax(dst) < ptrlen(dst) + len;
+
+ if (shrink && ptrmax(dst) > PARAMLEN
+ && ptrmax(dst)/4 > ptrlen(dst) + len)
+ /* we're wasting space, shrink dst */
+ mustalloc = 1;
+ }
+
+ if (failmax + sizeofptr < 0) {
+ /* overflow! */
+ error = NO_MEM_ERROR;
+ return dst;
+ }
+
+ if (mustalloc) {
+ /* dst must be (re)allocated */
+ ptr p;
+
+ /* ugly but working: check for overlapping dst and src */
+ if (dst && src >= ptrdata(dst) && src < ptrdata(dst) + ptrmax(dst))
+ overlap = 1;
+ else
+ overlap = 0;
+
+ /* find a suitable new size */
+ if (limit_mem && failmax > limit_mem) {
+ error = MEM_LIMIT_ERROR;
+ return dst;
+ }
+ if (failmax < PARAMLEN / 2)
+ newmax = PARAMLEN;
+ else if (failmax / 1024 < PARAMLEN && failmax + PARAMLEN + sizeofptr > 0)
+ newmax = failmax + PARAMLEN;
+ else
+ newmax = failmax;
+ if (limit_mem && newmax > limit_mem) {
+ if (len + (dst ? ptrlen(dst) : 0) > limit_mem)
+ len = limit_mem - (dst ? ptrlen(dst) : 0);
+ if (len < 0)
+ len = 0;
+ newmax = limit_mem;
+ }
+ if ((p = (ptr)realloc((void *)dst, newmax + sizeofptr))) {
+ if (dst == NULL)
+ p->signature = PTR_SIG;
+ if (overlap)
+ src = ptrdata(p) + (src - ptrdata(dst));
+ if (!dst)
+ p->len = 0;
+ p->max = newmax;
+ dst = p;
+ } else if ((p = ptrdup2(dst, newmax))) {
+ if (overlap)
+ src = ptrdata(p) + (src - ptrdata(dst));
+ ptrdel(dst);
+ dst = p;
+ } else {
+ error = NO_MEM_ERROR;
+ return dst;
+ }
+ }
+ if (ptrdata(dst) + ptrlen(dst) != src)
+ memmove(ptrdata(dst) + ptrlen(dst), src, len);
+ dst->len += len;
+ ptrdata(dst)[ptrlen(dst)] = '\0';
+ return dst;
+}
+
+ptr ptrmcat(ptr dst, char *src, int len)
+{
+ return __ptrmcat(dst, src, len, 1);
+}
+
+ptr ptrcat(ptr dst, ptr src)
+{
+ if (src)
+ return __ptrmcat(dst, ptrdata(src), ptrlen(src), 1);
+ return dst;
+}
+
+/*
+ * copy a ptr into another (ptrcpy), or a char* into a ptr (ptrmcpy);
+ * same warning as above if dst is too small or way too big.
+ */
+ptr __ptrmcpy(ptr dst, char *src, int len, int shrink)
+{
+ int newmax, failmax = len, overlap;
+ char mustalloc;
+
+ if (!src || len<=0) {
+ if (len>=0)
+ ptrzero(dst);
+ return dst;
+ }
+ if (failmax + sizeofptr < 0) {
+ /* overflow! */
+ error = NO_MEM_ERROR;
+ return dst;
+ }
+
+ if (!dst) {
+ mustalloc = 1;
+ } else {
+ mustalloc = ptrmax(dst) < len;
+
+ if (shrink && ptrmax(dst) > PARAMLEN && ptrmax(dst)/4 > len)
+ /* we're wasting space, shrink dst */
+ mustalloc = 1;
+ }
+
+ if (mustalloc) {
+ /* dst must be (re)allocated */
+ ptr p;
+
+ /* ugly but working: check for overlapping dst and src */
+ if (dst && src >= ptrdata(dst) && src < ptrdata(dst) + ptrmax(dst))
+ overlap = 1;
+ else
+ overlap = 0;
+
+ /* find a suitable new size */
+ if (limit_mem && failmax > limit_mem) {
+ error = MEM_LIMIT_ERROR;
+ return dst;
+ }
+ if (failmax < PARAMLEN / 2)
+ newmax = PARAMLEN;
+ else if (failmax / 1024 < PARAMLEN && failmax + PARAMLEN + sizeofptr > 0)
+ newmax = failmax + PARAMLEN;
+ else
+ newmax = failmax;
+ if (limit_mem && newmax > limit_mem) {
+ if (len > limit_mem)
+ len = limit_mem;
+ newmax = limit_mem;
+ }
+
+ if ((p = (ptr)realloc((void *)dst, newmax + sizeofptr))) {
+ if (dst == NULL)
+ p->signature = PTR_SIG;
+ if (overlap)
+ src = ptrdata(p) + (src - ptrdata(dst));
+ if (!dst)
+ p->len = 0;
+ p->max = newmax;
+ dst = p;
+ } else if ((p = ptrdup2(dst, newmax))) {
+ if (overlap)
+ src = ptrdata(p) + (src - ptrdata(dst));
+ ptrdel(dst);
+ dst = p;
+ } else {
+ error = NO_MEM_ERROR;
+ return dst;
+ }
+ }
+ if (ptrdata(dst) != src)
+ memmove(ptrdata(dst), src, len);
+ dst->len = len;
+ ptrdata(dst)[ptrlen(dst)] = '\0';
+ return dst;
+}
+
+ptr ptrmcpy(ptr dst, char *src, int len)
+{
+ return __ptrmcpy(dst, src, len, 1);
+}
+
+ptr ptrcpy(ptr dst, ptr src)
+{
+ if (src)
+ return __ptrmcpy(dst, ptrdata(src), ptrlen(src), 1);
+ ptrzero(dst);
+ return dst;
+}
+
+/* enlarge a ptr by len chars. create new if needed */
+ptr ptrpad(ptr p, int len)
+{
+ if (!p) {
+ if (len<=0)
+ return p;
+ else
+ return ptrnew(len);
+ }
+ if (len > ptrmax(p) - ptrlen(p)) {
+ /* must realloc the ptr */
+ len += ptrlen(p);
+ if (len < 0) {
+ /* overflow! */
+ error = NO_MEM_ERROR;
+ return p;
+ }
+ /*
+ * cheat: we use ptrmcpy with src==dst
+ * and do an out-of-boud read of src.
+ * works since dst (==src) gets enlarged
+ * before doing the copy.
+ */
+ p = ptrmcpy(p, ptrdata(p), len);
+ } else {
+ p->len += len;
+ ptrdata(p)[ptrlen(p)] = '\0';
+ }
+ return p;
+}
+
+/* set a ptr to be len chars at minimum. create new if needed */
+ptr ptrsetlen(ptr p, int len)
+{
+ if (!p) {
+ if (len<=0)
+ return p;
+ else {
+ if ((p = ptrnew(len)))
+ ptrdata(p)[p->len = len] = '\0';
+ return p;
+ }
+ }
+ return ptrpad(p, len - ptrlen(p));
+}
+
+/*
+ * compare two ptr (ptrcmp) or a ptr and a char* (ptrmcmp)
+ * if one is a truncated copy of the other, the shorter is considered smaller
+ */
+int ptrmcmp(ptr p, char *q, int lenq)
+{
+ int res;
+ if (!p || !ptrlen(p)) {
+ if (!q || lenq<=0)
+ /* both empty */
+ res = 0;
+ else
+ res = -1;
+ } else if (!q || lenq<=0)
+ res = 1;
+ else if ((res = memcmp(ptrdata(p), q, MIN2(ptrlen(p), lenq))))
+ ;
+ else if (ptrlen(p) < lenq)
+ res = -1;
+ else if (ptrlen(p) > lenq)
+ res = 1;
+ else
+ res = 0;
+ return res;
+}
+
+int ptrcmp(ptr p, ptr q)
+{
+ if (q)
+ return ptrmcmp(p, ptrdata(q), ptrlen(q));
+ else if (p)
+ return 1;
+ else
+ return 0;
+}
+
+/*
+ * find first occurrence of c in p
+ * return NULL if none found.
+ */
+char *ptrchr(ptr p, char c)
+{
+ if (p)
+ return (char *)memchr(ptrdata(p), c, ptrlen(p));
+ return (char*)p; /* shortcut for NULL */
+}
+
+/*
+ * find last occurrence of c in p
+ * return NULL if none found.
+ */
+char *memrchr(char *p, int lenp, char c)
+{
+ char *v, *s = p;
+
+ if (!p || lenp<=0)
+ return NULL;
+
+ v = s + lenp - 1;
+ while (v != s && *v != c) {
+ v--;
+ }
+ if (v != s)
+ return v;
+ else
+ return NULL;
+}
+
+char *ptrrchr(ptr p, char c)
+{
+ if (p)
+ return memrchr(ptrdata(p), ptrlen(p), c);
+ return (char*)p; /* shortcut for NULL */
+}
+
+#ifndef _GNU_SOURCE
+/*
+ * find first occurrence of needle in hay
+ *
+ * GNU libc has memmem(), for others we do by hand.
+ */
+char *memfind(char *hay, int haylen, char *needle, int needlelen)
+{
+ char *tmp;
+
+ if (!hay || haylen<=0 || needlelen<0)
+ return NULL;
+ if (!needle || !needlelen)
+ return hay;
+
+ while (haylen >= needlelen) {
+ /* find a matching first char */
+ if ((tmp = memchr(hay, *needle, haylen))) {
+ if ((haylen -= (tmp-hay)) < needlelen)
+ return NULL;
+ hay = tmp;
+ } else
+ return NULL;
+
+ /* got a matching first char,
+ * check the rest */
+ if (!memcmp(needle, tmp, needlelen))
+ return tmp;
+
+ hay++, haylen --;
+ }
+
+ return NULL;
+}
+#endif /* !_GNU_SOURCE */
+
+/*
+ * find first occurrence of q in p,
+ * return NULL if none found.
+ */
+char *ptrmfind(ptr p, char *q, int lenq)
+{
+ if (p) {
+ if (q && lenq>0)
+ return (char *)memfind(ptrdata(p), ptrlen(p), q, lenq);
+ return ptrdata(p);
+ }
+ return (char*)p; /* shortcut for NULL */
+}
+
+char *ptrfind(ptr p, ptr q)
+{
+ if (p) {
+ if (q)
+ return (char *)memfind(ptrdata(p), ptrlen(p), ptrdata(q), ptrlen(q));
+ return ptrdata(p);
+ }
+ return (char*)p; /* shortcut for NULL */
+}
+
+
+/*
+ * Scan p for the first occurrence of one of the characters in q,
+ * return NULL if none of them is found.
+ */
+char *memchrs(char *p, int lenp, char *q, int lenq)
+{
+ char *endp;
+
+ if (!q || lenq<=0)
+ return p;
+ if (!p || lenp<=0)
+ return NULL;
+
+ endp = p + lenp;
+
+ while (p < endp && !memchr(q, *p, lenq))
+ p++;
+
+ if (p == endp)
+ return NULL;
+ return p;
+}
+
+char *ptrmchrs(ptr p, char *q, int lenq)
+{
+ if (p)
+ return memchrs(ptrdata(p), ptrlen(p), q, lenq);
+ return (char*)p; /* shortcut for NULL */
+}
+
+char *ptrchrs(ptr p, ptr q)
+{
+ if (p) {
+ if (q)
+ return memchrs(ptrdata(p), ptrlen(p), ptrdata(q), ptrlen(q));
+ return ptrdata(p);
+ }
+ return (char*)p; /* shortcut for NULL */
+}
+
+
+/*
+ * Scan p for the last occurrence of one of the characters in q,
+ * return NULL if none of them is found.
+ */
+char *memrchrs(char *p, int lenp, char *q, int lenq)
+{
+ if (!p || lenp<=0) {
+ if (!q || lenq<=0)
+ return p;
+ else
+ return NULL;
+ }
+
+ p += lenp;
+ if (!q || lenq<=0)
+ return p;
+ do {
+ lenp--, p--;
+ } while (lenp >= 0 && !memchr(q, *p, lenq));
+
+ if (lenp < 0)
+ return NULL;
+ return p;
+}
+
+char *ptrmrchrs(ptr p, char *q, int lenq)
+{
+ if (p)
+ return memrchrs(ptrdata(p), ptrlen(p), q, lenq);
+ return (char*)p; /* shortcut for NULL */
+}
+
+char *ptrrchrs(ptr p, ptr q)
+{
+ if (p && q)
+ return memrchrs(ptrdata(p), ptrlen(p), ptrdata(q), ptrlen(q));
+ return p ? ptrdata(p) + ptrlen(p) : (char*)p; /* shortcut for NULL */
+}
+