# HG changeset patch # User David Demelier # Date 1385219645 -3600 # Node ID d4b8416e9ab1422c60445785408f613232e1622f # Parent 523156bb3af51f30c5e5b5b893c50414b691ffee Move C diff -r 523156bb3af5 -r d4b8416e9ab1 C/array.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/C/array.c Sat Nov 23 16:14:05 2013 +0100 @@ -0,0 +1,382 @@ +/* + * array.c -- manipulate dynamic arrays + * + * Copyright (c) 2011, 2012, David Demelier + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include "array.h" + +#define OFFSET(x) (arr->unit * (x)) + +static int grow(struct array *); + +int +array_init(struct array *arr, size_t unit) +{ + if (unit == 0) + return -1; + + arr->unit = unit; + arr->size = OFFSET(arr->chksize); + + /* Set defaults if needed */ + arr->chksize = (arr->chksize <= 0) ? ARRAY_DEFAULT_CHKSIZE : arr->chksize; + arr->malloc = (arr->malloc == NULL) ? &malloc : arr->malloc; + arr->realloc = (arr->realloc == NULL) ? &realloc : arr->realloc; + + if ((arr->data = arr->malloc(arr->size)) == NULL) + return -1; + + if (arr->flags & ARRAY_CLEARBITS) + memset(arr->data, 0, arr->size); + + return 0; +} + +/* + * Valid options that can be set for an array : + * l -> optional array block size of type int + * m -> malloc function that must matches void * (*malloc)(size_t) + * r -> realloc function that must matches void * (*realloc)(void *, size_t) + * f -> array flags of type int + */ +void +array_set(struct array *arr, const char *fmt, ...) +{ + va_list ap; + const char *p; + + va_start(ap, fmt); + for (p = fmt; *p != '\0'; ++p) + switch (*p) { + case 'l': + arr->chksize = va_arg(ap, int); + break; + case 'm': + arr->malloc = va_arg(ap, void *(*)(size_t)); + break; + case 'r': + arr->realloc = va_arg(ap, void *(*)(void *, size_t)); + break; + case 'f': + arr->flags = va_arg(ap, int); + break; + default: + break; + } +} + +/* + * Add to the head of array. NOTE: this may be very slow when adding a lot + * of object (about 100000). If you need to add a lot of data please consider + * using linked list instead. Returns -1 on failure or 0 on success. + */ +int +array_push(struct array *arr, const void *data) +{ + if (grow(arr) < 0) + return -1; + + memmove((char *)arr->data + arr->unit, arr->data, OFFSET(arr->length++)); + memcpy((char *)arr->data, data, arr->unit); + + return 0; +} + +/* + * Insert the data at the specified index. The function returns -1 on + * allocation failure or the position of the added element. + */ +int +array_insert(struct array *arr, const void *data, int index) +{ + if (arr->flags & ARRAY_INSERTSAFE) + if (index < 0 || index > arr->length) + return -1; + + if (index < 0) + return array_push(arr, data); + if (index >= arr->length) + return array_append(arr, data); + + /* Good place */ + memmove((char *)arr->data + OFFSET(index + 1), + (char *)arr->data + OFFSET(index), OFFSET(arr->length++ - index)); + memcpy((char *)arr->data + OFFSET(index), data, arr->unit); + + return index; +} + +/* + * Append the data to the end of array. Returns -1 on failure or the position + * of the added element. + */ +int +array_append(struct array *arr, const void *data) +{ + if (grow(arr) < 0) + return -1; + + memcpy((char *)arr->data + OFFSET(arr->length++), data, arr->unit); + + return (arr->length - 1); +} + +/* + * Remove the array's head. + */ +void +array_pop(struct array *arr) +{ + array_iremove(arr, 0); +} + +/* + * Remove the array's tail. + */ +void +array_unqueue(struct array *arr) +{ + array_iremove(arr, arr->length - 1); +} + +/* + * Remove the data at the specified index. Bounds are checked. + */ +void +array_iremove(struct array *arr, int index) +{ + if (arr->length > 0 && index >= 0 && index < arr->length) { + if (arr->flags & ARRAY_FASTREMOVE) + memmove((char *)arr->data + OFFSET(index), + (char *)arr->data + OFFSET(--arr->length), + arr->unit); + else + memmove((char *)arr->data + OFFSET(index), + (char *)arr->data + OFFSET(index + 1), + OFFSET(arr->length-- - index - 1)); + } + + if (arr->flags & ARRAY_CLEARBITS) + memset((char *)arr->data + OFFSET(arr->length), 0, arr->unit); +} + +/* + * Remove the object referenced by the `data' argument. Useful when you + * don't know the index. + */ +void +array_premove(struct array *arr, const void *data) +{ + void *elm; + int i; + + for (i = 0; i < arr->length; ++i) { + elm = (char *)arr->data + OFFSET(i); + + if (memcmp(elm, data, arr->unit) == 0) { + array_iremove(arr, i); + break; + } + } +} + +/* + * Swap the two elements referenced by index `i1' and `i2'. This function needs + * to allocate data to swap elements thus if the functions fails it returns -1 + * otherwise 0 is returned. + */ +int +array_iswap(struct array *arr, int i1, int i2) +{ + void *tmp; + + /* Out of bounds */ + if (i1 >= arr->length || i1 < 0 || i2 >= arr->length || i2 < 0) + return -1; + + if ((tmp = arr->malloc(arr->unit)) == NULL) + return -1; + + memcpy((char *)tmp, (char *)arr->data + OFFSET(i1), arr->unit); + memcpy((char *)arr->data + OFFSET(i1), (char *)arr->data + OFFSET(i2), + arr->unit); + memcpy((char *)arr->data + OFFSET(i2), (char *)tmp, arr->unit); + + /* + * Clear bytes for safety you probably don't want a password or + * secure data to be left somewhere in the memory. + */ + + if (arr->flags & ARRAY_CLEARBITS) + memset(tmp, 0, arr->unit); + free(tmp); + + return 0; +} + +/* + * Swap the two elements referenced by data `o1' and `o2'. This function + * may be slow on large arrays since it must travel all the object + * to find the indexes. + */ +int +array_pswap(struct array *arr, const void *o1, const void *o2) +{ + int found, i1, i2; + + for (i1 = found = 0; !found && i1 < arr->length; ++i1) + found = memcmp((char *)arr->data + OFFSET(i1), o1, arr->unit) == 0; + + if (!found) + return -1; + + for (i2 = found = 0; !found && i2 < arr->length; ++i2) + found = memcmp((char *)arr->data + OFFSET(i2), o2, arr->unit) == 0; + + if (!found) + return -1; + + return array_iswap(arr, --i1, --i2); +} + +/* + * Apply the function `fn' on each object and give the optional `udata' + * argument to the function too. + */ +void +array_map(const struct array *arr, array_map_t fn, void *udata) +{ + int i; + + for (i = 0; i < arr->length; ++i) + fn((char *)arr->data + OFFSET(i), udata); +} + +/* + * Call qsort function to sort the array. + */ +void +array_sort(struct array *arr, array_cmp_t fn) +{ + qsort(arr->data, arr->length, arr->unit, fn); +} + +/* + * Compare each object with the user supplied function. If the `fn' function + * returns 1, 1 is returned and dst points to the correct object, dst should + * be a pointer to a pointer of object, like (int **) for a array of int. + */ +int +array_find(const struct array *arr, array_cmp_t fn, void *dst, void *u) +{ + int st, i; + + for (i = st = 0; i < arr->length && st != 1; ++i) + st = fn((char *)arr->data + OFFSET(i), u); + + if (st && dst) + *(char **)dst = (char *)arr->data + OFFSET(i - 1); + + return (st) ? i - 1 : -1; +} + +void * +array_first(const struct array *arr) +{ + return arr->data; +} + +void * +array_last(const struct array *arr) +{ + if (arr->length == 0) + return array_first(arr); + + return (char *)arr->data + OFFSET(arr->length - 1); + +} + +void * +array_get(const struct array *arr, int idx) +{ + if (idx < 0) + return array_first(arr); + if (idx >= arr->length) + return array_last(arr); + + return (char *)arr->data + OFFSET(idx); +} + +/* + * Erase every bytes and set the length to 0. + */ +void +array_clear(struct array *arr) +{ + memset(arr->data, 0, arr->size); + arr->length = 0; +} + +/* + * Same as array_clear except it also free the array object. + */ +void +array_free(struct array *arr) +{ + array_clear(arr); + free(arr->data); + + arr->data = NULL; + arr->size = 0; +} + +/* + * Trim down the array to the correct size. + */ +void * +array_trim(struct array *arr) +{ + return arr->realloc(arr->data, arr->length * arr->unit); +} + +/* + * Increate the array storage when it is full. If the buffer is fixed size + * it returns -1 on full buffer otherwise 0 is returned if allocation + * succeeded. + */ +static int +grow(struct array *arr) +{ + if ((arr->size / arr->unit) > (size_t)arr->length) + return 0; + + if (!(arr->flags & ARRAY_FIXED)) { + if ((arr->data = arr->realloc(arr->data, arr->size + + OFFSET(arr->chksize))) == NULL) { + arr->size = arr->length = 0; + return -1; + } + + arr->size += OFFSET(arr->chksize); + } else + return -1; + + return 0; +} diff -r 523156bb3af5 -r d4b8416e9ab1 C/array.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/C/array.h Sat Nov 23 16:14:05 2013 +0100 @@ -0,0 +1,125 @@ +/* + * array.h -- manipulate dynamic arrays + * + * Copyright (c) 2011, 2012, David Demelier + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _ARRAY_H_ +#define _ARRAY_H_ + +#include + +#ifndef ARRAY_DEFAULT_CHKSIZE +#define ARRAY_DEFAULT_CHKSIZE 128 +#endif + +enum array_flags { + ARRAY_AUTO = 0, /* array grows automatically */ + ARRAY_FIXED = (1 << 0), /* fixed size length */ + ARRAY_FASTREMOVE = (1 << 1), /* use last object when removing */ + ARRAY_CLEARBITS = (1 << 2), /* clear data when inserting/removing */ + ARRAY_INSERTSAFE = (1 << 3) /* insertion must have valid indexes */ +}; + +struct array { + int flags; /* (ro) array flags (default AUTO) */ + void *data; /* (rw) array of data */ + int length; /* (ro) number of element inside */ + size_t size; /* (ro) current buffer size (allocated memory) */ + size_t unit; /* (ro) unit size (sizeof the object) */ + int chksize; /* (rw) chunk size (used when growing array) */ + + /* Own allocation functions */ + void * (*malloc)(size_t); + void * (*realloc)(void *, size_t); +}; + +typedef void (*array_map_t)(void *, void *); +typedef int (*array_cmp_t)(const void *, const void *); + +#ifdef __cplusplus +extern "C" { +#endif + +int +array_init(struct array *, size_t); + +void +array_set(struct array *, const char *, ...); + +int +array_push(struct array *, const void *); + +int +array_insert(struct array *, const void *, int); + +int +array_append(struct array *, const void *); + +void +array_pop(struct array *); + +void +array_unqueue(struct array *); + +void +array_iremove(struct array *, int); + +void +array_premove(struct array *, const void *); + +int +array_iswap(struct array *, int, int); + +int +array_pswap(struct array *, const void *, const void *); + +void +array_map(const struct array *, array_map_t, void *); + +void +array_sort(struct array *, array_cmp_t); + +int +array_find(const struct array *, array_cmp_t, void *, void *); + +void * +array_first(const struct array *); + +void * +array_get(const struct array *, int); + +void * +array_last(const struct array *); + +void +array_clear(struct array *); + +void +array_free(struct array *); + +void * +array_trim(struct array *); + +#define ARRAY_FOREACH(a, var, i) \ + for (i = 0, (var) = array_first((a)); \ + i < (a)->length; \ + (var) = array_get(a, ++i)) + +#ifdef __cplusplus +} +#endif + +#endif /* _ARRAY_H_ */ diff -r 523156bb3af5 -r d4b8416e9ab1 C/buf.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/C/buf.c Sat Nov 23 16:14:05 2013 +0100 @@ -0,0 +1,268 @@ +/* + * buf.c -- easy way to manipulate strings + * + * Copyright (c) 2011, 2012, David Demelier + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include "buf.h" + +#define BUF_AVAIL(buf) ((buf)->alsize - (buf)->length) +#define BUF_SAFE(buf) (!((buf)->flags & BUF_UNSAFE)) +#define BUF_FIXED(buf) ((buf)->flags & BUF_FIXED) +#define BUF_AUTO(buf) (buf->flags == 0) + +static void copy(struct buf *, const void *, size_t); +static int grow(struct buf *, size_t); + +int +buf_init(struct buf *buf, const char *txt) +{ + /* Set defaults if needed */ + buf->chksize = (buf->chksize <= 0) ? 128 : buf->chksize; + buf->alsize = buf->chksize + 1; + buf->malloc = (buf->malloc == NULL) ? &malloc : buf->malloc; + buf->realloc = (buf->realloc == NULL) ? &realloc : buf->realloc; + + if ((buf->text = buf->malloc(buf->alsize)) == NULL) + return -1; + + if (txt != NULL) + buf_cat(buf, txt); + + memset(buf->text, 0, buf->alsize); + + return 0; +} + +void +buf_set(struct buf *buf, const char *fmt, ...) +{ + va_list ap; + const char *p; + + va_start(ap, fmt); + for (p = fmt; *p != '\0'; ++p) + switch (*p) { + case 'l': + buf->chksize = va_arg(ap, int); + break; + case 'm': + buf->malloc = va_arg(ap, void *(*)(size_t)); + break; + case 'r': + buf->realloc = va_arg(ap, void *(*)(void *, size_t)); + break; + case 'f': + case 't': + buf->flags = va_arg(ap, int); + break; + default: + break; + } +} + +/* + * This function appends not more than max characters from str. + */ +int +buf_ncat(struct buf *buf, const char *str, size_t max) +{ + size_t tocopy = max; + + for (tocopy = 0; str[tocopy] != '\0' && tocopy < max; ++tocopy) + continue; + + if (BUF_AVAIL(buf) <= tocopy) { + /* Can't add more */ + if (BUF_SAFE(buf) && BUF_FIXED(buf)) + return -1; + + if (BUF_AUTO(buf)) { + if (grow(buf, tocopy) < 0) + return -1; + } else { + /* String is unsafe, truncate to the available size */ + tocopy = BUF_AVAIL(buf) - 1; + } + } + + copy(buf, str, tocopy); + + return 0; +} + +/* + * Append the string str to the end of the string buffer. + */ +int +buf_cat(struct buf *buf, const char *str) +{ + return buf_ncat(buf, str, strlen(str)); +} + +/* + * Append the caracter c to the end of buffer + */ +int +buf_putc(struct buf *buf, int c) +{ + char str[2] = { c, '\0' }; + + return buf_ncat(buf, str, 1); +} + +/* + * Concatenate the printf(3) like call to the string buffer, this function + * returns -1 on fixed safe buffer, otherwise 0 is returned if there + * is no allocation failure. + */ +int +buf_vprintf(struct buf *buf, const char *fmt, va_list ap) +{ + int copied, rv = 0, done = 0; + + if (BUF_FIXED(buf) && BUF_SAFE(buf)) + return -1; + + do { + copied = vsnprintf(&buf->text[buf->length], + BUF_AVAIL(buf), fmt, ap); + + if (copied >= (signed int)BUF_AVAIL(buf) || copied == -1) { + if (BUF_FIXED(buf)) + done = 1; + + /* + * vsnprintf returns -1 on windows, we need to grow + * the buffer by block size. + */ + if (grow(buf, buf->alsize + buf->chksize) < 0) { + done = 1; + rv = -1; + } + } else { + done = 1; + } + } while (!done); + + buf->length = strlen(buf->text); + + return rv; +} + +int +buf_printf(struct buf *buf, const char *fmt, ...) +{ + va_list ap; + int rv; + + va_start(ap, fmt); + rv = buf_vprintf(buf, fmt, ap); + va_end(ap); + + return rv; +} + +/* + * Realloc the string to it's size and remove useless bytes. + */ +int +buf_trim(struct buf *buf) +{ + if ((buf->text = realloc(buf->text, buf->length + 1)) == NULL) { + buf->alsize = 0; + return -1; + } + + buf->alsize = buf->length + 1; + + return 0; +} + +/* + * Remove `n' characters from the buffer, a positive value will cut the string + * from beginning, negative value will cut from end. + */ +void +buf_cut(struct buf *buf, int start) +{ + if ((start > 0 && start >= buf->length) || + (start < 0 && (int)buf->length + start < 0)) + return; + + if (start < 0 && (int)buf->length + start >= 0) + start = buf->length + start; + + buf->text[start] = '\0'; + buf->length -= buf->length - start; +} + +/* + * Clear the string buffer. + */ +void +buf_clear(struct buf *buf) +{ + memset(buf->text, 0, buf->alsize); + + buf->length = 0; +} + +void +buf_free(struct buf *buf) +{ + if (buf != NULL) { + buf_clear(buf); + free(buf->text); + + buf->text = NULL; + buf->alsize = 0; + } +} + +/* + * Append to the end of buffer the void ptr of count size. + */ +static void +copy(struct buf *buf, const void *ptr, size_t count) +{ + memcpy(buf->text + buf->length, ptr, count); + + buf->text[buf->length + count] = '\0'; + buf->length += count; +} + +/* + * Grow the text buffer until the available size fit the needed + * size. This function may return -1 on allocation failure. + */ +static int +grow(struct buf *buf, size_t needed) +{ + while (BUF_AVAIL(buf) <= needed) { + buf->text = buf->realloc(buf->text, buf->alsize + buf->chksize); + + if (buf->text == NULL) + return -1; + + buf->alsize += buf->chksize; + } + + return 0; +} diff -r 523156bb3af5 -r d4b8416e9ab1 C/buf.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/C/buf.h Sat Nov 23 16:14:05 2013 +0100 @@ -0,0 +1,88 @@ +/* + * buf.h -- easy way to manipulate strings + * + * Copyright (c) 2011, 2012, David Demelier + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _BUF_H_ +#define _BUF_H_ + +#include + +#ifdef __GNUC__ +# define _buf_at_printf(i1, i2) __attribute__ ((format (printf, i1, i2))) +#else +# define _buf_at_printf(i1, i2) +#endif + +enum buf_flags { + BUF_UNSAFE = (1 << 0), /* string may be truncated */ + BUF_FIXED = (1 << 1), /* string has fixed length */ +}; + +struct buf { + enum buf_flags flags; /* string flags */ + char *text; /* string text */ + size_t length; /* string length */ + size_t alsize; /* allocated size */ + int chksize; /* chunk size */ + int maxsize; /* max fixed length size */ + + void * (*malloc)(size_t); /* alternate malloc */ + void * (*realloc)(void *, size_t); /* alternate realloc */ +}; + +#ifdef __cplusplus +extern "C" { +#endif + +int +buf_init(struct buf *, const char *); + +void +buf_set(struct buf *, const char *, ...); + +int +buf_ncat(struct buf *, const char *, size_t); + +int +buf_cat(struct buf *, const char *); + +int +buf_putc(struct buf *, int); + +int +buf_vprintf(struct buf *, const char *, va_list); + +int +buf_printf(struct buf *, const char *, ...) _buf_at_printf(2, 3); + +int +buf_trim(struct buf *); + +void +buf_cut(struct buf *, int); + +void +buf_clear(struct buf *); + +void +buf_free(struct buf *); + +#ifdef __cplusplus +} +#endif + +#endif /* _BUF_H_ */ diff -r 523156bb3af5 -r d4b8416e9ab1 C/directory.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/C/directory.c Sat Nov 23 16:14:05 2013 +0100 @@ -0,0 +1,144 @@ +/* + * directory.c -- portable way to open directories + * + * Copyright (c) 2011, 2012 David Demelier + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include "directory.h" + +#if defined(_WIN32) /* WINDOWS */ + +struct directory * +directory_open(const char *path) +{ + WIN32_FIND_DATA fdata; + HANDLE h; + struct directory *res; + char respath[FILENAME_MAX + 1]; + + if (!(res = calloc(1, sizeof (struct directory)))) + return NULL; + + snprintf(respath, sizeof (respath), "%s/*", path); + + if ((h = FindFirstFile(respath, &fdata)) == INVALID_HANDLE_VALUE) { + free(res); + return NULL; + } + + do { + res->ents = realloc(res->ents, + sizeof (*res->ents) * (res->nents + 1)); + + /* Fail to reallocate */ + if (!res->ents) { + free(res); + res = NULL; + break; + } + + res->ents[res->nents].name = strdup(fdata.cFileName); + res->ents[res->nents].type = fdata.dwFileAttributes; + res->ents[res->nents++].length = strlen(fdata.cFileName); + } while (FindNextFile(h, &fdata) != 0); + + return res; +} + +const char * +directory_error(void) +{ + static char msg[1024]; + DWORD num; + + num = GetLastError(); + + FormatMessage( + FORMAT_MESSAGE_FROM_SYSTEM | + FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + num, + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + msg, + sizeof (msg), + NULL + ); + + return msg; +} + +#else /* UNIX */ + +# include + +struct directory * +directory_open(const char *path) +{ + DIR *dp; + struct dirent *ent; + struct directory *res; + + if (!(res = calloc(1, sizeof (struct directory)))) + return NULL; + + if (!(dp = opendir(path))) { + free(res); + return NULL; + } + + while ((ent = readdir(dp))) { + res->ents = realloc(res->ents, + sizeof (*res->ents) * (res->nents + 1)); + + /* Fail to reallocate */ + if (!res->ents) { + free(res); + res = NULL; + break; + } + + res->ents[res->nents].name = strdup(ent->d_name); + res->ents[res->nents].type = ent->d_type; + res->ents[res->nents++].length = ent->d_namlen; + } + + (void)closedir(dp); + + return res; +} + +const char * +directory_error(void) +{ + return strerror(errno); +} + +#endif + +void +directory_free(struct directory *dir) +{ + int i; + + for (i = 0; i < dir->nents; ++i) + free(dir->ents[i].name); + + free(dir->ents); + free(dir); +} diff -r 523156bb3af5 -r d4b8416e9ab1 C/directory.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/C/directory.h Sat Nov 23 16:14:05 2013 +0100 @@ -0,0 +1,61 @@ +/* + * directory.h -- portable way to open directories + * + * Copyright (c) 2011, 2012 David Demelier + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _DIRECTORY_H_ +#define _DIRECTORY_H_ + +struct directory { + int nents; /* number of entries */ + + struct { + char *name; /* entry name */ + int length; /* length of entry */ + int type; /* type of entry */ + } *ents; +}; + +#if defined(_WIN32) + +# include + +enum { + DIRECTORY_DIR = FILE_ATTRIBUTE_DIRECTORY, + DIRECTORY_FILE = FILE_ATTRIBUTE_NORMAL +}; + +#else + +# include + +enum { + DIRECTORY_DIR = DT_DIR, + DIRECTORY_FILE = DT_REG +}; + +#endif + +struct directory * +directory_open(const char *); + +const char * +directory_error(void); + +void +directory_free(struct directory *); + +#endif /* _DIRECTORY_H_ */ diff -r 523156bb3af5 -r d4b8416e9ab1 C/ini.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/C/ini.c Sat Nov 23 16:14:05 2013 +0100 @@ -0,0 +1,555 @@ +/* + * ini.c -- parse .ini like files + * + * Copyright (c) 2011, 2012, David Demelier + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include "ini.h" + +/* + * sys/queue.h bits. + */ + +#if !defined(TAILQ_FIRST) +#define TAILQ_FIRST(head) ((head)->tqh_first) +#endif + +#if !defined(TAILQ_FOREACH) +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = TAILQ_FIRST((head)); \ + (var); \ + (var) = TAILQ_NEXT((var), field)) +#endif + +#if !defined(TAILQ_FOREACH_SAFE) +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST((head)); \ + (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) +#endif + +#if !defined(TAILQ_INIT) +#define TAILQ_INIT(head) do { \ + TAILQ_FIRST((head)) = NULL; \ + (head)->tqh_last = &TAILQ_FIRST((head)); \ +} while (0) +#endif + +#if !defined(TAILQ_INSERT_TAIL) +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + TAILQ_NEXT((elm), field) = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ +} while (0) +#endif + +#if !defined(TAILQ_NEXT) +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) +#endif + +#if !defined(TAILQ_REMOVE) +#define TAILQ_REMOVE(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field)) != NULL) \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else { \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + } \ + *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ +} while (0) +#endif + +/* -------------------------------------------------------- + * Structure definitions + * -------------------------------------------------------- */ + +struct ini_private { + struct ini_section *current; /* current working section */ + int ignore; /* must ignore (no redefine) */ + FILE *fp; /* file pointer to read */ + + /* Line buffer */ + char *line; /* line data */ + int linesize; /* line allocated size */ + int lineno; /* number of line in file */ + + /* Error reporting */ + char error[1024]; +}; + +/* -------------------------------------------------------- + * Prototypes + * -------------------------------------------------------- */ + +#define F_VERBOSE(cg) ((cg)->flags & INI_VERBOSE) +#define F_NOREDEFINE(cg) ((cg)->flags & INI_NOREDEFINE) +#define F_FAILERROR(cg) ((cg)->flags & INI_FAILERROR) + +static char * +sstrndup(const char *src, size_t max) +{ + char *res; + size_t length; + + for (length = 0; length < max && src[length] != '\0'; ++length) + continue; + + if ((res = malloc(length + 1)) == NULL) + return NULL; + + memcpy(res, src, length); + res[length] = '\0'; + + return res; +} + +static void +sskip(char **lp) +{ + while (isspace (**lp) && **lp != '\0') + ++(*lp); +} + +static void +sseek(char **lp) +{ + while (!isspace(**lp) && **lp != '\0') + ++(*lp); +} + +static void +ini_set_error(struct ini_config *cg, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + if (cg->pv->error) + vsnprintf(cg->pv->error, sizeof (cg->pv->error), fmt, ap); + va_end(ap); +} + +static void +ini_warn(struct ini_config *cg, const char *fmt, ...) +{ + va_list ap; + + va_start(ap, fmt); + if (F_VERBOSE(cg)) { + vprintf(fmt, ap); + fputc('\n', stdout); + } + + if (F_FAILERROR(cg)) { + va_start(ap, fmt); + vsnprintf(cg->pv->error, sizeof (cg->pv->error), fmt, ap); + va_end(ap); + } + + va_end(ap); +} + +/* + * Add a new section, this function only returns -1 on fatal error that may + * be impossible to continue parsing for the current line. + */ + +static int +ini_add_section(struct ini_config *cg, char **lp) +{ + char *begin = *lp, *end; + size_t length; + struct ini_section *section = NULL; + + if (!(end = strchr(begin, ']'))) { + ini_warn(cg, "line %d: syntax error after [", cg->pv->lineno); + goto bad; + } + + length = end - begin; + + /* May not redefine? */ + if (cg->pv->current && F_NOREDEFINE(cg)) + if (strncmp(cg->pv->current->key, begin, length) == 0) { + ini_warn(cg, "line %d: redefining %s", cg->pv->lineno, + cg->pv->current->key); + goto bad; + } + + /* Allocate a new section and add it */ + if (!(section = calloc(1, sizeof (*section)))) + goto bad; + + if (!(section->key = sstrndup(begin, length))) + goto bad; + + TAILQ_INIT(§ion->options); + TAILQ_INSERT_TAIL(&cg->sections, section, link); + cg->pv->current = section; + cg->pv->ignore = 0; + + /* Trigger an event for the new section */ + if (cg->open) + cg->open(cg->data, section->key); + + *lp = &end[1]; + + return 0; + +bad: if (section) + free(section->key); + free(section); + + cg->pv->ignore = 1; + *lp = strchr(*lp, '\0'); + + return F_FAILERROR(cg) ? -1 : 0; +} + +/* + * Add a new option, the returns value is same as ini_add_section. + */ + +static int +ini_add_option(struct ini_config *cg, char **lp) +{ + char *begin = *lp, *equal, *end; + struct ini_option *option = NULL; + + if (!cg->pv->current) { + ini_warn(cg, "line %d: option within no section", cg->pv->lineno); + goto bad; + } + + if (cg->pv->ignore || + !(option = calloc(1, sizeof (*option)))) + goto bad; + + /* Not valid */ + if (!(equal = strchr(begin, '='))) { + ini_warn(cg, "line %d: missing =", cg->pv->lineno); + goto bad; + } + + /* End of option */ + end = begin; + sskip(&end); + sseek(&end); + + option->key = sstrndup(begin, end - begin); + + /* End of value */ + begin = &equal[1]; + sskip(&begin); + end = begin; + + if (*end == '\'' || *end == '"') { + for (++end; *end != *begin && *end != '\0'; ++end) + continue; + if (*end != *begin) { + ini_warn(cg, "line %d: missing %c", + cg->pv->lineno, *begin); + *lp = end; + goto bad; + } else + ++ begin; + } else + sseek(&end); + + option->value = sstrndup(begin, end - begin); + + if (!option->key || !option->value) { + ini_warn(cg, "line %d: syntax error", cg->pv->lineno); + goto bad; + } + + TAILQ_INSERT_TAIL(&cg->pv->current->options, option, link); + + /* Trigger an event for the new section */ + if (cg->get) + cg->get(cg->data, cg->pv->current->key, option); + + *lp = &end[1]; + + return 0; + +bad: if (option) { + free(option->key); + free(option->value); + } + free(option); + + *lp = strchr(*lp, '\0'); + + return F_FAILERROR(cg) ? -1 : 0; +} + +static int +ini_read_line(struct ini_config *cg) +{ + char *lp = cg->pv->line; + int rv; + + /* Ignore empty line */ + if (*lp == '\0' || *lp == '#' || *lp == ';') + return 0; + + while (*lp != '\0') { + sskip(&lp); + + if (*lp == '\0' || *lp == '#' || *lp == ';') + return 0; + + /* Begin of section */ + if (*lp == '[') { + ++ lp; + rv = ini_add_section(cg, &lp); + /* Begin of option */ + } else { + rv = ini_add_option(cg, &lp); + } + + if (rv < 0) + return -1; + } + + return 0; +} + +/* + * Read the next line until the next '\n' character is found. Returns 0 + * if the system had enough memory or -1 on allocation failure or on + * end of file. Only for mode == INI_LINEAR + */ + +static int +ini_get_line(struct ini_config *cg) +{ + int ch, pos; + + memset(cg->pv->line, 0, cg->pv->linesize); + pos = 0; + + while ((ch = fgetc(cg->pv->fp)) != '\n') { + if (feof(cg->pv->fp) || ferror(cg->pv->fp)) + return -1; + + /* End of buffer, realloc */ + if (pos == cg->pv->linesize) { + cg->pv->line = realloc(cg->pv->line, cg->pv->linesize + 512); + if (!cg->pv->line) + return -1; + + cg->pv->linesize += 512; + } + + cg->pv->line[pos++] = ch; + } + + return 0; +} + +static int +ini_open_file(struct ini_config *cg) +{ + if (!(cg->pv->fp = fopen(cg->path, "r"))) { + ini_set_error(cg, "open: %s", cg->path); + return -1; + } + + cg->pv->linesize = INI_DEFAULT_LINESIZE; + cg->pv->line = calloc(sizeof (char), cg->pv->linesize); + + if (!cg->pv->line) { + ini_set_error(cg, "malloc: %s", strerror(errno)); + return -1; + } + + return 0; +} + +/* -------------------------------------------------------- + * Public functions + * -------------------------------------------------------- */ + +struct ini_config * +ini_create(const char *path, enum ini_flags flags) +{ + struct ini_config *cg; + + cg = calloc(1, sizeof (*cg)); + if (!cg) + return NULL; + + cg->pv = calloc(1, sizeof (struct ini_private)); + if (!cg->pv) + return NULL; + + cg->path = path; + cg->flags = flags; + + return cg; +} + +void +ini_set_handlers(struct ini_config *cg, void *data, ini_open_t open, + ini_get_t get) +{ + if (!cg) + return; + + cg->data = data; + cg->open = open; + cg->get = get; +} + +int +ini_open(struct ini_config *cg) +{ + int rv = 0; + + /* Open the file and prepare data for reading */ + if (ini_open_file(cg) < 0) + return -1; + + cg->pv->ignore = 1; + cg->pv->lineno = 1; + + TAILQ_INIT(&cg->sections); + + while (ini_get_line(cg) != -1 && !rv) { + rv = ini_read_line(cg); + ++ cg->pv->lineno; + } + + fclose(cg->pv->fp); + + return rv; +} + +/* + * Search the section `sectname' in the config structure. If the section + * is not found, this function returns NULL. + */ + +struct ini_section * +ini_select_section(const struct ini_config *cg, const char *sectname) +{ + struct ini_section *s; + + TAILQ_FOREACH(s, &cg->sections, link) + if (strcmp(s->key, sectname) == 0) + return s; + + return NULL; +} + +/* + * Search the option `optname' in the section structure, argument + * section mustn't be NULL. If the option is not found, this function + * returns NULL. + */ + +struct ini_option * +ini_select_option(const struct ini_section *sc, const char *name) +{ + struct ini_option *o; + + TAILQ_FOREACH(o, &sc->options, link) + if (strcmp(o->key, name) == 0) + return o; + + return NULL; +} + +/* + * Find an option from the config, by section and option names. + * Returns the option or NULL if not found. + */ + +struct ini_option * +ini_find(const struct ini_config *cg, const char *scname, const char *optname) +{ + struct ini_section *sc; + + if ((sc = ini_select_section(cg, scname))) + return ini_select_option(sc, optname); + + return NULL; +} + +/* + * Return the last error or "No error" if there is no error. + */ + +const char * +ini_get_error(const struct ini_config *cg) +{ + if (!cg && errno != 0) + return strerror(errno); + + if (cg->pv->error[0] == '\0') { + if (errno != 0) + return strerror(errno); + + return "No error"; + } + + return cg->pv->error; +} + +/* + * Free everything, level may be set like this: + * 0, only free parser and private resources. + * 1, free all sections and their keys, + * 2, free all sections and options keys and values. + */ + +void +ini_free(struct ini_config *cg, int level) +{ + struct ini_section *s, *stmp; + struct ini_option *o, *otmp; + + if (level >= 1) { + TAILQ_FOREACH_SAFE(s, &cg->sections, link, stmp) { + if (level >= 2) { + TAILQ_FOREACH_SAFE(o, &s->options, link, otmp) { + TAILQ_REMOVE(&s->options, o, link); + free(o->key); + free(o->value); + free(o); + } + } + + TAILQ_REMOVE(&cg->sections, s, link); + free(s->key); + free(s); + } + } + + if (level >= 0) { + free(cg->pv->line); + free(cg->pv); + free(cg); + } +} diff -r 523156bb3af5 -r d4b8416e9ab1 C/ini.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/C/ini.h Sat Nov 23 16:14:05 2013 +0100 @@ -0,0 +1,131 @@ +/* + * ini.h -- parse .ini like files + * + * Copyright (c) 2011, 2012, David Demelier + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _INI_H_ +#define _INI_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#if !defined(INI_DEFAULT_LINESIZE) +# define INI_DEFAULT_LINESIZE 1024 +#endif + +/* + * sys/queue.h bits. + */ + +#if !defined(TAILQ_ENTRY) +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} +#endif + +#if !defined(TAILQ_HEAD) +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ +} +#endif + +enum ini_flags { + INI_VERBOSE = (1 << 0), /* be verbose */ + INI_NOREDEFINE = (1 << 1), /* do not allow redefinitions */ + INI_FAILERROR = (1 << 2) /* abort parsing on first error */ +}; + +typedef struct ini_config ini_config_t; +typedef struct ini_section ini_section_t; +typedef struct ini_option ini_option_t; +typedef struct ini_handler ini_handler_t; + +typedef void (*ini_open_t)(void *, const char *); +typedef void (*ini_get_t)(void *, const char *, const ini_option_t *); + +/* -------------------------------------------------------- + * Structure definitions + * -------------------------------------------------------- */ + +struct ini_private; + +struct ini_config { + const char *path; /* (ro) file path */ + enum ini_flags flags; /* (ro) optional flags */ + void *data; /* (rw) user data */ + + TAILQ_HEAD(, ini_section) sections; /* (ro) linked-list of sections */ + + /* Event driven method */ + void (*open)(void *, const char *); + void (*get)(void *, const char *, const struct ini_option *); + + /* Private data */ + struct ini_private *pv; +}; + +struct ini_option { + char *key; /* (rw) option name */ + char *value; /* (rw) option value */ + + TAILQ_ENTRY(ini_option) link; +}; + +struct ini_section { + char *key; /* (rw) section key */ + TAILQ_HEAD(, ini_option) options; /* (rw) list of options */ + + TAILQ_ENTRY(ini_section) link; +}; + +/* -------------------------------------------------------- + * Main functions + * -------------------------------------------------------- */ + +struct ini_config * +ini_create(const char *, enum ini_flags); + +void +ini_set_handlers(struct ini_config *, void *, ini_open_t, ini_get_t); + +int +ini_open(struct ini_config *); + +struct ini_section * +ini_select_section(const struct ini_config *, const char *); + +struct ini_option * +ini_select_option(const struct ini_section *, const char *); + +struct ini_option * +ini_find(const struct ini_config *, const char *, const char *); + +const char * +ini_get_error(const struct ini_config *); + +void +ini_free(struct ini_config *, int); + +#ifdef __cplusplus +} +#endif + +#endif /* _INI_H_ */ diff -r 523156bb3af5 -r d4b8416e9ab1 C/nsock.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/C/nsock.c Sat Nov 23 16:14:05 2013 +0100 @@ -0,0 +1,661 @@ +/* + * nsock.c -- portable BSD sockets wrapper + * + * Copyright (c) 2013 David Demelier + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +# include +# include + +#if defined(_WIN32) + + typedef SOCKET nsock_socket_t; + typedef const char * nsock_carg_t; + typedef char * nsock_arg_t; + +#else +# include +# include + +# define ioctlsocket(s) ioctl(s) +# define closesocket(s) close(s) + +# define gai_strerrorA gai_strerror + +# define INVALID_SOCKET -1 +# define SOCKET_ERROR -1 + + typedef int nsock_socket_t; + typedef const void * nsock_carg_t; + typedef void * nsock_arg_t; + +#endif + +#include "nsock.h" + +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ + size_t noclients; \ +} + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) + +#define TAILQ_FIRST(head) ((head)->tqh_first) + +#define TAILQ_FOREACH(var, head, field) \ + for ((var) = TAILQ_FIRST((head)); \ + (var); \ + (var) = TAILQ_NEXT((var), field)) + +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST((head)); \ + (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define TAILQ_INIT(head) do { \ + TAILQ_FIRST((head)) = NULL; \ + (head)->tqh_last = &TAILQ_FIRST((head)); \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ + TAILQ_FIRST((head))->field.tqe_prev = \ + &TAILQ_NEXT((elm), field); \ + else \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + TAILQ_FIRST((head)) = (elm); \ + (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ + (head)->noclients ++; \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + TAILQ_NEXT((elm), field) = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &TAILQ_NEXT((elm), field); \ + (head)->noclients ++; \ +} while (0) + +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if ((TAILQ_NEXT((elm), field)) != NULL) \ + TAILQ_NEXT((elm), field)->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else { \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + } \ + *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ + (head)->noclients --; \ +} while (0) + +struct nsock { + nsock_socket_t fd; + char error[128]; +}; + +struct nsock_address { + struct sockaddr_storage addr; + socklen_t addrlen; + char error[128]; +}; + +struct nsock_listener { + const struct nsock *sock; + char error[128]; + TAILQ_HEAD(, nsock_clt) head; +}; + +struct nsock_clt { + const struct nsock *sock; + TAILQ_ENTRY(nsock_clt) link; +}; + +/* -------------------------------------------------------- + * Private helpers + * -------------------------------------------------------- */ + +static void +nsock_set_error(char *buffer, size_t bufsize) +{ + memset(buffer, 0, bufsize); + +#if defined(_WIN32) + LPSTR str; + + FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, + NULL, + WSAGetLastError(), + MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), + (LPSTR)&str, 0, NULL); + + if (str) { + strncpy(buffer, str, bufsize); + LocalFree(str); + } +#else + strncpy(buffer, strerror(errno), bufsize); +#endif +} + +static void +nsock_set_errno(char *buffer, size_t bufsize, int no) +{ + memset(buffer, 0, bufsize); + strncpy(buffer, strerror(no), bufsize - 1); +} + +static struct nsock_clt * +nsock_clt_new(const struct nsock *ns) +{ + struct nsock_clt *clt; + + if ((clt = malloc(sizeof (struct nsock_clt))) == NULL) + return NULL; + + clt->sock = ns; + + return clt; +} + +/* -------------------------------------------------------- + * Sockets functions + * -------------------------------------------------------- */ + +void +nsock_init(void) +{ +#if defined(_WIN32) + WSADATA wsa; + WSAStartup(MAKEWORD(2, 2), &wsa); +#endif +} + +struct nsock * +nsock_new(void) +{ + struct nsock *ns; + + if ((ns = malloc(sizeof (struct nsock))) == NULL) + return NULL; + + return ns; +} + +int +nsock_create(struct nsock *ns, int domain, int type, int protocol) +{ + ns->fd = socket(domain, type, protocol); + + if (ns->fd == INVALID_SOCKET) + nsock_set_error(ns->error, sizeof (ns->error)); + + return ns->fd == INVALID_SOCKET ? -1 : 0; +} + +const char * +nsock_error(struct nsock *ns) +{ + if (ns == NULL) + return strerror(ENOMEM); + + return ns->error; +} + +int +nsock_bind(struct nsock *ns, const struct nsock_address *ep) +{ + int ret; + + ret = bind(ns->fd, (const struct sockaddr *)&ep->addr, ep->addrlen); + + if (ret == SOCKET_ERROR) + nsock_set_error(ns->error, sizeof (ns->error)); + + return ret == SOCKET_ERROR ? -1 : 0; +} + +int +nsock_listen(struct nsock *ns, int max) +{ + int ret; + + ret = listen(ns->fd, max); + + if (ret == SOCKET_ERROR) + nsock_set_error(ns->error, sizeof (ns->error)); + + return ret == SOCKET_ERROR ? -1 : 0; +} + +int +nsock_accept(struct nsock *ns, struct nsock **client, struct nsock_address **clientinfo) +{ + struct sockaddr_storage *st = NULL; + socklen_t *len = NULL; + int ret; + + if ((*client = malloc(sizeof (struct nsock))) == NULL) { + nsock_set_errno(ns->error, sizeof (ns->error), ENOMEM); + return -1; + } + + if (clientinfo != NULL) { + if ((*clientinfo = malloc(sizeof (struct nsock_address))) == NULL) { + free(client); + nsock_set_errno(ns->error, sizeof (ns->error), ENOMEM); + return -1; + } + + st = &(*clientinfo)->addr; + len = &(*clientinfo)->addrlen; + + /* Set the addrlen to sockaddr_storage first */ + *len = sizeof (struct sockaddr_storage); + } + + /* Prepare client */ + memset((*client)->error, 0, sizeof ((*client)->error)); + (*client)->fd = accept(ns->fd, (struct sockaddr *)st, len); + + if ((*client)->fd == INVALID_SOCKET) { + nsock_set_error(ns->error, sizeof (ns->error)); + + /* free clients and set to NULL so user will not use it */ + free(*client); + *client = NULL; + + if (clientinfo != NULL) { + free(*clientinfo); + *clientinfo = NULL; + } + + ret = -1; + } else + ret = 0; + + return ret; +} + +int +nsock_connect(struct nsock *ns, const struct nsock_address *ep) +{ + int ret; + + ret = connect(ns->fd, (const struct sockaddr *)&ep->addr, ep->addrlen); + + if (ret == SOCKET_ERROR) + nsock_set_error(ns->error, sizeof (ns->error)); + + return ret == SOCKET_ERROR ? -1 : 0; +} + +int +nsock_set(struct nsock *ns, int level, int name, const void *arg, unsigned arglen) +{ + int ret; + + ret = setsockopt(ns->fd, level, name, (nsock_carg_t)arg, arglen); + + if (ret == SOCKET_ERROR) + nsock_set_error(ns->error, sizeof (ns->error)); + + return ret == SOCKET_ERROR ? -1 : 0; +} + +long +nsock_recv(struct nsock *ns, void *data, size_t datasz, int flags) +{ + long nbread; + + nbread = recv(ns->fd, data, datasz, flags); + + if (nbread == -1) + nsock_set_error(ns->error, sizeof (ns->error)); + + return nbread; +} + +long +nsock_recvfrom(struct nsock *ns, struct nsock_address *ep, void *data, size_t datasz, int flags) +{ + struct sockaddr_storage *st = NULL; + socklen_t *len = NULL; + long nbread; + + if (ep != NULL) { + st = &ep->addr; + len = &ep->addrlen; + + /* Set the addrlen to sockaddr_storage first */ + *len = sizeof (struct sockaddr_storage); + } + + nbread = recvfrom(ns->fd, data, datasz, flags, + (struct sockaddr *)st, len); + + if (nbread == SOCKET_ERROR) + nsock_set_error(ns->error, sizeof (ns->error)); + + return nbread; +} + +long +nsock_send(struct nsock *ns, const void *data, size_t datasz, int flags) +{ + long nbsent; + + nbsent = send(ns->fd, data, datasz, flags); + + if (nbsent == -1) + nsock_set_error(ns->error, sizeof (ns->error)); + + return nbsent; +} + +long +nsock_sendto(struct nsock *ns, const struct nsock_address *ep, const void *data, size_t datasz, int flags) +{ + long nbsent; + + nbsent = sendto(ns->fd, data, datasz, flags, + (const struct sockaddr *)&ep->addr, ep->addrlen); + + if (nbsent == SOCKET_ERROR) + nsock_set_error(ns->error, sizeof (ns->error)); + + return nbsent; +} + +void +nsock_close(struct nsock *ns) +{ + closesocket(ns->fd); +} + +void +nsock_free(struct nsock *ns) +{ + free(ns); +} + +void +nsock_finish(void) +{ +#if defined(_WIN32) + WSACleanup(); +#endif +} + +/* -------------------------------------------------------- + * End point functions + * -------------------------------------------------------- */ + +struct nsock_address * +nsock_addr_new(void) +{ + struct nsock_address *ep; + + if ((ep = calloc(1, sizeof (struct nsock_address))) == NULL) + return NULL; + + return ep; +} + +const char * +nsock_addr_error(struct nsock_address *ep) +{ + if (ep == NULL) + return strerror(ENOMEM); + + return ep->error; +} + +int +nsock_addr_bind_ip(struct nsock_address *ep, const char *iface, unsigned port, int family) +{ + if (family == AF_INET6) { + struct sockaddr_in6 *ptr = (struct sockaddr_in6 *)&ep->addr; + + memset(ptr, 0, sizeof (struct sockaddr_in6)); + ptr->sin6_family = AF_INET6; + ptr->sin6_port = htons(port); + + if (iface == NULL || strcmp(iface, "*") == 0) + ptr->sin6_addr = in6addr_any; + else if (inet_pton(AF_INET6, iface, &ptr->sin6_addr) <= 0) { + nsock_set_error(ep->error, sizeof (ep->error)); + return -1; + } + + ep->addrlen = sizeof (struct sockaddr_in6); + } else { + struct sockaddr_in *ptr = (struct sockaddr_in *)&ep->addr; + + memset(ptr, 0, sizeof (struct sockaddr_in)); + ptr->sin_family = AF_INET; + ptr->sin_port = htons(port); + + if (iface == NULL || strcmp(iface, "*") == 0) + ptr->sin_addr.s_addr = INADDR_ANY; + else if (inet_pton(AF_INET, iface, &ptr->sin_addr) <= 0) { + nsock_set_error(ep->error, sizeof (ep->error)); + return -1; + } + + ep->addrlen = sizeof (struct sockaddr_in); + } + + return 0; +} + +int +nsock_addr_connect_ip(struct nsock_address *ep, const char *host, unsigned port, int family) +{ + struct addrinfo hints, *res; + char portstr[32]; + int error; + + memset(&hints, 0, sizeof (hints)); + hints.ai_family = family; + hints.ai_socktype = SOCK_STREAM; + + memset(portstr, 0, sizeof (portstr)); + sprintf(portstr, "%u", port); + + error = getaddrinfo(host, portstr, &hints, &res); + if (error) { + memset(ep->error, 0, sizeof (ep->error)); + strncpy(ep->error, gai_strerrorA(error), sizeof (ep->error) - 1); + return -1; + } + + memcpy(&ep->addr, res->ai_addr, res->ai_addrlen); + ep->addrlen = res->ai_addrlen; + + freeaddrinfo(res); + + return 0; +} + +#if !defined(_WIN32) + +void +nsock_addr_unix(struct nsock_address *ep, const char *path) +{ + struct sockaddr_un *ptr= (struct sockaddr_un *)&ep->addr; + + /* Path */ + memset(ptr, 0, sizeof (struct sockaddr_un)); + strncpy(ptr->sun_path, path, sizeof (ptr->sun_path) - 1); + ptr->sun_family = AF_UNIX; + + /* Len is computed with SUN_LEN */ + ep->addrlen = SUN_LEN(ptr); +} + +#endif + +struct sockaddr * +nsock_addr_getaddr(struct nsock_address *ep) +{ + return (struct sockaddr *)&ep->addr; +} + +socklen_t +nsock_addr_getaddrlen(const struct nsock_address *ep) +{ + return ep->addrlen; +} + +void +nsock_addr_free(struct nsock_address *ep) +{ + free(ep); +} + +/* -------------------------------------------------------- + * listener functions + * -------------------------------------------------------- */ + +struct nsock_listener * +nsock_lst_new(const struct nsock *ns) +{ + struct nsock_listener *ls; + + if ((ls = malloc(sizeof (struct nsock_listener))) == NULL) + return NULL; + + ls->sock = ns; + TAILQ_INIT(&ls->head); + + return ls; +} + +const char * +nsock_lst_error(struct nsock_listener *ls) +{ + if (ls == NULL) + return strerror(ENOMEM); + + return ls->error; +} + +int +nsock_lst_push(struct nsock_listener *ls, struct nsock *ns) +{ + struct nsock_clt *clt; + + if ((clt = nsock_clt_new(ns)) == NULL) + return -1; + + TAILQ_INSERT_HEAD(&ls->head, clt, link); + + return 0; +} + +int +nsock_lst_append(struct nsock_listener *ls, struct nsock *ns) +{ + struct nsock_clt *clt; + + if ((clt = nsock_clt_new(ns)) == NULL) + return -1; + + TAILQ_INSERT_TAIL(&ls->head, clt, link); + + return 0; +} + +size_t +nsock_lst_count(const struct nsock_listener *ls) +{ + return ls->head.noclients; +} + +void +nsock_lst_remove(struct nsock_listener *ls, const struct nsock *ns) +{ + struct nsock_clt *clt, *tmp; + + TAILQ_FOREACH_SAFE(clt, &ls->head, link, tmp) { + if (clt->sock == ns) { + TAILQ_REMOVE(&ls->head, clt, link); + free(clt); + break; + } + } +} + +struct nsock * +nsock_lst_select(struct nsock_listener *ls, long sec, long usec) +{ + fd_set fds; + struct timeval maxwait, *towait; + int error; + int fdmax; + struct nsock_clt *clt; + + fdmax = TAILQ_FIRST(&ls->head)->sock->fd; + + FD_ZERO(&fds); + TAILQ_FOREACH(clt, &ls->head, link) { + FD_SET(clt->sock->fd, &fds); + if ((int)clt->sock->fd > fdmax) + fdmax = clt->sock->fd; + } + + maxwait.tv_sec = sec; + maxwait.tv_usec = usec; + + // Set to NULL for infinite timeout. + towait = (sec == 0 && usec == 0) ? NULL : &maxwait; + error = select(fdmax + 1, &fds, NULL, NULL, towait); + + TAILQ_FOREACH(clt, &ls->head, link) + if (FD_ISSET(clt->sock->fd, &fds)) + return (struct nsock *)clt->sock; + + return NULL; +} + +void +nsock_lst_map(struct nsock_listener *ls, nsock_lst_map_t map, void *data) +{ + const struct nsock_clt *clt; + + TAILQ_FOREACH(clt, &ls->head, link) + map(clt->sock, data); +} + +void +nsock_lst_free(struct nsock_listener *ls) +{ + struct nsock_clt *clt, *tmp; + + TAILQ_FOREACH_SAFE(clt, &ls->head, link, tmp) + free(clt); + + free(ls); +} diff -r 523156bb3af5 -r d4b8416e9ab1 C/nsock.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/C/nsock.h Sat Nov 23 16:14:05 2013 +0100 @@ -0,0 +1,161 @@ +/* + * nsock.h -- portable BSD sockets wrapper + * + * Copyright (c) 2013 David Demelier + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _NSOCK_H_ +#define _NSOCK_H_ + +#if !defined(NSOCK_NOINCLUDES) +# if defined(_WIN32) +# include +# include +# else +# include +# include +# include + +# include + +# include + +# include +# include +# endif +#endif + +struct nsock; +struct nsock_address; +struct nsock_listener; + +/* -------------------------------------------------------- + * Sockets functions + * -------------------------------------------------------- */ + +void +nsock_init(void); + +struct nsock * +nsock_new(void); + +int +nsock_create(struct nsock *, int, int, int); + +const char * +nsock_error(struct nsock *); + +int +nsock_bind(struct nsock *, const struct nsock_address *); + +int +nsock_listen(struct nsock *, int); + +int +nsock_accept(struct nsock *, struct nsock **, struct nsock_address **); + +int +nsock_connect(struct nsock *, const struct nsock_address *); + +int +nsock_set(struct nsock *, int, int, const void *, unsigned); + +long +nsock_recv(struct nsock *, void *, size_t, int); + +long +nsock_recvfrom(struct nsock *, struct nsock_address *, void *, size_t, int); + +long +nsock_send(struct nsock *, const void *, size_t, int); + +long +nsock_sendto(struct nsock *, const struct nsock_address *, const void *, size_t, int); + +void +nsock_close(struct nsock *); + +void +nsock_free(struct nsock *); + +void +nsock_finish(void); + +/* -------------------------------------------------------- + * End point functions + * -------------------------------------------------------- */ + +struct nsock_address * +nsock_addr_new(void); + +const char * +nsock_addr_error(struct nsock_address *); + +int +nsock_addr_bind_ip(struct nsock_address *, const char *, unsigned, int); + +int +nsock_addr_connect_ip(struct nsock_address *, const char *, unsigned, int); + +#if !defined(_WIN32) + +void +nsock_addr_unix(struct nsock_address *, const char *); + +#endif + +struct sockaddr * +nsock_addr_getaddr(struct nsock_address *); + +socklen_t +nsock_addr_getaddrlen(const struct nsock_address *); + +void +nsock_addr_free(struct nsock_address *); + +/* -------------------------------------------------------- + * listener functions + * -------------------------------------------------------- */ + +typedef void (*nsock_lst_map_t)(const struct nsock *, void *); + +struct nsock_listener * +nsock_lst_new(const struct nsock *); + +const char * +nsock_lst_error(struct nsock_listener *); + +int +nsock_lst_push(struct nsock_listener *, struct nsock *); + +int +nsock_lst_append(struct nsock_listener *, struct nsock *); + +size_t +nsock_lst_count(const struct nsock_listener *); + +void +nsock_lst_remove(struct nsock_listener *, const struct nsock *); + +struct nsock * +nsock_lst_select(struct nsock_listener *, long, long); + +void +nsock_lst_map(struct nsock_listener *, nsock_lst_map_t, void *); + +void +nsock_lst_free(struct nsock_listener *); + +#endif /* !_NSOCK_H_ */ diff -r 523156bb3af5 -r d4b8416e9ab1 C/pack.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/C/pack.c Sat Nov 23 16:14:05 2013 +0100 @@ -0,0 +1,477 @@ +/* + * pack.c -- endian dependant binary file reader + * + * Copyright (c) 2011, 2012, David Demelier + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include +#include + +#include "pack.h" + +/* Compilation tunables */ +#if !defined(PACK_CHKSIZE) +# define PACK_CHKSIZE (256) /* default chunk size */ +#endif + +/* Type */ +enum pack_type { + TYPE_FP, + TYPE_FIXEDBUF, + TYPE_AUTOBUF +}; + +struct pack_sc { + enum pack_type type; /* which kind of work */ + short endian; /* endian */ + + /* if TYPE_FP */ + FILE * fp; /* file to write */ + + /* else */ + char * buf; /* bytes converted */ + size_t size; /* current length */ + size_t allocated; /* allocated size */ + + /* for reading */ + unsigned int position; /* position where to read */ +}; + +struct pack_value { + /* for writing */ + int nelem; /* number of element */ + int size; /* size of elements */ + uint64_t value; /* direct value */ + char * array; /* array of values */ + + /* for reading */ + char * dst; /* destination */ +}; + +#define SC_SET(s, tp, ed, f, b, al) do { \ + memset((s), 0, sizeof (struct pack_sc)); \ + (s)->type = tp; \ + (s)->endian = ed; \ + (s)->fp = f; \ + (s)->buf = b; \ + (s)->allocated = al; \ +} while (/* CONSTCOND */ 0) + +#define TOKNARG(tok, nelem) do { \ + if (p[1] == '[') { \ + char *end; \ + \ + /* Can statically write the number, or pass it */ \ + if (p[2] != ']') { \ + nelem = (int)strtol(&p[2], &end, 10); \ + p = end; \ + } else { \ + nelem = va_arg(ap, int); \ + while (!isspace(*p) && *p != ']' && *p != '\0') \ + ++p; \ + } \ + } else \ + nelem = 1; \ +} while (/* CONSTCOND */ 0) + +#define TOKSIZE(tok, size) do { \ + switch (tok) { \ + case 'c': \ + size = sizeof (uint8_t); \ + break; \ + case 's': \ + size = sizeof (uint16_t); \ + break; \ + case 'i': \ + size = sizeof (uint32_t); \ + break; \ + case 'l': \ + size = sizeof (uint64_t); \ + break; \ + default: \ + size = 0; \ + break; \ + } \ +} while (/* CONSTCOND */ 0) + +#define TOKGETARG(serv, tok, val, ap) do { \ + if ((val)->nelem == 1 && serv == writeto) { \ + uint64_t item; \ + switch (tok) { \ + case 'c': case 's': case 'i': \ + item = va_arg(ap, int); \ + break; \ + case 'l': \ + item = va_arg(ap, uint64_t); \ + break; \ + default: \ + item = 0; \ + break; \ + } \ + \ + memset(&(val)->value, 0, sizeof (uint64_t)); \ + memcpy(&(val)->value, &item, (val)->size); \ + (val)->array = (char *)&(val)->value; \ + } else { /* read is always a pointer */ \ + (val)->array = va_arg(ap, void *); \ + (val)->dst = (val)->array; \ + } \ +} while (/* CONSTCOND */ 0) + +#define GETCONV(ed, size, conv) do { \ + if (ed != PACK_HOST_BYTEORDER) { \ + switch ((size)) { \ + case (sizeof (uint16_t)): \ + conv = conv16; break; \ + case (sizeof (uint32_t)): \ + conv = conv32; break; \ + case (sizeof (uint64_t)): \ + conv = conv64; break; \ + default: \ + conv = NULL; \ + } \ + } else \ + conv = NULL; \ +} while (/* CONSTCOND */ 0) + +static void +conv16(void *item) +{ + *(uint16_t *)item = pack_swap16(*(uint16_t *)item); +} + +static void +conv32(void *item) +{ + *(uint32_t *)item = pack_swap32(*(uint32_t *)item); +} + +static void +conv64(void *item) +{ + *(uint64_t *)item = pack_swap64(*(uint64_t *)item); +} + +/* + * Function that write content into the buffer or file depending + * on the calling function. Returns the number of bytes written + * or -1 on failure. + */ +static long +writeto(struct pack_sc *sc, struct pack_value *val) +{ + void (*conv)(void *); + int i; + uint64_t item; + long nbytes = 0; + + /* Get converter */ + GETCONV(sc->endian, val->size, conv); + + for (i = 0; i < val->nelem; ++i) { + item = 0; + memcpy(&item, &val->array[i * val->size], val->size); + + if (conv != NULL) + conv(&item); + + switch (sc->type) { + case TYPE_FP: + fwrite(&item, val->size, 1, sc->fp); + break; + case TYPE_AUTOBUF: + if (sc->size + val->size >= sc->allocated) { + sc->allocated += PACK_CHKSIZE; + sc->buf = realloc(sc->buf, sc->allocated); + + if (sc->buf == NULL) + return -1; + } + /* FALLTHROUGH */ + case TYPE_FIXEDBUF: + if (sc->size + val->size <= sc->allocated) { + memcpy(&sc->buf[sc->size], &item, val->size); + sc->size += val->size; + } else + continue; + default: + break; + } + + nbytes += val->size; + } + + return nbytes; +} + +/* + * Function that read the file or buffer and fill array. + */ +static long +readfrom(struct pack_sc *sc, struct pack_value *val) +{ + void (*conv)(void *); + int i, oktoread; + uint64_t item; + long nbytes = 0; + + /* Get converter */ + GETCONV(sc->endian, val->size, conv); + + for (i = 0; i < val->nelem; ++i) { + item = oktoread = 0; + + switch (sc->type) { + case TYPE_FP: + fread(&item, val->size, 1, sc->fp); + oktoread = 1; + break; + case TYPE_FIXEDBUF: + if (sc->position + val->size <= sc->allocated) { + memcpy(&item, &sc->buf[sc->position], val->size); + sc->position += val->size; + oktoread = 1; + } + break; + default: + break; + } + + if (conv != NULL) + conv(&item); + + if (oktoread) { + memcpy(&val->dst[i * val->size], &item, val->size); + nbytes += val->size; + } + } + + return nbytes; +} + +/* + * Function that analyses the format, write or read the values depending + * on the calling functions. + */ +static long +packit(struct pack_sc *sc, long (*func)(struct pack_sc *, struct pack_value *), + const char *fmt, va_list ap) +{ + struct pack_value val; + const char *p; + int tok; + long nbytes = 0, rv; + + for (p = fmt; *p != '\0'; ++p) { + tok = *p; + + if (isspace(*p)) + continue; + + TOKNARG(tok, val.nelem); + TOKSIZE(tok, val.size); + + if (val.size == 0 || val.nelem == 0) + continue; + + TOKGETARG(func, tok, &val, ap); + if ((rv = func(sc, &val)) == -1) + return -1; + + nbytes += rv; + } + + return nbytes; +} + +long +pack_write(short ed, const char *path, const char *fmt, ...) +{ + va_list ap; + long rv; + + va_start(ap, fmt); + rv = pack_vwrite(ed, path, fmt, ap); + va_end(ap); + + return rv; +} + +long +pack_vwrite(short ed, const char *path, const char *fmt, va_list ap) +{ + FILE *fp; + long rv; + + if ((fp = fopen(path, "wb")) == NULL) + return -1; + + rv = pack_vfwrite(ed, fp, fmt, ap); + fclose(fp); + + return rv; +} + +long +pack_fwrite(short ed, FILE *fp, const char *fmt, ...) +{ + va_list ap; + long rv; + + va_start(ap, fmt); + rv = pack_vfwrite(ed, fp, fmt, ap); + va_end(ap); + + return rv; +} + +long +pack_vfwrite(short ed, FILE *fp, const char *fmt, va_list ap) +{ + struct pack_sc sc; + + SC_SET(&sc, TYPE_FP, ed, fp, NULL, 0); + + return packit(&sc, writeto, fmt, ap); +} + +long +pack_swrite(short ed, char *buf, size_t max, const char *fmt, ...) +{ + va_list ap; + long rv; + + va_start(ap, fmt); + rv = pack_vswrite(ed, buf, max, fmt, ap); + va_end(ap); + + return rv; +} + +long +pack_vswrite(short ed, char *buf, size_t max, const char *fmt, va_list ap) +{ + struct pack_sc sc; + + SC_SET(&sc, TYPE_FIXEDBUF, ed, NULL, buf, max); + + return packit(&sc, writeto, fmt, ap); +} + +long +pack_aswrite(short ed, char **bufp, const char *fmt, ...) +{ + va_list ap; + long rv; + + va_start(ap, fmt); + rv = pack_vaswrite(ed, bufp, fmt, ap); + va_end(ap); + + return rv; +} + +long +pack_vaswrite(short ed, char **bufp, const char *fmt, va_list ap) +{ + struct pack_sc sc; + int rv; + + SC_SET(&sc, TYPE_AUTOBUF, ed, NULL, NULL, PACK_CHKSIZE); + + if ((sc.buf = malloc(PACK_CHKSIZE)) == NULL) + return -1; + + rv = packit(&sc, writeto, fmt, ap); + *bufp = sc.buf; + + return rv; +} + +long +pack_read(short ed, const char *path, const char *fmt, ...) +{ + va_list ap; + long rv; + + va_start(ap, fmt); + rv = pack_vread(ed, path, fmt, ap); + va_end(ap); + + return rv; +} + +long +pack_vread(short ed, const char *path, const char *fmt, va_list ap) +{ + FILE *fp; + long rv; + + if ((fp = fopen(path, "rb")) == NULL) + return -1; + + rv = pack_vfread(ed, fp, fmt, ap); + fclose(fp); + + return rv; +} + +long +pack_fread(short ed, FILE *fp, const char *fmt, ...) +{ + va_list ap; + long rv; + + va_start(ap, fmt); + rv = pack_vfread(ed, fp, fmt, ap); + va_end(ap); + + return rv; +} + +long +pack_vfread(short ed, FILE *fp, const char *fmt, va_list ap) +{ + struct pack_sc sc; + + SC_SET(&sc, TYPE_FP, ed, fp, NULL, 0); + + return packit(&sc, readfrom, fmt, ap); +} + +long +pack_sread(short ed, const char *buf, size_t max, const char *fmt, ...) +{ + va_list ap; + long rv; + + va_start(ap, fmt); + rv = pack_vsread(ed, buf, max, fmt, ap); + va_end(ap); + + return rv; +} + +long +pack_vsread(short ed, const char *buf, size_t max, const char *fmt, va_list ap) +{ + struct pack_sc sc; + + SC_SET(&sc, TYPE_FIXEDBUF, ed, NULL, (char *)buf, max); + + return packit(&sc, readfrom, fmt, ap); +} diff -r 523156bb3af5 -r d4b8416e9ab1 C/pack.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/C/pack.h Sat Nov 23 16:14:05 2013 +0100 @@ -0,0 +1,80 @@ +/* + * pack.h -- endian dependant binary file reader + * + * Copyright (c) 2011, 2012, David Demelier + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _PACK_H_ +#define _PACK_H_ + +#include +#include + +#define PACK_LE 1234 +#define PACK_BE 4321 + +/* + * Endian detection based on SDL_endian.h + */ + +#undef PACK_HOST_BYTEORDER + +#if defined(__hppa__) || \ + defined(__m68k__) || defined(mc68000) || defined(_M_M68K) || \ + (defined(__MIPS__) && defined(__MISPEB__)) || \ + defined(__ppc__) || defined(__POWERPC__) || defined(_M_PPC) || \ + defined(__sparc__) +# define PACK_HOST_BYTEORDER PACK_BE +#else +# define PACK_HOST_BYTEORDER PACK_LE +#endif + +#define pack_swap16(x) \ + ((((x) >> 8) & 0x00FFL) | (((x) << 8) & 0xFF00L)) + +#define pack_swap32(x) ((((x) >> 24) & 0x000000FFL) \ + | (((x) >> 8) & 0x0000FF00L) \ + | (((x) << 8) & 0x00FF0000L) \ + | (((x) << 24) & 0xFF000000L)) + +#define pack_swap64(x) (((long) \ + ((int) pack_swap32((int) (((x) << 32) >> 32))) << 32) \ + | (int) pack_swap32((int) ((x) >> 32))) + +#ifdef __cplusplus +extern "C" { +#endif + +long pack_write(short, const char *, const char *, ...); +long pack_vwrite(short, const char *, const char *, va_list); +long pack_fwrite(short, FILE *, const char *, ...); +long pack_vfwrite(short, FILE *, const char *, va_list); +long pack_swrite(short, char *, size_t, const char *, ...); +long pack_vswrite(short, char *, size_t, const char *, va_list); +long pack_aswrite(short, char **, const char *, ...); +long pack_vaswrite(short, char **, const char *, va_list); + +long pack_read(short, const char *, const char *, ...); +long pack_vread(short, const char *, const char *, va_list); +long pack_fread(short, FILE *, const char *, ...); +long pack_vfread(short, FILE *, const char *, va_list); +long pack_sread(short, const char *, size_t, const char *, ...); +long pack_vsread(short, const char *, size_t, const char *, va_list); + +#ifdef __cplusplus +} +#endif + +#endif /* _PACK_H_ */ diff -r 523156bb3af5 -r d4b8416e9ab1 C/parray.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/C/parray.c Sat Nov 23 16:14:05 2013 +0100 @@ -0,0 +1,366 @@ +/* + * parray.c -- manipulate dynamic pointer arrays + * + * Copyright (c) 2011, 2012, David Demelier + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include +#include +#include + +#include "parray.h" + +#define LENGTH(x) ((x) * (sizeof (void *))) + +static int grow(struct parray *); + +int +parray_init(struct parray *arr) +{ + /* Set defaults if needed */ + arr->bsize = (arr->bsize <= 0) ? PARRAY_DEFAULT_BSIZE : arr->bsize; + arr->malloc = (arr->malloc == NULL) ? &malloc : arr->malloc; + arr->realloc = (arr->realloc == NULL) ? &realloc : arr->realloc; + + arr->bsize += (arr->flags & PARRAY_NULLEND) ? 1 : 0; + arr->size = LENGTH(arr->bsize); + + if ((arr->data = arr->malloc(arr->size)) == NULL) + return -1; + + memset(arr->data, 0, arr->size); + + return 0; +} + +/* + * Valid options that can be set for an array : + * l -> optional array block size of type int + * m -> malloc function that must matches void * (*malloc)(size_t) + * r -> realloc function that must matches void * (*realloc)(void *, size_t) + * f -> parray flags of type int + */ +void +parray_set(struct parray *arr, const char *fmt, ...) +{ + va_list ap; + const char *p; + + va_start(ap, fmt); + for (p = fmt; *p != '\0'; ++p) + switch (*p) { + case 'l': + arr->bsize = va_arg(ap, int); + break; + case 'm': + arr->malloc = va_arg(ap, void * (*)(size_t)); + break; + case 'r': + arr->realloc = va_arg(ap, void * (*)(void *, size_t)); + break; + case 'f': + arr->flags = va_arg(ap, int); + break; + default: + break; + } +} + +/* + * Add to the head of array. NOTE: this may be very slow when adding a lot + * of object (about 100000). If you need to add a lot of data please consider + * using linked list instead. Returns -1 on failure or 0 on success. + */ +int +parray_push(struct parray *arr, void *data) +{ + if (grow(arr) < 0) + return -1; + + memmove(&arr->data[1], &arr->data[0], LENGTH(arr->length++)); + arr->data[0] = data; + + if (arr->flags & PARRAY_NULLEND) + arr->data[arr->length] = NULL; + + return 0; +} + +/* + * Insert the data at the specified index. The function returns -1 on + * allocation failure or the position of the added element. + */ +int +parray_insert(struct parray *arr, void *data, int index) +{ + if (arr->flags & PARRAY_INSERTSAFE) + if (index < 0 || index > arr->length) + return -1; + + if (index < 0) + return parray_push(arr, data); + if (index >= arr->length) + return parray_append(arr, data); + + /* Good place */ + memmove(&arr->data[index + 1], &arr->data[index], + LENGTH(arr->length++ - index)); + arr->data[index] = data; + + if (arr->flags & PARRAY_NULLEND) + arr->data[arr->length] = NULL; + + return index; +} + +/* + * Append the data to the end of array. Returns -1 on failure or the position + * of the added element. + */ +int +parray_append(struct parray *arr, void *data) +{ + if (grow(arr) < 0) + return -1; + + arr->data[arr->length++] = data; + + if (arr->flags & PARRAY_NULLEND) + arr->data[arr->length] = NULL; + + return (arr->length - 1); +} + +/* + * Remove the array's head. + */ +void +parray_pop(struct parray *arr) +{ + parray_iremove(arr, 0); +} + +/* + * Remove the array's tail. + */ +void +parray_unqueue(struct parray *arr) +{ + parray_iremove(arr, arr->length - 1); +} + +/* + * Remove the data at the specified index. Bounds are checked. + */ +void +parray_iremove(struct parray *arr, int index) +{ + if (arr->length > 0 && index >= 0 && index < arr->length) { + if (arr->flags & PARRAY_FASTREMOVE) + arr->data[index] = arr->data[--arr->length]; + else + memmove(&arr->data[index], &arr->data[index + 1], + LENGTH(arr->length-- - index - 1)); + } + + arr->data[arr->length] = NULL; +} + +/* + * Remove the object referenced by the `data' argument. Useful when you + * don't know the index. + */ +void +parray_premove(struct parray *arr, const void *data) +{ + void *elm; + int i; + + PARRAY_FOREACH(arr, elm, i) { + if (elm == data) { + parray_iremove(arr, i); + break; + } + } +} + +/* + * Swap the two elements referenced by index `i1' and `i2'. This function needs + * to allocate data to swap elements thus if the functions fails it returns -1 + * otherwise 0 is returned. + */ +int +parray_iswap(struct parray *arr, int i1, int i2) +{ + void *tmp; + + /* Out of bounds */ + if (i1 >= arr->length || i1 < 0 || i2 >= arr->length || i2 < 0) + return -1; + + tmp = arr->data[i1]; + arr->data[i1] = arr->data[i2]; + arr->data[i2] = tmp; + + return 0; +} + +/* + * Swap the two elements referenced by data `o1' and `o2'. This function + * may be slow on large arrays since it must travel all the object + * to find the indexes. + */ +int +parray_pswap(struct parray *arr, const void *o1, const void *o2) +{ + int found, i1, i2; + + for (i1 = found = 0; !found && i1 < arr->length; ++i1) + found = arr->data[i1] == o1; + + if (!found) + return -1; + + for (i2 = found = 0; !found && i2 < arr->length; ++i2) + found = arr->data[i2] == o2; + + if (!found) + return -1; + + return parray_iswap(arr, --i1, --i2); +} + +/* + * Apply the function `fn' on each object and give the optional `udata' + * argument to the function too. + */ +void +parray_map(const struct parray *arr, parray_map_t fn, void *udata) +{ + int i; + + for (i = 0; i < arr->length; ++i) + fn(arr->data[i], udata); +} + +/* + * Compare each object with the user supplied function. If the `fn' function + * returns 1 then the index of the data position is returned and the parameter + * data points to the array data at the correct index. If the comparison + * function nevers returns 1, array_find returns -1. + */ +int +parray_find(const struct parray *arr, parray_cmp_t fn, void *ptr, void *u) +{ + int st, i; + + for (i = st = 0; i < arr->length && st != 1; ++i) + st = fn(arr->data[i], u); + + if (st && ptr) + *(void **)ptr = arr->data[i - 1]; + + return (st) ? i - 1 : -1; +} + +void * +parray_first(const struct parray *arr) +{ + return arr->data[0]; +} + +void * +parray_get(const struct parray *arr, int idx) +{ + if (idx < 0) + return parray_first(arr); + if (idx >= arr->length) + return parray_last(arr); + + return arr->data[idx]; +} + +void * +parray_last(const struct parray *arr) +{ + if (arr->length == 0) + return parray_first(arr); + + return arr->data[arr->length - 1]; +} + +/* + * Reset the array by setting each pointer to NULL and the length to 0. + */ +void +parray_clear(struct parray *arr) +{ + arr->data[0] = NULL; + arr->length = 0; +} + +/* + * Same as parray_clear except it also free the array object. + */ +void +parray_free(struct parray *arr) +{ + parray_clear(arr); + free(arr->data); + + arr->data = NULL; + arr->size = 0; +} + +/* + * Trim down the array to the correct size. + */ +void * +parray_trim(struct parray *arr) +{ + int count = arr->length; + + if (arr->flags & PARRAY_NULLEND) + ++ count; + + return arr->realloc(arr->data, count * sizeof (void *)); +} + +/* + * Increate the array storage when it is full. If the buffer is fixed size + * it returns -1 on full buffer otherwise 0 is returned if allocation + * succeeded. + */ +static int +grow(struct parray *arr) +{ + unsigned int toadd = (arr->flags & PARRAY_NULLEND) ? 2 : 1; + + if ((arr->size / sizeof (void *)) - arr->length >= toadd) + return 0; + + if (!(arr->flags & PARRAY_FIXED)) { + if ((arr->data = arr->realloc(arr->data, arr->size + + LENGTH(arr->bsize))) == NULL) { + arr->size = arr->length = 0; + return -1; + } + + arr->size += LENGTH(arr->bsize); + } else + return -1; + + return 0; +} diff -r 523156bb3af5 -r d4b8416e9ab1 C/parray.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/C/parray.h Sat Nov 23 16:14:05 2013 +0100 @@ -0,0 +1,121 @@ +/* + * parray.h -- manipulate dynamic pointer arrays + * + * Copyright (c) 2011, 2012, David Demelier + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _PARRAY_H_ +#define _PARRAY_H_ + +#include + +#ifndef PARRAY_DEFAULT_BSIZE +#define PARRAY_DEFAULT_BSIZE 128 +#endif + +enum parray_flags { + PARRAY_AUTO = 0, /* array grows automatically */ + PARRAY_FIXED = (1 << 0), /* fixed size length */ + PARRAY_FASTREMOVE = (1 << 1), /* use last object when removing */ + PARRAY_NULLEND = (1 << 2), /* always has a NULL pointer at end */ + PARRAY_INSERTSAFE = (1 << 3) /* insertion must have valid indexes */ +}; + +struct parray { + enum parray_flags flags; /* (ro) array flags (default AUTO) */ + void **data; /* (rw) array of data */ + int length; /* (ro) number of element inside */ + size_t size; /* (ro) current buffer size (allocated memory) */ + int bsize; /* (rw) block size (used when growing array) */ + + /* Own allocation functions */ + void * (*malloc)(size_t); + void * (*realloc)(void *, size_t); +}; + +typedef void (*parray_map_t)(void *, void *); +typedef int (*parray_cmp_t)(void *, void *); + +#ifdef __cplusplus +extern "C" { +#endif + +int +parray_init(struct parray *); + +void +parray_set(struct parray *, const char *, ...); + +int +parray_push(struct parray *, void *); + +int +parray_insert(struct parray *, void *, int); + +int +parray_append(struct parray *, void *); + +void +parray_pop(struct parray *); + +void +parray_unqueue(struct parray *); + +void +parray_iremove(struct parray *, int); + +void +parray_premove(struct parray *, const void *); + +int +parray_iswap(struct parray *, int, int); + +int +parray_pswap(struct parray *, const void *, const void *); + +void +parray_map(const struct parray *, parray_map_t, void *); + +int +parray_find(const struct parray *, parray_cmp_t, void *, void *); + +void * +parray_first(const struct parray *); + +void * +parray_get(const struct parray *, int); + +void * +parray_last(const struct parray *); + +void +parray_clear(struct parray *); + +void +parray_free(struct parray *); + +void * +parray_trim(struct parray *); + +#define PARRAY_FOREACH(a, o, i) \ + for (i = 0, o = (a)->data[i]; \ + i < (a)->length; \ + ++i, o = (a)->data[i]) + +#ifdef __cplusplus +} +#endif + +#endif /* _PARRAY_H_ */ diff -r 523156bb3af5 -r d4b8416e9ab1 array.c --- a/array.c Fri Nov 15 21:37:57 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,382 +0,0 @@ -/* - * array.c -- manipulate dynamic arrays - * - * Copyright (c) 2011, 2012, David Demelier - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include - -#include "array.h" - -#define OFFSET(x) (arr->unit * (x)) - -static int grow(struct array *); - -int -array_init(struct array *arr, size_t unit) -{ - if (unit == 0) - return -1; - - arr->unit = unit; - arr->size = OFFSET(arr->chksize); - - /* Set defaults if needed */ - arr->chksize = (arr->chksize <= 0) ? ARRAY_DEFAULT_CHKSIZE : arr->chksize; - arr->malloc = (arr->malloc == NULL) ? &malloc : arr->malloc; - arr->realloc = (arr->realloc == NULL) ? &realloc : arr->realloc; - - if ((arr->data = arr->malloc(arr->size)) == NULL) - return -1; - - if (arr->flags & ARRAY_CLEARBITS) - memset(arr->data, 0, arr->size); - - return 0; -} - -/* - * Valid options that can be set for an array : - * l -> optional array block size of type int - * m -> malloc function that must matches void * (*malloc)(size_t) - * r -> realloc function that must matches void * (*realloc)(void *, size_t) - * f -> array flags of type int - */ -void -array_set(struct array *arr, const char *fmt, ...) -{ - va_list ap; - const char *p; - - va_start(ap, fmt); - for (p = fmt; *p != '\0'; ++p) - switch (*p) { - case 'l': - arr->chksize = va_arg(ap, int); - break; - case 'm': - arr->malloc = va_arg(ap, void *(*)(size_t)); - break; - case 'r': - arr->realloc = va_arg(ap, void *(*)(void *, size_t)); - break; - case 'f': - arr->flags = va_arg(ap, int); - break; - default: - break; - } -} - -/* - * Add to the head of array. NOTE: this may be very slow when adding a lot - * of object (about 100000). If you need to add a lot of data please consider - * using linked list instead. Returns -1 on failure or 0 on success. - */ -int -array_push(struct array *arr, const void *data) -{ - if (grow(arr) < 0) - return -1; - - memmove((char *)arr->data + arr->unit, arr->data, OFFSET(arr->length++)); - memcpy((char *)arr->data, data, arr->unit); - - return 0; -} - -/* - * Insert the data at the specified index. The function returns -1 on - * allocation failure or the position of the added element. - */ -int -array_insert(struct array *arr, const void *data, int index) -{ - if (arr->flags & ARRAY_INSERTSAFE) - if (index < 0 || index > arr->length) - return -1; - - if (index < 0) - return array_push(arr, data); - if (index >= arr->length) - return array_append(arr, data); - - /* Good place */ - memmove((char *)arr->data + OFFSET(index + 1), - (char *)arr->data + OFFSET(index), OFFSET(arr->length++ - index)); - memcpy((char *)arr->data + OFFSET(index), data, arr->unit); - - return index; -} - -/* - * Append the data to the end of array. Returns -1 on failure or the position - * of the added element. - */ -int -array_append(struct array *arr, const void *data) -{ - if (grow(arr) < 0) - return -1; - - memcpy((char *)arr->data + OFFSET(arr->length++), data, arr->unit); - - return (arr->length - 1); -} - -/* - * Remove the array's head. - */ -void -array_pop(struct array *arr) -{ - array_iremove(arr, 0); -} - -/* - * Remove the array's tail. - */ -void -array_unqueue(struct array *arr) -{ - array_iremove(arr, arr->length - 1); -} - -/* - * Remove the data at the specified index. Bounds are checked. - */ -void -array_iremove(struct array *arr, int index) -{ - if (arr->length > 0 && index >= 0 && index < arr->length) { - if (arr->flags & ARRAY_FASTREMOVE) - memmove((char *)arr->data + OFFSET(index), - (char *)arr->data + OFFSET(--arr->length), - arr->unit); - else - memmove((char *)arr->data + OFFSET(index), - (char *)arr->data + OFFSET(index + 1), - OFFSET(arr->length-- - index - 1)); - } - - if (arr->flags & ARRAY_CLEARBITS) - memset((char *)arr->data + OFFSET(arr->length), 0, arr->unit); -} - -/* - * Remove the object referenced by the `data' argument. Useful when you - * don't know the index. - */ -void -array_premove(struct array *arr, const void *data) -{ - void *elm; - int i; - - for (i = 0; i < arr->length; ++i) { - elm = (char *)arr->data + OFFSET(i); - - if (memcmp(elm, data, arr->unit) == 0) { - array_iremove(arr, i); - break; - } - } -} - -/* - * Swap the two elements referenced by index `i1' and `i2'. This function needs - * to allocate data to swap elements thus if the functions fails it returns -1 - * otherwise 0 is returned. - */ -int -array_iswap(struct array *arr, int i1, int i2) -{ - void *tmp; - - /* Out of bounds */ - if (i1 >= arr->length || i1 < 0 || i2 >= arr->length || i2 < 0) - return -1; - - if ((tmp = arr->malloc(arr->unit)) == NULL) - return -1; - - memcpy((char *)tmp, (char *)arr->data + OFFSET(i1), arr->unit); - memcpy((char *)arr->data + OFFSET(i1), (char *)arr->data + OFFSET(i2), - arr->unit); - memcpy((char *)arr->data + OFFSET(i2), (char *)tmp, arr->unit); - - /* - * Clear bytes for safety you probably don't want a password or - * secure data to be left somewhere in the memory. - */ - - if (arr->flags & ARRAY_CLEARBITS) - memset(tmp, 0, arr->unit); - free(tmp); - - return 0; -} - -/* - * Swap the two elements referenced by data `o1' and `o2'. This function - * may be slow on large arrays since it must travel all the object - * to find the indexes. - */ -int -array_pswap(struct array *arr, const void *o1, const void *o2) -{ - int found, i1, i2; - - for (i1 = found = 0; !found && i1 < arr->length; ++i1) - found = memcmp((char *)arr->data + OFFSET(i1), o1, arr->unit) == 0; - - if (!found) - return -1; - - for (i2 = found = 0; !found && i2 < arr->length; ++i2) - found = memcmp((char *)arr->data + OFFSET(i2), o2, arr->unit) == 0; - - if (!found) - return -1; - - return array_iswap(arr, --i1, --i2); -} - -/* - * Apply the function `fn' on each object and give the optional `udata' - * argument to the function too. - */ -void -array_map(const struct array *arr, array_map_t fn, void *udata) -{ - int i; - - for (i = 0; i < arr->length; ++i) - fn((char *)arr->data + OFFSET(i), udata); -} - -/* - * Call qsort function to sort the array. - */ -void -array_sort(struct array *arr, array_cmp_t fn) -{ - qsort(arr->data, arr->length, arr->unit, fn); -} - -/* - * Compare each object with the user supplied function. If the `fn' function - * returns 1, 1 is returned and dst points to the correct object, dst should - * be a pointer to a pointer of object, like (int **) for a array of int. - */ -int -array_find(const struct array *arr, array_cmp_t fn, void *dst, void *u) -{ - int st, i; - - for (i = st = 0; i < arr->length && st != 1; ++i) - st = fn((char *)arr->data + OFFSET(i), u); - - if (st && dst) - *(char **)dst = (char *)arr->data + OFFSET(i - 1); - - return (st) ? i - 1 : -1; -} - -void * -array_first(const struct array *arr) -{ - return arr->data; -} - -void * -array_last(const struct array *arr) -{ - if (arr->length == 0) - return array_first(arr); - - return (char *)arr->data + OFFSET(arr->length - 1); - -} - -void * -array_get(const struct array *arr, int idx) -{ - if (idx < 0) - return array_first(arr); - if (idx >= arr->length) - return array_last(arr); - - return (char *)arr->data + OFFSET(idx); -} - -/* - * Erase every bytes and set the length to 0. - */ -void -array_clear(struct array *arr) -{ - memset(arr->data, 0, arr->size); - arr->length = 0; -} - -/* - * Same as array_clear except it also free the array object. - */ -void -array_free(struct array *arr) -{ - array_clear(arr); - free(arr->data); - - arr->data = NULL; - arr->size = 0; -} - -/* - * Trim down the array to the correct size. - */ -void * -array_trim(struct array *arr) -{ - return arr->realloc(arr->data, arr->length * arr->unit); -} - -/* - * Increate the array storage when it is full. If the buffer is fixed size - * it returns -1 on full buffer otherwise 0 is returned if allocation - * succeeded. - */ -static int -grow(struct array *arr) -{ - if ((arr->size / arr->unit) > (size_t)arr->length) - return 0; - - if (!(arr->flags & ARRAY_FIXED)) { - if ((arr->data = arr->realloc(arr->data, arr->size + - OFFSET(arr->chksize))) == NULL) { - arr->size = arr->length = 0; - return -1; - } - - arr->size += OFFSET(arr->chksize); - } else - return -1; - - return 0; -} diff -r 523156bb3af5 -r d4b8416e9ab1 array.h --- a/array.h Fri Nov 15 21:37:57 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,125 +0,0 @@ -/* - * array.h -- manipulate dynamic arrays - * - * Copyright (c) 2011, 2012, David Demelier - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _ARRAY_H_ -#define _ARRAY_H_ - -#include - -#ifndef ARRAY_DEFAULT_CHKSIZE -#define ARRAY_DEFAULT_CHKSIZE 128 -#endif - -enum array_flags { - ARRAY_AUTO = 0, /* array grows automatically */ - ARRAY_FIXED = (1 << 0), /* fixed size length */ - ARRAY_FASTREMOVE = (1 << 1), /* use last object when removing */ - ARRAY_CLEARBITS = (1 << 2), /* clear data when inserting/removing */ - ARRAY_INSERTSAFE = (1 << 3) /* insertion must have valid indexes */ -}; - -struct array { - int flags; /* (ro) array flags (default AUTO) */ - void *data; /* (rw) array of data */ - int length; /* (ro) number of element inside */ - size_t size; /* (ro) current buffer size (allocated memory) */ - size_t unit; /* (ro) unit size (sizeof the object) */ - int chksize; /* (rw) chunk size (used when growing array) */ - - /* Own allocation functions */ - void * (*malloc)(size_t); - void * (*realloc)(void *, size_t); -}; - -typedef void (*array_map_t)(void *, void *); -typedef int (*array_cmp_t)(const void *, const void *); - -#ifdef __cplusplus -extern "C" { -#endif - -int -array_init(struct array *, size_t); - -void -array_set(struct array *, const char *, ...); - -int -array_push(struct array *, const void *); - -int -array_insert(struct array *, const void *, int); - -int -array_append(struct array *, const void *); - -void -array_pop(struct array *); - -void -array_unqueue(struct array *); - -void -array_iremove(struct array *, int); - -void -array_premove(struct array *, const void *); - -int -array_iswap(struct array *, int, int); - -int -array_pswap(struct array *, const void *, const void *); - -void -array_map(const struct array *, array_map_t, void *); - -void -array_sort(struct array *, array_cmp_t); - -int -array_find(const struct array *, array_cmp_t, void *, void *); - -void * -array_first(const struct array *); - -void * -array_get(const struct array *, int); - -void * -array_last(const struct array *); - -void -array_clear(struct array *); - -void -array_free(struct array *); - -void * -array_trim(struct array *); - -#define ARRAY_FOREACH(a, var, i) \ - for (i = 0, (var) = array_first((a)); \ - i < (a)->length; \ - (var) = array_get(a, ++i)) - -#ifdef __cplusplus -} -#endif - -#endif /* _ARRAY_H_ */ diff -r 523156bb3af5 -r d4b8416e9ab1 buf.c --- a/buf.c Fri Nov 15 21:37:57 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,268 +0,0 @@ -/* - * buf.c -- easy way to manipulate strings - * - * Copyright (c) 2011, 2012, David Demelier - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include - -#include "buf.h" - -#define BUF_AVAIL(buf) ((buf)->alsize - (buf)->length) -#define BUF_SAFE(buf) (!((buf)->flags & BUF_UNSAFE)) -#define BUF_FIXED(buf) ((buf)->flags & BUF_FIXED) -#define BUF_AUTO(buf) (buf->flags == 0) - -static void copy(struct buf *, const void *, size_t); -static int grow(struct buf *, size_t); - -int -buf_init(struct buf *buf, const char *txt) -{ - /* Set defaults if needed */ - buf->chksize = (buf->chksize <= 0) ? 128 : buf->chksize; - buf->alsize = buf->chksize + 1; - buf->malloc = (buf->malloc == NULL) ? &malloc : buf->malloc; - buf->realloc = (buf->realloc == NULL) ? &realloc : buf->realloc; - - if ((buf->text = buf->malloc(buf->alsize)) == NULL) - return -1; - - if (txt != NULL) - buf_cat(buf, txt); - - memset(buf->text, 0, buf->alsize); - - return 0; -} - -void -buf_set(struct buf *buf, const char *fmt, ...) -{ - va_list ap; - const char *p; - - va_start(ap, fmt); - for (p = fmt; *p != '\0'; ++p) - switch (*p) { - case 'l': - buf->chksize = va_arg(ap, int); - break; - case 'm': - buf->malloc = va_arg(ap, void *(*)(size_t)); - break; - case 'r': - buf->realloc = va_arg(ap, void *(*)(void *, size_t)); - break; - case 'f': - case 't': - buf->flags = va_arg(ap, int); - break; - default: - break; - } -} - -/* - * This function appends not more than max characters from str. - */ -int -buf_ncat(struct buf *buf, const char *str, size_t max) -{ - size_t tocopy = max; - - for (tocopy = 0; str[tocopy] != '\0' && tocopy < max; ++tocopy) - continue; - - if (BUF_AVAIL(buf) <= tocopy) { - /* Can't add more */ - if (BUF_SAFE(buf) && BUF_FIXED(buf)) - return -1; - - if (BUF_AUTO(buf)) { - if (grow(buf, tocopy) < 0) - return -1; - } else { - /* String is unsafe, truncate to the available size */ - tocopy = BUF_AVAIL(buf) - 1; - } - } - - copy(buf, str, tocopy); - - return 0; -} - -/* - * Append the string str to the end of the string buffer. - */ -int -buf_cat(struct buf *buf, const char *str) -{ - return buf_ncat(buf, str, strlen(str)); -} - -/* - * Append the caracter c to the end of buffer - */ -int -buf_putc(struct buf *buf, int c) -{ - char str[2] = { c, '\0' }; - - return buf_ncat(buf, str, 1); -} - -/* - * Concatenate the printf(3) like call to the string buffer, this function - * returns -1 on fixed safe buffer, otherwise 0 is returned if there - * is no allocation failure. - */ -int -buf_vprintf(struct buf *buf, const char *fmt, va_list ap) -{ - int copied, rv = 0, done = 0; - - if (BUF_FIXED(buf) && BUF_SAFE(buf)) - return -1; - - do { - copied = vsnprintf(&buf->text[buf->length], - BUF_AVAIL(buf), fmt, ap); - - if (copied >= (signed int)BUF_AVAIL(buf) || copied == -1) { - if (BUF_FIXED(buf)) - done = 1; - - /* - * vsnprintf returns -1 on windows, we need to grow - * the buffer by block size. - */ - if (grow(buf, buf->alsize + buf->chksize) < 0) { - done = 1; - rv = -1; - } - } else { - done = 1; - } - } while (!done); - - buf->length = strlen(buf->text); - - return rv; -} - -int -buf_printf(struct buf *buf, const char *fmt, ...) -{ - va_list ap; - int rv; - - va_start(ap, fmt); - rv = buf_vprintf(buf, fmt, ap); - va_end(ap); - - return rv; -} - -/* - * Realloc the string to it's size and remove useless bytes. - */ -int -buf_trim(struct buf *buf) -{ - if ((buf->text = realloc(buf->text, buf->length + 1)) == NULL) { - buf->alsize = 0; - return -1; - } - - buf->alsize = buf->length + 1; - - return 0; -} - -/* - * Remove `n' characters from the buffer, a positive value will cut the string - * from beginning, negative value will cut from end. - */ -void -buf_cut(struct buf *buf, int start) -{ - if ((start > 0 && start >= buf->length) || - (start < 0 && (int)buf->length + start < 0)) - return; - - if (start < 0 && (int)buf->length + start >= 0) - start = buf->length + start; - - buf->text[start] = '\0'; - buf->length -= buf->length - start; -} - -/* - * Clear the string buffer. - */ -void -buf_clear(struct buf *buf) -{ - memset(buf->text, 0, buf->alsize); - - buf->length = 0; -} - -void -buf_free(struct buf *buf) -{ - if (buf != NULL) { - buf_clear(buf); - free(buf->text); - - buf->text = NULL; - buf->alsize = 0; - } -} - -/* - * Append to the end of buffer the void ptr of count size. - */ -static void -copy(struct buf *buf, const void *ptr, size_t count) -{ - memcpy(buf->text + buf->length, ptr, count); - - buf->text[buf->length + count] = '\0'; - buf->length += count; -} - -/* - * Grow the text buffer until the available size fit the needed - * size. This function may return -1 on allocation failure. - */ -static int -grow(struct buf *buf, size_t needed) -{ - while (BUF_AVAIL(buf) <= needed) { - buf->text = buf->realloc(buf->text, buf->alsize + buf->chksize); - - if (buf->text == NULL) - return -1; - - buf->alsize += buf->chksize; - } - - return 0; -} diff -r 523156bb3af5 -r d4b8416e9ab1 buf.h --- a/buf.h Fri Nov 15 21:37:57 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,88 +0,0 @@ -/* - * buf.h -- easy way to manipulate strings - * - * Copyright (c) 2011, 2012, David Demelier - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _BUF_H_ -#define _BUF_H_ - -#include - -#ifdef __GNUC__ -# define _buf_at_printf(i1, i2) __attribute__ ((format (printf, i1, i2))) -#else -# define _buf_at_printf(i1, i2) -#endif - -enum buf_flags { - BUF_UNSAFE = (1 << 0), /* string may be truncated */ - BUF_FIXED = (1 << 1), /* string has fixed length */ -}; - -struct buf { - enum buf_flags flags; /* string flags */ - char *text; /* string text */ - size_t length; /* string length */ - size_t alsize; /* allocated size */ - int chksize; /* chunk size */ - int maxsize; /* max fixed length size */ - - void * (*malloc)(size_t); /* alternate malloc */ - void * (*realloc)(void *, size_t); /* alternate realloc */ -}; - -#ifdef __cplusplus -extern "C" { -#endif - -int -buf_init(struct buf *, const char *); - -void -buf_set(struct buf *, const char *, ...); - -int -buf_ncat(struct buf *, const char *, size_t); - -int -buf_cat(struct buf *, const char *); - -int -buf_putc(struct buf *, int); - -int -buf_vprintf(struct buf *, const char *, va_list); - -int -buf_printf(struct buf *, const char *, ...) _buf_at_printf(2, 3); - -int -buf_trim(struct buf *); - -void -buf_cut(struct buf *, int); - -void -buf_clear(struct buf *); - -void -buf_free(struct buf *); - -#ifdef __cplusplus -} -#endif - -#endif /* _BUF_H_ */ diff -r 523156bb3af5 -r d4b8416e9ab1 directory.c --- a/directory.c Fri Nov 15 21:37:57 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,144 +0,0 @@ -/* - * directory.c -- portable way to open directories - * - * Copyright (c) 2011, 2012 David Demelier - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include - -#include "directory.h" - -#if defined(_WIN32) /* WINDOWS */ - -struct directory * -directory_open(const char *path) -{ - WIN32_FIND_DATA fdata; - HANDLE h; - struct directory *res; - char respath[FILENAME_MAX + 1]; - - if (!(res = calloc(1, sizeof (struct directory)))) - return NULL; - - snprintf(respath, sizeof (respath), "%s/*", path); - - if ((h = FindFirstFile(respath, &fdata)) == INVALID_HANDLE_VALUE) { - free(res); - return NULL; - } - - do { - res->ents = realloc(res->ents, - sizeof (*res->ents) * (res->nents + 1)); - - /* Fail to reallocate */ - if (!res->ents) { - free(res); - res = NULL; - break; - } - - res->ents[res->nents].name = strdup(fdata.cFileName); - res->ents[res->nents].type = fdata.dwFileAttributes; - res->ents[res->nents++].length = strlen(fdata.cFileName); - } while (FindNextFile(h, &fdata) != 0); - - return res; -} - -const char * -directory_error(void) -{ - static char msg[1024]; - DWORD num; - - num = GetLastError(); - - FormatMessage( - FORMAT_MESSAGE_FROM_SYSTEM | - FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - num, - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - msg, - sizeof (msg), - NULL - ); - - return msg; -} - -#else /* UNIX */ - -# include - -struct directory * -directory_open(const char *path) -{ - DIR *dp; - struct dirent *ent; - struct directory *res; - - if (!(res = calloc(1, sizeof (struct directory)))) - return NULL; - - if (!(dp = opendir(path))) { - free(res); - return NULL; - } - - while ((ent = readdir(dp))) { - res->ents = realloc(res->ents, - sizeof (*res->ents) * (res->nents + 1)); - - /* Fail to reallocate */ - if (!res->ents) { - free(res); - res = NULL; - break; - } - - res->ents[res->nents].name = strdup(ent->d_name); - res->ents[res->nents].type = ent->d_type; - res->ents[res->nents++].length = ent->d_namlen; - } - - (void)closedir(dp); - - return res; -} - -const char * -directory_error(void) -{ - return strerror(errno); -} - -#endif - -void -directory_free(struct directory *dir) -{ - int i; - - for (i = 0; i < dir->nents; ++i) - free(dir->ents[i].name); - - free(dir->ents); - free(dir); -} diff -r 523156bb3af5 -r d4b8416e9ab1 directory.h --- a/directory.h Fri Nov 15 21:37:57 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,61 +0,0 @@ -/* - * directory.h -- portable way to open directories - * - * Copyright (c) 2011, 2012 David Demelier - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _DIRECTORY_H_ -#define _DIRECTORY_H_ - -struct directory { - int nents; /* number of entries */ - - struct { - char *name; /* entry name */ - int length; /* length of entry */ - int type; /* type of entry */ - } *ents; -}; - -#if defined(_WIN32) - -# include - -enum { - DIRECTORY_DIR = FILE_ATTRIBUTE_DIRECTORY, - DIRECTORY_FILE = FILE_ATTRIBUTE_NORMAL -}; - -#else - -# include - -enum { - DIRECTORY_DIR = DT_DIR, - DIRECTORY_FILE = DT_REG -}; - -#endif - -struct directory * -directory_open(const char *); - -const char * -directory_error(void); - -void -directory_free(struct directory *); - -#endif /* _DIRECTORY_H_ */ diff -r 523156bb3af5 -r d4b8416e9ab1 ini.c --- a/ini.c Fri Nov 15 21:37:57 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,555 +0,0 @@ -/* - * ini.c -- parse .ini like files - * - * Copyright (c) 2011, 2012, David Demelier - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include -#include -#include - -#include "ini.h" - -/* - * sys/queue.h bits. - */ - -#if !defined(TAILQ_FIRST) -#define TAILQ_FIRST(head) ((head)->tqh_first) -#endif - -#if !defined(TAILQ_FOREACH) -#define TAILQ_FOREACH(var, head, field) \ - for ((var) = TAILQ_FIRST((head)); \ - (var); \ - (var) = TAILQ_NEXT((var), field)) -#endif - -#if !defined(TAILQ_FOREACH_SAFE) -#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = TAILQ_FIRST((head)); \ - (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ - (var) = (tvar)) -#endif - -#if !defined(TAILQ_INIT) -#define TAILQ_INIT(head) do { \ - TAILQ_FIRST((head)) = NULL; \ - (head)->tqh_last = &TAILQ_FIRST((head)); \ -} while (0) -#endif - -#if !defined(TAILQ_INSERT_TAIL) -#define TAILQ_INSERT_TAIL(head, elm, field) do { \ - TAILQ_NEXT((elm), field) = NULL; \ - (elm)->field.tqe_prev = (head)->tqh_last; \ - *(head)->tqh_last = (elm); \ - (head)->tqh_last = &TAILQ_NEXT((elm), field); \ -} while (0) -#endif - -#if !defined(TAILQ_NEXT) -#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) -#endif - -#if !defined(TAILQ_REMOVE) -#define TAILQ_REMOVE(head, elm, field) do { \ - if ((TAILQ_NEXT((elm), field)) != NULL) \ - TAILQ_NEXT((elm), field)->field.tqe_prev = \ - (elm)->field.tqe_prev; \ - else { \ - (head)->tqh_last = (elm)->field.tqe_prev; \ - } \ - *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ -} while (0) -#endif - -/* -------------------------------------------------------- - * Structure definitions - * -------------------------------------------------------- */ - -struct ini_private { - struct ini_section *current; /* current working section */ - int ignore; /* must ignore (no redefine) */ - FILE *fp; /* file pointer to read */ - - /* Line buffer */ - char *line; /* line data */ - int linesize; /* line allocated size */ - int lineno; /* number of line in file */ - - /* Error reporting */ - char error[1024]; -}; - -/* -------------------------------------------------------- - * Prototypes - * -------------------------------------------------------- */ - -#define F_VERBOSE(cg) ((cg)->flags & INI_VERBOSE) -#define F_NOREDEFINE(cg) ((cg)->flags & INI_NOREDEFINE) -#define F_FAILERROR(cg) ((cg)->flags & INI_FAILERROR) - -static char * -sstrndup(const char *src, size_t max) -{ - char *res; - size_t length; - - for (length = 0; length < max && src[length] != '\0'; ++length) - continue; - - if ((res = malloc(length + 1)) == NULL) - return NULL; - - memcpy(res, src, length); - res[length] = '\0'; - - return res; -} - -static void -sskip(char **lp) -{ - while (isspace (**lp) && **lp != '\0') - ++(*lp); -} - -static void -sseek(char **lp) -{ - while (!isspace(**lp) && **lp != '\0') - ++(*lp); -} - -static void -ini_set_error(struct ini_config *cg, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - if (cg->pv->error) - vsnprintf(cg->pv->error, sizeof (cg->pv->error), fmt, ap); - va_end(ap); -} - -static void -ini_warn(struct ini_config *cg, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - if (F_VERBOSE(cg)) { - vprintf(fmt, ap); - fputc('\n', stdout); - } - - if (F_FAILERROR(cg)) { - va_start(ap, fmt); - vsnprintf(cg->pv->error, sizeof (cg->pv->error), fmt, ap); - va_end(ap); - } - - va_end(ap); -} - -/* - * Add a new section, this function only returns -1 on fatal error that may - * be impossible to continue parsing for the current line. - */ - -static int -ini_add_section(struct ini_config *cg, char **lp) -{ - char *begin = *lp, *end; - size_t length; - struct ini_section *section = NULL; - - if (!(end = strchr(begin, ']'))) { - ini_warn(cg, "line %d: syntax error after [", cg->pv->lineno); - goto bad; - } - - length = end - begin; - - /* May not redefine? */ - if (cg->pv->current && F_NOREDEFINE(cg)) - if (strncmp(cg->pv->current->key, begin, length) == 0) { - ini_warn(cg, "line %d: redefining %s", cg->pv->lineno, - cg->pv->current->key); - goto bad; - } - - /* Allocate a new section and add it */ - if (!(section = calloc(1, sizeof (*section)))) - goto bad; - - if (!(section->key = sstrndup(begin, length))) - goto bad; - - TAILQ_INIT(§ion->options); - TAILQ_INSERT_TAIL(&cg->sections, section, link); - cg->pv->current = section; - cg->pv->ignore = 0; - - /* Trigger an event for the new section */ - if (cg->open) - cg->open(cg->data, section->key); - - *lp = &end[1]; - - return 0; - -bad: if (section) - free(section->key); - free(section); - - cg->pv->ignore = 1; - *lp = strchr(*lp, '\0'); - - return F_FAILERROR(cg) ? -1 : 0; -} - -/* - * Add a new option, the returns value is same as ini_add_section. - */ - -static int -ini_add_option(struct ini_config *cg, char **lp) -{ - char *begin = *lp, *equal, *end; - struct ini_option *option = NULL; - - if (!cg->pv->current) { - ini_warn(cg, "line %d: option within no section", cg->pv->lineno); - goto bad; - } - - if (cg->pv->ignore || - !(option = calloc(1, sizeof (*option)))) - goto bad; - - /* Not valid */ - if (!(equal = strchr(begin, '='))) { - ini_warn(cg, "line %d: missing =", cg->pv->lineno); - goto bad; - } - - /* End of option */ - end = begin; - sskip(&end); - sseek(&end); - - option->key = sstrndup(begin, end - begin); - - /* End of value */ - begin = &equal[1]; - sskip(&begin); - end = begin; - - if (*end == '\'' || *end == '"') { - for (++end; *end != *begin && *end != '\0'; ++end) - continue; - if (*end != *begin) { - ini_warn(cg, "line %d: missing %c", - cg->pv->lineno, *begin); - *lp = end; - goto bad; - } else - ++ begin; - } else - sseek(&end); - - option->value = sstrndup(begin, end - begin); - - if (!option->key || !option->value) { - ini_warn(cg, "line %d: syntax error", cg->pv->lineno); - goto bad; - } - - TAILQ_INSERT_TAIL(&cg->pv->current->options, option, link); - - /* Trigger an event for the new section */ - if (cg->get) - cg->get(cg->data, cg->pv->current->key, option); - - *lp = &end[1]; - - return 0; - -bad: if (option) { - free(option->key); - free(option->value); - } - free(option); - - *lp = strchr(*lp, '\0'); - - return F_FAILERROR(cg) ? -1 : 0; -} - -static int -ini_read_line(struct ini_config *cg) -{ - char *lp = cg->pv->line; - int rv; - - /* Ignore empty line */ - if (*lp == '\0' || *lp == '#' || *lp == ';') - return 0; - - while (*lp != '\0') { - sskip(&lp); - - if (*lp == '\0' || *lp == '#' || *lp == ';') - return 0; - - /* Begin of section */ - if (*lp == '[') { - ++ lp; - rv = ini_add_section(cg, &lp); - /* Begin of option */ - } else { - rv = ini_add_option(cg, &lp); - } - - if (rv < 0) - return -1; - } - - return 0; -} - -/* - * Read the next line until the next '\n' character is found. Returns 0 - * if the system had enough memory or -1 on allocation failure or on - * end of file. Only for mode == INI_LINEAR - */ - -static int -ini_get_line(struct ini_config *cg) -{ - int ch, pos; - - memset(cg->pv->line, 0, cg->pv->linesize); - pos = 0; - - while ((ch = fgetc(cg->pv->fp)) != '\n') { - if (feof(cg->pv->fp) || ferror(cg->pv->fp)) - return -1; - - /* End of buffer, realloc */ - if (pos == cg->pv->linesize) { - cg->pv->line = realloc(cg->pv->line, cg->pv->linesize + 512); - if (!cg->pv->line) - return -1; - - cg->pv->linesize += 512; - } - - cg->pv->line[pos++] = ch; - } - - return 0; -} - -static int -ini_open_file(struct ini_config *cg) -{ - if (!(cg->pv->fp = fopen(cg->path, "r"))) { - ini_set_error(cg, "open: %s", cg->path); - return -1; - } - - cg->pv->linesize = INI_DEFAULT_LINESIZE; - cg->pv->line = calloc(sizeof (char), cg->pv->linesize); - - if (!cg->pv->line) { - ini_set_error(cg, "malloc: %s", strerror(errno)); - return -1; - } - - return 0; -} - -/* -------------------------------------------------------- - * Public functions - * -------------------------------------------------------- */ - -struct ini_config * -ini_create(const char *path, enum ini_flags flags) -{ - struct ini_config *cg; - - cg = calloc(1, sizeof (*cg)); - if (!cg) - return NULL; - - cg->pv = calloc(1, sizeof (struct ini_private)); - if (!cg->pv) - return NULL; - - cg->path = path; - cg->flags = flags; - - return cg; -} - -void -ini_set_handlers(struct ini_config *cg, void *data, ini_open_t open, - ini_get_t get) -{ - if (!cg) - return; - - cg->data = data; - cg->open = open; - cg->get = get; -} - -int -ini_open(struct ini_config *cg) -{ - int rv = 0; - - /* Open the file and prepare data for reading */ - if (ini_open_file(cg) < 0) - return -1; - - cg->pv->ignore = 1; - cg->pv->lineno = 1; - - TAILQ_INIT(&cg->sections); - - while (ini_get_line(cg) != -1 && !rv) { - rv = ini_read_line(cg); - ++ cg->pv->lineno; - } - - fclose(cg->pv->fp); - - return rv; -} - -/* - * Search the section `sectname' in the config structure. If the section - * is not found, this function returns NULL. - */ - -struct ini_section * -ini_select_section(const struct ini_config *cg, const char *sectname) -{ - struct ini_section *s; - - TAILQ_FOREACH(s, &cg->sections, link) - if (strcmp(s->key, sectname) == 0) - return s; - - return NULL; -} - -/* - * Search the option `optname' in the section structure, argument - * section mustn't be NULL. If the option is not found, this function - * returns NULL. - */ - -struct ini_option * -ini_select_option(const struct ini_section *sc, const char *name) -{ - struct ini_option *o; - - TAILQ_FOREACH(o, &sc->options, link) - if (strcmp(o->key, name) == 0) - return o; - - return NULL; -} - -/* - * Find an option from the config, by section and option names. - * Returns the option or NULL if not found. - */ - -struct ini_option * -ini_find(const struct ini_config *cg, const char *scname, const char *optname) -{ - struct ini_section *sc; - - if ((sc = ini_select_section(cg, scname))) - return ini_select_option(sc, optname); - - return NULL; -} - -/* - * Return the last error or "No error" if there is no error. - */ - -const char * -ini_get_error(const struct ini_config *cg) -{ - if (!cg && errno != 0) - return strerror(errno); - - if (cg->pv->error[0] == '\0') { - if (errno != 0) - return strerror(errno); - - return "No error"; - } - - return cg->pv->error; -} - -/* - * Free everything, level may be set like this: - * 0, only free parser and private resources. - * 1, free all sections and their keys, - * 2, free all sections and options keys and values. - */ - -void -ini_free(struct ini_config *cg, int level) -{ - struct ini_section *s, *stmp; - struct ini_option *o, *otmp; - - if (level >= 1) { - TAILQ_FOREACH_SAFE(s, &cg->sections, link, stmp) { - if (level >= 2) { - TAILQ_FOREACH_SAFE(o, &s->options, link, otmp) { - TAILQ_REMOVE(&s->options, o, link); - free(o->key); - free(o->value); - free(o); - } - } - - TAILQ_REMOVE(&cg->sections, s, link); - free(s->key); - free(s); - } - } - - if (level >= 0) { - free(cg->pv->line); - free(cg->pv); - free(cg); - } -} diff -r 523156bb3af5 -r d4b8416e9ab1 ini.h --- a/ini.h Fri Nov 15 21:37:57 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,131 +0,0 @@ -/* - * ini.h -- parse .ini like files - * - * Copyright (c) 2011, 2012, David Demelier - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _INI_H_ -#define _INI_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#if !defined(INI_DEFAULT_LINESIZE) -# define INI_DEFAULT_LINESIZE 1024 -#endif - -/* - * sys/queue.h bits. - */ - -#if !defined(TAILQ_ENTRY) -#define TAILQ_ENTRY(type) \ -struct { \ - struct type *tqe_next; /* next element */ \ - struct type **tqe_prev; /* address of previous next element */ \ -} -#endif - -#if !defined(TAILQ_HEAD) -#define TAILQ_HEAD(name, type) \ -struct name { \ - struct type *tqh_first; /* first element */ \ - struct type **tqh_last; /* addr of last next element */ \ -} -#endif - -enum ini_flags { - INI_VERBOSE = (1 << 0), /* be verbose */ - INI_NOREDEFINE = (1 << 1), /* do not allow redefinitions */ - INI_FAILERROR = (1 << 2) /* abort parsing on first error */ -}; - -typedef struct ini_config ini_config_t; -typedef struct ini_section ini_section_t; -typedef struct ini_option ini_option_t; -typedef struct ini_handler ini_handler_t; - -typedef void (*ini_open_t)(void *, const char *); -typedef void (*ini_get_t)(void *, const char *, const ini_option_t *); - -/* -------------------------------------------------------- - * Structure definitions - * -------------------------------------------------------- */ - -struct ini_private; - -struct ini_config { - const char *path; /* (ro) file path */ - enum ini_flags flags; /* (ro) optional flags */ - void *data; /* (rw) user data */ - - TAILQ_HEAD(, ini_section) sections; /* (ro) linked-list of sections */ - - /* Event driven method */ - void (*open)(void *, const char *); - void (*get)(void *, const char *, const struct ini_option *); - - /* Private data */ - struct ini_private *pv; -}; - -struct ini_option { - char *key; /* (rw) option name */ - char *value; /* (rw) option value */ - - TAILQ_ENTRY(ini_option) link; -}; - -struct ini_section { - char *key; /* (rw) section key */ - TAILQ_HEAD(, ini_option) options; /* (rw) list of options */ - - TAILQ_ENTRY(ini_section) link; -}; - -/* -------------------------------------------------------- - * Main functions - * -------------------------------------------------------- */ - -struct ini_config * -ini_create(const char *, enum ini_flags); - -void -ini_set_handlers(struct ini_config *, void *, ini_open_t, ini_get_t); - -int -ini_open(struct ini_config *); - -struct ini_section * -ini_select_section(const struct ini_config *, const char *); - -struct ini_option * -ini_select_option(const struct ini_section *, const char *); - -struct ini_option * -ini_find(const struct ini_config *, const char *, const char *); - -const char * -ini_get_error(const struct ini_config *); - -void -ini_free(struct ini_config *, int); - -#ifdef __cplusplus -} -#endif - -#endif /* _INI_H_ */ diff -r 523156bb3af5 -r d4b8416e9ab1 nsock.c --- a/nsock.c Fri Nov 15 21:37:57 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,661 +0,0 @@ -/* - * nsock.c -- portable BSD sockets wrapper - * - * Copyright (c) 2013 David Demelier - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -# include -# include - -#if defined(_WIN32) - - typedef SOCKET nsock_socket_t; - typedef const char * nsock_carg_t; - typedef char * nsock_arg_t; - -#else -# include -# include - -# define ioctlsocket(s) ioctl(s) -# define closesocket(s) close(s) - -# define gai_strerrorA gai_strerror - -# define INVALID_SOCKET -1 -# define SOCKET_ERROR -1 - - typedef int nsock_socket_t; - typedef const void * nsock_carg_t; - typedef void * nsock_arg_t; - -#endif - -#include "nsock.h" - -#define TAILQ_HEAD(name, type) \ -struct name { \ - struct type *tqh_first; /* first element */ \ - struct type **tqh_last; /* addr of last next element */ \ - size_t noclients; \ -} - -#define TAILQ_ENTRY(type) \ -struct { \ - struct type *tqe_next; /* next element */ \ - struct type **tqe_prev; /* address of previous next element */ \ -} - -#define TAILQ_EMPTY(head) ((head)->tqh_first == NULL) - -#define TAILQ_FIRST(head) ((head)->tqh_first) - -#define TAILQ_FOREACH(var, head, field) \ - for ((var) = TAILQ_FIRST((head)); \ - (var); \ - (var) = TAILQ_NEXT((var), field)) - -#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ - for ((var) = TAILQ_FIRST((head)); \ - (var) && ((tvar) = TAILQ_NEXT((var), field), 1); \ - (var) = (tvar)) - -#define TAILQ_INIT(head) do { \ - TAILQ_FIRST((head)) = NULL; \ - (head)->tqh_last = &TAILQ_FIRST((head)); \ -} while (0) - -#define TAILQ_INSERT_HEAD(head, elm, field) do { \ - if ((TAILQ_NEXT((elm), field) = TAILQ_FIRST((head))) != NULL) \ - TAILQ_FIRST((head))->field.tqe_prev = \ - &TAILQ_NEXT((elm), field); \ - else \ - (head)->tqh_last = &TAILQ_NEXT((elm), field); \ - TAILQ_FIRST((head)) = (elm); \ - (elm)->field.tqe_prev = &TAILQ_FIRST((head)); \ - (head)->noclients ++; \ -} while (0) - -#define TAILQ_INSERT_TAIL(head, elm, field) do { \ - TAILQ_NEXT((elm), field) = NULL; \ - (elm)->field.tqe_prev = (head)->tqh_last; \ - *(head)->tqh_last = (elm); \ - (head)->tqh_last = &TAILQ_NEXT((elm), field); \ - (head)->noclients ++; \ -} while (0) - -#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) - -#define TAILQ_REMOVE(head, elm, field) do { \ - if ((TAILQ_NEXT((elm), field)) != NULL) \ - TAILQ_NEXT((elm), field)->field.tqe_prev = \ - (elm)->field.tqe_prev; \ - else { \ - (head)->tqh_last = (elm)->field.tqe_prev; \ - } \ - *(elm)->field.tqe_prev = TAILQ_NEXT((elm), field); \ - (head)->noclients --; \ -} while (0) - -struct nsock { - nsock_socket_t fd; - char error[128]; -}; - -struct nsock_address { - struct sockaddr_storage addr; - socklen_t addrlen; - char error[128]; -}; - -struct nsock_listener { - const struct nsock *sock; - char error[128]; - TAILQ_HEAD(, nsock_clt) head; -}; - -struct nsock_clt { - const struct nsock *sock; - TAILQ_ENTRY(nsock_clt) link; -}; - -/* -------------------------------------------------------- - * Private helpers - * -------------------------------------------------------- */ - -static void -nsock_set_error(char *buffer, size_t bufsize) -{ - memset(buffer, 0, bufsize); - -#if defined(_WIN32) - LPSTR str; - - FormatMessageA( - FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM, - NULL, - WSAGetLastError(), - MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), - (LPSTR)&str, 0, NULL); - - if (str) { - strncpy(buffer, str, bufsize); - LocalFree(str); - } -#else - strncpy(buffer, strerror(errno), bufsize); -#endif -} - -static void -nsock_set_errno(char *buffer, size_t bufsize, int no) -{ - memset(buffer, 0, bufsize); - strncpy(buffer, strerror(no), bufsize - 1); -} - -static struct nsock_clt * -nsock_clt_new(const struct nsock *ns) -{ - struct nsock_clt *clt; - - if ((clt = malloc(sizeof (struct nsock_clt))) == NULL) - return NULL; - - clt->sock = ns; - - return clt; -} - -/* -------------------------------------------------------- - * Sockets functions - * -------------------------------------------------------- */ - -void -nsock_init(void) -{ -#if defined(_WIN32) - WSADATA wsa; - WSAStartup(MAKEWORD(2, 2), &wsa); -#endif -} - -struct nsock * -nsock_new(void) -{ - struct nsock *ns; - - if ((ns = malloc(sizeof (struct nsock))) == NULL) - return NULL; - - return ns; -} - -int -nsock_create(struct nsock *ns, int domain, int type, int protocol) -{ - ns->fd = socket(domain, type, protocol); - - if (ns->fd == INVALID_SOCKET) - nsock_set_error(ns->error, sizeof (ns->error)); - - return ns->fd == INVALID_SOCKET ? -1 : 0; -} - -const char * -nsock_error(struct nsock *ns) -{ - if (ns == NULL) - return strerror(ENOMEM); - - return ns->error; -} - -int -nsock_bind(struct nsock *ns, const struct nsock_address *ep) -{ - int ret; - - ret = bind(ns->fd, (const struct sockaddr *)&ep->addr, ep->addrlen); - - if (ret == SOCKET_ERROR) - nsock_set_error(ns->error, sizeof (ns->error)); - - return ret == SOCKET_ERROR ? -1 : 0; -} - -int -nsock_listen(struct nsock *ns, int max) -{ - int ret; - - ret = listen(ns->fd, max); - - if (ret == SOCKET_ERROR) - nsock_set_error(ns->error, sizeof (ns->error)); - - return ret == SOCKET_ERROR ? -1 : 0; -} - -int -nsock_accept(struct nsock *ns, struct nsock **client, struct nsock_address **clientinfo) -{ - struct sockaddr_storage *st = NULL; - socklen_t *len = NULL; - int ret; - - if ((*client = malloc(sizeof (struct nsock))) == NULL) { - nsock_set_errno(ns->error, sizeof (ns->error), ENOMEM); - return -1; - } - - if (clientinfo != NULL) { - if ((*clientinfo = malloc(sizeof (struct nsock_address))) == NULL) { - free(client); - nsock_set_errno(ns->error, sizeof (ns->error), ENOMEM); - return -1; - } - - st = &(*clientinfo)->addr; - len = &(*clientinfo)->addrlen; - - /* Set the addrlen to sockaddr_storage first */ - *len = sizeof (struct sockaddr_storage); - } - - /* Prepare client */ - memset((*client)->error, 0, sizeof ((*client)->error)); - (*client)->fd = accept(ns->fd, (struct sockaddr *)st, len); - - if ((*client)->fd == INVALID_SOCKET) { - nsock_set_error(ns->error, sizeof (ns->error)); - - /* free clients and set to NULL so user will not use it */ - free(*client); - *client = NULL; - - if (clientinfo != NULL) { - free(*clientinfo); - *clientinfo = NULL; - } - - ret = -1; - } else - ret = 0; - - return ret; -} - -int -nsock_connect(struct nsock *ns, const struct nsock_address *ep) -{ - int ret; - - ret = connect(ns->fd, (const struct sockaddr *)&ep->addr, ep->addrlen); - - if (ret == SOCKET_ERROR) - nsock_set_error(ns->error, sizeof (ns->error)); - - return ret == SOCKET_ERROR ? -1 : 0; -} - -int -nsock_set(struct nsock *ns, int level, int name, const void *arg, unsigned arglen) -{ - int ret; - - ret = setsockopt(ns->fd, level, name, (nsock_carg_t)arg, arglen); - - if (ret == SOCKET_ERROR) - nsock_set_error(ns->error, sizeof (ns->error)); - - return ret == SOCKET_ERROR ? -1 : 0; -} - -long -nsock_recv(struct nsock *ns, void *data, size_t datasz, int flags) -{ - long nbread; - - nbread = recv(ns->fd, data, datasz, flags); - - if (nbread == -1) - nsock_set_error(ns->error, sizeof (ns->error)); - - return nbread; -} - -long -nsock_recvfrom(struct nsock *ns, struct nsock_address *ep, void *data, size_t datasz, int flags) -{ - struct sockaddr_storage *st = NULL; - socklen_t *len = NULL; - long nbread; - - if (ep != NULL) { - st = &ep->addr; - len = &ep->addrlen; - - /* Set the addrlen to sockaddr_storage first */ - *len = sizeof (struct sockaddr_storage); - } - - nbread = recvfrom(ns->fd, data, datasz, flags, - (struct sockaddr *)st, len); - - if (nbread == SOCKET_ERROR) - nsock_set_error(ns->error, sizeof (ns->error)); - - return nbread; -} - -long -nsock_send(struct nsock *ns, const void *data, size_t datasz, int flags) -{ - long nbsent; - - nbsent = send(ns->fd, data, datasz, flags); - - if (nbsent == -1) - nsock_set_error(ns->error, sizeof (ns->error)); - - return nbsent; -} - -long -nsock_sendto(struct nsock *ns, const struct nsock_address *ep, const void *data, size_t datasz, int flags) -{ - long nbsent; - - nbsent = sendto(ns->fd, data, datasz, flags, - (const struct sockaddr *)&ep->addr, ep->addrlen); - - if (nbsent == SOCKET_ERROR) - nsock_set_error(ns->error, sizeof (ns->error)); - - return nbsent; -} - -void -nsock_close(struct nsock *ns) -{ - closesocket(ns->fd); -} - -void -nsock_free(struct nsock *ns) -{ - free(ns); -} - -void -nsock_finish(void) -{ -#if defined(_WIN32) - WSACleanup(); -#endif -} - -/* -------------------------------------------------------- - * End point functions - * -------------------------------------------------------- */ - -struct nsock_address * -nsock_addr_new(void) -{ - struct nsock_address *ep; - - if ((ep = calloc(1, sizeof (struct nsock_address))) == NULL) - return NULL; - - return ep; -} - -const char * -nsock_addr_error(struct nsock_address *ep) -{ - if (ep == NULL) - return strerror(ENOMEM); - - return ep->error; -} - -int -nsock_addr_bind_ip(struct nsock_address *ep, const char *iface, unsigned port, int family) -{ - if (family == AF_INET6) { - struct sockaddr_in6 *ptr = (struct sockaddr_in6 *)&ep->addr; - - memset(ptr, 0, sizeof (struct sockaddr_in6)); - ptr->sin6_family = AF_INET6; - ptr->sin6_port = htons(port); - - if (iface == NULL || strcmp(iface, "*") == 0) - ptr->sin6_addr = in6addr_any; - else if (inet_pton(AF_INET6, iface, &ptr->sin6_addr) <= 0) { - nsock_set_error(ep->error, sizeof (ep->error)); - return -1; - } - - ep->addrlen = sizeof (struct sockaddr_in6); - } else { - struct sockaddr_in *ptr = (struct sockaddr_in *)&ep->addr; - - memset(ptr, 0, sizeof (struct sockaddr_in)); - ptr->sin_family = AF_INET; - ptr->sin_port = htons(port); - - if (iface == NULL || strcmp(iface, "*") == 0) - ptr->sin_addr.s_addr = INADDR_ANY; - else if (inet_pton(AF_INET, iface, &ptr->sin_addr) <= 0) { - nsock_set_error(ep->error, sizeof (ep->error)); - return -1; - } - - ep->addrlen = sizeof (struct sockaddr_in); - } - - return 0; -} - -int -nsock_addr_connect_ip(struct nsock_address *ep, const char *host, unsigned port, int family) -{ - struct addrinfo hints, *res; - char portstr[32]; - int error; - - memset(&hints, 0, sizeof (hints)); - hints.ai_family = family; - hints.ai_socktype = SOCK_STREAM; - - memset(portstr, 0, sizeof (portstr)); - sprintf(portstr, "%u", port); - - error = getaddrinfo(host, portstr, &hints, &res); - if (error) { - memset(ep->error, 0, sizeof (ep->error)); - strncpy(ep->error, gai_strerrorA(error), sizeof (ep->error) - 1); - return -1; - } - - memcpy(&ep->addr, res->ai_addr, res->ai_addrlen); - ep->addrlen = res->ai_addrlen; - - freeaddrinfo(res); - - return 0; -} - -#if !defined(_WIN32) - -void -nsock_addr_unix(struct nsock_address *ep, const char *path) -{ - struct sockaddr_un *ptr= (struct sockaddr_un *)&ep->addr; - - /* Path */ - memset(ptr, 0, sizeof (struct sockaddr_un)); - strncpy(ptr->sun_path, path, sizeof (ptr->sun_path) - 1); - ptr->sun_family = AF_UNIX; - - /* Len is computed with SUN_LEN */ - ep->addrlen = SUN_LEN(ptr); -} - -#endif - -struct sockaddr * -nsock_addr_getaddr(struct nsock_address *ep) -{ - return (struct sockaddr *)&ep->addr; -} - -socklen_t -nsock_addr_getaddrlen(const struct nsock_address *ep) -{ - return ep->addrlen; -} - -void -nsock_addr_free(struct nsock_address *ep) -{ - free(ep); -} - -/* -------------------------------------------------------- - * listener functions - * -------------------------------------------------------- */ - -struct nsock_listener * -nsock_lst_new(const struct nsock *ns) -{ - struct nsock_listener *ls; - - if ((ls = malloc(sizeof (struct nsock_listener))) == NULL) - return NULL; - - ls->sock = ns; - TAILQ_INIT(&ls->head); - - return ls; -} - -const char * -nsock_lst_error(struct nsock_listener *ls) -{ - if (ls == NULL) - return strerror(ENOMEM); - - return ls->error; -} - -int -nsock_lst_push(struct nsock_listener *ls, struct nsock *ns) -{ - struct nsock_clt *clt; - - if ((clt = nsock_clt_new(ns)) == NULL) - return -1; - - TAILQ_INSERT_HEAD(&ls->head, clt, link); - - return 0; -} - -int -nsock_lst_append(struct nsock_listener *ls, struct nsock *ns) -{ - struct nsock_clt *clt; - - if ((clt = nsock_clt_new(ns)) == NULL) - return -1; - - TAILQ_INSERT_TAIL(&ls->head, clt, link); - - return 0; -} - -size_t -nsock_lst_count(const struct nsock_listener *ls) -{ - return ls->head.noclients; -} - -void -nsock_lst_remove(struct nsock_listener *ls, const struct nsock *ns) -{ - struct nsock_clt *clt, *tmp; - - TAILQ_FOREACH_SAFE(clt, &ls->head, link, tmp) { - if (clt->sock == ns) { - TAILQ_REMOVE(&ls->head, clt, link); - free(clt); - break; - } - } -} - -struct nsock * -nsock_lst_select(struct nsock_listener *ls, long sec, long usec) -{ - fd_set fds; - struct timeval maxwait, *towait; - int error; - int fdmax; - struct nsock_clt *clt; - - fdmax = TAILQ_FIRST(&ls->head)->sock->fd; - - FD_ZERO(&fds); - TAILQ_FOREACH(clt, &ls->head, link) { - FD_SET(clt->sock->fd, &fds); - if ((int)clt->sock->fd > fdmax) - fdmax = clt->sock->fd; - } - - maxwait.tv_sec = sec; - maxwait.tv_usec = usec; - - // Set to NULL for infinite timeout. - towait = (sec == 0 && usec == 0) ? NULL : &maxwait; - error = select(fdmax + 1, &fds, NULL, NULL, towait); - - TAILQ_FOREACH(clt, &ls->head, link) - if (FD_ISSET(clt->sock->fd, &fds)) - return (struct nsock *)clt->sock; - - return NULL; -} - -void -nsock_lst_map(struct nsock_listener *ls, nsock_lst_map_t map, void *data) -{ - const struct nsock_clt *clt; - - TAILQ_FOREACH(clt, &ls->head, link) - map(clt->sock, data); -} - -void -nsock_lst_free(struct nsock_listener *ls) -{ - struct nsock_clt *clt, *tmp; - - TAILQ_FOREACH_SAFE(clt, &ls->head, link, tmp) - free(clt); - - free(ls); -} diff -r 523156bb3af5 -r d4b8416e9ab1 nsock.h --- a/nsock.h Fri Nov 15 21:37:57 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,161 +0,0 @@ -/* - * nsock.h -- portable BSD sockets wrapper - * - * Copyright (c) 2013 David Demelier - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _NSOCK_H_ -#define _NSOCK_H_ - -#if !defined(NSOCK_NOINCLUDES) -# if defined(_WIN32) -# include -# include -# else -# include -# include -# include - -# include - -# include - -# include -# include -# endif -#endif - -struct nsock; -struct nsock_address; -struct nsock_listener; - -/* -------------------------------------------------------- - * Sockets functions - * -------------------------------------------------------- */ - -void -nsock_init(void); - -struct nsock * -nsock_new(void); - -int -nsock_create(struct nsock *, int, int, int); - -const char * -nsock_error(struct nsock *); - -int -nsock_bind(struct nsock *, const struct nsock_address *); - -int -nsock_listen(struct nsock *, int); - -int -nsock_accept(struct nsock *, struct nsock **, struct nsock_address **); - -int -nsock_connect(struct nsock *, const struct nsock_address *); - -int -nsock_set(struct nsock *, int, int, const void *, unsigned); - -long -nsock_recv(struct nsock *, void *, size_t, int); - -long -nsock_recvfrom(struct nsock *, struct nsock_address *, void *, size_t, int); - -long -nsock_send(struct nsock *, const void *, size_t, int); - -long -nsock_sendto(struct nsock *, const struct nsock_address *, const void *, size_t, int); - -void -nsock_close(struct nsock *); - -void -nsock_free(struct nsock *); - -void -nsock_finish(void); - -/* -------------------------------------------------------- - * End point functions - * -------------------------------------------------------- */ - -struct nsock_address * -nsock_addr_new(void); - -const char * -nsock_addr_error(struct nsock_address *); - -int -nsock_addr_bind_ip(struct nsock_address *, const char *, unsigned, int); - -int -nsock_addr_connect_ip(struct nsock_address *, const char *, unsigned, int); - -#if !defined(_WIN32) - -void -nsock_addr_unix(struct nsock_address *, const char *); - -#endif - -struct sockaddr * -nsock_addr_getaddr(struct nsock_address *); - -socklen_t -nsock_addr_getaddrlen(const struct nsock_address *); - -void -nsock_addr_free(struct nsock_address *); - -/* -------------------------------------------------------- - * listener functions - * -------------------------------------------------------- */ - -typedef void (*nsock_lst_map_t)(const struct nsock *, void *); - -struct nsock_listener * -nsock_lst_new(const struct nsock *); - -const char * -nsock_lst_error(struct nsock_listener *); - -int -nsock_lst_push(struct nsock_listener *, struct nsock *); - -int -nsock_lst_append(struct nsock_listener *, struct nsock *); - -size_t -nsock_lst_count(const struct nsock_listener *); - -void -nsock_lst_remove(struct nsock_listener *, const struct nsock *); - -struct nsock * -nsock_lst_select(struct nsock_listener *, long, long); - -void -nsock_lst_map(struct nsock_listener *, nsock_lst_map_t, void *); - -void -nsock_lst_free(struct nsock_listener *); - -#endif /* !_NSOCK_H_ */ diff -r 523156bb3af5 -r d4b8416e9ab1 pack.c --- a/pack.c Fri Nov 15 21:37:57 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,477 +0,0 @@ -/* - * pack.c -- endian dependant binary file reader - * - * Copyright (c) 2011, 2012, David Demelier - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include -#include - -#include "pack.h" - -/* Compilation tunables */ -#if !defined(PACK_CHKSIZE) -# define PACK_CHKSIZE (256) /* default chunk size */ -#endif - -/* Type */ -enum pack_type { - TYPE_FP, - TYPE_FIXEDBUF, - TYPE_AUTOBUF -}; - -struct pack_sc { - enum pack_type type; /* which kind of work */ - short endian; /* endian */ - - /* if TYPE_FP */ - FILE * fp; /* file to write */ - - /* else */ - char * buf; /* bytes converted */ - size_t size; /* current length */ - size_t allocated; /* allocated size */ - - /* for reading */ - unsigned int position; /* position where to read */ -}; - -struct pack_value { - /* for writing */ - int nelem; /* number of element */ - int size; /* size of elements */ - uint64_t value; /* direct value */ - char * array; /* array of values */ - - /* for reading */ - char * dst; /* destination */ -}; - -#define SC_SET(s, tp, ed, f, b, al) do { \ - memset((s), 0, sizeof (struct pack_sc)); \ - (s)->type = tp; \ - (s)->endian = ed; \ - (s)->fp = f; \ - (s)->buf = b; \ - (s)->allocated = al; \ -} while (/* CONSTCOND */ 0) - -#define TOKNARG(tok, nelem) do { \ - if (p[1] == '[') { \ - char *end; \ - \ - /* Can statically write the number, or pass it */ \ - if (p[2] != ']') { \ - nelem = (int)strtol(&p[2], &end, 10); \ - p = end; \ - } else { \ - nelem = va_arg(ap, int); \ - while (!isspace(*p) && *p != ']' && *p != '\0') \ - ++p; \ - } \ - } else \ - nelem = 1; \ -} while (/* CONSTCOND */ 0) - -#define TOKSIZE(tok, size) do { \ - switch (tok) { \ - case 'c': \ - size = sizeof (uint8_t); \ - break; \ - case 's': \ - size = sizeof (uint16_t); \ - break; \ - case 'i': \ - size = sizeof (uint32_t); \ - break; \ - case 'l': \ - size = sizeof (uint64_t); \ - break; \ - default: \ - size = 0; \ - break; \ - } \ -} while (/* CONSTCOND */ 0) - -#define TOKGETARG(serv, tok, val, ap) do { \ - if ((val)->nelem == 1 && serv == writeto) { \ - uint64_t item; \ - switch (tok) { \ - case 'c': case 's': case 'i': \ - item = va_arg(ap, int); \ - break; \ - case 'l': \ - item = va_arg(ap, uint64_t); \ - break; \ - default: \ - item = 0; \ - break; \ - } \ - \ - memset(&(val)->value, 0, sizeof (uint64_t)); \ - memcpy(&(val)->value, &item, (val)->size); \ - (val)->array = (char *)&(val)->value; \ - } else { /* read is always a pointer */ \ - (val)->array = va_arg(ap, void *); \ - (val)->dst = (val)->array; \ - } \ -} while (/* CONSTCOND */ 0) - -#define GETCONV(ed, size, conv) do { \ - if (ed != PACK_HOST_BYTEORDER) { \ - switch ((size)) { \ - case (sizeof (uint16_t)): \ - conv = conv16; break; \ - case (sizeof (uint32_t)): \ - conv = conv32; break; \ - case (sizeof (uint64_t)): \ - conv = conv64; break; \ - default: \ - conv = NULL; \ - } \ - } else \ - conv = NULL; \ -} while (/* CONSTCOND */ 0) - -static void -conv16(void *item) -{ - *(uint16_t *)item = pack_swap16(*(uint16_t *)item); -} - -static void -conv32(void *item) -{ - *(uint32_t *)item = pack_swap32(*(uint32_t *)item); -} - -static void -conv64(void *item) -{ - *(uint64_t *)item = pack_swap64(*(uint64_t *)item); -} - -/* - * Function that write content into the buffer or file depending - * on the calling function. Returns the number of bytes written - * or -1 on failure. - */ -static long -writeto(struct pack_sc *sc, struct pack_value *val) -{ - void (*conv)(void *); - int i; - uint64_t item; - long nbytes = 0; - - /* Get converter */ - GETCONV(sc->endian, val->size, conv); - - for (i = 0; i < val->nelem; ++i) { - item = 0; - memcpy(&item, &val->array[i * val->size], val->size); - - if (conv != NULL) - conv(&item); - - switch (sc->type) { - case TYPE_FP: - fwrite(&item, val->size, 1, sc->fp); - break; - case TYPE_AUTOBUF: - if (sc->size + val->size >= sc->allocated) { - sc->allocated += PACK_CHKSIZE; - sc->buf = realloc(sc->buf, sc->allocated); - - if (sc->buf == NULL) - return -1; - } - /* FALLTHROUGH */ - case TYPE_FIXEDBUF: - if (sc->size + val->size <= sc->allocated) { - memcpy(&sc->buf[sc->size], &item, val->size); - sc->size += val->size; - } else - continue; - default: - break; - } - - nbytes += val->size; - } - - return nbytes; -} - -/* - * Function that read the file or buffer and fill array. - */ -static long -readfrom(struct pack_sc *sc, struct pack_value *val) -{ - void (*conv)(void *); - int i, oktoread; - uint64_t item; - long nbytes = 0; - - /* Get converter */ - GETCONV(sc->endian, val->size, conv); - - for (i = 0; i < val->nelem; ++i) { - item = oktoread = 0; - - switch (sc->type) { - case TYPE_FP: - fread(&item, val->size, 1, sc->fp); - oktoread = 1; - break; - case TYPE_FIXEDBUF: - if (sc->position + val->size <= sc->allocated) { - memcpy(&item, &sc->buf[sc->position], val->size); - sc->position += val->size; - oktoread = 1; - } - break; - default: - break; - } - - if (conv != NULL) - conv(&item); - - if (oktoread) { - memcpy(&val->dst[i * val->size], &item, val->size); - nbytes += val->size; - } - } - - return nbytes; -} - -/* - * Function that analyses the format, write or read the values depending - * on the calling functions. - */ -static long -packit(struct pack_sc *sc, long (*func)(struct pack_sc *, struct pack_value *), - const char *fmt, va_list ap) -{ - struct pack_value val; - const char *p; - int tok; - long nbytes = 0, rv; - - for (p = fmt; *p != '\0'; ++p) { - tok = *p; - - if (isspace(*p)) - continue; - - TOKNARG(tok, val.nelem); - TOKSIZE(tok, val.size); - - if (val.size == 0 || val.nelem == 0) - continue; - - TOKGETARG(func, tok, &val, ap); - if ((rv = func(sc, &val)) == -1) - return -1; - - nbytes += rv; - } - - return nbytes; -} - -long -pack_write(short ed, const char *path, const char *fmt, ...) -{ - va_list ap; - long rv; - - va_start(ap, fmt); - rv = pack_vwrite(ed, path, fmt, ap); - va_end(ap); - - return rv; -} - -long -pack_vwrite(short ed, const char *path, const char *fmt, va_list ap) -{ - FILE *fp; - long rv; - - if ((fp = fopen(path, "wb")) == NULL) - return -1; - - rv = pack_vfwrite(ed, fp, fmt, ap); - fclose(fp); - - return rv; -} - -long -pack_fwrite(short ed, FILE *fp, const char *fmt, ...) -{ - va_list ap; - long rv; - - va_start(ap, fmt); - rv = pack_vfwrite(ed, fp, fmt, ap); - va_end(ap); - - return rv; -} - -long -pack_vfwrite(short ed, FILE *fp, const char *fmt, va_list ap) -{ - struct pack_sc sc; - - SC_SET(&sc, TYPE_FP, ed, fp, NULL, 0); - - return packit(&sc, writeto, fmt, ap); -} - -long -pack_swrite(short ed, char *buf, size_t max, const char *fmt, ...) -{ - va_list ap; - long rv; - - va_start(ap, fmt); - rv = pack_vswrite(ed, buf, max, fmt, ap); - va_end(ap); - - return rv; -} - -long -pack_vswrite(short ed, char *buf, size_t max, const char *fmt, va_list ap) -{ - struct pack_sc sc; - - SC_SET(&sc, TYPE_FIXEDBUF, ed, NULL, buf, max); - - return packit(&sc, writeto, fmt, ap); -} - -long -pack_aswrite(short ed, char **bufp, const char *fmt, ...) -{ - va_list ap; - long rv; - - va_start(ap, fmt); - rv = pack_vaswrite(ed, bufp, fmt, ap); - va_end(ap); - - return rv; -} - -long -pack_vaswrite(short ed, char **bufp, const char *fmt, va_list ap) -{ - struct pack_sc sc; - int rv; - - SC_SET(&sc, TYPE_AUTOBUF, ed, NULL, NULL, PACK_CHKSIZE); - - if ((sc.buf = malloc(PACK_CHKSIZE)) == NULL) - return -1; - - rv = packit(&sc, writeto, fmt, ap); - *bufp = sc.buf; - - return rv; -} - -long -pack_read(short ed, const char *path, const char *fmt, ...) -{ - va_list ap; - long rv; - - va_start(ap, fmt); - rv = pack_vread(ed, path, fmt, ap); - va_end(ap); - - return rv; -} - -long -pack_vread(short ed, const char *path, const char *fmt, va_list ap) -{ - FILE *fp; - long rv; - - if ((fp = fopen(path, "rb")) == NULL) - return -1; - - rv = pack_vfread(ed, fp, fmt, ap); - fclose(fp); - - return rv; -} - -long -pack_fread(short ed, FILE *fp, const char *fmt, ...) -{ - va_list ap; - long rv; - - va_start(ap, fmt); - rv = pack_vfread(ed, fp, fmt, ap); - va_end(ap); - - return rv; -} - -long -pack_vfread(short ed, FILE *fp, const char *fmt, va_list ap) -{ - struct pack_sc sc; - - SC_SET(&sc, TYPE_FP, ed, fp, NULL, 0); - - return packit(&sc, readfrom, fmt, ap); -} - -long -pack_sread(short ed, const char *buf, size_t max, const char *fmt, ...) -{ - va_list ap; - long rv; - - va_start(ap, fmt); - rv = pack_vsread(ed, buf, max, fmt, ap); - va_end(ap); - - return rv; -} - -long -pack_vsread(short ed, const char *buf, size_t max, const char *fmt, va_list ap) -{ - struct pack_sc sc; - - SC_SET(&sc, TYPE_FIXEDBUF, ed, NULL, (char *)buf, max); - - return packit(&sc, readfrom, fmt, ap); -} diff -r 523156bb3af5 -r d4b8416e9ab1 pack.h --- a/pack.h Fri Nov 15 21:37:57 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,80 +0,0 @@ -/* - * pack.h -- endian dependant binary file reader - * - * Copyright (c) 2011, 2012, David Demelier - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _PACK_H_ -#define _PACK_H_ - -#include -#include - -#define PACK_LE 1234 -#define PACK_BE 4321 - -/* - * Endian detection based on SDL_endian.h - */ - -#undef PACK_HOST_BYTEORDER - -#if defined(__hppa__) || \ - defined(__m68k__) || defined(mc68000) || defined(_M_M68K) || \ - (defined(__MIPS__) && defined(__MISPEB__)) || \ - defined(__ppc__) || defined(__POWERPC__) || defined(_M_PPC) || \ - defined(__sparc__) -# define PACK_HOST_BYTEORDER PACK_BE -#else -# define PACK_HOST_BYTEORDER PACK_LE -#endif - -#define pack_swap16(x) \ - ((((x) >> 8) & 0x00FFL) | (((x) << 8) & 0xFF00L)) - -#define pack_swap32(x) ((((x) >> 24) & 0x000000FFL) \ - | (((x) >> 8) & 0x0000FF00L) \ - | (((x) << 8) & 0x00FF0000L) \ - | (((x) << 24) & 0xFF000000L)) - -#define pack_swap64(x) (((long) \ - ((int) pack_swap32((int) (((x) << 32) >> 32))) << 32) \ - | (int) pack_swap32((int) ((x) >> 32))) - -#ifdef __cplusplus -extern "C" { -#endif - -long pack_write(short, const char *, const char *, ...); -long pack_vwrite(short, const char *, const char *, va_list); -long pack_fwrite(short, FILE *, const char *, ...); -long pack_vfwrite(short, FILE *, const char *, va_list); -long pack_swrite(short, char *, size_t, const char *, ...); -long pack_vswrite(short, char *, size_t, const char *, va_list); -long pack_aswrite(short, char **, const char *, ...); -long pack_vaswrite(short, char **, const char *, va_list); - -long pack_read(short, const char *, const char *, ...); -long pack_vread(short, const char *, const char *, va_list); -long pack_fread(short, FILE *, const char *, ...); -long pack_vfread(short, FILE *, const char *, va_list); -long pack_sread(short, const char *, size_t, const char *, ...); -long pack_vsread(short, const char *, size_t, const char *, va_list); - -#ifdef __cplusplus -} -#endif - -#endif /* _PACK_H_ */ diff -r 523156bb3af5 -r d4b8416e9ab1 parray.c --- a/parray.c Fri Nov 15 21:37:57 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,366 +0,0 @@ -/* - * parray.c -- manipulate dynamic pointer arrays - * - * Copyright (c) 2011, 2012, David Demelier - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#include -#include -#include - -#include "parray.h" - -#define LENGTH(x) ((x) * (sizeof (void *))) - -static int grow(struct parray *); - -int -parray_init(struct parray *arr) -{ - /* Set defaults if needed */ - arr->bsize = (arr->bsize <= 0) ? PARRAY_DEFAULT_BSIZE : arr->bsize; - arr->malloc = (arr->malloc == NULL) ? &malloc : arr->malloc; - arr->realloc = (arr->realloc == NULL) ? &realloc : arr->realloc; - - arr->bsize += (arr->flags & PARRAY_NULLEND) ? 1 : 0; - arr->size = LENGTH(arr->bsize); - - if ((arr->data = arr->malloc(arr->size)) == NULL) - return -1; - - memset(arr->data, 0, arr->size); - - return 0; -} - -/* - * Valid options that can be set for an array : - * l -> optional array block size of type int - * m -> malloc function that must matches void * (*malloc)(size_t) - * r -> realloc function that must matches void * (*realloc)(void *, size_t) - * f -> parray flags of type int - */ -void -parray_set(struct parray *arr, const char *fmt, ...) -{ - va_list ap; - const char *p; - - va_start(ap, fmt); - for (p = fmt; *p != '\0'; ++p) - switch (*p) { - case 'l': - arr->bsize = va_arg(ap, int); - break; - case 'm': - arr->malloc = va_arg(ap, void * (*)(size_t)); - break; - case 'r': - arr->realloc = va_arg(ap, void * (*)(void *, size_t)); - break; - case 'f': - arr->flags = va_arg(ap, int); - break; - default: - break; - } -} - -/* - * Add to the head of array. NOTE: this may be very slow when adding a lot - * of object (about 100000). If you need to add a lot of data please consider - * using linked list instead. Returns -1 on failure or 0 on success. - */ -int -parray_push(struct parray *arr, void *data) -{ - if (grow(arr) < 0) - return -1; - - memmove(&arr->data[1], &arr->data[0], LENGTH(arr->length++)); - arr->data[0] = data; - - if (arr->flags & PARRAY_NULLEND) - arr->data[arr->length] = NULL; - - return 0; -} - -/* - * Insert the data at the specified index. The function returns -1 on - * allocation failure or the position of the added element. - */ -int -parray_insert(struct parray *arr, void *data, int index) -{ - if (arr->flags & PARRAY_INSERTSAFE) - if (index < 0 || index > arr->length) - return -1; - - if (index < 0) - return parray_push(arr, data); - if (index >= arr->length) - return parray_append(arr, data); - - /* Good place */ - memmove(&arr->data[index + 1], &arr->data[index], - LENGTH(arr->length++ - index)); - arr->data[index] = data; - - if (arr->flags & PARRAY_NULLEND) - arr->data[arr->length] = NULL; - - return index; -} - -/* - * Append the data to the end of array. Returns -1 on failure or the position - * of the added element. - */ -int -parray_append(struct parray *arr, void *data) -{ - if (grow(arr) < 0) - return -1; - - arr->data[arr->length++] = data; - - if (arr->flags & PARRAY_NULLEND) - arr->data[arr->length] = NULL; - - return (arr->length - 1); -} - -/* - * Remove the array's head. - */ -void -parray_pop(struct parray *arr) -{ - parray_iremove(arr, 0); -} - -/* - * Remove the array's tail. - */ -void -parray_unqueue(struct parray *arr) -{ - parray_iremove(arr, arr->length - 1); -} - -/* - * Remove the data at the specified index. Bounds are checked. - */ -void -parray_iremove(struct parray *arr, int index) -{ - if (arr->length > 0 && index >= 0 && index < arr->length) { - if (arr->flags & PARRAY_FASTREMOVE) - arr->data[index] = arr->data[--arr->length]; - else - memmove(&arr->data[index], &arr->data[index + 1], - LENGTH(arr->length-- - index - 1)); - } - - arr->data[arr->length] = NULL; -} - -/* - * Remove the object referenced by the `data' argument. Useful when you - * don't know the index. - */ -void -parray_premove(struct parray *arr, const void *data) -{ - void *elm; - int i; - - PARRAY_FOREACH(arr, elm, i) { - if (elm == data) { - parray_iremove(arr, i); - break; - } - } -} - -/* - * Swap the two elements referenced by index `i1' and `i2'. This function needs - * to allocate data to swap elements thus if the functions fails it returns -1 - * otherwise 0 is returned. - */ -int -parray_iswap(struct parray *arr, int i1, int i2) -{ - void *tmp; - - /* Out of bounds */ - if (i1 >= arr->length || i1 < 0 || i2 >= arr->length || i2 < 0) - return -1; - - tmp = arr->data[i1]; - arr->data[i1] = arr->data[i2]; - arr->data[i2] = tmp; - - return 0; -} - -/* - * Swap the two elements referenced by data `o1' and `o2'. This function - * may be slow on large arrays since it must travel all the object - * to find the indexes. - */ -int -parray_pswap(struct parray *arr, const void *o1, const void *o2) -{ - int found, i1, i2; - - for (i1 = found = 0; !found && i1 < arr->length; ++i1) - found = arr->data[i1] == o1; - - if (!found) - return -1; - - for (i2 = found = 0; !found && i2 < arr->length; ++i2) - found = arr->data[i2] == o2; - - if (!found) - return -1; - - return parray_iswap(arr, --i1, --i2); -} - -/* - * Apply the function `fn' on each object and give the optional `udata' - * argument to the function too. - */ -void -parray_map(const struct parray *arr, parray_map_t fn, void *udata) -{ - int i; - - for (i = 0; i < arr->length; ++i) - fn(arr->data[i], udata); -} - -/* - * Compare each object with the user supplied function. If the `fn' function - * returns 1 then the index of the data position is returned and the parameter - * data points to the array data at the correct index. If the comparison - * function nevers returns 1, array_find returns -1. - */ -int -parray_find(const struct parray *arr, parray_cmp_t fn, void *ptr, void *u) -{ - int st, i; - - for (i = st = 0; i < arr->length && st != 1; ++i) - st = fn(arr->data[i], u); - - if (st && ptr) - *(void **)ptr = arr->data[i - 1]; - - return (st) ? i - 1 : -1; -} - -void * -parray_first(const struct parray *arr) -{ - return arr->data[0]; -} - -void * -parray_get(const struct parray *arr, int idx) -{ - if (idx < 0) - return parray_first(arr); - if (idx >= arr->length) - return parray_last(arr); - - return arr->data[idx]; -} - -void * -parray_last(const struct parray *arr) -{ - if (arr->length == 0) - return parray_first(arr); - - return arr->data[arr->length - 1]; -} - -/* - * Reset the array by setting each pointer to NULL and the length to 0. - */ -void -parray_clear(struct parray *arr) -{ - arr->data[0] = NULL; - arr->length = 0; -} - -/* - * Same as parray_clear except it also free the array object. - */ -void -parray_free(struct parray *arr) -{ - parray_clear(arr); - free(arr->data); - - arr->data = NULL; - arr->size = 0; -} - -/* - * Trim down the array to the correct size. - */ -void * -parray_trim(struct parray *arr) -{ - int count = arr->length; - - if (arr->flags & PARRAY_NULLEND) - ++ count; - - return arr->realloc(arr->data, count * sizeof (void *)); -} - -/* - * Increate the array storage when it is full. If the buffer is fixed size - * it returns -1 on full buffer otherwise 0 is returned if allocation - * succeeded. - */ -static int -grow(struct parray *arr) -{ - unsigned int toadd = (arr->flags & PARRAY_NULLEND) ? 2 : 1; - - if ((arr->size / sizeof (void *)) - arr->length >= toadd) - return 0; - - if (!(arr->flags & PARRAY_FIXED)) { - if ((arr->data = arr->realloc(arr->data, arr->size + - LENGTH(arr->bsize))) == NULL) { - arr->size = arr->length = 0; - return -1; - } - - arr->size += LENGTH(arr->bsize); - } else - return -1; - - return 0; -} diff -r 523156bb3af5 -r d4b8416e9ab1 parray.h --- a/parray.h Fri Nov 15 21:37:57 2013 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,121 +0,0 @@ -/* - * parray.h -- manipulate dynamic pointer arrays - * - * Copyright (c) 2011, 2012, David Demelier - * - * Permission to use, copy, modify, and/or distribute this software for any - * purpose with or without fee is hereby granted, provided that the above - * copyright notice and this permission notice appear in all copies. - * - * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - */ - -#ifndef _PARRAY_H_ -#define _PARRAY_H_ - -#include - -#ifndef PARRAY_DEFAULT_BSIZE -#define PARRAY_DEFAULT_BSIZE 128 -#endif - -enum parray_flags { - PARRAY_AUTO = 0, /* array grows automatically */ - PARRAY_FIXED = (1 << 0), /* fixed size length */ - PARRAY_FASTREMOVE = (1 << 1), /* use last object when removing */ - PARRAY_NULLEND = (1 << 2), /* always has a NULL pointer at end */ - PARRAY_INSERTSAFE = (1 << 3) /* insertion must have valid indexes */ -}; - -struct parray { - enum parray_flags flags; /* (ro) array flags (default AUTO) */ - void **data; /* (rw) array of data */ - int length; /* (ro) number of element inside */ - size_t size; /* (ro) current buffer size (allocated memory) */ - int bsize; /* (rw) block size (used when growing array) */ - - /* Own allocation functions */ - void * (*malloc)(size_t); - void * (*realloc)(void *, size_t); -}; - -typedef void (*parray_map_t)(void *, void *); -typedef int (*parray_cmp_t)(void *, void *); - -#ifdef __cplusplus -extern "C" { -#endif - -int -parray_init(struct parray *); - -void -parray_set(struct parray *, const char *, ...); - -int -parray_push(struct parray *, void *); - -int -parray_insert(struct parray *, void *, int); - -int -parray_append(struct parray *, void *); - -void -parray_pop(struct parray *); - -void -parray_unqueue(struct parray *); - -void -parray_iremove(struct parray *, int); - -void -parray_premove(struct parray *, const void *); - -int -parray_iswap(struct parray *, int, int); - -int -parray_pswap(struct parray *, const void *, const void *); - -void -parray_map(const struct parray *, parray_map_t, void *); - -int -parray_find(const struct parray *, parray_cmp_t, void *, void *); - -void * -parray_first(const struct parray *); - -void * -parray_get(const struct parray *, int); - -void * -parray_last(const struct parray *); - -void -parray_clear(struct parray *); - -void -parray_free(struct parray *); - -void * -parray_trim(struct parray *); - -#define PARRAY_FOREACH(a, o, i) \ - for (i = 0, o = (a)->data[i]; \ - i < (a)->length; \ - ++i, o = (a)->data[i]) - -#ifdef __cplusplus -} -#endif - -#endif /* _PARRAY_H_ */