diff options
Diffstat (limited to 'dlib')
-rw-r--r-- | dlib/Makefile.am | 6 | ||||
-rw-r--r-- | dlib/dlib.c | 750 | ||||
-rw-r--r-- | dlib/dlib.h | 158 |
3 files changed, 914 insertions, 0 deletions
diff --git a/dlib/Makefile.am b/dlib/Makefile.am new file mode 100644 index 00000000..378cd785 --- /dev/null +++ b/dlib/Makefile.am @@ -0,0 +1,6 @@ +noinst_LIBRARIES = libDlib.a + +libDlib_a_SOURCES = \ + dlib.h \ + dlib.c + diff --git a/dlib/dlib.c b/dlib/dlib.c new file mode 100644 index 00000000..bba1cc5e --- /dev/null +++ b/dlib/dlib.c @@ -0,0 +1,750 @@ +/* + * File: dlib.c + * + * Copyright (C) 2006 Jorge Arellano Cid <jcid@dillo.org> + * + * 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 3 of the License, or + * (at your option) any later version. + */ + +/* Memory allocation, Simple dynamic strings, Lists (simple and sorted), + * and a few utility functions + */ + +/* + * TODO: vsnprintf() is in C99, maybe a simple replacement if necessary. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <unistd.h> +#include <errno.h> +#include <ctype.h> + +#include "dlib.h" + +/* + *- Memory -------------------------------------------------------------------- + */ + +void *dMalloc (size_t size) +{ + void *value = malloc (size); + if (value == 0) + exit(1); + return value; +} + +void *dRealloc (void *mem, size_t size) +{ + void *value = realloc (mem, size); + if (value == 0) + exit(1); + return value; +} + +void *dMalloc0 (size_t size) +{ + void *value = dMalloc (size); + memset (value, 0, size); + return value; +} + +void dFree (void *mem) +{ + if (mem) + free(mem); +} + +/* + *- strings (char *) ---------------------------------------------------------- + */ + +char *dStrdup(const char *s) +{ + if (s) { + int len = strlen(s)+1; + char *ns = dNew(char, len); + memcpy(ns, s, len); + return ns; + } + return NULL; +} + +char *dStrndup(const char *s, size_t sz) +{ + if (s) { + char *ns = dNew(char, sz+1); + memcpy(ns, s, sz); + ns[sz] = 0; + return ns; + } + return NULL; +} + +/* + * Concatenate a NULL-terminated list of strings + */ +char *dStrconcat(const char *s1, ...) +{ + va_list args; + char *s, *ns = NULL; + + if (s1) { + Dstr *dstr = dStr_sized_new(64); + va_start(args, s1); + for (s = (char*)s1; s; s = va_arg(args, char*)) + dStr_append(dstr, s); + va_end(args); + ns = dstr->str; + dStr_free(dstr, 0); + } + return ns; +} + +/* + * Remove leading and trailing whitespace + */ +char *dStrstrip(char *s) +{ + char *p; + int len; + + if (s && *s) { + for (p = s; isspace(*p); ++p); + for (len = strlen(p); len && isspace(p[len-1]); --len); + if (p > s) + memmove(s, p, len); + s[len] = 0; + } + return s; +} + +/* + * Return a new string of length 'len' filled with 'c' characters + */ +char *dStrnfill(size_t len, char c) +{ + char *ret = dNew(char, len+1); + for (ret[len] = 0; len > 0; ret[--len] = c); + return ret; +} + +/* + * strsep() implementation + */ +char *dStrsep(char **orig, const char *delim) +{ + char *str, *p; + + if (!(str = *orig)) + return NULL; + + p = strpbrk(str, delim); + if (p) { + *p++ = 0; + *orig = p; + } else { + *orig = NULL; + } + return str; +} + +/* + * Case insensitive strstr + */ +char *dStristr(const char *haystack, const char *needle) +{ + int i, j; + + for (i = 0, j = 0; haystack[i] && needle[j]; ++i) + if (tolower(haystack[i]) == tolower(needle[j])) { + ++j; + } else if (j) { + i -= j; + j = 0; + } + + if (!needle[j]) /* Got all */ + return (char *)(haystack + i - j); + return NULL; +} + + +/* + *- dStr ---------------------------------------------------------------------- + */ + +/* + * Private allocator + */ +static void dStr_resize(Dstr *ds, int n_sz, int keep) +{ + if (n_sz >= 0) { + if (keep && n_sz > ds->len) { + ds->str = (Dstr_char_t*) dRealloc (ds->str, n_sz*sizeof(Dstr_char_t)); + ds->sz = n_sz; + } else { + if (ds->str) + free(ds->str); + ds->str = dNew(Dstr_char_t, n_sz); + ds->sz = n_sz; + ds->len = 0; + ds->str[0] = 0; + } + } +} + +/* + * Create a new string with a given size. + * Initialized to "" + */ +Dstr *dStr_sized_new (int sz) +{ + if (sz < 2) + sz = 2; + + Dstr *ds = dNew(Dstr, 1); + ds->str = NULL; + dStr_resize(ds, sz, 0); + return ds; +} + +/* + * Return memory if there's too much allocated + */ +void dStr_fit (Dstr *ds) +{ + dStr_resize(ds, ds->len + 1, 1); +} + +/* + * Insert a C string, at a given position, into a Dstr (providing length). + * Note: It also works with embedded nil characters. + */ +void dStr_insert_l (Dstr *ds, int pos_0, const char *s, int l) +{ + int n_sz; + + if (ds && s && l && pos_0 >= 0 && pos_0 <= ds->len) { + for (n_sz = ds->sz; ds->len + l >= n_sz; n_sz *= 2); + if (n_sz > ds->sz) { + dStr_resize(ds, n_sz, (ds->len > 0) ? 1 : 0); + } + if (pos_0 < ds->len) + memmove(ds->str+pos_0+l, ds->str+pos_0, ds->len-pos_0); + memcpy(ds->str+pos_0, s, l); + ds->len += l; + ds->str[ds->len] = 0; + } +} + +/* + * Insert a C string, at a given position, into a Dstr + */ +void dStr_insert (Dstr *ds, int pos_0, const char *s) +{ + if (s) + dStr_insert_l(ds, pos_0, s, strlen(s)); +} + +/* + * Append a C string to a Dstr (providing length). + * Note: It also works with embedded nil characters. + */ +void dStr_append_l (Dstr *ds, const char *s, int l) +{ + dStr_insert_l(ds, ds->len, s, l); +} + +/* + * Append a C string to a Dstr. + */ +void dStr_append (Dstr *ds, const char *s) +{ + dStr_append_l(ds, s, strlen(s)); +} + +/* + * Create a new string. + * Initialized to 's' or empty if 's == NULL' + */ +Dstr *dStr_new (const char *s) +{ + Dstr *ds = dStr_sized_new(0); + if (s) + dStr_append(ds, s); + return ds; +} + +/* + * Free a dillo string. + * if 'all' free everything, else free the structure only. + */ +void dStr_free (Dstr *ds, int all) +{ + if (ds) { + if (all && ds->str) + free(ds->str); + free(ds); + } +} + +/* + * Append one character. + */ +void dStr_append_c (Dstr *ds, int c) +{ + char cs[2]; + + if (ds) { + if (ds->sz > ds->len + 1) { + ds->str[ds->len++] = (Dstr_char_t)c; + ds->str[ds->len] = 0; + } else { + cs[0] = (Dstr_char_t)c; + cs[1] = 0; + dStr_append_l (ds, cs, 1); + } + } +} + +/* + * Truncate a Dstr to be 'len' bytes long. + */ +void dStr_truncate (Dstr *ds, int len) +{ + if (ds && len < ds->len) { + ds->str[len] = 0; + ds->len = len; + } +} + +/* + * Erase a substring. + */ +void dStr_erase (Dstr *ds, int pos_0, int len) +{ + if (ds && pos_0 >= 0 && len > 0 && pos_0 + len <= ds->len) { + memmove(ds->str + pos_0, ds->str + pos_0 + len, ds->len - pos_0 - len); + ds->len -= len; + ds->str[ds->len] = 0; + } +} + +/* + * vsprintf-like function that appends. + * Used by: dStr_vsprintf(), dStr_sprintf() and dStr_sprintfa(). + */ +void dStr_vsprintfa (Dstr *ds, const char *format, va_list argp) +{ + int n, n_sz; + + if (ds && format) { + while (1) { + n = vsnprintf(ds->str + ds->len, ds->sz - ds->len, format, argp); + if (n > -1 && n < ds->sz - ds->len) { + ds->len += n; /* Success! */ + break; + } else if (n > -1) { /* glibc >= 2.1 */ + n_sz = ds->len + n + 1; + } else { /* old glibc */ + n_sz = ds->sz * 2; + } + dStr_resize(ds, n_sz, (ds->len > 0) ? 1 : 0); + } + } +} + +/* + * vsprintf-like function. + */ +void dStr_vsprintf (Dstr *ds, const char *format, va_list argp) +{ + if (ds) { + dStr_truncate(ds, 0); + dStr_vsprintfa(ds, format, argp); + } +} + +/* + * Printf-like function + */ +void dStr_sprintf (Dstr *ds, const char *format, ...) +{ + va_list argp; + + if (ds && format) { + va_start(argp, format); + dStr_vsprintf(ds, format, argp); + va_end(argp); + } +} + +/* + * Printf-like function that appends. + */ +void dStr_sprintfa (Dstr *ds, const char *format, ...) +{ + va_list argp; + + if (ds && format) { + va_start(argp, format); + dStr_vsprintfa(ds, format, argp); + va_end(argp); + } +} + +/* + *- dList --------------------------------------------------------------------- + */ + +/* + * Create a new empty list + */ +Dlist *dList_new(int size) +{ + if (size <= 0) + return NULL; + + Dlist *l = dNew(Dlist, 1); + l->len = 0; + l->sz = size; + l->list = dNew(void*, l->sz); + return l; +} + +/* + * Free a list (not its elements) + */ +void dList_free (Dlist *lp) +{ + if (!lp) + return; + + dFree(lp->list); + dFree(lp); +} + +/* + * Insert an element at a given position [0 based] + */ +void dList_insert_pos (Dlist *lp, void *data, int pos0) +{ + int i; + + if (!lp || pos0 < 0 || pos0 > lp->len) + return; + + if (lp->sz == lp->len) { + lp->sz *= 2; + lp->list = (void**) dRealloc (lp->list, lp->sz*sizeof(void*)); + } + ++lp->len; + + for (i = lp->len - 1; i > pos0; --i) + lp->list[i] = lp->list[i - 1]; + lp->list[pos0] = data; +} + +/* + * Append a data item to the list + */ +void dList_append (Dlist *lp, void *data) +{ + dList_insert_pos(lp, data, lp->len); +} + +/* + * Prepend a data item to the list + */ +void dList_prepend (Dlist *lp, void *data) +{ + dList_insert_pos(lp, data, 0); +} + +/* + * For completing the ADT. + */ +int dList_length (Dlist *lp) +{ + if (!lp) + return 0; + return lp->len; +} + +/* + * Remove a data item without preserving order. + */ +void dList_remove_fast (Dlist *lp, const void *data) +{ + int i; + + if (!lp) + return; + + for (i = 0; i < lp->len; ++i) { + if (lp->list[i] == data) { + lp->list[i] = lp->list[--lp->len]; + break; + } + } +} + +/* + * Remove a data item preserving order. + */ +void dList_remove (Dlist *lp, const void *data) +{ + int i, j; + + if (!lp) + return; + + for (i = 0; i < lp->len; ++i) { + if (lp->list[i] == data) { + --lp->len; + for (j = i; j < lp->len; ++j) + lp->list[j] = lp->list[j + 1]; + break; + } + } +} + +/* + * Return the nth data item, + * NULL when not found or 'n0' is out of range + */ +void *dList_nth_data (Dlist *lp, int n0) +{ + if (!lp || n0 < 0 || n0 >= lp->len) + return NULL; + return lp->list[n0]; +} + +/* + * Return the found data item, or NULL if not present. + */ +void *dList_find (Dlist *lp, const void *data) +{ + int i = dList_find_idx(lp, data); + return (i >= 0) ? lp->list[i] : NULL; +} + +/* + * Search a data item. + * Return value: its index if found, -1 if not present. + * (this is useful for a list of integers, for finding number zero). + */ +int dList_find_idx (Dlist *lp, const void *data) +{ + int i, ret = -1; + + if (!lp) + return ret; + + for (i = 0; i < lp->len; ++i) { + if (lp->list[i] == data) { + ret = i; + break; + } + } + return ret; +} + +/* + * Search a data item using a custom function. + * func() is given the list item and the user data as parameters. + * Return: data item when found, NULL otherwise. + */ +void *dList_find_custom (Dlist *lp, const void *data, dCompareFunc func) +{ + int i; + void *ret = NULL; + + if (!lp) + return ret; + + for (i = 0; i < lp->len; ++i) { + if (func(lp->list[i], data) == 0) { + ret = lp->list[i]; + break; + } + } + return ret; +} + +/* + * QuickSort implementation. + * This allows for a simple compare function for all the ADT. + */ +static void QuickSort(void **left, void **right, dCompareFunc compare) +{ + void **p = left, **q = right, **t = left; + + while (1) { + while (p != t && compare(*p, *t) < 0) + ++p; + while (q != t && compare(*q, *t) > 0) + --q; + if (p > q) + break; + if (p < q) { + void *tmp = *p; + *p = *q; + *q = tmp; + if (t == p) + t = q; + else if (t == q) + t = p; + } + if (++p > --q) + break; + } + + if (left < q) + QuickSort(left, q, compare); + if (p < right) + QuickSort(p, right, compare); +} + +/* + * Sort the list using a custom function + */ +void dList_sort (Dlist *lp, dCompareFunc func) +{ + if (lp && lp->len > 1) { + QuickSort(lp->list, lp->list + lp->len - 1, func); + } +} + +/* + * Insert an element into a sorted list. + * The comparison function receives two list elements. + */ +void dList_insert_sorted (Dlist *lp, void *data, dCompareFunc func) +{ + int i, st, min, max; + + if (lp) { + min = st = i = 0; + max = lp->len - 1; + while (min <= max) { + i = (min + max) / 2; + st = func(lp->list[i], data); + if (st < 0) { + min = i + 1; + } else if (st > 0) { + max = i - 1; + } else { + break; + } + } + dList_insert_pos(lp, data, (st >= 0) ? i : i+1); + } +} + +/* + * Search a sorted list. + * Return the found data item, or NULL if not present. + * func() is given the list item and the user data as parameters. + */ +void *dList_find_sorted (Dlist *lp, const void *data, dCompareFunc func) +{ + int i, st, min, max; + void *ret = NULL; + + if (lp && lp->len) { + min = 0; + max = lp->len - 1; + while (min <= max) { + i = (min + max) / 2; + st = func(lp->list[i], data); + if (st < 0) { + min = i + 1; + } else if (st > 0) { + max = i - 1; + } else { + ret = lp->list[i]; + break; + } + } + } + + return ret; +} + +/* + *- Misc utility functions ---------------------------------------------------- + */ + +/* + * Return the current working directory in a new string + */ +char *dGetcwd () +{ + size_t size = 128; + + while (1) { + char *buffer = dNew(char, size); + if (getcwd (buffer, size) == buffer) + return buffer; + dFree (buffer); + if (errno != ERANGE) + return 0; + size *= 2; + } +} + +/* + * Return the home directory in a static string (don't free) + */ +char *dGethomedir () +{ + static char *homedir = NULL; + + if (!homedir) { + if (getenv("HOME")) { + homedir = dStrdup(getenv("HOME")); + + } else if (getenv("HOMEDRIVE") && getenv("HOMEPATH")) { + homedir = dStrconcat(getenv("HOMEDRIVE"), getenv("HOMEPATH"), NULL); + } + } + return homedir; +} + +/* + * Get a line from a FILE stream. + * It handles backslash as line-continues character. + * Return value: read line on success, NULL on EOF. + */ +char *dGetline (FILE *stream) +{ + int ch; + Dstr *dstr; + char *line; + + dReturn_val_if_fail (stream, 0); + + dstr = dStr_sized_new(64); + while((ch = fgetc(stream)) != EOF) { + if (ch == '\\') { + /* continue with the next line */ + while((ch = fgetc(stream)) != EOF && ch != '\n'); + continue; + } + dStr_append_c(dstr, ch); + if (ch == '\n') + break; + } + + line = (dstr->len) ? dstr->str : NULL; + dStr_free(dstr, (line) ? 0 : 1); + return line; +} + diff --git a/dlib/dlib.h b/dlib/dlib.h new file mode 100644 index 00000000..6caf7c97 --- /dev/null +++ b/dlib/dlib.h @@ -0,0 +1,158 @@ +#ifndef __DLIB_H__ +#define __DLIB_H__ + +#include <stdio.h> /* for FILE* */ +#include <stddef.h> /* for size_t */ +#include <stdarg.h> /* for va_list */ +#include <string.h> /* for strerror */ +#include <strings.h> /* for strcasecmp, strncasecmp (POSIX 2001) */ + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +/* + *-- Common macros ----------------------------------------------------------- + */ +#ifndef FALSE +#define FALSE (0) +#endif + +#ifndef TRUE +#define TRUE (!FALSE) +#endif + +#undef MAX +#define MAX(a, b) (((a) > (b)) ? (a) : (b)) + +#undef MIN +#define MIN(a, b) (((a) < (b)) ? (a) : (b)) + +/* + *-- Casts ------------------------------------------------------------------- + */ +/* TODO: include a void* size test in configure.in */ +#define VOIDP2INT(p) ((int)(p)) +#define INT2VOIDP(i) ((void*)(i)) + +/* + *-- Memory ------------------------------------------------------------------- + */ +#define dNew(type, count) \ + ((type *) dMalloc ((unsigned) sizeof (type) * (count))) +#define dNew0(type, count) \ + ((type *) dMalloc0 ((unsigned) sizeof (type) * (count))) + +void *dMalloc (size_t size); +void *dRealloc (void *mem, size_t size); +void *dMalloc0 (size_t size); +void dFree (void *mem); + +/* + *- Debug macros -------------------------------------------------------------- + */ +#define D_STMT_START do +#define D_STMT_END while (0) +#define dReturn_if_fail(expr) \ + D_STMT_START{ \ + if (!(expr)) { return; }; \ + }D_STMT_END +#define dReturn_val_if_fail(expr,val) \ + D_STMT_START{ \ + if (!(expr)) { return val; }; \ + }D_STMT_END + +/* + *- C strings ----------------------------------------------------------------- + */ +char *dStrdup(const char *s); +char *dStrndup(const char *s, size_t sz); +char *dStrconcat(const char *s1, ...); +char *dStrstrip(char *s); +char *dStrnfill(size_t len, char c); +char *dStrsep(char **orig, const char *delim); +char *dStristr(const char *haystack, const char *needle); + +/* these are in POSIX 2001. Could be implemented if a port requires it */ +#define dStrcasecmp strcasecmp +#define dStrncasecmp strncasecmp +#define dStrerror strerror + +/* + *-- dStr --------------------------------------------------------------------- + */ +#define Dstr_char_t char + +typedef struct _dstr { + int sz; /* allocated size (private) */ + int len; + Dstr_char_t *str; +} Dstr; + +Dstr *dStr_new (const char *s); +Dstr *dStr_sized_new (int sz); +void dStr_fit (Dstr *ds); +void dStr_free (Dstr *ds, int all); +void dStr_append_c (Dstr *ds, int c); +void dStr_append (Dstr *ds, const char *s); +void dStr_append_l (Dstr *ds, const char *s, int l); +void dStr_insert (Dstr *ds, int pos_0, const char *s); +void dStr_insert_l (Dstr *ds, int pos_0, const char *s, int l); +void dStr_truncate (Dstr *ds, int len); +void dStr_erase (Dstr *ds, int pos_0, int len); +void dStr_vsprintfa (Dstr *ds, const char *format, va_list argp); +void dStr_vsprintf (Dstr *ds, const char *format, va_list argp); +void dStr_sprintf (Dstr *ds, const char *format, ...); +void dStr_sprintfa (Dstr *ds, const char *format, ...); + +/* + *-- dList -------------------------------------------------------------------- + */ +struct Dlist_ { + int sz; /* allocated size (private) */ + int len; + void **list; +}; + +typedef struct Dlist_ Dlist; + +/* dCompareFunc: + * Return: 0 if parameters are equal (for dList_find_custom). + * Return: 0 if equal, < 0 if (a < b), > 0 if (b < a) --for insert sorted. + * + * For finding a data node with an external key, the comparison function + * parameters are: first the data node, and then the key. + */ +typedef int (*dCompareFunc) (const void *a, const void *b); + + +Dlist *dList_new(int size); +void dList_free (Dlist *lp); +void dList_append (Dlist *lp, void *data); +void dList_prepend (Dlist *lp, void *data); +int dList_length (Dlist *lp); +void dList_remove (Dlist *lp, const void *data); +void dList_remove_fast (Dlist *lp, const void *data); +void *dList_nth_data (Dlist *lp, int n0); +void *dList_find (Dlist *lp, const void *data); +int dList_find_idx (Dlist *lp, const void *data); +void *dList_find_custom (Dlist *lp, const void *data, dCompareFunc func); +void dList_sort (Dlist *lp, dCompareFunc func); +void dList_insert_sorted (Dlist *lp, void *data, dCompareFunc func); +void *dList_find_sorted (Dlist *lp, const void *data, dCompareFunc func); + +/* + *- Misc utility functions ---------------------------------------------------- + */ +char *dGetcwd (); +char *dGethomedir (); +char *dGetline (FILE *stream); + + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __DLIB_H__ */ + |