Fri, 30 Nov 2012 21:18:13 +0100
added existing source code
--- a/.hgignore Fri Nov 30 21:11:33 2012 +0100 +++ b/.hgignore Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,6 @@ +syntax:regexp +^nbproject/.*$ +^build/.*$ +core$ +^.c?project$ +^.settings/.*$
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Makefile Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,62 @@ +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. +# +# Copyright 2011 Olaf Wintermann. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + + +# +# available configurations: +# gcc +# suncc +# windows +# osx +# + +#ifndef CONF + CONF=gcc +#endif + +include $(CONF).mk + +all: build ucx dav + +build: + mkdir build + +ucx: FORCE build + cd ucx; $(MAKE) CONF=$(CONF) all + +dav: FORCE ucx + cd dav; $(MAKE) CONF=$(CONF) all + +run: FORCE dav + ./build/dav$(APP_EXT) + +clean: FORCE + $(RM) $(RMFLAGS) build/*.${OBJ_EXT} + +FORCE: +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dav/Makefile Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,51 @@ +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. +# +# Copyright 2011 Olaf Wintermann. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +include ../$(CONF).mk + +CFLAGS += `xml2-config --cflags` +LDFLAGS += `curl-config --libs` `xml2-config --libs` + +SRC = main.c +SRC += propfind.c +SRC += utils.c + + +OBJ = $(SRC:%.c=../build/%.$(OBJ_EXT)) + +all: ../build/dav + +../build/dav: $(OBJ) + $(LD) $(LDFLAGS) $(LOFLAGS)../build/dav$(APP_EXT) $(OBJ) \ + ../build/libucx.$(LIB_EXT) + +../build/%.$(OBJ_EXT): %.c ../build + $(CC) $(CFLAGS) -I../ $(COFLAGS)$@ $< + +../build: + mkdir -p build
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dav/main.c Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,127 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2012 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <libxml/xmlerror.h> + +#include "propfind.h" +#include "utils.h" +#include "main.h" + +void xmlerrorfnc(void * ctx, const char * msg, ... ) { + // nothing +} + +int main(int argc, char **argv) { + xmlGenericErrorFunc fnc = xmlerrorfnc; + initGenericErrorDefaultFunc(&fnc); + + if(argc < 2) { + print_usage(); + return -1; + } + + if(!strcmp(argv[1], "list") || !strcmp(argv[1], "ls")) { + return cmd_list(argc - 2, argv + 2); + } else if(!strcmp(argv[1], "get")) { + return cmd_get(argc - 2, argv + 2); + } + + print_usage(); + return -1; +} + +void print_usage() { + +} + +int cmd_list(int argc, char **argv) { + if(argc == 0) { + return -1; + } + + char *url = argv[0]; // TODO: use arg as url or alias + + CURL *curl = curl_easy_init(); + curl_easy_setopt(curl, CURLOPT_URL, url); + Propfind *propfind = dav_propfind(curl); + + UCX_FOREACH(UcxDlist*, propfind->children, ch) { + DavResource *resource = ch->data; + printf("%s\n", resource->name); + } + + // TODO: free propfind stuff + curl_easy_cleanup(curl); + + return 0; +} + +int cmd_get(int argc, char **argv) { + if(argc == 0) { + return -1; + } + + char *url = argv[0]; // TODO: use arg as url or alias + + CURL *curl = curl_easy_init(); + curl_easy_setopt(curl, CURLOPT_URL, url); + Propfind *propfind = dav_propfind(curl); + + if(propfind->resource->collection) { + UCX_FOREACH(UcxDlist*, propfind->children, chd) { + DavResource *resource = chd->data; + if(!resource->collection) { + char *resurl = util_child_url(propfind->url, resource->href); + get_file(curl, resurl, resource->name); + } + } + } else { + get_file(curl, propfind->url, propfind->resource->name); + } + + // TODO: free propfind stuff + curl_easy_cleanup(curl); + + return 0; +} + +void get_file(CURL *curl, char *url, char *path) { + curl_easy_setopt(curl, CURLOPT_URL, url); + + FILE *out = fopen(path, "w"); + + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, fwrite); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, out); + + CURLcode res = curl_easy_perform(curl); + + fclose(out); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dav/main.h Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,50 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2012 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef MAIN_H +#define MAIN_H + +#include <curl/curl.h> +#include "propfind.h" + +#ifdef __cplusplus +extern "C" { +#endif + +void print_usage(); +int cmd_list(int argc, char **argv); +int cmd_get(int argc, char **argv); + +void get_file(CURL *curl, char *url, char *path); + +#ifdef __cplusplus +} +#endif + +#endif /* MAIN_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dav/propfind.c Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,226 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2012 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include "utils.h" +#include "propfind.h" + +Propfind* dav_propfind(CURL *handle) { + Propfind *response = malloc(sizeof(Propfind)); + response->resource = NULL; + response->children = NULL; + + curl_easy_setopt(handle, CURLOPT_CUSTOMREQUEST, "PROPFIND"); + + struct curl_slist *headers = NULL; + headers = curl_slist_append(headers, "Content-Type: text/xml"); + curl_easy_setopt(handle, CURLOPT_HTTPHEADER, headers); + + UcxBuffer *rqbuf = create_propfind_request_body(); + UcxBuffer *rpbuf = ucx_buffer_new(NULL, 4096, UCX_BUFFER_AUTOEXTEND); + //printf("request\n%s\n", body->space); + + curl_easy_setopt(handle, CURLOPT_UPLOAD, 1); + curl_easy_setopt(handle, CURLOPT_READFUNCTION, ucx_buffer_read); + curl_easy_setopt(handle, CURLOPT_READDATA, rqbuf); + curl_easy_setopt(handle, CURLOPT_INFILESIZE, rqbuf->size); + + curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, ucx_buffer_write); + curl_easy_setopt(handle, CURLOPT_WRITEDATA, rpbuf); + + ucx_buffer_seek(rqbuf, 0, SEEK_SET); + CURLcode res = curl_easy_perform(handle); + if(res == CURLE_OK) { + //printf("response\n%s\n", rpbuf->space); + + char *url = NULL; + curl_easy_getinfo(handle, CURLINFO_EFFECTIVE_URL, &url); + response->url = util_url_path(url); + + parse_propfind(response, rpbuf); + + response->url = strdup(url); + } + curl_easy_reset(handle); + + return response; +} + +UcxBuffer* create_propfind_request_body() { + UcxBuffer *buf = ucx_buffer_new(NULL, 512, 0); + sstr_t s; + + s = ST("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"); + ucx_buffer_write(s.ptr, 1, s.length, buf); + + s = ST("<D:propfind xmlns:D=\"DAV:\">\n"); + ucx_buffer_write(s.ptr, 1, s.length, buf); + + s = ST("<D:prop>\n"); + ucx_buffer_write(s.ptr, 1, s.length, buf); + + s = ST("<D:creationdate />\n<D:getlastmodified />\n"); + ucx_buffer_write(s.ptr, 1, s.length, buf); + + s = ST("<D:getcontentlength />\n<D:getcontenttype />\n"); + ucx_buffer_write(s.ptr, 1, s.length, buf); + + s = ST("<D:resourcetype />\n"); + ucx_buffer_write(s.ptr, 1, s.length, buf); + + s = ST("</D:prop>\n</D:propfind>\n"); + ucx_buffer_write(s.ptr, 1, s.length, buf); + + return buf; +} + +int parse_propfind(Propfind *propfind, UcxBuffer *response) { + xmlTextReaderPtr reader = xmlReaderForMemory( + response->space, + response->size, + propfind->url, + NULL, + 0); + + int ret = 0; + if(reader != NULL) { + int r; + while((r = xmlTextReaderRead(reader)) == 1) { + int nodetype = xmlTextReaderNodeType(reader); + if(nodetype == XML_READER_TYPE_ELEMENT) { + const xmlChar *name = xmlTextReaderConstLocalName(reader); + if(!xmlStrcmp(name, BAD_CAST "response")) { + r = parse_response(reader, propfind); + if(r != 0) { + ret = -1; + break; + } + } + } + } + xmlFreeTextReader(reader); + } + + return ret; +} + +int parse_response(xmlTextReaderPtr reader, Propfind *propfind) { + DavResource *res = calloc(sizeof(DavResource), 1); + if(res == NULL) { + return -1; + } + + /* + * 0: href + * 1: creationdate + * 2: getlastmodified + * 3: getcontentlength + * 4: getcontenttype + * 5: resourcetype + */ + int valuetype = -1; + + int r; + while((r = xmlTextReaderRead(reader)) == 1) { + int nodetype = xmlTextReaderNodeType(reader); + + if(nodetype == XML_READER_TYPE_END_ELEMENT) { + const xmlChar *name = xmlTextReaderConstLocalName(reader); + if(!xmlStrcmp(name, BAD_CAST "response")) { + break; + } + } + + switch(nodetype) { + case XML_READER_TYPE_ELEMENT: { + const xmlChar *name = xmlTextReaderConstLocalName(reader); + if(!xmlStrcmp(name, BAD_CAST "href")) { + valuetype = 0; + } else if(!xmlStrcmp(name, BAD_CAST "creationdate")) { + valuetype = 1; + } else if(!xmlStrcmp(name, BAD_CAST "getlastmodified")) { + valuetype = 2; + } else if(!xmlStrcmp(name, BAD_CAST "getcontentlength")) { + valuetype = 3; + } else if(!xmlStrcmp(name, BAD_CAST "getcontenttype")) { + valuetype = 4; + } else if(!xmlStrcmp(name, BAD_CAST "resourcetype")) { + valuetype = 5; + } else if(!xmlStrcmp(name, BAD_CAST "collection") + && valuetype == 5) { + res->collection = 1; + } else { + valuetype = -1; + } + break; + } + case XML_READER_TYPE_TEXT: { + const xmlChar *cvalue = xmlTextReaderConstValue(reader); + if(cvalue == NULL) { + break; + } + char *value = strdup((char*)cvalue); + switch(valuetype) { + case 0: { + res->href = value; + res->name = util_resource_name(value); + break; + } + case 1: { + res->creationdate = 0; // TODO + break; + } + case 2: { + res->lastmodified = 0; // TODO + break; + } + case 3: { + res->contentlength = atoi(value); + break; + } + case 4: { + res->contenttype = value; + //break; + } + } + //break; + } + } + } + + if(!strcmp(res->href, propfind->url)) { + propfind->resource = res; + } else { + propfind->children = ucx_dlist_append(propfind->children, res); + } + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dav/propfind.h Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,72 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2012 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PROPFIND_H +#define PROPFIND_H + +#include <inttypes.h> +#include <ucx/string.h> +#include <ucx/dlist.h> +#include <ucx/buffer.h> +#include <curl/curl.h> + +#include <libxml/xmlreader.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct { + char *name; + char *href; + uint64_t contentlength; + char *contenttype; + time_t creationdate; + time_t lastmodified; + int collection; +} DavResource; + +typedef struct { + char *url; + DavResource *resource; + UcxDlist *children; +} Propfind; + +Propfind* dav_propfind(CURL *handle); + +UcxBuffer* create_propfind_request_body(); + +int parse_propfind(Propfind *propfind, UcxBuffer *response); +int parse_response(xmlTextReaderPtr reader, Propfind *propfind); + +#ifdef __cplusplus +} +#endif + +#endif /* PROPFIND_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dav/utils.c Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,109 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2012 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include <time.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <ucx/string.h> + +#include "utils.h" + + +time_t parse_creationdate(char *str) { + // TODO + return 1234; +} + +time_t parse_lastmodified(char *str) { + // TODO + return 1234; +} + + +char* util_url_path(char *url) { + char *path = NULL; + int slashcount = 0; + char c; + int i = 0; + while((c = url[i]) != 0) { + if(c == '/') { + slashcount++; + if(slashcount == 3) { + path = url + i; + break; + } + } + i++; + } + return path; +} + +char* util_resource_name(char *url) { + int si = 0; + int osi = 0; + int i = 0; + char c; + while((c = url[i]) != 0) { + if(c == '/') { + osi = si; + si = i; + } + i++; + } + + char *name = url + si + 1;; + if(name[0] == 0) { + name = url + osi + 1; + if(name[0 == 0]) { + return url; + } + } + + return name; +} + +char* util_child_url(char *base, char *path) { + char *basepath = util_url_path(base); + int baselen = basepath - base; + int pathlen = strlen(path); + + int len = baselen + pathlen + 1; + char *url = malloc(len); + url[len - 1] = 0; + url[len - 2] = 0; + + if(url == NULL) { + return NULL; + } + + memcpy(url, base, baselen); + memcpy(url + baselen, path, pathlen); + + return url; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/dav/utils.h Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,53 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2012 Olaf Wintermann. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef UTILS_H +#define UTILS_H + +#include <sys/types.h> + +#ifdef __cplusplus +extern "C" { +#endif + +time_t parse_creationdate(char *str); +time_t parse_lastmodified(char *str); + +char* util_url_path(char *url); + +char* util_resource_name(char *url); + +char* util_child_url(char *url, char *href); + + +#ifdef __cplusplus +} +#endif + +#endif /* UTILS_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gcc.mk Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,44 @@ +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. +# +# Copyright 2011 Olaf Wintermann. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +CC = gcc +LD = gcc +AR = ar +RM = rm + +CFLAGS = -std=gnu99 -g -c +COFLAGS = -o +LDFLAGS = +LOFLAGS = -o +ARFLAGS = -r +RMFLAGS = -f + +OBJ_EXT = o +LIB_EXT = a +APP_EXT = +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/osx.mk Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,44 @@ +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. +# +# Copyright 2011 Olaf Wintermann. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +CC = gcc +LD = gcc +AR = ar +RM = rm + +CFLAGS = -std=gnu99 -g -c +COFLAGS = -o +LDFLAGS = +LOFLAGS = -o +ARFLAGS = -r +RMFLAGS = -f + +OBJ_EXT = o +LIB_EXT = a +APP_EXT = +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/suncc.mk Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,44 @@ +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. +# +# Copyright 2011 Olaf Wintermann. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +CC = cc +LD = cc +AR = ar +RM = rm + +CFLAGS = -g -c +COFLAGS = -o +LDFLAGS = +LOFLAGS = -o +ARFLAGS = -r +RMFLAGS = -f + +OBJ_EXT = o +LIB_EXT = a +APP_EXT = +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ucx/Makefile Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,53 @@ +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. +# +# Copyright 2011 Olaf Wintermann. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are met: +# +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +# AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE +# LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +# CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +# SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +# INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +# CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +# ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +# POSSIBILITY OF SUCH DAMAGE. +# + +include ../$(CONF).mk + +# list of source files +SRC = list.c +SRC += dlist.c +SRC += map.c +SRC += mempool.c +SRC += string.c +SRC += test.c +SRC += allocator.c +SRC += logging.c +SRC += buffer.c + +OBJ = $(SRC:%.c=../build/%.$(OBJ_EXT)) + +all: libucx + +libucx: $(OBJ) + $(AR) $(ARFLAGS) $(AOFLAGS)../build/libucx.$(LIB_EXT) $(OBJ) + +../build/%.$(OBJ_EXT): %.c ../build + $(CC) $(CFLAGS) $(COFLAGS)$@ $< + +../build: + mkdir -p ../build
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ucx/allocator.c Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,14 @@ +#include <stdlib.h> +#include "allocator.h" + +void *ucx_default_malloc(void *ignore, size_t n) { + return malloc(n); +} + +void *ucx_default_calloc(void *ignore, size_t n, size_t size) { + return calloc(n, size); +} + +void *ucx_default_realloc(void *ignore, void *data, size_t n) { + return realloc(data, n); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ucx/allocator.h Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,33 @@ +#ifndef ALLOCATOR_H +#define ALLOCATOR_H + +#include "ucx.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void*(*ucx_allocator_malloc)(void *pool, size_t n); +typedef void*(*ucx_allocator_calloc)(void *pool, size_t n, size_t size); +typedef void*(*ucx_allocator_realloc)(void *pool, void *data, size_t n); + +typedef struct { + void *pool; + ucx_allocator_malloc malloc; + ucx_allocator_calloc calloc; + ucx_allocator_realloc realloc; +} UcxAllocator; + +void *ucx_default_malloc(void *ignore, size_t n); +void *ucx_default_calloc(void *ignore, size_t n, size_t size); +void *ucx_default_realloc(void *ignore, void *data, size_t n); + +#define UCX_ALLOCATOR_DEFAULT {NULL, \ + ucx_default_malloc, ucx_default_calloc, ucx_default_realloc} + +#ifdef __cplusplus +} +#endif + +#endif /* ALLOCATOR_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ucx/buffer.c Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,204 @@ +#include "buffer.h" +#include <stdarg.h> +#include <stdlib.h> +#include <string.h> + +UcxBuffer *ucx_buffer_new(void *space, size_t size, int flags) { + UcxBuffer *buffer = (UcxBuffer*) malloc(sizeof(UcxBuffer)); + if (buffer) { + buffer->flags = flags; + if (!space) { + buffer->space = malloc(size); + if (!buffer->space) { + free(buffer); + return NULL; + } + memset(buffer->space, 0, size); + buffer->flags |= UCX_BUFFER_AUTOFREE; + } else { + buffer->space = space; + } + buffer->capacity = size; + buffer->size = 0; + + buffer->pos = 0; + } + + return buffer; +} + +void ucx_buffer_free(UcxBuffer *buffer) { + if ((buffer->flags & UCX_BUFFER_AUTOFREE) == UCX_BUFFER_AUTOFREE) { + free(buffer->space); + } + free(buffer); +} + +UcxBuffer* ucx_buffer_extract( + UcxBuffer *src, size_t start, size_t length, int flags) { + if(src->size == 0) { + return NULL; + } + if (length == 0) { + length = src->size - start; + } + if (start+length > src->size) { + return NULL; + } + + UcxBuffer *dst = (UcxBuffer*) malloc(sizeof(UcxBuffer)); + if (dst) { + dst->space = malloc(length); + if (!dst->space) { + free(dst); + return NULL; + } + dst->capacity = length; + dst->size = length; + dst->flags = flags | UCX_BUFFER_AUTOFREE; + dst->pos = 0; + memcpy(dst->space, src->space+start, length); + } + return dst; +} + +int ucx_buffer_seek(UcxBuffer *buffer, off_t offset, int whence) { + off_t npos; + switch (whence) { + case SEEK_SET: + npos = 0; + break; + case SEEK_CUR: + npos = buffer->pos; + break; + case SEEK_END: + npos = buffer->size; + break; + } + + npos += offset; + + if (npos < 0 || npos > buffer->size) { + return -1; + } else { + buffer->pos = npos; + return 0; + } + +} + +int ucx_buffer_eof(UcxBuffer *buffer) { + return buffer->pos >= buffer->size; +} + +int ucx_buffer_extend(UcxBuffer *buffer, size_t len) { + size_t newcap = buffer->capacity; + while (buffer->pos + len > newcap) newcap <<= 1; + + char *newspace = realloc(buffer->space, newcap); + if (newspace) { + memset(newspace+buffer->size, 0, newcap-buffer->size); + buffer->space = newspace; + buffer->capacity = newcap; + } else { + return -1; + } + + return 0; +} + +size_t ucx_buffer_write(const void *ptr, size_t size, size_t nitems, + UcxBuffer *buffer) { + size_t len = size * nitems; + if (buffer->pos + len > buffer->capacity) { + if ((buffer->flags & UCX_BUFFER_AUTOEXTEND) == UCX_BUFFER_AUTOEXTEND) { + if(ucx_buffer_extend(buffer, len)) { + return -1; + } + } else { + len = buffer->capacity - buffer->pos; + if (size > 1) len -= len%size; + } + } + + if (len <= 0) { + return len; + } + + memcpy(buffer->space + buffer->pos, ptr, len); + buffer->pos += len; + if(buffer->pos > buffer->size) { + buffer->size = buffer->pos; + } + + return len / size; +} + +size_t ucx_buffer_read(void *ptr, size_t size, size_t nitems, + UcxBuffer *buffer) { + size_t len = size * nitems; + if (buffer->pos + len > buffer->size) { + len = buffer->size - buffer->pos; + if (size > 1) len -= len%size; + } + + if (len <= 0) { + return len; + } + + memcpy(ptr, buffer->space + buffer->pos, len); + buffer->pos += len; + + return len / size; +} + +int ucx_buffer_putc(UcxBuffer *buffer, int c) { + if(buffer->pos >= buffer->capacity) { + if ((buffer->flags & UCX_BUFFER_AUTOEXTEND) == UCX_BUFFER_AUTOEXTEND) { + if(ucx_buffer_extend(buffer, 1)) { + return EOF; + } + } else { + return EOF; + } + } + + c &= 0xFF; + buffer->space[buffer->pos] = (char) c; + buffer->pos++; + if(buffer->pos > buffer->size) { + buffer->size = buffer->pos; + } + return c; +} + +int ucx_buffer_getc(UcxBuffer *buffer) { + if (ucx_buffer_eof(buffer)) { + return EOF; + } else { + int c = buffer->space[buffer->pos]; + buffer->pos++; + return c; + } +} + +size_t ucx_buffer_generic_copy(void *s1, void *s2, + read_func readfnc, write_func writefnc, size_t bufsize) { + size_t ncp = 0; + char *buf = malloc(bufsize); + if(buf == NULL) { + return 0; + } + + size_t r; + while((r = readfnc(buf, 1, bufsize, s1)) != 0) { + r = writefnc(buf, 1, r, s2); + ncp += r; + if(r == 0) { + break; + } + } + + free(buf); + return ncp; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ucx/buffer.h Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,100 @@ +#ifndef BUFFER_H +#define BUFFER_H + +#include "ucx.h" +#include <sys/types.h> +#include <stdio.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define UCX_BUFFER_DEFAULT 0x00 +#define UCX_BUFFER_AUTOFREE 0x01 +/* the buffer may automatically double its size on write operations */ +#define UCX_BUFFER_AUTOEXTEND 0x02 + +/* the user shall not modify values, but may get the latest pointer */ +typedef struct { + char *space; + size_t pos; + size_t capacity; + size_t size; + int flags; +} UcxBuffer; + +/* if space is NULL, new space is allocated and the autofree flag is enforced */ +UcxBuffer *ucx_buffer_new(void *space, size_t size, int flags); +void ucx_buffer_free(UcxBuffer* buffer); + +/* + * the autofree flag is enforced for the new buffer + * if length is zero, the whole remaining buffer shall be extracted + * the position of the new buffer is set to zero + */ +UcxBuffer* ucx_buffer_extract(UcxBuffer *src, + size_t start, size_t length, int flags); +#define ucx_buffer_clone(src,flags) \ + ucx_buffer_extract(src, 0, 0, flags) + +/* + * Moves the position of the buffer to a new position relative to whence. + * + * SEEK_SET marks the start of the buffer + * SEEK_CUR marks the current position + * SEEK_END marks the first 0-byte in the buffer + * + * ucx_memseek returns 0 on success and -1 if the new position is beyond the + * bounds of the allocated buffer. In that case the position of the buffer + * remains unchanged. + * + */ +int ucx_buffer_seek(UcxBuffer *buffer, off_t offset, int whence); + +/* + * returns non-zero, if the current buffer position has exceeded the last + * available byte of the underlying buffer + * + */ +int ucx_buffer_eof(UcxBuffer *buffer); + + +int ucx_buffere_extend(UcxBuffer *buffer, size_t len); + +size_t ucx_buffer_write(const void *ptr, size_t size, size_t nitems, + UcxBuffer *buffer); + +size_t ucx_buffer_read(void *ptr, size_t size, size_t nitems, + UcxBuffer *buffer); + +/* when autoextend is enabled, ensure you get the latest pointer to the data */ +//define ucx_buffer_write(data, itemsize, nitems, buffer) \ +// ucx_bufio(data, itemsize, nitems, buffer, 0) +//define ucx_buffer_read(data, itemsize, nitems, buffer) \ +// ucx_bufio(data, itemsize, nitems, buffer, 1) +int ucx_buffer_putc(UcxBuffer *b, int c); +int ucx_buffer_getc(UcxBuffer *b); + + +/* + * copies all bytes from s1 to s2 + * uses the read function r to read from s1 und writes the data using the + * write function w to s2 + * returns the number of bytes copied + */ +size_t ucx_buffer_generic_copy(void *s1, void *s2, read_func r, write_func w, + size_t bufsize); + + +#define UCX_DEFAULT_BUFFER_SIZE 0x4000000 + +#define ucx_buffer_copy(s1,s2,r,w) \ + ucx_buffer_generic_copy(s1, s2, (read_func)r, (write_func)w, \ + UCX_DEFAULT_BUFFER_SIZE) + +#ifdef __cplusplus +} +#endif + +#endif /* BUFFER_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ucx/dlist.c Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,234 @@ +#include "dlist.h" + +UcxDlist *restrict ucx_dlist_clone(UcxDlist *restrict l, + copy_func fnc, void *data) { + UcxDlist *ret = NULL; + while (l != NULL) { + if (fnc != NULL) { + ret = ucx_dlist_append(ret, fnc(l->data, data)); + } else { + ret = ucx_dlist_append(ret, l->data); + } + l = l->next; + } + return ret; +} + +int ucx_dlist_equals(const UcxDlist *l1, const UcxDlist *l2, + cmp_func fnc, void* data) { + if (l1 == l2) return 1; + + while (l1 != NULL && l2 != NULL) { + if (fnc == NULL) { + if (l1->data != l2->data) return 0; + } else { + if (fnc(l1->data, l2->data, data) != 0) return 0; + } + l1 = l1->next; + l2 = l2->next; + } + + return (l1 == NULL && l2 == NULL); +} + +void ucx_dlist_free(UcxDlist *l) { + UcxDlist *e = l, *f; + while (e != NULL) { + f = e; + e = e->next; + free(f); + } +} + +UcxDlist *ucx_dlist_append(UcxDlist *l, void *data) { + UcxDlist *nl = (UcxDlist*) malloc(sizeof(UcxDlist)); + if (nl == NULL) return NULL; + + nl->data = data; + nl->next = NULL; + if (l == NULL) { + nl->prev = NULL; + return nl; + } else { + UcxDlist *t = ucx_dlist_last(l); + t->next = nl; + nl->prev = t; + return l; + } +} + +UcxDlist *ucx_dlist_prepend(UcxDlist *l, void *data) { + UcxDlist *nl = ucx_dlist_append(NULL, data); + if (nl == NULL) return NULL; + + if (l != NULL) { + nl->next = l; + l->prev = nl; + } + return nl; +} + +UcxDlist *ucx_dlist_concat(UcxDlist *restrict l1, UcxDlist *restrict l2) { + if (l1 == NULL) { + return l2; + } else { + UcxDlist *last = ucx_dlist_last(l1); + last->next = l2; + l2->prev = last; + return l1; + } +} + +UcxDlist *ucx_dlist_last(const UcxDlist *l) { + if (l == NULL) return NULL; + + const UcxDlist *e = l; + while (e->next != NULL) { + e = e->next; + } + return (UcxDlist*)e; +} + +UcxDlist *ucx_dlist_get(const UcxDlist *l, int index) { + if (l == NULL) return NULL; + + const UcxDlist *e = l; + while (e->next != NULL && index > 0) { + e = e->next; + index--; + } + + return (UcxDlist*)(index == 0 ? e : NULL); +} + +size_t ucx_dlist_size(const UcxDlist *l) { + if (l == NULL) return 0; + + const UcxDlist *e = l; + size_t s = 1; + while (e->next != NULL) { + e = e->next; + s++; + } + + return s; +} + +UcxDlist *ucx_dlist_sort_merge(int length, + UcxDlist* restrict ls, UcxDlist* restrict le, UcxDlist* restrict re, + cmp_func fnc, void* data) { + + UcxDlist** sorted = (UcxDlist**) malloc(sizeof(UcxDlist*)*length); + UcxDlist *rc, *lc; + + lc = ls; rc = le; + int n = 0; + while (lc && lc != le && rc != re) { + if (fnc(lc->data, rc->data, data) <= 0) { + sorted[n] = lc; + lc = lc->next; + } else { + sorted[n] = rc; + rc = rc->next; + } + n++; + } + while (lc && lc != le) { + sorted[n] = lc; + lc = lc->next; + n++; + } + while (rc && rc != re) { + sorted[n] = rc; + rc = rc->next; + n++; + } + + // Update pointer + sorted[0]->prev = NULL; + for (int i = 0 ; i < length-1 ; i++) { + sorted[i]->next = sorted[i+1]; + sorted[i+1]->prev = sorted[i]; + } + sorted[length-1]->next = NULL; + + UcxDlist *ret = sorted[0]; + free(sorted); + return ret; +} + +UcxDlist *ucx_dlist_sort(UcxDlist *l, cmp_func fnc, void *data) { + if (l == NULL) { + return NULL; + } + + UcxDlist *lc; + int ln = 1; + + UcxDlist *restrict ls = l, *restrict le, *restrict re; + lc = ls; + while (lc->next != NULL && fnc(lc->next->data, lc->data, data) > 0) { + lc = lc->next; + ln++; + } + le = lc->next; + + if (le == NULL) { + return l; // this list is already sorted :) + } else { + UcxDlist *rc; + int rn = 1; + rc = le; + while (rc->next != NULL && fnc(rc->next->data, rc->data, data) > 0) { + rc = rc->next; + rn++; + } + re = rc->next; + + // Something left? Sort it! + UcxDlist *remainder = re; + size_t remainder_length = ucx_dlist_size(remainder); + if (remainder != NULL) { + remainder = ucx_dlist_sort(remainder, fnc, data); + } + + // {ls,...,le->prev} and {rs,...,re->prev} are sorted - merge them + UcxDlist *sorted = ucx_dlist_sort_merge(ln+rn, + ls, le, re, + fnc, data); + + // merge sorted list with (also sorted) remainder + l = ucx_dlist_sort_merge(ln+rn+remainder_length, + sorted, remainder, NULL, fnc, data); + + return l; + } +} + +/* dlist specific functions */ +UcxDlist *ucx_dlist_first(const UcxDlist *l) { + if (l == NULL) return NULL; + + const UcxDlist *e = l; + while (e->prev != NULL) { + e = e->prev; + } + return (UcxDlist *)e; +} + +UcxDlist *ucx_dlist_remove(UcxDlist *l, UcxDlist *e) { + if (e->prev == NULL) { + if(e->next != NULL) { + e->next->prev = NULL; + l = e->next; + } else { + l = NULL; + } + + } else { + e->prev->next = e->next; + e->next->prev = e->prev; + } + free(e); + return l; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ucx/dlist.h Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,46 @@ +/* + * + */ + +#ifndef DLIST_H +#define DLIST_H + +#include "ucx.h" +#include <stddef.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct UcxDlist UcxDlist; +struct UcxDlist { + void *data; + UcxDlist *restrict next; + UcxDlist *restrict prev; +}; + +UcxDlist *restrict ucx_dlist_clone(UcxDlist *restrict l, + copy_func fnc, void* data); +int ucx_dlist_equals(const UcxDlist *l1, const UcxDlist *l2, + cmp_func fnc, void* data); + +void ucx_dlist_free(UcxDlist *l); +UcxDlist *ucx_dlist_append(UcxDlist *l, void *data); +UcxDlist *ucx_dlist_prepend(UcxDlist *l, void *data); +UcxDlist *ucx_dlist_concat(UcxDlist *restrict l1, UcxDlist *restrict l2); +UcxDlist *ucx_dlist_last(const UcxDlist *l); +UcxDlist *ucx_dlist_get(const UcxDlist *l, int index); +size_t ucx_dlist_size(const UcxDlist *l); + +UcxDlist *ucx_dlist_sort(UcxDlist *l, cmp_func fnc, void *data); + +/* dlist specific functions */ +UcxDlist *ucx_dlist_first(const UcxDlist *l); +UcxDlist *ucx_dlist_remove(UcxDlist *l, UcxDlist *e); + +#ifdef __cplusplus +} +#endif + +#endif /* DLIST_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ucx/list.c Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,219 @@ +#include "list.h" + +UcxList *restrict ucx_list_clone(UcxList *restrict l, + copy_func fnc, void *data) { + UcxList *ret = NULL; + while (l != NULL) { + if (fnc != NULL) { + ret = ucx_list_append(ret, fnc(l->data, data)); + } else { + ret = ucx_list_append(ret, l->data); + } + l = l->next; + } + return ret; +} + +int ucx_list_equals(const UcxList *l1, const UcxList *l2, + cmp_func fnc, void* data) { + if (l1 == l2) return 1; + + while (l1 != NULL && l2 != NULL) { + if (fnc == NULL) { + if (l1->data != l2->data) return 0; + } else { + if (fnc(l1->data, l2->data, data) != 0) return 0; + } + l1 = l1->next; + l2 = l2->next; + } + + return (l1 == NULL && l2 == NULL); +} + +void ucx_list_free(UcxList *l) { + UcxList *e = l, *f; + while (e != NULL) { + f = e; + e = e->next; + free(f); + } +} + +UcxList *ucx_list_append(UcxList *l, void *data) { + UcxList *nl = (UcxList*) malloc(sizeof(UcxList)); + if (nl == NULL) return NULL; + + nl->data = data; + nl->next = NULL; + if (l == NULL) { + return nl; + } else { + UcxList *t = ucx_list_last(l); + t->next = nl; + return l; + } +} + +UcxList *ucx_list_prepend(UcxList *l, void *data) { + UcxList *nl = ucx_list_append(NULL, data); + if (nl == NULL) return NULL; + + if (l != NULL) { + nl->next = l; + } + return nl; +} + +UcxList *ucx_list_concat(UcxList *restrict l1, UcxList *restrict l2) { + if (l1 == NULL) { + return l2; + } else { + UcxList *last = ucx_list_last(l1); + last->next = l2; + return l1; + } +} + +UcxList *ucx_list_last(const UcxList *l) { + if (l == NULL) return NULL; + + const UcxList *e = l; + while (e->next != NULL) { + e = e->next; + } + return (UcxList*)e; +} + +UcxList *ucx_list_get(const UcxList *l, int index) { + if (l == NULL) return NULL; + + const UcxList *e = l; + while (e->next != NULL && index > 0) { + e = e->next; + index--; + } + + return (UcxList*)(index == 0 ? e : NULL); +} + +size_t ucx_list_size(const UcxList *l) { + if (l == NULL) return 0; + + const UcxList *e = l; + size_t s = 1; + while (e->next != NULL) { + e = e->next; + s++; + } + + return s; +} + +UcxList *ucx_list_sort_merge(int length, + UcxList* restrict ls, UcxList* restrict le, UcxList* restrict re, + cmp_func fnc, void* data) { + + UcxList** sorted = (UcxList**) malloc(sizeof(UcxList*)*length); + UcxList *rc, *lc; + + lc = ls; rc = le; + int n = 0; + while (lc && lc != le && rc != re) { + if (fnc(lc->data, rc->data, data) <= 0) { + sorted[n] = lc; + lc = lc->next; + } else { + sorted[n] = rc; + rc = rc->next; + } + n++; + } + while (lc && lc != le) { + sorted[n] = lc; + lc = lc->next; + n++; + } + while (rc && rc != re) { + sorted[n] = rc; + rc = rc->next; + n++; + } + + // Update pointer + for (int i = 0 ; i < length-1 ; i++) { + sorted[i]->next = sorted[i+1]; + } + sorted[length-1]->next = NULL; + + UcxList *ret = sorted[0]; + free(sorted); + return ret; +} + +UcxList *ucx_list_sort(UcxList *l, cmp_func fnc, void *data) { + if (l == NULL) { + return NULL; + } + + UcxList *lc; + int ln = 1; + + UcxList *restrict ls = l, *restrict le, *restrict re; + lc = ls; + while (lc->next != NULL && fnc(lc->next->data, lc->data, data) > 0) { + lc = lc->next; + ln++; + } + le = lc->next; + + if (le == NULL) { + return l; // this list is already sorted :) + } else { + UcxList *rc; + int rn = 1; + rc = le; + while (rc->next != NULL && fnc(rc->next->data, rc->data, data) > 0) { + rc = rc->next; + rn++; + } + re = rc->next; + + // Something left? Sort it! + UcxList *remainder = re; + size_t remainder_length = ucx_list_size(remainder); + if (remainder != NULL) { + remainder = ucx_list_sort(remainder, fnc, data); + } + + // {ls,...,le->prev} and {rs,...,re->prev} are sorted - merge them + UcxList *sorted = ucx_list_sort_merge(ln+rn, + ls, le, re, + fnc, data); + + // merge sorted list with (also sorted) remainder + l = ucx_list_sort_merge(ln+rn+remainder_length, + sorted, remainder, NULL, fnc, data); + + return l; + } +} + +/* list specific functions */ +UcxList *ucx_list_remove(UcxList *l, UcxList *e) { + if (e == l) { + l = e->next; + free(e); + } else { + UcxList *f = l; + while (f->next != NULL && f->next != e) { + f = f->next; + } + /* perform remove if this element is found in this list */ + if (f->next == e) { + f->next = e->next; + free(e); + } + } + return l; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ucx/list.h Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,44 @@ +/* + * + */ + +#ifndef LIST_H +#define LIST_H + +#include "ucx.h" +#include <stddef.h> + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct UcxList UcxList; +struct UcxList { + void *data; + UcxList *next; +}; + +UcxList *restrict ucx_list_clone(UcxList *restrict l, + copy_func fnc, void *data); +int ucx_list_equals(const UcxList *l1, const UcxList *l2, + cmp_func fnc, void *data); + +void ucx_list_free(UcxList *l); +UcxList *ucx_list_append(UcxList *l, void *data); +UcxList *ucx_list_prepend(UcxList *l, void *data); +UcxList *ucx_list_concat(UcxList *restrict l1, UcxList *restrict l2); +UcxList *ucx_list_last(const UcxList *l); +UcxList *ucx_list_get(const UcxList *l, int index); +size_t ucx_list_size(const UcxList *l); + +UcxList *ucx_list_sort(UcxList *l, cmp_func fnc, void *data); + +/* list specific functions */ +UcxList *ucx_list_remove(UcxList *l, UcxList *e); + +#ifdef __cplusplus +} +#endif + +#endif /* LIST_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ucx/logging.c Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,20 @@ +#include "logging.h" +#include <stdlib.h> + +UcxLogger *ucx_logger_new(FILE *stream, unsigned int level) { + UcxLogger *logger = (UcxLogger*) malloc(sizeof(UcxLogger)); + if (logger != NULL) { + logger->stream = stream; + logger->level = level; + } + + return logger; +} + +void ucx_logger_log(UcxLogger *logger, unsigned int level, + const sstr_t message) { + if (level <= logger->level) { + fwrite(message.ptr, 1, message.length, logger->stream); + fflush(logger->stream); + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ucx/logging.h Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,37 @@ +#ifndef LOGGING_H +#define LOGGING_H + +#include "ucx.h" +#include "string.h" +#include <stdio.h> + +#ifdef __cplusplus +extern "C" { +#endif + +/* leave enough space for custom log levels */ +#define UCX_LOGGER_ERROR 0x00 +#define UCX_LOGGER_WARN 0x10 +#define UCX_LOGGER_INFO 0x20 +#define UCX_LOGGER_TRACE 0x30 + +typedef struct { + FILE *stream; + unsigned int level; +} UcxLogger; + +UcxLogger *ucx_logger_new(FILE *stream, unsigned int level); +/* neither provide a free function nor a parameter for an allocator */ + +void ucx_logger_log(UcxLogger *logger, unsigned int level, + const sstr_t message); +#define ucx_logger_error(l,m) ucx_logger_log(l, UCX_LOGGER_ERROR, m) +#define ucx_logger_info(l,m) ucx_logger_log(l, UCX_LOGGER_INFO, m) +#define ucx_logger_warn(l,m) ucx_logger_log(l, UCX_LOGGER_WARN, m) +#define ucx_logger_trace(l,m) ucx_logger_log(l, UCX_LOGGER_TRACE, m) + +#ifdef __cplusplus +} +#endif + +#endif /* LOGGING_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ucx/map.c Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,390 @@ +/* + * + */ + +#include <stdlib.h> +#include <string.h> + +#include "map.h" + +UcxMap *ucx_map_new(size_t size) { + if(size == 0) { + size = 16; + } + + UcxMap *map = (UcxMap*)malloc(sizeof(UcxMap)); + if(map == NULL) { + return NULL; + } + + map->map = (UcxMapElement**)calloc(size, sizeof(UcxMapElement*)); + if(map->map == NULL) { + free(map); + return NULL; + } + map->size = size; + map->count = 0; + + return map; +} + +void ucx_map_free_elmlist(UcxMap *map) { + for (size_t n = 0 ; n < map->size ; n++) { + UcxMapElement *elem = map->map[n]; + if (elem != NULL) { + do { + UcxMapElement *next = elem->next; + free(elem->key.data); + free(elem); + elem = next; + } while (elem != NULL); + } + } + free(map->map); +} + +void ucx_map_free(UcxMap *map) { + ucx_map_free_elmlist(map); + free(map); +} + +int ucx_map_copy(UcxMap *restrict from, UcxMap *restrict to, + copy_func fnc, void *data) { + UcxMapIterator i = ucx_map_iterator(from); + void *value; + UCX_MAP_FOREACH(value, i) { + int ret = ucx_map_put(to, i.cur->key, fnc ? fnc(value, data) : value); + if(ret != 0) { + return 1; + } + } + return 0; +} + +UcxMap *ucx_map_clone(UcxMap *map, copy_func fnc, void *data) { + size_t bs = (map->count * 5) >> 1; + UcxMap *newmap = ucx_map_new(bs > map->size ? bs : map->size); + if(newmap == NULL) { + return NULL; + } + ucx_map_copy(map, newmap, fnc, data); + return newmap; +} + +int ucx_map_rehash(UcxMap *map) { + size_t load = (map->size * 3) >> 2; + if (map->count > load) { + UcxMap oldmap; + oldmap.map = map->map; + oldmap.size = map->size; + oldmap.count = map->count; + + map->size = (map->count * 5) >> 1; + map->map = (UcxMapElement**)calloc(map->size, sizeof(UcxMapElement*)); + if(map->map == NULL) { + *map = oldmap; + return 1; + } + map->count = 0; + ucx_map_copy(&oldmap, map, NULL, NULL); + + /* free the UcxMapElement list of oldmap */ + ucx_map_free_elmlist(&oldmap); + } + return 0; +} + +int ucx_map_put(UcxMap *map, UcxKey key, void *data) { + if(key.hash == 0) { + key.hash = ucx_hash((char*)key.data, key.len); + } + + size_t slot = key.hash%map->size; + UcxMapElement *restrict elm = map->map[slot]; + UcxMapElement *restrict prev = NULL; + + while (elm != NULL && elm->key.hash < key.hash) { + prev = elm; + elm = elm->next; + } + + if (elm == NULL || elm->key.hash != key.hash) { + UcxMapElement *e = (UcxMapElement*)malloc(sizeof(UcxMapElement)); + if(e == NULL) { + return -1; + } + e->key.data = NULL; + if (prev) { + prev->next = e; + } else { + map->map[slot] = e; + } + e->next = elm; + elm = e; + } + + if(elm->key.data == NULL) { + void *kd = malloc(key.len); + if (kd == NULL) { + return -1; + } + memcpy(kd, key.data, key.len); + key.data = kd; + elm->key = key; + map->count++; + } + elm->data = data; + + return 0; +} + +void* ucx_map_get_and_remove(UcxMap *map, UcxKey key, _Bool remove) { + if(key.hash == 0) { + key.hash = ucx_hash((char*)key.data, key.len); + } + + size_t slot = key.hash%map->size; + UcxMapElement *restrict elm = map->map[slot]; + UcxMapElement *restrict pelm = NULL; + while (elm && elm->key.hash <= key.hash) { + if(elm->key.hash == key.hash) { + int n = (key.len > elm->key.len) ? elm->key.len : key.len; + if (memcmp(elm->key.data, key.data, n) == 0) { + void *data = elm->data; + if (remove) { + if (pelm) { + pelm->next = elm->next; + } else { + map->map[slot] = elm->next; + } + free(elm); + map->count--; + } + + return data; + } + } + pelm = elm; + elm = pelm->next; + } + + return NULL; +} + +void *ucx_map_get(UcxMap *map, UcxKey key) { + return ucx_map_get_and_remove(map, key, 0); +} + +void *ucx_map_remove(UcxMap *map, UcxKey key) { + return ucx_map_get_and_remove(map, key, 1); +} + +UcxKey ucx_key(void *data, size_t len) { + UcxKey key; + key.data = data; + key.len = len; + key.hash = ucx_hash((const char*) data, len); + return key; +} + + +int ucx_hash(const char *data, size_t len) { + /* murmur hash 2 */ + + int m = 0x5bd1e995; + int r = 24; + + int h = 25 ^ len; + + int i = 0; + while (len >= 4) { + int k = data[i + 0] & 0xFF; + k |= (data[i + 1] & 0xFF) << 8; + k |= (data[i + 2] & 0xFF) << 16; + k |= (data[i + 3] & 0xFF) << 24; + + k *= m; + k ^= k >> r; + k *= m; + + h *= m; + h ^= k; + + i += 4; + len -= 4; + } + + switch (len) { + case 3: h ^= (data[i + 2] & 0xFF) << 16; + /* no break */ + case 2: h ^= (data[i + 1] & 0xFF) << 8; + /* no break */ + case 1: h ^= (data[i + 0] & 0xFF); h *= m; + /* no break */ + } + + h ^= h >> 13; + h *= m; + h ^= h >> 15; + + return h; +} + +UcxMapIterator ucx_map_iterator(UcxMap *map) { + UcxMapIterator i; + i.map = map; + i.cur = NULL; + i.index = 0; + return i; +} + +int ucx_map_iter_next(UcxMapIterator *i, void **elm) { + UcxMapElement *e = i->cur; + + if(e == NULL) { + e = i->map->map[0]; + } else { + e = e->next; + } + + while(i->index < i->map->size) { + if(e != NULL) { + if(e->data != NULL) { + i->cur = e; + *elm = e->data; + return 0; + } + + e = e->next; + } else { + i->index++; + + if(i->index < i->map->size) { + e = i->map->map[i->index]; + } + } + } + + return 1; +} + +int ucx_map_load_enc(UcxMap *map, FILE *f, UcxAllocator allocator, + ucx_map_coder decoder, void* decdata) { + + int c; int r, n; + + char *key, *value; + + while ((c = fgetc(f)) > 0) { + /* Discard leading spaces and comments */ + if (c < 33) continue; + if (c == '#' || c == '!') { + while ((c = (char) fgetc(f)) > 0) { + if (c == '\n') break; + } + continue; + } + + /* read into key buffer */ + n = 16; + key = (char*) malloc(n); + r = 0; + do { + if (c == '=') break; + if (r > n - 2) { + n *= 2; + key = (char*) realloc(key, n); + } + key[r] = c; + r++; + } while ((c = fgetc(f)) > 0); + if (c <= 0) { + free(key); + return 1; + } + key[r] = 0; + while (key[--r] == ' ') key[r] = 0; + + /* skip whitespaces */ + while ((c = fgetc(f)) > 0) { + if (c > 32) break; + } + if (c <= 0) { + free(key); + return 1; + } + + /* read into value buffer */ + n = 64; + value = (char*) malloc(n); + r = 0; + do { + if (c == '\n') break; + if (r > n - 2) { + n *= 2; + value = (char*) realloc(value, n); + } + value[r] = c; + r++; + } while ((c = fgetc(f)) > 0); + value[r] = 0; + while (value[--r] < 33) value[r] = 0; + + if (decoder) { + size_t decodedSize; + void *decoded = decoder(value, decdata, &decodedSize); + free(value); + value = (char*) decoded; + r = decodedSize; + } else { + r += 2; + value = (char*) realloc(value, r); + } + + if (allocator.pool) { + void *pooledValue = allocator.malloc(allocator.pool, r); + memcpy(pooledValue, value, r); + free(value); + value = (char*) pooledValue; + } + + ucx_map_cstr_put(map, key, value); + free(key); + } + + return 0; +} + +int ucx_map_store_enc(UcxMap *map, FILE *f, + ucx_map_coder encoder, void *encdata) { + UcxMapIterator iter = ucx_map_iterator(map); + char *k, *v; + sstr_t key, value; + int written; + + UCX_MAP_FOREACH(v, iter) { + k = (char*) iter.cur->key.data; + key = sstr(k); + if (encoder) { + size_t encodedSize; + void *encoded = encoder(v, encdata, &encodedSize); + value = sstrn((char*) encoded,encodedSize - 1); + } else { + value = sstr(v); + } + + written = 0; + written += fwrite(key.ptr, 1, key.length, f); + written += fwrite(" = ", 1, 3, f); + written += fwrite(value.ptr, 1, value.length, f); + written += fwrite("\n", 1, 1, f); + + if (encoder) { + free(value.ptr); + } + + if (written != key.length + value.length + 4) return 1; + } + + return 0; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ucx/map.h Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,106 @@ +/* + * + */ + +#ifndef MAP_H +#define MAP_H + +#include "ucx.h" +#include "string.h" +#include "mempool.h" +#include <stdio.h> + +#ifdef __cplusplus +extern "C" { +#endif + +#define UCX_MAP_FOREACH(elm,iter) \ + for(;ucx_map_iter_next(&iter,(void**)&elm)==0;) + +typedef struct UcxMap UcxMap; +typedef struct UcxKey UcxKey; +typedef struct UcxMapElement UcxMapElement; +typedef struct UcxMapIterator UcxMapIterator; + +/* + * param 1: element + * param 2: additional data + * param 3: size of encoded data will be stored here + * returns encoded / decoded string or NULL on failure + */ +typedef void*(*ucx_map_coder)(void*,void*,size_t*); + +struct UcxMap { + UcxMapElement **map; + size_t size; + size_t count; +}; + +struct UcxKey { + void *data; + size_t len; + int hash; +}; + +struct UcxMapElement { + void *data; + UcxMapElement *next; + UcxKey key; +}; + +struct UcxMapIterator { + UcxMap *map; + UcxMapElement *cur; + int index; +}; + + +UcxMap *ucx_map_new(size_t size); +void ucx_map_free(UcxMap *map); +/* you cannot clone maps with more than 390 mio entries */ +int ucx_map_copy(UcxMap *restrict from, UcxMap *restrict to, + copy_func fnc, void *data); +UcxMap *ucx_map_clone(UcxMap *map, copy_func fnc, void *data); +int ucx_map_rehash(UcxMap *map); + +int ucx_map_put(UcxMap *map, UcxKey key, void *data); +void* ucx_map_get(UcxMap *map, UcxKey key); +void* ucx_map_remove(UcxMap *map, UcxKey key); + +#define ucx_map_sstr_put(m, s, d) \ + ucx_map_put(m, ucx_key((void*)s.ptr, s.length), d) +#define ucx_map_cstr_put(m, s, d) \ + ucx_map_put(m, ucx_key((void*)s, 1+strlen(s)), d) +#define ucx_map_sstr_get(m, s) \ + ucx_map_get(m, ucx_key((void*)s.ptr, s.length)) +#define ucx_map_cstr_get(m, s) \ + ucx_map_get(m, ucx_key((void*)s, 1+strlen(s))) +#define ucx_map_sstr_remove(m, s) \ + ucx_map_remove(m, ucx_key((void*)s.ptr, s.length)) +#define ucx_map_cstr_remove(m, s) \ + ucx_map_remove(m, ucx_key((void*)s, 1+strlen(s))) + +UcxKey ucx_key(void *data, size_t len); + +int ucx_hash(const char *data, size_t len); + +UcxMapIterator ucx_map_iterator(UcxMap *map); + +int ucx_map_iter_next(UcxMapIterator *i, void **elm); + +/* use macros for string maps only, values are not encoded */ +#define ucx_map_load(map, f, alloc) ucx_map_load_enc(map, f, alloc, NULL, NULL) +#define ucx_map_store(map, f) ucx_map_store_enc(map, f, NULL, NULL) + +int ucx_map_load_enc(UcxMap *map, FILE *f, UcxAllocator allocator, + ucx_map_coder decoder, void* decdata); +/* encoders shall provide null terminated strings*/ +int ucx_map_store_enc(UcxMap *map, FILE *f, + ucx_map_coder encoder, void* encdata); + +#ifdef __cplusplus +} +#endif + +#endif /* MAP_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ucx/mempool.c Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,120 @@ +/* + * + */ + +#include <stdlib.h> +#include <string.h> +#include <stdio.h> +#include <inttypes.h> + +#include "mempool.h" + +typedef struct { + ucx_destructor destructor; + char c; +} ucx_memchunk; + +typedef struct { + ucx_destructor destructor; + void *ptr; +} ucx_regdestr; + +void ucx_mempool_shared_destr(void* ptr) { + ucx_regdestr *rd = (ucx_regdestr*)ptr; + rd->destructor(rd->ptr); +} + +UcxMempool *ucx_mempool_new(size_t n) { + UcxMempool *pool = (UcxMempool*)malloc(sizeof(UcxMempool)); + if (pool == NULL) return NULL; + + pool->data = (void**) malloc(n * sizeof(void*)); + if (pool->data == NULL) { + free(pool); + return NULL; + } + + pool->ndata = 0; + pool->size = n; + return pool; +} + +int ucx_mempool_chcap(UcxMempool *pool, size_t newcap) { + void **data = (void**) realloc(pool->data, newcap*sizeof(void*)); + if (data == NULL) { + return 1; + } else { + pool->data = data; + pool->size = newcap; + return EXIT_SUCCESS; + } +} + +void *ucx_mempool_malloc(UcxMempool *pool, size_t n) { + ucx_memchunk *mem = (ucx_memchunk*)malloc(sizeof(ucx_destructor) + n); + if (mem == NULL) return NULL; + + if (pool->ndata >= pool->size) { + ucx_mempool_chcap(pool, pool->size + 16); + } + + mem->destructor = NULL; + pool->data[pool->ndata] = mem; + pool->ndata++; + + return &mem->c; +} + +void *ucx_mempool_calloc(UcxMempool *pool, size_t nelem, size_t elsize) { + void *ptr = ucx_mempool_malloc(pool, nelem*elsize); + if(ptr == NULL) { + return NULL; + } + memset(ptr, 0, nelem * elsize); + return ptr; +} + +void *ucx_mempool_realloc(UcxMempool *pool, void *ptr, size_t n) { + char *mem = ((char*)ptr) - sizeof(ucx_destructor); + char *newm = (char*) realloc(mem, n + sizeof(ucx_destructor)); + if (newm == NULL) return NULL; + if (mem != newm) { + for(int i=0;i<pool->ndata;i++) { + if(pool->data[i] == mem) { + pool->data[i] = newm; + return newm + sizeof(ucx_destructor); + } + } + fprintf(stderr, "FATAL: 0x%08"PRIxPTR" not in mpool 0x%08"PRIxPTR"\n", + (intptr_t)ptr, (intptr_t)pool); + exit(1); + } else { + return newm + sizeof(ucx_destructor); + } +} + +void ucx_mempool_free(UcxMempool *pool) { + ucx_memchunk *chunk; + for(int i=0;i<pool->ndata;i++) { + chunk = (ucx_memchunk*) pool->data[i]; + if(chunk->destructor != NULL) { + chunk->destructor(&chunk->c); + } + free(chunk); + } + free(pool->data); + free(pool); +} + +void ucx_mempool_set_destr(void *ptr, ucx_destructor func) { + *(ucx_destructor*)((char*)ptr-sizeof(ucx_destructor)) = func; +} + +void ucx_mempool_reg_destr(UcxMempool *pool, void *ptr, ucx_destructor destr) { + ucx_regdestr *rd = (ucx_regdestr*)ucx_mempool_malloc( + pool, + sizeof(ucx_regdestr)); + rd->destructor = destr; + rd->ptr = ptr; + ucx_mempool_set_destr(rd, ucx_mempool_shared_destr); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ucx/mempool.h Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,48 @@ +/* + * + */ + +#ifndef MPOOL_H +#define MPOOL_H + +#include "ucx.h" +#include <stddef.h> +#include "allocator.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef void(*ucx_destructor)(void*); + +typedef struct { + void **data; + size_t ndata; + size_t size; +} UcxMempool; + +#define UCX_ALLOCATOR_MEMPOOL(pool) {pool, \ + (ucx_allocator_malloc) ucx_mempool_malloc, \ + (ucx_allocator_calloc) ucx_mempool_calloc, \ + (ucx_allocator_realloc) ucx_mempool_realloc} + +#define ucx_mempool_new_default() ucx_mempool_new(16) +UcxMempool *ucx_mempool_new(size_t n); +int ucx_mempool_chcap(UcxMempool *pool, size_t newcap); + +void *ucx_mempool_malloc(UcxMempool *pool, size_t n); +void *ucx_mempool_calloc(UcxMempool *pool, size_t nelem, size_t elsize); +void *ucx_mempool_realloc(UcxMempool *pool, void *ptr, size_t n); + +void ucx_mempool_free(UcxMempool *pool); + +void ucx_mempool_set_destr(void *ptr, ucx_destructor func); +void ucx_mempool_reg_destr(UcxMempool *pool, void *ptr, ucx_destructor destr); + + +#ifdef __cplusplus +} +#endif + +#endif /* MPOOL_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ucx/string.c Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,172 @@ +/* + * File: sstring.c + * Author: olaf + * + * Created on 17. Juni 2010, 13:27 + */ + +#include <stdlib.h> +#include <string.h> +#include <stdarg.h> + +#include "string.h" + +sstr_t sstr(char *s) { + sstr_t string; + string.ptr = s; + string.length = strlen(s); + return string; +} + +sstr_t sstrn(char *s, size_t n) { + sstr_t string; + string.ptr = s; + string.length = n; + return string; +} + +size_t sstrnlen(size_t n, sstr_t s, ...) { + va_list ap; + size_t size = s.length; + va_start(ap, s); + + for (int i=0;i<n-1;i++) { + sstr_t str = va_arg(ap, sstr_t); + size += str.length; + } + va_end(ap); + + return size; +} + +sstr_t sstrcat(sstr_t s, ...) { + va_list ap; + va_start(ap, s); + s.ptr[0] = 0; + + sstr_t str = va_arg (ap, sstr_t); + while (str.ptr != NULL) { + s.ptr = strncat (s.ptr, str.ptr, s.length); + str = va_arg (ap, sstr_t); + } + va_end(ap); + + return s; +} + +sstr_t sstrncat(size_t n, sstr_t s, sstr_t c1, ...) { + va_list ap; + va_start(ap, c1); + s.ptr[0] = 0; + + size_t len = s.length; + size_t cplen = c1.length > len ? len : c1.length; + char *ptr = s.ptr; + + memcpy(ptr, c1.ptr, cplen); + len -= cplen; + ptr += cplen; + for (int i=0;i<n-1;i++) { + sstr_t str = va_arg (ap, sstr_t); + cplen = str.length > len ? len : str.length; + if(cplen <= 0) { + va_end(ap); + return s; + } + memcpy(ptr, str.ptr, cplen); + len -= cplen; + ptr += cplen; + } + va_end(ap); + + return s; +} + +sstr_t sstrsubs(sstr_t s, size_t start) { + return sstrsubsl (s, start, s.length-start); +} + +sstr_t sstrsubsl(sstr_t s, size_t start, size_t length) { + sstr_t new_sstr; + if (start < 0 || start >= s.length || length < 0) { + return s; + } + if (length > s.length-start) { + length = s.length-start; + } + new_sstr.ptr = &s.ptr[start]; + new_sstr.length = length; + return new_sstr; +} + +sstr_t* sstrsplit(sstr_t s, sstr_t d, size_t *n) { + if (d.length == 0) { + return NULL; + } + + sstr_t* result; + size_t nmax = *n; + *n = 1; + + /* special case: exact match - no processing needed */ + if (s.length == d.length && strncmp(s.ptr, d.ptr, s.length) == 0) { + *n = 0; + return NULL; + } + sstr_t sv = sstrdup(s); + + for (int i = 0 ; i < s.length ; i++) { + if (sv.ptr[i] == d.ptr[0]) { + _Bool match = 1; + for (int j = 1 ; j < d.length ; j++) { + if (j+i < s.length) { + match &= (sv.ptr[i+j] == d.ptr[j]); + } else { + match = 0; + break; + } + } + if (match) { + (*n)++; + for (int j = 0 ; j < d.length ; j++) { + sv.ptr[i+j] = 0; + } + i += d.length; + } + } + if ((*n) == nmax) break; + } + result = (sstr_t*) malloc(sizeof(sstr_t) * (*n)); + + char *pptr = sv.ptr; + for (int i = 0 ; i < *n ; i++) { + size_t l = strlen(pptr); + char* ptr = (char*) malloc(l + 1); + memcpy(ptr, pptr, l); + ptr[l] = 0; + + result[i] = sstrn(ptr, l); + pptr += l + d.length; + } + + free(sv.ptr); + + return result; +} + +int sstrcmp(sstr_t s1, sstr_t s2) { + return strncmp(s1.ptr, s2.ptr, s1.length>s2.length ? s2.length: s1.length); +} + +sstr_t sstrdup(sstr_t s) { + sstr_t newstring; + newstring.ptr = (char*) malloc(s.length + 1); + if (newstring.ptr != NULL) { + newstring.length = s.length; + newstring.ptr[newstring.length] = 0; + + memcpy(newstring.ptr, s.ptr, s.length); + } + + return newstring; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ucx/string.h Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,99 @@ +/* + * File: sstring.h + * Author: olaf + * + * Created on 17. Juni 2010, 13:26 + */ + +#ifndef _SSTRING_H +#define _SSTRING_H + +#include "ucx.h" +#include <stddef.h> + +/* use macros for literals only */ +#define S(s) { (char*)s, sizeof(s)-1 } +#define ST(s) sstrn((char*)s, sizeof(s)-1) + +#ifdef __cplusplus +extern "C" { +#endif + +typedef struct sstring { + char *ptr; + size_t length; +} sstr_t; + +/* + * creates a new sstr_t from a null terminated string + * + * s null terminated string + */ +sstr_t sstr(char *s); + +/* + * creates a new sstr_t from a string and length + * + * s string + * n length of string + */ +sstr_t sstrn(char *s, size_t n); + + +/* + * gets the length of n sstr_t strings + * + * n number of strings + * s string + * ... strings + */ +size_t sstrnlen(size_t n, sstr_t s, ...); + + +/* + * concatenates n strings + * + * n number of strings + * s new string with enough memory allocated + * ... strings + */ +sstr_t sstrncat(size_t n, sstr_t s, sstr_t c1, ...); + + +/* + * + */ +sstr_t sstrsubs(sstr_t s, size_t start); + +/* + * + */ +sstr_t sstrsubsl(sstr_t s, size_t start, size_t length); + +/* + * splits s into n parts + * + * s the string to split + * d the delimiter string + * n the maximum size of the resulting list + * a size of 0 indicates an unbounded list size + * the actual size of the list will be stored here + * + * Hint: use this value to avoid dynamic reallocation of the result list + * + * Returns a list of the split strings + * NOTE: this list needs to be freed manually after usage + * + * Returns NULL on error + */ +sstr_t* sstrsplit(sstr_t s, sstr_t d, size_t *n); + +int sstrcmp(sstr_t s1, sstr_t s2); + +sstr_t sstrdup(sstr_t s); + +#ifdef __cplusplus +} +#endif + +#endif /* _SSTRING_H */
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ucx/test.c Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,39 @@ +/* + * File: test.c + * Author: Mike + * + * Created on 18. Februar 2012, 14:15 + */ + +#include "test.h" + +UcxTestSuite* ucx_test_suite_new() { + UcxTestSuite* suite = (UcxTestSuite*) malloc(sizeof(UcxTestSuite)); + if (suite != NULL) { + suite->success = 0; + suite->failure = 0; + suite->tests = NULL; + } + return suite; +} + +void ucx_test_suite_free(UcxTestSuite* suite) { + ucx_list_free(suite->tests); + free(suite); +} + +void ucx_test_register(UcxTestSuite* suite, UcxTest test) { + suite->tests = ucx_list_append(suite->tests, (void*) test); +} + +void ucx_test_run(UcxTestSuite* suite, FILE* output) { + suite->success = 0; + suite->failure = 0; + UCX_FOREACH (UcxList*, suite->tests, e) { + UcxTest test = (UcxTest) (e->data); + test(suite, output); + } + fwrite("\nAll test completed.\n", 1, 21, output); + fprintf(output, " Total: %d\n Success: %d\n Failure: %d\n", + suite->success+suite->failure, suite->success, suite->failure); +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ucx/test.h Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,90 @@ +/* + * File: test.h + * Author: Mike + * + * Created on 18. Februar 2012, 14:15 + * + * + * + * Usage of this test framework: + * + * **** IN HEADER FILE: **** + * + * UCX_TEST_DECLARE(function_name) + * + * **** IN SOURCE FILE: **** + * + * UCX_TEST_IMPLEMENT(function_name) { + * <memory allocation and other stuff here> + * UCX_TEST_BEGIN + * <tests with UCX_TEST_ASSERT here> + * UCX_TEST_END + * <cleanup of memory here> + * } + * + * PLEASE NOTE: if a test fails, a longjump is performed + * back to the UCX_TEST_BEGIN macro! + * + * You may use multiple BEGIN-END blocks if you are aware of the + * longjmp behaviour. + * + */ + +#ifndef TEST_H +#define TEST_H + +#include "ucx.h" +#include <stdio.h> +#include <string.h> +#include <setjmp.h> +#include "list.h" + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __FUNCTION__ +#define __FUNCTION__ __func__ +#endif + +typedef struct { + unsigned int success; + unsigned int failure; + UcxList *tests; +} UcxTestSuite; + +typedef void(*UcxTest)(UcxTestSuite*,FILE*); + +UcxTestSuite* ucx_test_suite_new(); +void ucx_test_suite_free(UcxTestSuite*); + +void ucx_test_register(UcxTestSuite*, UcxTest); +void ucx_test_run(UcxTestSuite*, FILE*); + +#define UCX_TEST_DECLARE(name) void name(UcxTestSuite*,FILE *) +#define UCX_TEST_IMPLEMENT(name) void name(UcxTestSuite* _suite_,FILE *_output_) + +#define UCX_TEST_BEGIN fwrite("Running ", 1, 8, _output_);\ + fwrite(__FUNCTION__, 1, strlen(__FUNCTION__), _output_);\ + fwrite("... ", 1, 4, _output_);\ + jmp_buf _env_; \ + if (!setjmp(_env_)) { + +#define UCX_TEST_ASSERT(condition,message) if (!(condition)) { \ + fwrite(message".\n", 1, 2+strlen(message), _output_); \ + _suite_->failure++; \ + longjmp(_env_, 1);\ + } + +#define UCX_TEST_SUBROUTINE(name,data) void name(UcxTestSuite* _suite_,\ + FILE *_output_, jmp_buf _env_, void* data) +#define UCX_TEST_CALL_SUBROUTINE(name,data) name(_suite_,_output_,_env_,data); + +#define UCX_TEST_END fwrite("success.\n", 1, 9, _output_); _suite_->success++;} + +#ifdef __cplusplus +} +#endif + +#endif /* TEST_H */ +
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/ucx/ucx.h Fri Nov 30 21:18:13 2012 +0100 @@ -0,0 +1,51 @@ +/* + * File: ucx.h + * Author: olaf + * + * Created on 31. Dezember 2011, 17:17 + */ + +#ifndef UCX_H +#define UCX_H + +#include <stdlib.h> + +#ifdef __cplusplus +#ifndef _Bool +#define _Bool bool +#define restrict +#endif +extern "C" { +#endif + +#define UCX_FOREACH(type,list,elem) \ + for (type elem = list ; elem != NULL ; elem = elem->next) + +#ifdef __cplusplus +#define ucx_dynarray_new(type,identifier,length)\ + type* identifier; identifier = new type[length] +#define ucx_dynarray_free(identifier) delete [] identifier +#else +#define ucx_dynarray_new(type,identifier,length)\ + type identifier[length] +#define ucx_dynarray_free(identifier) +#endif + +/* element1,element2,custom data -> {-1,0,1} */ +typedef int(*cmp_func)(void*,void*,void*); + +/* element,custom data -> copy of element */ +typedef void*(*copy_func)(void*,void*); + +/* buffer, element size, element count, stream */ +typedef size_t(*write_func)(const void*, size_t, size_t, void*); + +/* buffer, element size, element count, stream */ +typedef size_t(*read_func)(void*, size_t, size_t, void*); + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_H */ +