diff options
Diffstat (limited to 'src/ptr.c')
-rw-r--r-- | src/ptr.c | 586 |
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 */ +} + |