# HG changeset patch # User Olaf Wintermann # Date 1378675627 -7200 # Node ID fac51f87def01e2841652be51fa1986ca9a7721a # Parent 279f343bbf6c527e80d17be1b458ff772e7f21d1 ucx update diff -r 279f343bbf6c -r fac51f87def0 Makefile --- a/Makefile Wed Jul 31 13:02:06 2013 +0200 +++ b/Makefile Sun Sep 08 23:27:07 2013 +0200 @@ -26,10 +26,16 @@ # POSSIBILITY OF SUCH DAMAGE. # -all: config.mk +all: config.mk build/bin build/lib @echo "build server" cd src; $(MAKE) all +build/bin: + mkdir -p build/bin + +build/lib: + mkdir -p build/lib + config.mk: @echo "create config" ./configure @@ -37,11 +43,6 @@ clean: @echo "clean" rm -f -R build - rm -f -R work - -cleanbuild: - @echo "clean build" - rm -f -R build cleanall: @echo "clean all" diff -r 279f343bbf6c -r fac51f87def0 make/clang.mk --- a/make/clang.mk Wed Jul 31 13:02:06 2013 +0200 +++ b/make/clang.mk Sun Sep 08 23:27:07 2013 +0200 @@ -32,3 +32,4 @@ CXX = c++ LD = cc +SHLIB_FLAGS = -shared diff -r 279f343bbf6c -r fac51f87def0 make/gcc.mk --- a/make/gcc.mk Wed Jul 31 13:02:06 2013 +0200 +++ b/make/gcc.mk Sun Sep 08 23:27:07 2013 +0200 @@ -26,9 +26,13 @@ # POSSIBILITY OF SUCH DAMAGE. # -CFLAGS = -std=gnu99 +CFLAGS = -std=gnu99 -g +LDFLAGS = -Wl,-R,'$$ORIGIN/../lib' CC = gcc CXX = g++ LD = gcc +SHLIB_CFLAGS = -fPIC +SHLIB_LDFLAGS = -shared + diff -r 279f343bbf6c -r fac51f87def0 make/install.mk --- a/make/install.mk Wed Jul 31 13:02:06 2013 +0200 +++ b/make/install.mk Sun Sep 08 23:27:07 2013 +0200 @@ -45,9 +45,8 @@ cp ../templates/config/acl.conf $(INSTALL_DIR)/config/acl.conf sed s:%%WS_HOST%%:$(HOST):g ../templates/config/server.template > $(INSTALL_DIR)/config/server.conf @echo "copy binaries" - mv ../work/bin/webservd ../work/bin/webservd.bin - cp ../work/bin/webservd.bin $(INSTALL_DIR)/bin/webservd - rm ../work/bin/webservd.bin + cp ../build/bin/webservd$(APP_EXT) $(INSTALL_DIR)/bin/ + cp ../build/lib/libucx$(LIB_EXT) $(INSTALL_DIR)/lib/ @echo "copy includes" cp ../src/server/public/nsapi.h $(INSTALL_DIR)/include/nsapi.h cp ../src/server/public/auth.h $(INSTALL_DIR)/include/auth.h diff -r 279f343bbf6c -r fac51f87def0 make/linux.mk --- a/make/linux.mk Wed Jul 31 13:02:06 2013 +0200 +++ b/make/linux.mk Sun Sep 08 23:27:07 2013 +0200 @@ -35,4 +35,8 @@ # platform dependend source files PLATFORM_DAEMONOBJ = event_linux.o +# platform dependend vars +OBJ_EXT = .o +LIB_EXT = .so +APP_EXT = diff -r 279f343bbf6c -r fac51f87def0 make/osx.mk --- a/make/osx.mk Wed Jul 31 13:02:06 2013 +0200 +++ b/make/osx.mk Sun Sep 08 23:27:07 2013 +0200 @@ -35,4 +35,8 @@ # platform dependend source files PLATFORM_DAEMONOBJ = event_bsd.o +# platform dependend vars +OBJ_EXT = .o +LIB_EXT = .dylib +APP_EXT = diff -r 279f343bbf6c -r fac51f87def0 make/solaris.mk --- a/make/solaris.mk Wed Jul 31 13:02:06 2013 +0200 +++ b/make/solaris.mk Sun Sep 08 23:27:07 2013 +0200 @@ -37,4 +37,8 @@ # platform dependend source files PLATFORM_DAEMONOBJ = event_solaris.o +# platform dependend vars +OBJ_EXT = .o +LIB_EXT = .so +APP_EXT = diff -r 279f343bbf6c -r fac51f87def0 make/suncc.mk --- a/make/suncc.mk Wed Jul 31 13:02:06 2013 +0200 +++ b/make/suncc.mk Sun Sep 08 23:27:07 2013 +0200 @@ -27,8 +27,11 @@ # CFLAGS += -xc99 -g -D_REENTRANT +LDFLAGS += -R../lib CC = cc CXX = CC LD = cc +SHLIB_CFLAGS = -Kpic +SHLIB_FLAGS = -G diff -r 279f343bbf6c -r fac51f87def0 src/Makefile --- a/src/Makefile Wed Jul 31 13:02:06 2013 +0200 +++ b/src/Makefile Sun Sep 08 23:27:07 2013 +0200 @@ -28,5 +28,11 @@ BUILD_ROOT = ../ -all: - cd server; $(MAKE) all +all: _ucx _server + + +_ucx: + cd ucx; $(MAKE) + +_server: + cd server; $(MAKE) diff -r 279f343bbf6c -r fac51f87def0 src/server/Makefile --- a/src/server/Makefile Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/Makefile Sun Sep 08 23:27:07 2013 +0200 @@ -33,11 +33,11 @@ OBJ_DIR = $(BUILD_ROOT)/build/ -MAIN_TARGET = $(BUILD_ROOT)/work/bin/webservd +MAIN_TARGET = $(BUILD_ROOT)/build/bin/webservd all: preparation $(MAIN_TARGET) $(PLUGINS) -include ucx/objs.mk +#include ucx/objs.mk include util/objs.mk include safs/objs.mk include webdav/objs.mk @@ -45,7 +45,6 @@ include config/objs.mk include admin/objs.mk -include ucx/Makefile include util/Makefile include safs/Makefile include webdav/Makefile @@ -57,9 +56,8 @@ OBJ_DIRS = daemon safs ucx util webdav config admin plugins MK_OBJ_DIRS = $(OBJ_DIRS:%=$(OBJ_DIR)server/%) -MK_OBJ_DIRS += $(BUILD_ROOT)/work/bin -include ucx/Makefile +LDFLAGS += -lucx preparation: $(MK_OBJ_DIRS) @@ -67,7 +65,7 @@ mkdir -p $@ $(MAIN_TARGET): $(MAINOBJS) - $(CXX) -o $(MAIN_TARGET) $(MAINOBJS) $(LDFLAGS) + $(CXX) -o $(MAIN_TARGET) $(MAINOBJS) -L$(BUILD_ROOT)/build/lib $(LDFLAGS) ../../build/server/ucx/%.o: %.c diff -r 279f343bbf6c -r fac51f87def0 src/server/config/acl.c --- a/src/server/config/acl.c Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/config/acl.c Sun Sep 08 23:27:07 2013 +0200 @@ -28,6 +28,7 @@ #include #include +#include #include "acl.h" @@ -44,10 +45,6 @@ conf->pathACLs = NULL; int r = cfg_parse_basic_file((ConfigParser*)conf, in); - UcxMempool *mp = conf->parser.mp; - cfg_list_destr(mp, conf->namedACLs); - cfg_list_destr(mp, conf->uriACLs); - cfg_list_destr(mp, conf->pathACLs); if(r != 0) { free_acl_file(conf); return NULL; @@ -59,15 +56,15 @@ } void free_acl_file(ACLFile *conf) { - ucx_mempool_destroy(conf->parser.mp); + ucx_mempool_destroy(conf->parser.mp->pool); free(conf); } int acl_parse(void *p, ConfigLine *begin, ConfigLine *end, sstr_t line) { ACLFile *aclf = p; - UcxMempool *mp = aclf->parser.mp; + UcxAllocator *mp = aclf->parser.mp; - if(sstr_startswith(line, sstr("ACL "))) { + if(sstrsuffix(line, sstr("ACL "))) { sstr_t param = sstrsubs(line, 4); UcxList *plist = cfg_param_list(param, mp); ACLConfig *acl = OBJ_NEW(mp, ACLConfig); @@ -83,19 +80,19 @@ if(name.ptr) { acl->id = name; - aclf->namedACLs = ucx_list_append(aclf->namedACLs, acl); + aclf->namedACLs = ucx_list_append_a(mp, aclf->namedACLs, acl); } else if(path.ptr) { acl->id = path; - aclf->pathACLs = ucx_list_append(aclf->pathACLs, acl); + aclf->pathACLs = ucx_list_append_a(mp, aclf->pathACLs, acl); } else if(uri.ptr) { acl->id = uri; - aclf->uriACLs = ucx_list_append(aclf->uriACLs, acl); + aclf->uriACLs = ucx_list_append_a(mp, aclf->uriACLs, acl); } if(type.ptr) { acl->type = type; } - } else if(sstr_startswith(line, sstr("Authenticate "))) { + } else if(sstrsuffix(line, sstr("Authenticate "))) { sstr_t param = sstrsubs(line, 13); UcxList *plist = cfg_param_list(param, mp); aclf->cur->authparam = plist; @@ -111,7 +108,7 @@ int parse_ace(ACLFile *f, sstr_t line) { ACLConfig *cur = f->cur; - UcxMempool *mp = f->parser.mp; + UcxAllocator *mp = f->parser.mp; size_t tkn = 0; sstr_t *tk = sstrsplit(line, sstr(":"), &tkn); @@ -133,12 +130,12 @@ // next token is the user name s = tk[1]; n++; - ace->who = sstrdup_mp(mp, s); + ace->who = sstrdup_a(mp, s); } else if(!sstrcmp(s, sstr("group"))) { // next token is the group name s = tk[1]; n++; - ace->who = sstrdup_mp(mp, s); + ace->who = sstrdup_a(mp, s); ace->flags = ACLCFG_IDENTIFIER_GROUP; } else if(!sstrcmp(s, sstr("owner@"))) { ace->flags = ACLCFG_OWNER; @@ -148,7 +145,7 @@ ace->flags = ACLCFG_EVERYONE; } else { // you can specify only the user name in the ace - ace->who = sstrdup_mp(mp, s); + ace->who = sstrdup_a(mp, s); } n++; //next token @@ -219,7 +216,7 @@ return 1; } - cur->entries = ucx_list_append(cur->entries, ace); + cur->entries = ucx_list_append_a(mp, cur->entries, ace); return 0; } diff -r 279f343bbf6c -r fac51f87def0 src/server/config/conf.c --- a/src/server/config/conf.c Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/config/conf.c Sun Sep 08 23:27:07 2013 +0200 @@ -32,7 +32,8 @@ int cfg_parse_basic_file(ConfigParser *parser, FILE *in) { parser->lines = NULL; - parser->mp = ucx_mempool_new(512); + UcxMempool *mp = ucx_mempool_new(512); + parser->mp = ucx_mempool_allocator(mp); // one logical line over many lines sstr_t mline; @@ -48,14 +49,13 @@ // put the line to the list ConfigLine *line = OBJ_NEW(parser->mp, ConfigLine); - line->line = sstrdup_mp(parser->mp, l); // TODO: check for 0-len str + line->line = sstrdup_a(parser->mp, l); // TODO: check for 0-len str line->object = NULL; line->type = LINE_OTHER; if(parser->lines) { - parser->lines = ucx_dlist_append(parser->lines, line); + parser->lines = ucx_list_append_a(parser->mp, parser->lines, line); } else { - parser->lines = ucx_dlist_append(parser->lines, line); - cfg_dlist_destr(parser->mp, parser->lines); + parser->lines = ucx_list_append_a(parser->mp, parser->lines, line); } // check if the line contains something @@ -67,7 +67,7 @@ if(mline.ptr != NULL) { // concate lines char *ptr = ucx_mempool_malloc( - parser->mp, + mp, mline.length + l.length + 1); memcpy(ptr, mline.ptr, mline.length); @@ -83,7 +83,7 @@ } if(l.ptr[l.length - 1] == '\\') { if(mline.ptr == NULL) { - mline = sstrdup_mp(parser->mp, l); + mline = sstrdup_a(parser->mp, l); start_line = line; } } else { @@ -277,7 +277,7 @@ * parses a line containing a directive and returns a ConfigDirective object * or NULL if an error occurs */ -ConfigDirective* cfg_parse_directive(sstr_t line, UcxMempool *mp) { +ConfigDirective* cfg_parse_directive(sstr_t line, UcxAllocator *mp) { if(line.length < 6) { printf("line too short\n"); return NULL; // line too short @@ -296,7 +296,7 @@ // create directive object ConfigDirective *directive = OBJ_NEW(mp, ConfigDirective); - directive->directive_type = sstrdup_mp(mp, name); + directive->directive_type = sstrdup_a(mp, name); directive->type_num = cfg_get_directive_type_num(name); directive->condition = NULL; // set later by main parsing function //directive->param = NULL; @@ -305,7 +305,7 @@ param_str.ptr = name.ptr + i; param_str.length = line.length - i; param_str = sstrtrim(param_str); - directive->value = sstrdup_mp(mp, param_str); + directive->value = sstrdup_a(mp, param_str); /* sstr_t pname; @@ -337,7 +337,7 @@ return directive; } -UcxList* cfg_param_list(sstr_t param_str, UcxMempool *mp) { +UcxList* cfg_param_list(sstr_t param_str, UcxAllocator *mp) { sstr_t pname; sstr_t pvalue; UcxList *plist = NULL; @@ -349,19 +349,18 @@ // create param object ConfigParam *param = OBJ_NEW(mp, ConfigParam); - param->name = sstrdup_mp(mp, pname); + param->name = sstrdup_a(mp, pname); if(pvalue.length > 0) { - param->value = sstrdup_mp(mp, pvalue); + param->value = sstrdup_a(mp, pvalue); } else { param->value.ptr = NULL; param->value.length = 0; } // add param to list - plist = ucx_list_append(plist, param); + plist = ucx_list_append_a(mp, plist, param); } - cfg_list_destr(mp, plist); return plist; } @@ -477,7 +476,7 @@ return sstrtrim(name); } -ConfigTag* cfg_parse_begin_tag(sstr_t line, UcxMempool *mp) { +ConfigTag* cfg_parse_begin_tag(sstr_t line, UcxAllocator *mp) { if(line.length < 4) { return NULL; // this line can't contain a valid tag } @@ -501,7 +500,7 @@ // create tag object ConfigTag *tag = OBJ_NEW(mp, ConfigTag); - tag->name = sstrdup_mp(mp, name); + tag->name = sstrdup_a(mp, name); tag->param = NULL; // parse parameters @@ -512,7 +511,7 @@ if(param_str.length == 0) { return tag; // no parameters } - tag->param_str = sstrdup_mp(mp, param_str); + tag->param_str = sstrdup_a(mp, param_str); sstr_t pname; sstr_t pvalue; @@ -524,16 +523,16 @@ // create param object ConfigParam *param = OBJ_NEW(mp, ConfigParam); - param->name = sstrdup_mp(mp, pname); + param->name = sstrdup_a(mp, pname); if(pvalue.length > 0) { - param->value = sstrdup_mp(mp, pvalue); + param->value = sstrdup_a(mp, pvalue); } else { param->value.ptr = NULL; param->value.length = 0; } // add param to list - tag->param = cfg_list_append(mp, tag->param, param); + tag->param = ucx_list_append_a(mp, tag->param, param); } return tag; @@ -546,7 +545,7 @@ * gets a ConfigDirective with a specific name from a List of directives * returns a directive or NULL, if the directive cannot be found */ -ConfigDirective* cfg_directivelist_get(UcxDlist *dirs, sstr_t name) { +ConfigDirective* cfg_directivelist_get(UcxList *dirs, sstr_t name) { while(dirs != NULL) { ConfigDirective *d = dirs->data; if(d != NULL) { @@ -559,7 +558,7 @@ return NULL; } -sstr_t cfg_directivelist_get_str(UcxDlist *dirs, sstr_t name) { +sstr_t cfg_directivelist_get_str(UcxList *dirs, sstr_t name) { ConfigDirective *d = cfg_directivelist_get(dirs, name); if(d == NULL) { sstr_t n; @@ -593,24 +592,12 @@ static void cfg_list_free(void *list) { ucx_list_free(list); } -static void cfg_dlist_free(void *dlist) { - ucx_dlist_free(dlist); -} + static void cfg_map_free(void *map) { ucx_map_free(map); } -void cfg_list_destr(UcxMempool *mp, UcxList *list) { - if(list) { - ucx_mempool_reg_destr(mp, list, cfg_list_free); - } -} -void cfg_dlist_destr(UcxMempool *mp, UcxDlist *dlist) { - if(dlist) { - ucx_mempool_reg_destr(mp, dlist, cfg_dlist_free); - } -} void cfg_map_destr(UcxMempool *mp, UcxMap *map) { if(map) { @@ -618,23 +605,5 @@ } } -UcxList* cfg_list_append(UcxMempool *mp, UcxList *list, void *data) { - if(list) { - return ucx_list_append(list, data); - } else { - UcxList *r = ucx_list_append(list, data); - cfg_list_destr(mp, r); - return r; - } -} -UcxDlist* cfg_dlist_append(UcxMempool *mp, UcxDlist *list, void *data) { - if(list) { - return ucx_dlist_append(list, data); - } else { - UcxDlist *r = ucx_dlist_append(list, data); - cfg_dlist_destr(mp, r); - return r; - } -} diff -r 279f343bbf6c -r fac51f87def0 src/server/config/conf.h --- a/src/server/config/conf.h Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/config/conf.h Sun Sep 08 23:27:07 2013 +0200 @@ -32,19 +32,18 @@ #include #include -#include "../ucx/list.h" -#include "../ucx/dlist.h" -#include "../ucx/map.h" -#include "../ucx/mempool.h" -#include "../ucx/string.h" +#include +#include +#include +#include #ifdef __cplusplus extern "C" { #endif // mempool malloc macro -#define OBJ_NEW(pool, type) (type*)ucx_mempool_malloc(pool, sizeof(type)) -#define OBJ_NEW_N(pool, type) (type*)ucx_mempool_calloc(pool, 1, sizeof(type)) +#define OBJ_NEW(p, type) (type*)(p)->malloc((p)->pool, sizeof(type)) +#define OBJ_NEW_N(p, type) (type*)(p)->calloc((p)->pool, 1, sizeof(type)) // line types #define LINE_OTHER 0 @@ -76,8 +75,8 @@ } ConfigParam; typedef struct _cfg_parser { - UcxMempool *mp; - UcxDlist *lines; + UcxAllocator *mp; + UcxList *lines; cfg_parse_f parse; } ConfigParser; @@ -117,9 +116,9 @@ sstr_t cfg_param_get(UcxList *list, sstr_t name); -ConfigDirective* cfg_parse_directive(sstr_t line, UcxMempool *mp); +ConfigDirective* cfg_parse_directive(sstr_t line, UcxAllocator *mp); -UcxList* cfg_param_list(sstr_t param_str, UcxMempool *mp); +UcxList* cfg_param_list(sstr_t param_str, UcxAllocator *mp); int cfg_get_directive_type_num(sstr_t type); @@ -131,19 +130,15 @@ sstr_t cfg_get_end_tag_name(sstr_t line); -ConfigTag* cfg_parse_begin_tag(sstr_t line, UcxMempool *mp); +ConfigTag* cfg_parse_begin_tag(sstr_t line, UcxAllocator *mp); -ConfigDirective* cfg_directivelist_get(UcxDlist *dirs, sstr_t name); +ConfigDirective* cfg_directivelist_get(UcxList *dirs, sstr_t name); -sstr_t cfg_directivelist_get_str(UcxDlist *dirs, sstr_t name); +sstr_t cfg_directivelist_get_str(UcxList *dirs, sstr_t name); sstr_t cfg_directive_pstr1(ConfigDirective *dir); -void cfg_list_destr(UcxMempool *mp, UcxList *list); -void cfg_dlist_destr(UcxMempool *mp, UcxDlist *list); void cfg_map_destr(UcxMempool *mp, UcxMap *map); -UcxList* cfg_list_append(UcxMempool *mp, UcxList *list, void *data); -UcxDlist* cfg_dlist_append(UcxMempool *mp, UcxDlist *list, void *data); #ifdef __cplusplus } diff -r 279f343bbf6c -r fac51f87def0 src/server/config/initconf.c --- a/src/server/config/initconf.c Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/config/initconf.c Sun Sep 08 23:27:07 2013 +0200 @@ -44,7 +44,6 @@ conf->directives = NULL; int r = cfg_parse_basic_file((ConfigParser*)conf, in); - cfg_dlist_destr(conf->parser.mp, conf->directives); if(r != 0) { free_init_config(conf); return NULL; @@ -55,7 +54,7 @@ } void free_init_config(InitConfig *conf) { - ucx_mempool_destroy(conf->parser.mp); + ucx_mempool_destroy(conf->parser.mp->pool); free(conf); } @@ -71,7 +70,7 @@ d->begin = begin; d->end = end; if(d->type_num == 6) { - conf->directives = ucx_dlist_append(conf->directives, d); + conf->directives = ucx_list_append(conf->directives, d); } else { fprintf(stderr, "Warning: Non Init directive in init.conf\n"); } diff -r 279f343bbf6c -r fac51f87def0 src/server/config/initconf.h --- a/src/server/config/initconf.h Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/config/initconf.h Sun Sep 08 23:27:07 2013 +0200 @@ -38,7 +38,7 @@ typedef struct _init_conf { ConfigParser parser; char *file; - UcxDlist *directives; + UcxList *directives; } InitConfig; InitConfig *load_init_config(char *file); diff -r 279f343bbf6c -r fac51f87def0 src/server/config/keyfile.c --- a/src/server/config/keyfile.c Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/config/keyfile.c Sun Sep 08 23:27:07 2013 +0200 @@ -43,7 +43,6 @@ conf->users = NULL; int r = cfg_parse_basic_file((ConfigParser*)conf, in); - cfg_list_destr(conf->parser.mp, conf->users); if(r != 0) { // TODO: free return NULL; @@ -58,13 +57,13 @@ if(conf->users) { ucx_list_free(conf->users); } - ucx_mempool_destroy(conf->parser.mp); + ucx_mempool_destroy(conf->parser.mp->pool); free(conf); } int keyfile_parse(void *p, ConfigLine *begin, ConfigLine *end, sstr_t line) { KeyfileConfig *conf = p; - UcxMempool *mp = conf->parser.mp; + UcxAllocator *mp = conf->parser.mp; size_t tkn = 0; sstr_t *tk = sstrsplit(line, sstrn(";", 1), &tkn); @@ -78,7 +77,7 @@ entry->numgroups = 0; // get user name - entry->name = sstrdup_mp(mp, tk[0]); + entry->name = sstrdup_a(mp, tk[0]); // get hash sstr_t hash = sstrtrim(tk[1]); @@ -105,28 +104,28 @@ entry->hashtype = KEYFILE_SSHA; } else { // unkown hash type - fprintf(stderr, "unknown hash type: %s\n", sstrdup(hash_type).ptr); + fprintf(stderr, "unknown hash type: %s\n", sstrdup_a(mp, hash_type).ptr); return 1; } - entry->hashdata = sstrdup_mp(mp, hash_data); + entry->hashdata = sstrdup_a(mp, hash_data); // get groups if(tkn == 3) { sstr_t groups_str = sstrtrim(tk[2]); size_t ngroups = 0; sstr_t *groups = sstrsplit(groups_str, sstrn(",", 1), &ngroups); - entry->groups = calloc(ngroups, sizeof(sstr_t)); + entry->groups = mp->calloc(mp->pool, ngroups, sizeof(sstr_t)); entry->numgroups = ngroups; for(int i=0;igroups[i] = sstrdup_mp(mp, sstrtrim(groups[i])); + entry->groups[i] = sstrdup_a(mp, sstrtrim(groups[i])); free(groups[i].ptr); } free(groups); } // add user - conf->users = ucx_list_append(conf->users, entry); + conf->users = ucx_list_append_a(mp, conf->users, entry); // free tokens for(int i=0;i #include +#include #include "mimeconf.h" typedef struct { @@ -49,7 +50,6 @@ conf->directives = NULL; conf->ntypes = 0; int r = cfg_parse_basic_file((ConfigParser*)conf, in); - cfg_list_destr(conf->parser.mp, conf->directives); if(r != 0) { // TODO: free return NULL; @@ -61,19 +61,19 @@ } void free_mime_config(MimeConfig *conf) { - ucx_mempool_destroy(conf->parser.mp); + ucx_mempool_destroy(conf->parser.mp->pool); free(conf); } int mimeconf_parse(void *p, ConfigLine *begin, ConfigLine *end, sstr_t line) { MimeConfig *conf = p; - UcxMempool *mp = conf->parser.mp; + UcxAllocator *mp = conf->parser.mp; // parse mime directive - MimeDirective *dir = ucx_mempool_calloc(mp, 1, sizeof(MimeDirective)); + MimeDirective *dir = OBJ_NEW_N(mp, MimeDirective); UcxList *params = cfg_param_list(line, mp); - UCX_FOREACH(UcxList*, params, pl) { + UCX_FOREACH(pl, params) { ConfigParam *param = pl->data; if(!sstrcmp(param->name, sstr("type"))) { @@ -84,16 +84,15 @@ size_t nx = 0; sstr_t *exts = sstrsplit(param->value, sstrn(",", 1), &nx); for(int i=0;iexts = ucx_list_append(dir->exts, extstr.ptr); + sstr_t extstr = sstrdup_a(mp, exts[i]); + dir->exts = ucx_list_append_a(mp, dir->exts, extstr.ptr); free(exts[i].ptr); } free(exts); } } - cfg_list_destr(mp, dir->exts); - conf->directives = ucx_list_append(conf->directives, dir); + conf->directives = ucx_list_append_a(mp, conf->directives, dir); conf->ntypes++; return 0; diff -r 279f343bbf6c -r fac51f87def0 src/server/config/objconf.c --- a/src/server/config/objconf.c Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/config/objconf.c Sun Sep 08 23:27:07 2013 +0200 @@ -66,11 +66,11 @@ void free_object_config(ObjectConfig *conf) { // free other lists if(conf->levels) { - ucx_list_free(conf->levels); + //ucx_list_free(conf->levels); } // free mempool - ucx_mempool_destroy(conf->parser.mp); + ucx_mempool_destroy(conf->parser.mp->pool); free(conf); } @@ -122,7 +122,7 @@ } int objconf_on_begin_tag(ObjectConfig *conf, ConfigTag *tag) { - UcxMempool *mp = conf->parser.mp; + UcxAllocator *mp = conf->parser.mp; if(tag->type_num != TAG_OBJECT) { ConfigParserLevel *l = conf->levels->data; if(l->tag->type_num != TAG_OBJECT) { @@ -141,14 +141,14 @@ obj->ppath = cfg_param_get(tag->param, sstr("ppath")); conf->obj = obj; - conf->objects = cfg_dlist_append(mp, conf->objects, obj); + conf->objects = ucx_list_append_a(mp, conf->objects, obj); // create tree level object ConfigParserLevel *lvl = OBJ_NEW(mp, ConfigParserLevel); lvl->iftag = NULL; lvl->levelnum = 1; lvl->tag = tag; - conf->levels = ucx_list_prepend(conf->levels, lvl); + conf->levels = ucx_list_prepend_a(mp, conf->levels, lvl); break; } @@ -161,7 +161,7 @@ lvl->iftag = NULL; lvl->levelnum = last_lvl->levelnum + 1; lvl->tag = tag; - conf->levels = ucx_list_prepend(conf->levels, lvl); + conf->levels = ucx_list_prepend_a(mp, conf->levels, lvl); last_lvl->iftag = tag; break; @@ -211,7 +211,10 @@ } // remove level - conf->levels = ucx_list_remove(conf->levels, conf->levels); + conf->levels = ucx_list_remove_a( + conf->parser.mp, + conf->levels, + conf->levels); } return 0; @@ -227,7 +230,7 @@ } // add directive to current object - conf->obj->directives[dir->type_num] = cfg_dlist_append( + conf->obj->directives[dir->type_num] = ucx_list_append_a( conf->parser.mp, conf->obj->directives[dir->type_num], dir); diff -r 279f343bbf6c -r fac51f87def0 src/server/config/objconf.h --- a/src/server/config/objconf.h Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/config/objconf.h Sun Sep 08 23:27:07 2013 +0200 @@ -42,7 +42,7 @@ sstr_t name; sstr_t ppath; // directives - UcxDlist *directives[6]; + UcxList *directives[6]; } ConfigObject; /* @@ -58,8 +58,8 @@ ConfigParser parser; char *file; //UcxDlist *lines; - UcxDlist *conditions; - UcxDlist *objects; + UcxList *conditions; + UcxList *objects; // private parser temp var ConfigObject *obj; // add directives to this object diff -r 279f343bbf6c -r fac51f87def0 src/server/config/serverconf.c --- a/src/server/config/serverconf.c Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/config/serverconf.c Sun Sep 08 23:27:07 2013 +0200 @@ -41,11 +41,11 @@ ServerConfig *conf = malloc(sizeof(ServerConfig)); conf->parser.parse = serverconf_parse; conf->file = file; - conf->objects = ucx_map_new(16); conf->obj = NULL; + conf->objects = ucx_map_new(16); int r = cfg_parse_basic_file((ConfigParser*)conf, in); - cfg_map_destr(conf->parser.mp, conf->objects); + cfg_map_destr(conf->parser.mp->pool, conf->objects); if(r != 0) { // TODO: free return NULL; @@ -57,13 +57,13 @@ } void free_server_config(ServerConfig *conf) { - ucx_mempool_destroy(conf->parser.mp); + ucx_mempool_destroy(conf->parser.mp->pool); free(conf); } int serverconf_parse(void *p, ConfigLine *begin, ConfigLine *end, sstr_t line){ ServerConfig *conf = p; - UcxMempool *mp = conf->parser.mp; + UcxAllocator *mp = conf->parser.mp; begin->type = cfg_get_line_type(line); switch(begin->type) { @@ -81,7 +81,7 @@ // add object to server config UcxList *list = ucx_map_sstr_get(conf->objects, obj->type); - list = cfg_list_append(mp, list, obj); + list = ucx_list_append_a(mp, list, obj); ucx_map_sstr_put(conf->objects, obj->type, list); conf->obj = obj; @@ -109,19 +109,19 @@ d->end = end; //printf("%s.%s\n", conf->obj->type.ptr, d->directive_type.ptr); - conf->obj->directives = cfg_dlist_append(mp, conf->obj->directives, d); + conf->obj->directives = ucx_list_append_a(mp, conf->obj->directives, d); } } return 0; } -UcxList* srvcfg_get_listeners(ServerConfig *cfg, UcxMempool *mp, int *error) { +UcxList* srvcfg_get_listeners(ServerConfig *cfg, UcxAllocator *mp, int *error) { mp = mp ? mp : cfg->parser.mp; UcxList *list = ucx_map_sstr_get(cfg->objects, sstrn("Listener", 8)); UcxList *lslist = NULL; - UCX_FOREACH(UcxList*, list, elm) { + UCX_FOREACH(elm, list) { ServerConfigObject *ls = elm->data; sstr_t name = cfg_directivelist_get_str(ls->directives, sstr("Name")); sstr_t port = cfg_directivelist_get_str(ls->directives, sstr("Port")); @@ -132,7 +132,7 @@ ls->directives, sstr("Threadpool")); - CfgListener *listener = ucx_mempool_calloc(mp, 1, sizeof(CfgListener)); + CfgListener *listener = OBJ_NEW_N(mp, CfgListener); // threadpool is optional, all other configs must be set if(!name.ptr || !port.ptr || !vs.ptr) { // TODO: log error @@ -143,7 +143,7 @@ } if(name.ptr) { - listener->name = sstrdup_mp(mp, name); + listener->name = sstrdup_a(mp, name); } if(port.ptr) { // don't expect that port is null terminated, sstrdup it to be sure @@ -152,13 +152,13 @@ free(portdp.ptr); } if(vs.ptr) { - listener->vs = sstrdup_mp(mp, vs); + listener->vs = sstrdup_a(mp, vs); } if(threadpool.ptr) { - listener->threadpool = sstrdup_mp(mp, threadpool); + listener->threadpool = sstrdup_a(mp, threadpool); } - lslist = cfg_list_append(mp, lslist, listener); + lslist = ucx_list_append_a(mp, lslist, listener); } return lslist; diff -r 279f343bbf6c -r fac51f87def0 src/server/config/serverconf.h --- a/src/server/config/serverconf.h Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/config/serverconf.h Sun Sep 08 23:27:07 2013 +0200 @@ -40,7 +40,7 @@ ConfigLine *end; sstr_t type; - UcxDlist *directives; + UcxList *directives; } ServerConfigObject; typedef struct _server_conf { @@ -110,7 +110,7 @@ int serverconf_parse(void *p, ConfigLine *begin, ConfigLine *end, sstr_t line); -UcxList* srvcfg_get_listeners(ServerConfig *cfg, UcxMempool *mp, int *error); +UcxList* srvcfg_get_listeners(ServerConfig *cfg, UcxAllocator *mp, int *error); #ifdef __cplusplus diff -r 279f343bbf6c -r fac51f87def0 src/server/daemon/acldata.h --- a/src/server/daemon/acldata.h Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/daemon/acldata.h Sun Sep 08 23:27:07 2013 +0200 @@ -33,7 +33,6 @@ #include "../config/acl.h" #include "../ucx/list.h" -#include "../ucx/dlist.h" #include "../ucx/map.h" #ifdef __cplusplus diff -r 279f343bbf6c -r fac51f87def0 src/server/daemon/auth.c --- a/src/server/daemon/auth.c Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/daemon/auth.c Sun Sep 08 23:27:07 2013 +0200 @@ -28,6 +28,7 @@ #include #include +#include #include #include "../ucx/map.h" diff -r 279f343bbf6c -r fac51f87def0 src/server/daemon/auth.h --- a/src/server/daemon/auth.h Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/daemon/auth.h Sun Sep 08 23:27:07 2013 +0200 @@ -30,6 +30,7 @@ #define AUTH_H #include +#include #include "../public/auth.h" #ifdef __cplusplus diff -r 279f343bbf6c -r fac51f87def0 src/server/daemon/config.c --- a/src/server/daemon/config.c Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/daemon/config.c Sun Sep 08 23:27:07 2013 +0200 @@ -66,10 +66,10 @@ fprintf(stderr, "Cannot load init.conf\n"); return 1; } - UcxMempool *mp = cfg->parser.mp; + UcxAllocator *mp = cfg->parser.mp; cfg_pool = pool_create(); // one pool for one Configuration - UcxDlist *dirs = cfg->directives; + UcxList *dirs = cfg->directives; while(dirs != NULL) { ConfigDirective *dir = dirs->data; @@ -178,7 +178,7 @@ } UcxList *list = ucx_map_sstr_get(serverconf->objects, sstrn("Runtime", 7)); - UCX_FOREACH(UcxList*, list, elm) { + UCX_FOREACH(elm, list) { ServerConfigObject *scfgobj = elm->data; if(cfg_handle_runtime(serverconfig, scfgobj)) { // error @@ -187,7 +187,7 @@ } list = ucx_map_sstr_get(serverconf->objects, sstrn("Threadpool", 10)); - UCX_FOREACH(UcxList*, list, elm) { + UCX_FOREACH(elm, list) { if(cfg_handle_threadpool(serverconfig, elm->data)) { return NULL; } @@ -199,7 +199,7 @@ } list = ucx_map_sstr_get(serverconf->objects, sstrn("EventHandler", 12)); - UCX_FOREACH(UcxList*, list, elm) { + UCX_FOREACH(elm, list) { if(cfg_handle_eventhandler( serverconfig, (ServerConfigObject*)elm->data)) { // error @@ -213,7 +213,7 @@ } list = ucx_map_sstr_get(serverconf->objects, sstrn("AccessLog", 9)); - UCX_FOREACH(UcxList*, list, elm) { + UCX_FOREACH(elm, list) { ServerConfigObject *scfgobj = elm->data; if(cfg_handle_accesslog(serverconfig, scfgobj)) { return NULL; @@ -221,7 +221,7 @@ } list = ucx_map_sstr_get(serverconf->objects, sstrn("AuthDB", 6)); - UCX_FOREACH(UcxList*, list, elm) { + UCX_FOREACH(elm, list) { ServerConfigObject *scfgobj = elm->data; if(cfg_handle_authdb(serverconfig, scfgobj)) { return NULL; @@ -229,7 +229,7 @@ } list = ucx_map_sstr_get(serverconf->objects, sstrn("Listener", 8)); - UCX_FOREACH(UcxList*, list, elm) { + UCX_FOREACH(elm, list) { ServerConfigObject *scfgobj = elm->data; if(cfg_handle_listener(serverconfig, scfgobj)) { return NULL; @@ -237,7 +237,7 @@ } list = ucx_map_sstr_get(serverconf->objects, sstrn("VirtualServer", 13)); - UCX_FOREACH(UcxList*, list, elm) { + UCX_FOREACH(elm, list) { ServerConfigObject *scfgobj = elm->data; if(cfg_handle_vs(serverconfig, scfgobj)) { return NULL; @@ -290,7 +290,7 @@ int cfg_handle_runtime(ServerConfiguration *cfg, ServerConfigObject *obj) { sstr_t user = cfg_directivelist_get_str(obj->directives, sstr("User")); if(user.ptr) { - cfg->user = sstrdup_pool(cfg->pool, user); + //cfg->user = sstrdup_pool(cfg->pool, user); } sstr_t tmp = cfg_directivelist_get_str(obj->directives, sstr("Temp")); if(tmp.ptr) { @@ -308,7 +308,7 @@ file.length = base.length + mf.length; file.ptr = alloca(file.length + 1); file.ptr[file.length] = 0; - file = sstrncat(2, file, base, mf); + file = sstrncat(file, 2, base, mf); ConfigFile *f = cfgmgr_get_file(file); if(f == NULL) { @@ -610,7 +610,7 @@ file.length = base.length + objfile.length + 1; file.ptr = alloca(file.length); file.ptr[file.length] = 0; - file = sstrncat(2, file, base, objfile); + file = sstrncat(file, 2, base, objfile); // the file is managed by the configuration manager ConfigFile *f = cfgmgr_get_file(file); @@ -635,7 +635,7 @@ file.length = base.length + aclfile.length + 1; file.ptr = alloca(file.length); file.ptr[file.length] = 0; - file = sstrncat(2, file, base, aclfile); + file = sstrncat(file, 2, base, aclfile); ConfigFile *aclf = cfgmgr_get_file(file); if(aclf == NULL) { @@ -696,7 +696,7 @@ // new conf function test ObjectConfig *cfg = load_object_config(file); - UcxMempool *mp = cfg->parser.mp; + UcxAllocator *mp = cfg->parser.mp; if(cfg == NULL) { return NULL; } @@ -709,10 +709,10 @@ // convert ObjectConfig to HTTPObjectConfig // add objects - conf->nobj = ucx_dlist_size(cfg->objects); + conf->nobj = ucx_list_size(cfg->objects); conf->objects = pool_calloc(pool, conf->nobj, sizeof(httpd_object*)); - UcxDlist *objlist = cfg->objects; + UcxList *objlist = cfg->objects; int i = 0; while(objlist != NULL) { ConfigObject *cob = objlist->data; @@ -735,7 +735,7 @@ // add directives for(int i=0;i<6;i++) { - UcxDlist *dirs = cob->directives[i]; + UcxList *dirs = cob->directives[i]; while(dirs != NULL) { ConfigDirective *cfgdir = dirs->data; @@ -792,10 +792,10 @@ mimemap->map = map; // add ext type pairs - UCX_FOREACH(UcxList*, mimecfg->directives, md) { + UCX_FOREACH(md, mimecfg->directives) { MimeDirective *d = md->data; // add the type for each extension to the map - UCX_FOREACH(UcxList*, d->exts, xl) { + UCX_FOREACH(xl, d->exts) { sstr_t ext = sstr(xl->data); sstr_t value = sstrdup(d->type); ucx_map_sstr_put(map, ext, value.ptr); @@ -836,7 +836,7 @@ ACLFile *aclfile = load_acl_file(file->file.ptr); ACLData *acldata = acl_data_new(); - UCX_FOREACH(UcxList*, aclfile->namedACLs, elm) { + UCX_FOREACH(elm, aclfile->namedACLs) { ACLConfig *ac = elm->data; ACLList *acl = acl_config_convert(cfg, ac); printf("put acl: %s\n", ac->id.ptr); @@ -874,7 +874,7 @@ int ei = 0; // convert entries - UCX_FOREACH(UcxList*, acl->entries, elm) { + UCX_FOREACH(elm, acl->entries) { ACEConfig *acecfg = elm->data; // copy data @@ -934,7 +934,7 @@ Keyfile *keyfile = keyfile_new(); - UCX_FOREACH(UcxList*, conf->users, elm) { + UCX_FOREACH(elm, conf->users) { KeyfileEntry *user = elm->data; keyfile_add_user( keyfile, diff -r 279f343bbf6c -r fac51f87def0 src/server/daemon/config.h --- a/src/server/daemon/config.h Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/daemon/config.h Sun Sep 08 23:27:07 2013 +0200 @@ -44,11 +44,10 @@ #include "keyfile_auth.h" #include "log.h" -#include "../ucx/list.h" -#include "../ucx/dlist.h" -#include "../ucx/map.h" -#include "../ucx/mempool.h" -#include "../ucx/string.h" +#include +#include +#include +#include #ifdef __cplusplus extern "C" { diff -r 279f343bbf6c -r fac51f87def0 src/server/daemon/configmanager.c --- a/src/server/daemon/configmanager.c Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/daemon/configmanager.c Sun Sep 08 23:27:07 2013 +0200 @@ -31,7 +31,7 @@ #include "../public/nsapi.h" -#include "../ucx/string.h" +#include #include "httplistener.h" #include "log.h" diff -r 279f343bbf6c -r fac51f87def0 src/server/daemon/configmanager.h --- a/src/server/daemon/configmanager.h Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/daemon/configmanager.h Sun Sep 08 23:27:07 2013 +0200 @@ -33,11 +33,10 @@ #include "vserver.h" -#include "../ucx/list.h" -#include "../ucx/dlist.h" -#include "../ucx/map.h" -#include "../ucx/mempool.h" -#include "../ucx/string.h" +#include +#include +#include +#include #include diff -r 279f343bbf6c -r fac51f87def0 src/server/daemon/httprequest.c --- a/src/server/daemon/httprequest.c Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/daemon/httprequest.c Sun Sep 08 23:27:07 2013 +0200 @@ -516,7 +516,7 @@ sstr_t translated; translated.length = docroot.length + uri.length; translated.ptr = alloca(translated.length + 1); - translated = sstrncat(2, translated, docroot, uri); + translated = sstrncat(translated, 2, docroot, uri); pblock_kvinsert( pb_key_ppath, diff -r 279f343bbf6c -r fac51f87def0 src/server/daemon/keyfile_auth.h --- a/src/server/daemon/keyfile_auth.h Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/daemon/keyfile_auth.h Sun Sep 08 23:27:07 2013 +0200 @@ -31,6 +31,7 @@ #include "../public/auth.h" #include "../ucx/map.h" +#include #ifdef __cplusplus extern "C" { diff -r 279f343bbf6c -r fac51f87def0 src/server/daemon/ldap_auth.c --- a/src/server/daemon/ldap_auth.c Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/daemon/ldap_auth.c Sun Sep 08 23:27:07 2013 +0200 @@ -40,7 +40,7 @@ #ifdef SOLARIS ldap_unbind(ldap); #else - ldap_unbind_ext_s(ld, NULL, NULL); + ldap_unbind_ext_s(ldap, NULL, NULL); #endif } diff -r 279f343bbf6c -r fac51f87def0 src/server/daemon/log.c --- a/src/server/daemon/log.c Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/daemon/log.c Sun Sep 08 23:27:07 2013 +0200 @@ -40,9 +40,10 @@ #include "log.h" #include "../util/strbuf.h" #include "../util/io.h" -#include "../ucx/map.h" #include "../util/atomic.h" +#include + static int is_initialized = 0; static int log_file_fd; @@ -236,7 +237,7 @@ message.length = lpre.length + len; message.ptr = malloc(message.length + 1); - message = sstrncat(2, message, lpre, lmsg); + message = sstrncat(message, 2, lpre, lmsg); /* write message to the log file */ log_file_writeln(message.ptr, message.length); diff -r 279f343bbf6c -r fac51f87def0 src/server/daemon/log.h --- a/src/server/daemon/log.h Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/daemon/log.h Sun Sep 08 23:27:07 2013 +0200 @@ -30,7 +30,7 @@ #define LOG_H #include "../public/nsapi.h" -#include "../ucx/string.h" +#include #include diff -r 279f343bbf6c -r fac51f87def0 src/server/public/webdav.h --- a/src/server/public/webdav.h Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/public/webdav.h Sun Sep 08 23:27:07 2013 +0200 @@ -58,7 +58,7 @@ typedef uint8_t xmlch_t; -typedef struct UcxDlist List; +typedef struct UcxList List; typedef struct UcxMap Map; typedef struct _strbuf Buffer; diff -r 279f343bbf6c -r fac51f87def0 src/server/util/object.c --- a/src/server/util/object.c Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/util/object.c Sun Sep 08 23:27:07 2013 +0200 @@ -344,7 +344,7 @@ } else if(c == '"' || c == '\'') { *type = EXPR_OP_STRING; sstr_t s = sstrn(token+1, len-2); - s = sstrdup_pool(pool, s); + //s = sstrdup_pool(pool, s); *val = s.ptr; } } diff -r 279f343bbf6c -r fac51f87def0 src/server/util/pool.c --- a/src/server/util/pool.c Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/util/pool.c Sun Sep 08 23:27:07 2013 +0200 @@ -703,3 +703,17 @@ } #endif /* PER_POOL_STATISTICS */ +// new +sstr_t sstrdup_pool(pool_handle_t *pool, sstr_t s) { + sstr_t newstring; + newstring.ptr = (char*)pool_malloc(pool, 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; +} + diff -r 279f343bbf6c -r fac51f87def0 src/server/util/pool.h --- a/src/server/util/pool.h Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/util/pool.h Sun Sep 08 23:27:07 2013 +0200 @@ -52,6 +52,9 @@ * */ +// new +#include + #ifndef NETSITE_H //include "netsite.h" #include "../public/nsapi.h" @@ -80,6 +83,8 @@ NSAPI_PUBLIC int INTpool_init(pblock *pb, Session *sn, Request *rq); +sstr_t sstrdup_pool(pool_handle_t *pool, sstr_t s); + #ifdef DEBUG_CACHES NSAPI_PUBLIC int INTpool_service_debug(pblock *pb, Session *sn, Request *rq); #endif diff -r 279f343bbf6c -r fac51f87def0 src/server/util/util.c --- a/src/server/util/util.c Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/util/util.c Sun Sep 08 23:27:07 2013 +0200 @@ -53,6 +53,8 @@ #include "../daemon/netsite.h" #include "../public/nsapi.h" +#include +#include #include "util.h" @@ -484,9 +486,9 @@ return newstr; } if(s.length == 1) { - newstr = sstrncat(3, newstr, parent, s, child); + newstr = sstrncat(newstr, 3, parent, s, child); } else { - newstr = sstrncat(2, newstr, parent, child); + newstr = sstrncat(newstr, 2, parent, child); } newstr.ptr[newstr.length] = '\0'; @@ -568,3 +570,17 @@ return pb; } + +// TODO: remove +sstr_t sstrdup_mp(UcxMempool *pool, sstr_t s) { + sstr_t newstring; + newstring.ptr = (char*)ucx_mempool_malloc(pool, 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; +} diff -r 279f343bbf6c -r fac51f87def0 src/server/util/util.h --- a/src/server/util/util.h Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/util/util.h Sun Sep 08 23:27:07 2013 +0200 @@ -35,7 +35,7 @@ #define BASE_UTIL_H #include "../daemon/netsite.h" -#include "../ucx/string.h" +#include #include "pool.h" #include diff -r 279f343bbf6c -r fac51f87def0 src/server/webdav/davparser.cpp --- a/src/server/webdav/davparser.cpp Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/webdav/davparser.cpp Sun Sep 08 23:27:07 2013 +0200 @@ -98,8 +98,8 @@ } void dav_free_propfind(PropfindRequest *rq) { - ucx_dlist_free(rq->forbiddenProps); - ucx_dlist_free(rq->notFoundProps); + ucx_list_free(rq->forbiddenProps); + ucx_list_free(rq->notFoundProps); //ucx_dlist_free(rq->properties); // uses pool sbuf_free(rq->out); } @@ -154,9 +154,9 @@ } void dav_free_proppatch(ProppatchRequest *rq) { - ucx_dlist_free(rq->removeProps); - ucx_dlist_free(rq->setProps); + ucx_list_free(rq->removeProps); + ucx_list_free(rq->setProps); xmlnsmap_free(rq->nsmap); ucx_map_free(rq->propstat->map); - ucx_dlist_free(rq->propstat->okprop); + ucx_list_free(rq->propstat->okprop); } diff -r 279f343bbf6c -r fac51f87def0 src/server/webdav/davparser.h --- a/src/server/webdav/davparser.h Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/webdav/davparser.h Sun Sep 08 23:27:07 2013 +0200 @@ -31,7 +31,6 @@ #include "../public/nsapi.h" -#include "../ucx/dlist.h" #include #include "webdav.h" diff -r 279f343bbf6c -r fac51f87def0 src/server/webdav/parser.c --- a/src/server/webdav/parser.c Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/webdav/parser.c Sun Sep 08 23:27:07 2013 +0200 @@ -114,11 +114,11 @@ property->name = pool_strdup(pool, (const char*)name); // add property to DavRequest - UcxDlist *elm = pool_malloc(pool, sizeof(UcxDlist)); + UcxList *elm = pool_malloc(pool, sizeof(UcxList)); elm->prev = NULL; elm->next = NULL; elm->data = property; - p->rq->properties = ucx_dlist_concat(p->rq->properties, elm); + p->rq->properties = ucx_list_concat(p->rq->properties, elm); } return 0; diff -r 279f343bbf6c -r fac51f87def0 src/server/webdav/saxhandler.cpp --- a/src/server/webdav/saxhandler.cpp Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/webdav/saxhandler.cpp Sun Sep 08 23:27:07 2013 +0200 @@ -32,23 +32,23 @@ #include #include "../ucx/string.h" -#include "../ucx/dlist.h" +#include "../ucx/list.h" #include "../util/pool.h" #include "saxhandler.h" using namespace std; -void xstack_push(UcxDlist **stack, XmlElement *elm) { - *stack = ucx_dlist_prepend(*stack, elm); +void xstack_push(UcxList **stack, XmlElement *elm) { + *stack = ucx_list_prepend(*stack, elm); } -XmlElement* xstack_pop(UcxDlist **stack) { +XmlElement* xstack_pop(UcxList **stack) { if(*stack == NULL) { return NULL; } XmlElement* ret = (XmlElement*)(*stack)->data; - UcxDlist *newstack = ucx_dlist_remove(*stack, *stack); + UcxList *newstack = ucx_list_remove(*stack, *stack); *stack = newstack; return ret; } @@ -121,12 +121,12 @@ if(!strcmp(ns, xmlns) && !strcmp(name, property->name)) { // add property to DavRequest - UcxDlist *elm = (UcxDlist*)pool_malloc(pool, sizeof(UcxDlist)); + UcxList *elm = (UcxList*)pool_malloc(pool, sizeof(UcxList)); elm->prev = NULL; elm->next = NULL; elm->data = property; //printf("saxhandler: add property: {%s}\n", property->name); - davrq->properties = ucx_dlist_concat(davrq->properties, elm); + davrq->properties = ucx_list_concat(davrq->properties, elm); property = NULL; } @@ -160,7 +160,7 @@ } ProppatchHandler::~ProppatchHandler() { - ucx_dlist_free(xmlStack); + ucx_list_free(xmlStack); } void ProppatchHandler::startElement( @@ -236,13 +236,13 @@ /* add the property to the proppatch request */ switch(updateMode) { case 0: { - davrq->setProps = ucx_dlist_append( + davrq->setProps = ucx_list_append( davrq->setProps, rootElement); break; } case 1: { - davrq->removeProps = ucx_dlist_append( + davrq->removeProps = ucx_list_append( davrq->removeProps, rootElement); break; diff -r 279f343bbf6c -r fac51f87def0 src/server/webdav/saxhandler.h --- a/src/server/webdav/saxhandler.h Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/webdav/saxhandler.h Sun Sep 08 23:27:07 2013 +0200 @@ -39,8 +39,8 @@ #define XSTACK_PUSH(elm) xstack_push(&xmlStack, elm) #define XSTACK_POP() xstack_pop(&xmlStack) #define XSTACK_CUR() (xmlStack) ? (XmlElement*)xmlStack->data : NULL; -void xstack_push(UcxDlist **stack, XmlElement *elm); -XmlElement* xstack_pop(UcxDlist **stack); +void xstack_push(UcxList **stack, XmlElement *elm); +XmlElement* xstack_pop(UcxList **stack); class PropfindHandler : public DefaultHandler { public: @@ -100,7 +100,7 @@ bool davPropTag; XmlElement *rootElement; XmlElement *newElement; - UcxDlist *xmlStack; + UcxList *xmlStack; //DavProperty *property; int updateMode; /* 0 = set, 1 = remove, -1 = undefined */ diff -r 279f343bbf6c -r fac51f87def0 src/server/webdav/webdav.c --- a/src/server/webdav/webdav.c Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/webdav/webdav.c Sun Sep 08 23:27:07 2013 +0200 @@ -31,7 +31,8 @@ #include #include "webdav.h" -#include "../ucx/string.h" +#include +#include #include "../util/pool.h" #include "../util/pblock.h" #include "../util/date.h" @@ -541,7 +542,7 @@ int error) { // TODO: different errors - davrq->notFoundProps = ucx_dlist_append(davrq->notFoundProps, prop); + davrq->notFoundProps = ucx_list_append(davrq->notFoundProps, prop); } @@ -712,7 +713,7 @@ void xmlelm_add_child(XmlElement *parent, XmlElement *child) { if(parent->ctlen == 0) { - parent->content = ucx_dlist_append(parent->content, child); + parent->content = ucx_list_append(parent->content, child); } } @@ -728,7 +729,7 @@ sbuf_append(out, sstrn(" />", 3)); } else { sbuf_append(out, sstrn(">", 1)); - DAV_FOREACH(pr, (UcxDlist*)elm->content) { + DAV_FOREACH(pr, (UcxList*)elm->content) { xmlelm_write((XmlElement*)pr->data, out, 1); } sbuf_append(out, sstrn("okprop = ucx_dlist_append(propstat->okprop, prop); + propstat->okprop = ucx_list_append(propstat->okprop, prop); } else { UcxKey key; key.data = &status; key.len = sizeof(int); - UcxDlist *list = ucx_map_get(propstat->map, key); - list = ucx_dlist_append(list, prop); + UcxList *list = ucx_map_get(propstat->map, key); + list = ucx_list_append(list, prop); ucx_map_put(propstat->map, key, list); } @@ -790,7 +791,7 @@ } UcxMapIterator iter = ucx_map_iterator(propstat->map); - UcxDlist *proplist; + UcxList *proplist; UCX_MAP_FOREACH(key, proplist, iter) { if(proplist) { sbuf_puts(out, "\n\n"); diff -r 279f343bbf6c -r fac51f87def0 src/server/webdav/webdav.h --- a/src/server/webdav/webdav.h Wed Jul 31 13:02:06 2013 +0200 +++ b/src/server/webdav/webdav.h Sun Sep 08 23:27:07 2013 +0200 @@ -30,17 +30,17 @@ #define WEBDAV_H #include "../public/webdav.h" +#include "../util/strbuf.h" -#include "../ucx/map.h" -#include "../ucx/dlist.h" -#include "../util/strbuf.h" +#include +#include #ifdef __cplusplus extern "C" { #endif #define DAV_FOREACH(elem, list) \ - for (UcxDlist *elem = list ; elem != NULL ; elem = elem->next) + for (UcxList *elem = list ; elem != NULL ; elem = elem->next) int webdav_init(pblock *pb, Session *sn, Request *rq); int webdav_setcollection(pblock *pb, Session *sn, Request *rq); diff -r 279f343bbf6c -r fac51f87def0 src/ucx/Makefile --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/Makefile Sun Sep 08 23:27:07 2013 +0200 @@ -0,0 +1,56 @@ +# +# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. +# +# Copyright 2013 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. +# + +BUILD_ROOT = ../.. + +include $(BUILD_ROOT)/config.mk + +# list of source files +SRC = utils.c +SRC += list.c +SRC += map.c +SRC += properties.c +SRC += mempool.c +SRC += string.c +SRC += test.c +SRC += allocator.c +SRC += logging.c +SRC += buffer.c + +OBJ = $(SRC:%.c=$(BUILD_ROOT)/build/ucx/%$(OBJ_EXT)) + +all: $(BUILD_ROOT)/build/ucx $(BUILD_ROOT)/build/lib/libucx$(LIB_EXT) + +$(BUILD_ROOT)/build/lib/libucx$(LIB_EXT): $(OBJ) + $(CC) $(SHLIB_LDFLAGS) -o $@ $(OBJ) + +$(BUILD_ROOT)/build/ucx/%$(OBJ_EXT): %.c + $(CC) $(CFLAGS) $(SHLIB_CFLAGS) -c -o $@ $< + +$(BUILD_ROOT)/build/ucx: + mkdir -p $(BUILD_ROOT)/build/ucx diff -r 279f343bbf6c -r fac51f87def0 src/ucx/allocator.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/allocator.c Sun Sep 08 23:27:07 2013 +0200 @@ -0,0 +1,59 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 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 +#include "allocator.h" + +UcxAllocator default_allocator = { + NULL, + ucx_default_malloc, + ucx_default_calloc, + ucx_default_realloc, + ucx_default_free +}; + +UcxAllocator *ucx_default_allocator() { + UcxAllocator *allocator = &default_allocator; + return allocator; +} + +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); +} + +void ucx_default_free(void *ignore, void *data) { + free(data); +} diff -r 279f343bbf6c -r fac51f87def0 src/ucx/allocator.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/allocator.h Sun Sep 08 23:27:07 2013 +0200 @@ -0,0 +1,171 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 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. + */ +/** + * Allocator for custom memory management. + * + * An UCX allocator consists of a pointer to the memory area / pool and four + * function pointers to memory management functions operating on this memory + * area / pool. These functions shall behave equivalent to the standard libc + * functions malloc(), calloc(), realloc() and free(). + * + * The signature of the memory management functions is based on the signature + * of the respective libc function but each of them takes the pointer to the + * memory area / pool as first argument. + * + * As the pointer to the memory area / pool can be arbitrarily chosen, any data + * can be provided to the memory management functions. An UcxMempool is just + * one example. + * + * @see mempool.h + * @see UcxMap + * + * @file allocator.h + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_ALLOCATOR_H +#define UCX_ALLOCATOR_H + +#include "ucx.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * A function pointer to the allocators malloc() function. + * @see UcxAllocator + */ +typedef void*(*ucx_allocator_malloc)(void *pool, size_t n); + +/** + * A function pointer to the allocators calloc() function. + * @see UcxAllocator + */ +typedef void*(*ucx_allocator_calloc)(void *pool, size_t n, size_t size); + +/** + * A function pointer to the allocators realloc() function. + * @see UcxAllocator + */ +typedef void*(*ucx_allocator_realloc)(void *pool, void *data, size_t n); + +/** + * A function pointer to the allocators free() function. + * @see UcxAllocator + */ +typedef void(*ucx_allocator_free)(void *pool, void *data); + +/** + * UCX allocator data structure containing memory management functions. + */ +typedef struct { + /** Pointer to an area of memory or a complex memory pool. + * This pointer will be passed to any memory management function as first + * argument. + */ + void *pool; + /** + * The malloc() function for this allocator. + */ + ucx_allocator_malloc malloc; + /** + * The calloc() function for this allocator. + */ + ucx_allocator_calloc calloc; + /** + * The realloc() function for this allocator. + */ + ucx_allocator_realloc realloc; + /** + * The free() function for this allocator. + */ + ucx_allocator_free free; +} UcxAllocator; + +/** + * Returns a pointer to the default allocator. + * + * The default allocator contains wrappers to the standard libc memory + * management functions. Use this function to get a pointer to a globally + * available allocator. You may also define an own UcxAllocator by assigning + * #UCX_ALLOCATOR_DEFAULT to a variable and pass the address of this variable + * to any function that takes an UcxAllocator as argument. Note that using + * this function is the recommended way of passing a default allocator, thus + * it never runs out of scope. + * + * @return a pointer to the default allocator + * + * @see UCX_ALLOCATOR_DEFAULT + */ +UcxAllocator *ucx_default_allocator(); + +/** + * A wrapper for the standard libc malloc() function. + * @param ignore ignored (may be used by allocators for pooled memory) + * @param n argument passed to malloc() + * @return return value of malloc() + */ +void *ucx_default_malloc(void *ignore, size_t n); +/** + * A wrapper for the standard libc calloc() function. + * @param ignore ignored (may be used by allocators for pooled memory) + * @param n argument passed to calloc() + * @param size argument passed to calloc() + * @return return value of calloc() + */ +void *ucx_default_calloc(void *ignore, size_t n, size_t size); +/** + * A wrapper for the standard libc realloc() function. + * @param ignore ignored (may be used by allocators for pooled memory) + * @param data argumend passed to realloc() + * @param n argument passed to realloc() + * @return return value of realloc() + */ +void *ucx_default_realloc(void *ignore, void *data, size_t n); +/** + * A wrapper for the standard libc free() function. + * @param ignore ignored (may be used by allocators for pooled memory) + * @param data argument passed to free() + */ +void ucx_default_free(void *ignore, void *data); + +/** + * Convenient macro for a default allocator struct definition. + */ +#define UCX_ALLOCATOR_DEFAULT {NULL, \ + ucx_default_malloc, ucx_default_calloc, ucx_default_realloc, \ + ucx_default_free } + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_ALLOCATOR_H */ + diff -r 279f343bbf6c -r fac51f87def0 src/ucx/buffer.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/buffer.c Sun Sep 08 23:27:07 2013 +0200 @@ -0,0 +1,214 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 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 "buffer.h" +#include +#include +#include + +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 = (char*)malloc(size); + if (!buffer->space) { + free(buffer); + return NULL; + } + memset(buffer->space, 0, size); + buffer->flags |= UCX_BUFFER_AUTOFREE; + } else { + buffer->space = (char*)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 = (char*)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) { + size_t npos; + switch (whence) { + case SEEK_CUR: + npos = buffer->pos; + break; + case SEEK_END: + npos = buffer->size; + break; + default: + npos = 0; + } + + npos += offset; + + if (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 = (char*)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_puts(UcxBuffer *buffer, char *str) { + return ucx_buffer_write((const void*)str, 1, strlen(str), buffer); +} diff -r 279f343bbf6c -r fac51f87def0 src/ucx/buffer.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/buffer.h Sun Sep 08 23:27:07 2013 +0200 @@ -0,0 +1,267 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 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. + */ + +/** + * @file buffer.h + * + * Advanced buffer implementation. + * + * Instances of UcxBuffer can be used to read from or to write to like one + * would do with a stream. This allows the use of ucx_stream_copy() to copy + * contents from one buffer to another. + * + * Some features for convenient use of the buffer + * can be enabled. See the documentation of the macro constants for more + * information. + * + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_BUFFER_H +#define UCX_BUFFER_H + +#include "ucx.h" +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * No buffer features enabled (all flags cleared). + */ +#define UCX_BUFFER_DEFAULT 0x00 + +/** + * If this flag is enabled, the buffer will automatically free its contents. + */ +#define UCX_BUFFER_AUTOFREE 0x01 + +/** + * If this flag is enabled, the buffer will automatically extends its capacity. + */ +#define UCX_BUFFER_AUTOEXTEND 0x02 + +/** UCX Buffer. */ +typedef struct { + /** A pointer to the buffer contents. */ + char *space; + /** Current position of the buffer. */ + size_t pos; + /** Current capacity (i.e. maximum size) of the buffer. */ + size_t capacity; + /** Current size of the buffer content. */ + size_t size; + /** + * Flag register for buffer features. + * @see #UCX_BUFFER_DEFAULT + * @see #UCX_BUFFER_AUTOFREE + * @see #UCX_BUFFER_AUTOEXTEND + */ + int flags; +} UcxBuffer; + +/** + * Creates a new buffer. + * + * Note: you may provide NULL as argument for + * space. Then this function will allocate the space and enforce + * the #UCX_BUFFER_AUTOFREE flag. + * + * @param space pointer to the memory area, or NULL to allocate + * new memory + * @param size the size of the buffer + * @param flags buffer features (see UcxBuffer.flags) + * @return the new buffer + */ +UcxBuffer *ucx_buffer_new(void *space, size_t size, int flags); + +/** + * Destroys a buffer. + * + * If the #UCX_BUFFER_AUTOFREE feature is enabled, the contents of the buffer + * are also freed. + * + * @param buffer the buffer to destroy + */ +void ucx_buffer_free(UcxBuffer* buffer); + +/** + * Creates a new buffer and fills it with extracted content from another buffer. + * + * Note: the #UCX_BUFFER_AUTOFREE feature is enforced for the new buffer. + * + * @param src the source buffer + * @param start the start position of extraction + * @param length the count of bytes to extract or 0 if all of the remaining + * bytes shall be extracted + * @param flags feature mask for the new buffer + * @return + */ +UcxBuffer* ucx_buffer_extract(UcxBuffer *src, + size_t start, size_t length, int flags); + +/** + * A shorthand macro for the full extraction of the buffer. + * + * @param src the source buffer + * @param flags feature mask for the new buffer + * @return a new buffer with the extracted content + */ +#define ucx_buffer_clone(src,flags) \ + ucx_buffer_extract(src, 0, 0, flags) + +/** + * Moves the position of the buffer. + * + * The new position is relative to the whence argument. + * + * SEEK_SET marks the start of the buffer. + * SEEK_CUR marks the current position. + * SEEK_END marks the first 0-byte in the buffer. + * + * @param buffer + * @param offset position offset relative to whence + * @param whence one of SEEK_SET, SEEK_CUR or SEEK_END + * @return 0 on success, non-zero if the position is invalid + * + */ +int ucx_buffer_seek(UcxBuffer *buffer, off_t offset, int whence); + +/** + * Clears the buffer by resetting the position and deleting the data. + * + * The data is deleted by a zeroing it with call to memset(). + * + * @param buffer the buffer to be cleared + */ +#define ucx_buffer_clear(buffer) memset(buffer->space, 0, buffer->size); \ + buffer->size = 0; buffer->pos = 0; + +/** + * Tests, if the buffer position has exceeded the buffer capacity. + * + * @param buffer the buffer to test + * @return non-zero, if the current buffer position has exceeded the last + * available byte of the buffer. + */ +int ucx_buffer_eof(UcxBuffer *buffer); + + +/** + * Extends the capacity of the buffer. + * + * Note: The buffer capacity increased by a power of two. I.e. + * the buffer capacity is doubled, as long as it would not hold the current + * content plus the additional required bytes. + * + * Attention: the argument provided is the count of additional + * bytes the buffer shall hold. It is NOT the total count of bytes the + * buffer shall hold. + * + * @param buffer the buffer to extend + * @param additional_bytes the count of additional bytes the buffer shall + * at least hold + * @return 0 on success or a non-zero value on failure + */ +int ucx_buffer_extend(UcxBuffer *buffer, size_t additional_bytes); + +/** + * Writes data to an UcxBuffer. + * + * The position of the buffer is increased by the number of bytes read. + * + * @param ptr a pointer to the memory area containing the bytes to be written + * @param size the length of one element + * @param nitems the element count + * @param buffer the UcxBuffer to write to + * @return the total count of bytes written + */ +size_t ucx_buffer_write(const void *ptr, size_t size, size_t nitems, + UcxBuffer *buffer); + +/** + * Reads data from an UcxBuffer. + * + * The position of the buffer is increased by the number of bytes read. + * + * @param ptr a pointer to the memory area where to store the read data + * @param size the length of one element + * @param nitems the element count + * @param buffer the UcxBuffer to read from + * @return the total count of bytes read + */ +size_t ucx_buffer_read(void *ptr, size_t size, size_t nitems, + UcxBuffer *buffer); + +/** + * Writes a character to a buffer. + * + * The least significant byte of the argument is written to the buffer. If the + * end of the buffer is reached and #UCX_BUFFER_AUTOEXTEND feature is enabled, + * the buffer capacity is extended by ucx_buffer_extend(). If the feature is + * disabled or buffer extension fails, EOF is returned. + * + * On successful write the position of the buffer is increased. + * + * @param buffer the buffer to write to + * @param c the character to write as int value + * @return the byte that has bean written as int value or + * EOF when the end of the stream is reached and automatic + * extension is not enabled or not possible + */ +int ucx_buffer_putc(UcxBuffer *buffer, int c); + +/** + * Gets a character from a buffer. + * + * The current position of the buffer is increased after a successful read. + * + * @param buffer the buffer to read from + * @return the character as int value or EOF, if the + * end of the buffer is reached + */ +int ucx_buffer_getc(UcxBuffer *buffer); + +/** + * Writes a string to a buffer. + * + * @param buffer the buffer + * @param str the string + * @return the number of bytes written + */ +size_t ucx_buffer_puts(UcxBuffer *buffer, char *str); + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_BUFFER_H */ + diff -r 279f343bbf6c -r fac51f87def0 src/ucx/list.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/list.c Sun Sep 08 23:27:07 2013 +0200 @@ -0,0 +1,321 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 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 "list.h" + +UcxList *ucx_list_clone(UcxList *l, copy_func fnc, void *data) { + return ucx_list_clone_a(ucx_default_allocator(), l, fnc, data); +} + +UcxList *ucx_list_clone_a(UcxAllocator *alloc, UcxList *l, + copy_func fnc, void *data) { + UcxList *ret = NULL; + while (l) { + if (fnc) { + ret = ucx_list_append_a(alloc, ret, fnc(l->data, data)); + } else { + ret = ucx_list_append_a(alloc, 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) { + ucx_list_free_a(ucx_default_allocator(), l); +} + +void ucx_list_free_a(UcxAllocator *alloc, UcxList *l) { + UcxList *e = l, *f; + while (e != NULL) { + f = e; + e = e->next; + alloc->free(alloc->pool, f); + } +} + +UcxList *ucx_list_append(UcxList *l, void *data) { + return ucx_list_append_a(ucx_default_allocator(), l, data); +} + +UcxList *ucx_list_append_a(UcxAllocator *alloc, UcxList *l, void *data) { + UcxList *nl = (UcxList*) alloc->malloc(alloc->pool, sizeof(UcxList)); + if (!nl) { + return NULL; + } + + nl->data = data; + nl->next = NULL; + if (l) { + UcxList *t = ucx_list_last(l); + t->next = nl; + nl->prev = t; + return l; + } else { + nl->prev = NULL; + return nl; + } +} + +UcxList *ucx_list_prepend(UcxList *l, void *data) { + return ucx_list_prepend_a(ucx_default_allocator(), l, data); +} + +UcxList *ucx_list_prepend_a(UcxAllocator *alloc, UcxList *l, void *data) { + UcxList *nl = ucx_list_append_a(alloc, NULL, data); + if (!nl) { + return NULL; + } + l = ucx_list_first(l); + + if (l) { + nl->next = l; + l->prev = nl; + } + return nl; +} + +UcxList *ucx_list_concat(UcxList *l1, UcxList *l2) { + if (l1) { + UcxList *last = ucx_list_last(l1); + last->next = l2; + l2->prev = last; + return l1; + } else { + return l2; + } +} + +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; +} + +ssize_t ucx_list_indexof(const UcxList *list, const UcxList *elem) { + ssize_t index = 0; + while (list) { + if (list == elem) { + return index; + } + list = list->next; + index++; + } + return -1; +} + +UcxList *ucx_list_get(const UcxList *l, int index) { + if (l == NULL) return NULL; + + const UcxList *e = l; + while (e->next && index > 0) { + e = e->next; + index--; + } + + return (UcxList*)(index == 0 ? e : NULL); +} + +ssize_t ucx_list_find(UcxList *l, void *elem, cmp_func fnc, void *cmpdata) { + ssize_t index = 0; + UCX_FOREACH(e, l) { + if (fnc) { + if (fnc(elem, e->data, cmpdata) == 0) { + return index; + } + } else { + if (elem == e->data) { + return index; + } + } + index++; + } + return -1; +} + +int ucx_list_contains(UcxList *l, void *elem, cmp_func fnc, void *cmpdata) { + return ucx_list_find(l, elem, fnc, cmpdata) > -1; +} + +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 + 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; + + 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; + } +} + +UcxList *ucx_list_first(const UcxList *l) { + if (!l) { + return NULL; + } + + const UcxList *e = l; + while (e->prev) { + e = e->prev; + } + return (UcxList *)e; +} + +UcxList *ucx_list_remove(UcxList *l, UcxList *e) { + return ucx_list_remove_a(ucx_default_allocator(), l, e); +} + +UcxList *ucx_list_remove_a(UcxAllocator *alloc, UcxList *l, UcxList *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; + } + alloc->free(alloc->pool, e); + return l; +} diff -r 279f343bbf6c -r fac51f87def0 src/ucx/list.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/list.h Sun Sep 08 23:27:07 2013 +0200 @@ -0,0 +1,378 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 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. + */ +/** + * Doubly linked list implementation. + * + * @file list.h + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_LIST_H +#define UCX_LIST_H + +#include "ucx.h" +#include "allocator.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Loop statement for UCX lists. + * + * The first argument is a pointer to the list. In most cases this will be the + * pointer to the first element of the list, but it may also be an arbitrary + * element of the list. The iteration will then start with that element. + * + * The second argument is the name of the iteration variable. The scope of + * this variable is limited to the UCX_FOREACH statement. + * + * @param list The first element of the list + * @param elem The variable name of the element + */ +#define UCX_FOREACH(elem,list) \ + for (UcxList* elem = list ; elem != NULL ; elem = elem->next) + +/** + * UCX list type. + * @see UcxList + */ +typedef struct UcxList UcxList; + +/** + * UCX list structure. + */ +struct UcxList { + /** + * List element payload. + */ + void *data; + /** + * Pointer to the next list element or NULL, if this is the + * last element. + */ + UcxList *next; + /** + * Pointer to the previous list element or NULL, if this is + * the first element. + */ + UcxList *prev; +}; + +/** + * Creates an element-wise copy of a list. + * + * This function clones the specified list by creating new list elements and + * copying the data with the specified copy_func(). If no copy_func() is + * specified, a shallow copy is created and the new list will reference the + * same data as the source list. + * + * @param list the list to copy + * @param cpyfnc a pointer to the function that shall copy an element (may be + * NULL) + * @param data additional data for the copy_func() + * @return a pointer to the copy + */ +UcxList *ucx_list_clone(UcxList *list, copy_func cpyfnc, void* data); + +/** + * Creates an element-wise copy of a list using an UcxAllocator. + * + * See ucx_list_clone() for details. + * + * Keep in mind, that you might want to pass the allocator as an (part of the) + * argument for the data parameter, if you want the copy_func() to + * make use of the allocator. + * + * @param allocator the allocator to use + * @param list the list to copy + * @param cpyfnc a pointer to the function that shall copy an element (may be + * NULL) + * @param data additional data for the copy_func() + * @return a pointer to the copy + * @see ucx_list_clone() + */ +UcxList *ucx_list_clone_a(UcxAllocator *allocator, UcxList *list, + copy_func cpyfnc, void* data); + +/** + * Compares two UCX lists element-wise by using a compare function. + * + * Each element of the two specified lists are compared by using the specified + * compare function and the additional data. The type and content of this + * additional data depends on the cmp_func() used. + * + * If the list pointers denote elements within a list, the lists are compared + * starting with the denoted elements. Thus any previous elements are not taken + * into account. This might be useful to check, if certain list tails match + * each other. + * + * @param list1 the first list + * @param list2 the second list + * @param cmpfnc the compare function + * @param data additional data for the compare function + * @return 1, if and only if the two lists equal element-wise, 0 otherwise + */ +int ucx_list_equals(const UcxList *list1, const UcxList *list2, + cmp_func cmpfnc, void* data); + +/** + * Destroys the entire list. + * + * The members of the list are not automatically freed, so ensure they are + * otherwise referenced or a memory leak will occur. + * + * Caution: the argument MUST denote an entire list (i.e. a call + * to ucx_list_first() on the argument must return the argument itself) + * + * @param list the list to free + */ +void ucx_list_free(UcxList *list); + +/** + * Destroys the entire list using an UcxAllocator. + * + * See ucx_list_free() for details. + * + * @param allocator the allocator to use + * @param list the list to free + * @see ucx_list_free() + */ +void ucx_list_free_a(UcxAllocator *allocator, UcxList *list); + +/** + * Inserts an element at the end of the list. + * + * This is generally an O(n) operation, as the end of the list is seeked with + * ucx_list_last(). + * + * @param list the list where to append the data, or NULL to + * create a new list + * @param data the data to insert + * @return list, if it is not NULL or a pointer to + * the newly created list otherwise + */ +UcxList *ucx_list_append(UcxList *list, void *data); + +/** + * Inserts an element at the end of the list using an UcxAllocator. + * + * See ucx_list_append() for details. + * + * @param allocator the allocator to use + * @param list the list where to append the data, or NULL to + * create a new list + * @param data the data to insert + * @return list, if it is not NULL or a pointer to + * the newly created list otherwise + * @see ucx_list_append() + */ +UcxList *ucx_list_append_a(UcxAllocator *allocator, UcxList *list, void *data); + +/** + * Inserts an element at the beginning of the list. + * + * You should overwrite the old list pointer by calling + * mylist = ucx_list_prepend(mylist, mydata);. However, you may + * also perform successive calls of ucx_list_prepend() on the same list pointer, + * as this function always searchs for the head of the list with + * ucx_list_first(). + * + * @param list the list where to insert the data or NULL to create + * a new list + * @param data the data to insert + * @return a pointer to the new list head + */ +UcxList *ucx_list_prepend(UcxList *list, void *data); + +/** + * Inserts an element at the beginning of the list using an UcxAllocator. + * + * See ucx_list_prepend() for details. + * + * @param allocator the allocator to use + * @param list the list where to insert the data or NULL to create + * a new list + * @param data the data to insert + * @return a pointer to the new list head + * @see ucx_list_prepend() + */ +UcxList *ucx_list_prepend_a(UcxAllocator *allocator, UcxList *list, void *data); + +/** + * Concatenates two lists. + * + * Either of the two arguments may be NULL. + * + * This function modifies the references to the next/previous element of + * the last/first element of list1/ + * list2. + * + * @param list1 first list + * @param list2 second list + * @return if list1 is NULL, list2 is + * returned, otherwise list1 is returned + */ +UcxList *ucx_list_concat(UcxList *list1, UcxList *list2); + +/** + * Returns the first element of a list. + * + * If the argument is the list pointer, it is directly returned. Otherwise + * this function traverses to the first element of the list and returns the + * list pointer. + * + * @param elem one element of the list + * @return the first element of the list, the specified element is a member of + */ +UcxList *ucx_list_first(const UcxList *elem); + +/** + * Returns the last element of a list. + * + * If the argument has no successor, it is the last element and therefore + * directly returned. Otherwise this function traverses to the last element of + * the list and returns it. + * + * @param elem one element of the list + * @return the last element of the list, the specified element is a member of + */ +UcxList *ucx_list_last(const UcxList *elem); + +/** + * Returns the list element at the specified index. + * + * @param list the list to retrieve the element from + * @param index index of the element to return + * @return the element at the specified index or NULL, if the + * index is greater than the list size + */ +UcxList *ucx_list_get(const UcxList *list, int index); + +/** + * Returns the index of an element. + * + * @param list the list where to search for the element + * @param elem the element to find + * @return the index of the element or -1 if the list does not contain the + * element + */ +ssize_t ucx_list_indexof(const UcxList *list, const UcxList *elem); + +/** + * Returns the element count of the list. + * + * @param list the list whose elements are counted + * @return the element count + */ +size_t ucx_list_size(const UcxList *list); + +/** + * Returns the index of an element containing the specified data. + * + * This function uses a cmp_func() to compare the data of each list element + * with the specified data. If no cmp_func is provided, the pointers are + * compared. + * + * If the list contains the data more than once, the index of the first + * occurrence is returned. + * + * @param list the list where to search for the data + * @param elem the element data + * @param cmpfnc the compare function + * @param data additional data for the compare function + * @return the index of the element containing the specified data or -1 if the + * data is not found in this list + */ +ssize_t ucx_list_find(UcxList *list, void *elem, cmp_func cmpfnc, void *data); + +/** + * Checks, if a list contains a specific element. + * + * An element is found, if ucx_list_find() returns a value greater than -1. + * + * @param list the list where to search for the data + * @param elem the element data + * @param cmpfnc the compare function + * @param data additional data for the compare function + * @return 1, if and only if the list contains the specified element data + * @see ucx_list_find() + */ +int ucx_list_contains(UcxList *list, void *elem, cmp_func cmpfnc, void *data); + +/** + * Sorts an UcxList with natural merge sort. + * + * This function uses O(n) additional temporary memory for merge operations + * that is automatically freed after each merge. + * + * As the head of the list might change, you MUST call this function + * as follows: mylist = ucx_list_sort(mylist, mycmpfnc, mydata);. + * + * @param list the list to sort + * @param cmpfnc the function that shall be used to compare the element data + * @param data additional data for the cmp_func() + * @return the sorted list + */ +UcxList *ucx_list_sort(UcxList *list, cmp_func cmpfnc, void *data); + +/** + * Removes an element from the list. + * + * If the first element is removed, the list pointer changes. So it is + * highly recommended to always update the pointer by calling + * mylist = ucx_list_remove(mylist, myelem);. + * + * @param list the list from which the element shall be removed + * @param element the element to removed + * @return returns the updated list pointer or NULL, if the list + * is now empty + */ +UcxList *ucx_list_remove(UcxList *list, UcxList *element); + +/** + * Removes an element from the list using an UcxAllocator. + * + * See ucx_list_remove() for details. + * + * @param allocator the allocator to use + * @param list the list from which the element shall be removed + * @param element the element to removed + * @return returns the updated list pointer or NULL, if the list + * @see ucx_list_remove() + */ +UcxList *ucx_list_remove_a(UcxAllocator *allocator, UcxList *list, + UcxList *element); + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_LIST_H */ + diff -r 279f343bbf6c -r fac51f87def0 src/ucx/logging.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/logging.c Sun Sep 08 23:27:07 2013 +0200 @@ -0,0 +1,108 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 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 "logging.h" +#include +#include +#include +#include + +UcxLogger *ucx_logger_new(void *stream, unsigned int level, unsigned int mask) { + UcxLogger *logger = (UcxLogger*) malloc(sizeof(UcxLogger)); + if (logger != NULL) { + logger->stream = stream; + logger->writer = (write_func)fwrite; + logger->dateformat = (char*) "%F %T %z "; + logger->level = level; + logger->mask = mask; + logger->levels = ucx_map_new(8); + + unsigned int l; + l = UCX_LOGGER_ERROR; + ucx_map_int_put(logger->levels, l, (void*) "[ERROR]"); + l = UCX_LOGGER_WARN; + ucx_map_int_put(logger->levels, l, (void*) "[WARNING]"); + l = UCX_LOGGER_INFO; + ucx_map_int_put(logger->levels, l, (void*) "[INFO]"); + l = UCX_LOGGER_TRACE; + ucx_map_int_put(logger->levels, l, (void*) "[TRACE]"); + } + + return logger; +} + +void ucx_logger_free(UcxLogger *logger) { + ucx_map_free(logger->levels); + free(logger); +} + +// estimated max. message length (documented) +#define UCX_LOGGER_MSGMAX 4096 + +void ucx_logger_logf(UcxLogger *logger, unsigned int level, const char* file, + const unsigned int line, const char *format, ...) { + if (level <= logger->level) { + char msg[UCX_LOGGER_MSGMAX]; + char *text; + size_t k = 0; + size_t n; + + if ((logger->mask & UCX_LOGGER_LEVEL) > 0) { + text = (char*) ucx_map_int_get(logger->levels, level); + n = strlen(text); + memcpy(msg+k, text, n); + k += n; + msg[k++] = ' '; + } + if ((logger->mask & UCX_LOGGER_TIMESTAMP) > 0) { + time_t now = time(NULL); + k += strftime(msg+k, 128, logger->dateformat, localtime(&now)); + } + if ((logger->mask & UCX_LOGGER_SOURCE) > 0) { + n = strlen(file); + memcpy(msg+k, file, n); + k += n; +#ifdef _WIN32 + k += _snprintf(msg+k, UCX_LOGGER_MSGMAX-k, ":%d ", line); +#else + k += snprintf(msg+k, UCX_LOGGER_MSGMAX-k, ":%d ", line); +#endif /* _WIN32 */ + } + + msg[k++] = '-'; msg[k++] = ' '; + + va_list args; + va_start (args, format); + k += vsnprintf(msg+k, UCX_LOGGER_MSGMAX-k-1, format, args); + va_end (args); + + msg[k++] = '\n'; + + logger->writer(msg, 1, k, logger->stream); + } +} diff -r 279f343bbf6c -r fac51f87def0 src/ucx/logging.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/logging.h Sun Sep 08 23:27:07 2013 +0200 @@ -0,0 +1,237 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 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. + */ +/** + * Logging API. + * + * @file logging.h + * @author Mike Becker, Olaf Wintermann + */ +#ifndef UCX_LOGGING_H +#define UCX_LOGGING_H + +#include "ucx.h" +#include "map.h" +#include "string.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/* leave enough space for custom log levels */ + +/** Log level for error messages. */ +#define UCX_LOGGER_ERROR 0x00 + +/** Log level for warning messages. */ +#define UCX_LOGGER_WARN 0x10 + +/** Log level for information messages. */ +#define UCX_LOGGER_INFO 0x20 + +/** Log level for debug messages. */ +#define UCX_LOGGER_DEBUG 0x30 + +/** Log level for trace messages. */ +#define UCX_LOGGER_TRACE 0x40 + +/** + * Output flag for the log level. + * If this flag is set, the log message will contain the log level. + * @see UcxLogger.mask + */ +#define UCX_LOGGER_LEVEL 0x01 + +/** + * Output flag for the timestmap. + * If this flag is set, the log message will contain the timestmap. + * @see UcxLogger.mask + */ +#define UCX_LOGGER_TIMESTAMP 0x02 + +/** + * Output flag for the source. + * If this flag is set, the log message will contain the source file and line + * number. + * @see UcxLogger.mask + */ +#define UCX_LOGGER_SOURCE 0x04 + +/** + * The UCX Logger object. + */ +typedef struct { + /** The stream this logger writes its messages to.*/ + void *stream; + + /** + * The write function that shall be used. + * For standard file or stdout loggers this might be standard fwrite + * (default). + */ + write_func writer; + + /** + * The date format for timestamp outputs + * (default: "%F %T %z "). + * @see UCX_LOGGER_TIMESTAMP + */ + char *dateformat; + + /** + * The level, this logger operates on. + * If a log command is issued, the message will only be logged, if the log + * level of the message is less or equal than the log level of the logger. + */ + unsigned int level; + + /** + * A configuration mask for automatic output. + * For each flag that is set, the logger automatically outputs some extra + * information like the timestamp or the source file and line number. + * See the documentation for the flags for details. + */ + unsigned int mask; + + /** + * A map of valid log levels for this logger. + * + * The keys represent all valid log levels and the values provide string + * representations, that are used, if the UCX_LOGGER_LEVEL flag is set. + * + * The exact data types are unsigned int for the key and + * const char* for the value. + * + * @see UCX_LOGGER_LEVEL + */ + UcxMap* levels; +} UcxLogger; + +/** + * Creates a new logger. + * @param stream the stream, which the logger shall write to + * @param level the level on which the logger shall operate + * @param mask configuration mask (cf. UcxLogger.mask) + * @return a new logger object + */ +UcxLogger *ucx_logger_new(void *stream, unsigned int level, unsigned int mask); + +/** + * Destroys the logger. + * + * The map containing the valid log levels is also automatically destroyed. + * + * @param logger the logger to destroy + */ +void ucx_logger_free(UcxLogger* logger); + +/** + * Internal log function - use macros instead. + * + * This function uses the format and variadic arguments for a + * printf()-style output of the log message. + * + * Dependent on the UcxLogger.mask some information is prepended. The complete + * format is: + * + * [LEVEL] [TIMESTAMP] [SOURCEFILE]:[LINENO] message + * + * Attention: the message (including automatically generated information) + * MUST NOT exceed the size of 4 KB. + * + * @param logger the logger to use + * @param level the level to log on + * @param file information about the source file + * @param line information about the source line number + * @param format format string + * @param ... arguments + * @see ucx_logger_log() + */ +void ucx_logger_logf(UcxLogger *logger, unsigned int level, const char* file, + const unsigned int line, const char* format, ...); + +/** + * Logs a message at the specified level. + * @param logger the logger to use + * @param level the level to log the message on + * @param ... format string and arguments + * @see ucx_logger_logf() + */ +#define ucx_logger_log(logger, level, ...) \ + ucx_logger_logf(logger, level, __FILE__, __LINE__, __VA_ARGS__) + +/** + * Shortcut for logging an error message. + * @param logger the logger to use + * @param ... format string and arguments + * @see ucx_logger_logf() + */ +#define ucx_logger_error(logger, ...) \ + ucx_logger_log(logger, UCX_LOGGER_ERROR, __VA_ARGS__) + +/** + * Shortcut for logging an information message. + * @param logger the logger to use + * @param ... format string and arguments + * @see ucx_logger_logf() + */ +#define ucx_logger_info(logger, ...) \ + ucx_logger_log(logger, UCX_LOGGER_INFO, __VA_ARGS__) + +/** + * Shortcut for logging a warning message. + * @param logger the logger to use + * @param ... format string and arguments + * @see ucx_logger_logf() + */ +#define ucx_logger_warn(logger, ...) \ + ucx_logger_log(logger, UCX_LOGGER_WARN, __VA_ARGS__) + +/** + * Shortcut for logging a debug message. + * @param logger the logger to use + * @param ... format string and arguments + * @see ucx_logger_logf() + */ +#define ucx_logger_debug(logger, ...) \ + ucx_logger_log(logger, UCX_LOGGER_DEBUG, __VA_ARGS__) + +/** + * Shortcut for logging a trace message. + * @param logger the logger to use + * @param ... format string and arguments + * @see ucx_logger_logf() + */ +#define ucx_logger_trace(logger, ...) \ + ucx_logger_log(logger, UCX_LOGGER_TRACE, __VA_ARGS__) + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_LOGGING_H */ diff -r 279f343bbf6c -r fac51f87def0 src/ucx/map.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/map.c Sun Sep 08 23:27:07 2013 +0200 @@ -0,0 +1,315 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 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 +#include + +#include "map.h" + +UcxMap *ucx_map_new(size_t size) { + return ucx_map_new_a(NULL, size); +} + +UcxMap *ucx_map_new_a(UcxAllocator *allocator, size_t size) { + if(size == 0) { + size = 16; + } + + if(!allocator) { + allocator = ucx_default_allocator(); + } + + UcxMap *map = (UcxMap*)allocator->malloc(allocator->pool, sizeof(UcxMap)); + if (!map) { + return NULL; + } + + map->allocator = allocator; + map->map = (UcxMapElement**)allocator->calloc( + allocator->pool, + size, + sizeof(UcxMapElement*)); + if(map->map == NULL) { + allocator->free(allocator->pool, map); + return NULL; + } + map->size = size; + map->count = 0; + + return map; +} + +static 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; + map->allocator->free(map->allocator->pool, elem->key.data); + map->allocator->free(map->allocator->pool, elem); + elem = next; + } while (elem != NULL); + } + } + map->allocator->free(map->allocator->pool, map->map); +} + +void ucx_map_free(UcxMap *map) { + ucx_map_free_elmlist(map); + map->allocator->free(map->allocator->pool, 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(key, value, i) { + if (ucx_map_put(to, key, fnc ? fnc(value, data) : value)) { + 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) { + 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; + oldmap.allocator = map->allocator; + + map->size = (map->count * 5) >> 1; + map->map = (UcxMapElement**)map->allocator->calloc( + map->allocator->pool, + map->size, + sizeof(UcxMapElement*)); + if (!map->map) { + *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) { + UcxAllocator *allocator = map->allocator; + + 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 && elm->key.hash < key.hash) { + prev = elm; + elm = elm->next; + } + + if (!elm || elm->key.hash != key.hash) { + UcxMapElement *e = (UcxMapElement*)allocator->malloc( + allocator->pool, + sizeof(UcxMapElement)); + if (!e) { + 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) { + void *kd = allocator->malloc(allocator->pool, key.len); + if (!kd) { + 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; + } + map->allocator->free(map->allocator->pool, elm->key.data); + map->allocator->free(map->allocator->pool, 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, UcxKey *key, void **elm) { + UcxMapElement *e = i->cur; + + if (e) { + e = e->next; + } else { + e = i->map->map[0]; + } + + while (i->index < i->map->size) { + if (e) { + if (e->data) { + i->cur = e; + *elm = e->data; + *key = e->key; + return 1; + } + + e = e->next; + } else { + i->index++; + + if (i->index < i->map->size) { + e = i->map->map[i->index]; + } + } + } + + return 0; +} + diff -r 279f343bbf6c -r fac51f87def0 src/ucx/map.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/map.h Sun Sep 08 23:27:07 2013 +0200 @@ -0,0 +1,392 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 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. + */ + +/** + * @file map.h + * + * Hash map implementation. + * + * This implementation uses murmur hash 2 and separate chaining with linked + * lists. + * + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_MAP_H +#define UCX_MAP_H + +#include "ucx.h" +#include "string.h" +#include "allocator.h" +#include + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * Loop statement for UCX maps. + * + * The key variable is implicitly defined, but the + * value variable must be already declared as type information + * cannot be inferred. + * + * @param key the variable name for the key + * @param value the variable name for the value + * @param iter an UcxMapIterator + * @see ucx_map_iterator() + */ +#define UCX_MAP_FOREACH(key,value,iter) \ + for(UcxKey key;ucx_map_iter_next(&iter,&key, (void**)&value);) + +/** Type for the UCX map. @see UcxMap */ +typedef struct UcxMap UcxMap; + +/** Type for a key of an UcxMap. @see UcxKey */ +typedef struct UcxKey UcxKey; + +/** Type for an element of an UcxMap. @see UcxMapElement */ +typedef struct UcxMapElement UcxMapElement; + +/** Type for an iterator over an UcxMap. @see UcxMapIterator */ +typedef struct UcxMapIterator UcxMapIterator; + +/** Structure for the UCX map. */ +struct UcxMap { + /** An allocator that is used for the map elements. */ + UcxAllocator *allocator; + /** The array of map element lists. */ + UcxMapElement **map; + /** The size of the map is the length of the element list array. */ + size_t size; + /** The count of elements currently stored in this map. */ + size_t count; +}; + +/** Structure for a key of an UcxMap. */ +struct UcxKey { + /** The key data. */ + void *data; + /** The length of the key data. */ + size_t len; + /** The hash value of the key data. */ + int hash; +}; + +/** Structure for an element of an UcxMap. */ +struct UcxMapElement { + /** The value data. */ + void *data; + + /** A pointer to the next element in the current list. */ + UcxMapElement *next; + + /** The corresponding key. */ + UcxKey key; +}; + +/** Structure for an iterator over an UcxMap. */ +struct UcxMapIterator { + /** The map to iterate over. */ + UcxMap *map; + + /** The current map element. */ + UcxMapElement *cur; + + /** + * The current index of the element list array. + * Attention: this is NOT the element index! Do NOT + * manually iterate over the map by increasing this index. Use + * ucx_map_iter_next(). + * @see UcxMap.map*/ + size_t index; +}; + +/** + * Creates a new hash map with the specified size. + * @param size the size of the hash map + * @return a pointer to the new hash map + */ +UcxMap *ucx_map_new(size_t size); + +/** + * Creates a new hash map with the specified size using an UcxAllocator. + * @param allocator the allocator to use + * @param size the size of the hash map + * @return a pointer to the new hash map + */ +UcxMap *ucx_map_new_a(UcxAllocator *allocator, size_t size); + +/** + * Frees a hash map. + * + * Note: the contents are not freed, use an UcxMempool for that + * purpose. + * + * @param map the map to be freed + */ +void ucx_map_free(UcxMap *map); + +/** + * Copies contents from a map to another map using a copy function. + * + * Note: The destination map does not need to be empty. However, if it + * contains data with keys that are also present in the source map, the contents + * are overwritten. + * + * @param from the source map + * @param to the destination map + * @param fnc the copy function or NULL if the pointer address + * shall be copied + * @param data additional data for the copy function + * @return 0 on success or a non-zero value on memory allocation errors + */ +int ucx_map_copy(UcxMap *restrict from, UcxMap *restrict to, + copy_func fnc, void *data); + +/** + * Clones the map and rehashes if necessary. + * + * Note: In contrast to ucx_map_rehash() the load factor is irrelevant. + * This function always ensures a new UcxMap.size of at least + * 2.5*UcxMap.count. + * + * @param map the map to clone + * @param fnc the copy function to use or NULL if the new and + * the old map shall share the data pointers + * @param data additional data for the copy function + * @return the cloned map + * @see ucx_map_copy() + */ +UcxMap *ucx_map_clone(UcxMap *map, copy_func fnc, void *data); + +/** + * Increases size of the hash map, if necessary. + * + * The load value is 0.75*UcxMap.size. If the element count exceeds the load + * value, the map needs to be rehashed. Otherwise no action is performed and + * this function simply returns 0. + * + * The rehashing process ensures, that the UcxMap.size is at least + * 2.5*UcxMap.count. So there is enough room for additional elements without + * the need of another soon rehashing. + * + * You can use this function to dramatically increase access performance. + * + * @param map the map to rehash + * @return 1, if a memory allocation error occurred, 0 otherwise + */ +int ucx_map_rehash(UcxMap *map); + +/** + * Puts a key/value-pair into the map. + * + * @param map the map + * @param key the key + * @param value the value + * @return 0 on success, non-zero value on failure + */ +int ucx_map_put(UcxMap *map, UcxKey key, void *value); + +/** + * Retrieves a value by using a key. + * + * @param map the map + * @param key the key + * @return the value + */ +void* ucx_map_get(UcxMap *map, UcxKey key); + +/** + * Removes a key/value-pair from the map by using the key. + * + * @param map the map + * @param key the key + * @return the removed value + */ +void* ucx_map_remove(UcxMap *map, UcxKey key); + +/** + * Shorthand for putting data with a sstr_t key into the map. + * @param map the map + * @param key the key + * @param value the value + * @return 0 on success, non-zero value on failure + * @see ucx_map_put() + */ +#define ucx_map_sstr_put(map, key, value) \ + ucx_map_put(map, ucx_key(key.ptr, key.length), (void*)value) + +/** + * Shorthand for putting data with a C string key into the map. + * @param map the map + * @param key the key + * @param value the value + * @return 0 on success, non-zero value on failure + * @see ucx_map_put() + */ +#define ucx_map_cstr_put(map, key, value) \ + ucx_map_put(map, ucx_key((void*)key, strlen(key)), (void*)value) + +/** + * Shorthand for putting data with an integer key into the map. + * @param map the map + * @param key the key + * @param value the value + * @return 0 on success, non-zero value on failure + * @see ucx_map_put() + */ +#define ucx_map_int_put(map, key, value) \ + ucx_map_put(map, ucx_key((void*)&key, sizeof(key)), (void*)value) + +/** + * Shorthand for getting data from the map with a sstr_t key. + * @param map the map + * @param key the key + * @return the value + * @see ucx_map_get() + */ +#define ucx_map_sstr_get(map, key) \ + ucx_map_get(map, ucx_key(key.ptr, key.length)) + +/** + * Shorthand for getting data from the map with a C string key. + * @param map the map + * @param key the key + * @return the value + * @see ucx_map_get() + */ +#define ucx_map_cstr_get(map, key) \ + ucx_map_get(map, ucx_key((void*)key, strlen(key))) + +/** + * Shorthand for getting data from the map with an integer key. + * @param map the map + * @param key the key + * @return the value + * @see ucx_map_get() + */ +#define ucx_map_int_get(map, key) \ + ucx_map_get(map, ucx_key((void*)&key, sizeof(int))) + +/** + * Shorthand for removing data from the map with a sstr_t key. + * @param map the map + * @param key the key + * @return the removed value + * @see ucx_map_remove() + */ +#define ucx_map_sstr_remove(map, key) \ + ucx_map_remove(map, ucx_key(key.ptr, key.length)) + +/** + * Shorthand for removing data from the map with a C string key. + * @param map the map + * @param key the key + * @return the removed value + * @see ucx_map_remove() + */ +#define ucx_map_cstr_remove(map, key) \ + ucx_map_remove(map, ucx_key((void*)key, strlen(key))) + +/** + * Shorthand for removing data from the map with an integer key. + * @param map the map + * @param key the key + * @return the removed value + * @see ucx_map_remove() + */ +#define ucx_map_int_remove(map, key) \ + ucx_map_remove(map, ucx_key((void*)&key, sizeof(key))) + +/** + * Creates an UcxKey based on the given data. + * + * This function implicitly computes the hash. + * + * @param data the data for the key + * @param len the length of the data + * @return an UcxKey with implicitly computed hash + * @see ucx_hash() + */ +UcxKey ucx_key(void *data, size_t len); + +/** + * Computes a murmur hash-2. + * + * @param data the data to hash + * @param len the length of the data + * @return the murmur hash-2 of the data + */ +int ucx_hash(const char *data, size_t len); + +/** + * Creates an iterator for a map. + * + * Note: An UcxMapIterator iterates over all elements in all element + * lists successively. Therefore the order highly depends on the key hashes and + * may vary under different map sizes. So generally you may NOT rely on + * the iteration order. + * + * Note: The iterator is NOT initialized. You need to call + * ucx_map_iter_next() at least once before accessing any information. However, + * it is not recommended to access the fields of an UcxMapIterator directly. + * + * @param map the map to create the iterator for + * @return an iterator initialized on the first element of the + * first element list + * @see ucx_map_iter_next() + */ +UcxMapIterator ucx_map_iterator(UcxMap *map); + +/** + * Proceeds to the next element of the map (if any). + * + * Subsequent calls on the same iterator proceed to the next element and + * store the key/value-pair into the memory specified as arguments of this + * function. + * + * If no further elements are found, this function returns zero and leaves the + * last found key/value-pair in memory. + * + * @param iterator the iterator to use + * @param key a pointer to the memory where to store the key + * @param value a pointer to the memory where to store the value + * @return 1, if another element was found, 0 if all elements has been processed + * @see ucx_map_iterator() + */ +int ucx_map_iter_next(UcxMapIterator *iterator, UcxKey *key, void **value); + + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_MAP_H */ + diff -r 279f343bbf6c -r fac51f87def0 src/ucx/mempool.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/mempool.c Sun Sep 08 23:27:07 2013 +0200 @@ -0,0 +1,204 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 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 +#include +#include +#ifdef __cplusplus +#define __STDC_FORMAT_MACROS +#endif +#include + +#include "mempool.h" + +/** Capsule for destructible memory chunks. */ +typedef struct { + /** The destructor for the memory chunk. */ + ucx_destructor destructor; + /** + * First byte of the memory chunk. + * Note, that the address &c is also the address + * of the whole memory chunk. + */ + char c; +} ucx_memchunk; + +/** Capsule for data and its destructor. */ +typedef struct { + /** The destructor for the data. */ + ucx_destructor destructor; + /** A pointer to the data. */ + void *ptr; +} ucx_regdestr; + +UCX_EXTERN 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) { + 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) { + pool->data = data; + pool->size = newcap; + return EXIT_SUCCESS; + } else { + return EXIT_FAILURE; + } +} + +void *ucx_mempool_malloc(UcxMempool *pool, size_t n) { + if (pool->ndata >= pool->size) { + // The hard coded 16 is documented for this function and ucx_mempool_new + if (ucx_mempool_chcap(pool, pool->size + 16) == EXIT_FAILURE) { + return NULL; + } + } + + ucx_memchunk *mem = (ucx_memchunk*)malloc(sizeof(ucx_destructor) + n); + if (!mem) { + return NULL; + } + + 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) { + 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) { + return NULL; + } + if (mem != newm) { + for(size_t 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(EXIT_FAILURE); + } else { + return newm + sizeof(ucx_destructor); + } +} + +void ucx_mempool_free(UcxMempool *pool, void *ptr) { + ucx_memchunk *chunk = (ucx_memchunk*)((char*)ptr-sizeof(ucx_destructor)); + for(size_t i=0 ; indata ; i++) { + if(chunk == pool->data[i]) { + if(chunk->destructor != NULL) { + chunk->destructor(&(chunk->c)); + } + free(chunk); + size_t last_index = pool->ndata - 1; + if(i != last_index) { + pool->data[i] = pool->data[last_index]; + pool->data[last_index] = NULL; + } + pool->ndata--; + return; + } + } + fprintf(stderr, "FATAL: 0x%08" PRIxPTR" not in mpool 0x%08" PRIxPTR"\n", + (intptr_t)ptr, (intptr_t)pool); + exit(EXIT_FAILURE); +} + +void ucx_mempool_destroy(UcxMempool *pool) { + ucx_memchunk *chunk; + for(size_t i=0 ; indata ; i++) { + chunk = (ucx_memchunk*) pool->data[i]; + if(chunk) { + if(chunk->destructor) { + 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); +} + +UcxAllocator* ucx_mempool_allocator(UcxMempool *pool) { + UcxAllocator *allocator = (UcxAllocator*)ucx_mempool_malloc( + pool, sizeof(UcxAllocator)); + if(!allocator) { + return NULL; + } + allocator->malloc = (ucx_allocator_malloc)ucx_mempool_malloc; + allocator->calloc = (ucx_allocator_calloc)ucx_mempool_calloc; + allocator->realloc = (ucx_allocator_realloc)ucx_mempool_realloc; + allocator->free = (ucx_allocator_free)ucx_mempool_free; + allocator->pool = pool; + return allocator; +} diff -r 279f343bbf6c -r fac51f87def0 src/ucx/mempool.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/mempool.h Sun Sep 08 23:27:07 2013 +0200 @@ -0,0 +1,226 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 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. + */ + +/** + * @file mempool.h + * + * Memory pool implementation. + * + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_MEMPOOL_H +#define UCX_MEMPOOL_H + +#include "ucx.h" +#include +#include "allocator.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * A function pointer to a destructor function. + * @see ucx_mempool_setdestr() + * @see ucx_mempool_regdestr() + */ +typedef void(*ucx_destructor)(void*); + +/** + * UCX mempool structure. + */ +typedef struct { + /** List of pointers to pooled memory. */ + void **data; + + /** Count of pooled memory items. */ + size_t ndata; + + /** Memory pool size. */ + size_t size; +} UcxMempool; + +/** Shorthand for a new default memory pool with a capacity of 16 elements. */ +#define ucx_mempool_new_default() ucx_mempool_new(16) + + +/** + * Creates a memory pool with the specified initial size. + * + * As the created memory pool automatically grows in size by 16 elements, when + * trying to allocate memory on a full pool, it is recommended that you use + * a multiple of 16 for the initial size. + * + * @param n initial pool size (should be a multiple of 16) + * @return a pointer to the new memory pool + */ +UcxMempool *ucx_mempool_new(size_t n); + +/** + * Resizes a memory pool. + * + * @param pool the pool to resize + * @param newcap the new capacity + * @return EXIT_SUCCESS on success or + * EXIT_FAILURE on failure + */ +int ucx_mempool_chcap(UcxMempool *pool, size_t newcap); + +/** + * Changes the pool size to the next smallest multiple of 16. + * + * You may use this macro, to reduce the pool size after freeing + * many pooled memory items. + * + * @param pool the pool to clamp + * @return EXIT_SUCCESS on success or + * EXIT_FAILURE on failure + */ +#define ucx_mempool_clamp(pool) ucx_mempool_chcap(pool, \ + (pool->ndata & ~0xF)+0x10) + +/** + * Allocates pooled memory. + * + * @param pool the memory pool + * @param n amount of memory to allocate + * @return a pointer to the allocated memory + * @see ucx_allocator_malloc() + */ +void *ucx_mempool_malloc(UcxMempool *pool, size_t n); +/** + * Allocates a pooled memory array. + * + * The contents of the allocated memory is set to zero. + * + * @param pool the memory pool + * @param nelem amount of elements to allocate + * @param elsize amount of memory per element + * @return a pointer to the allocated memory + * @see ucx_allocator_calloc() + */ +void *ucx_mempool_calloc(UcxMempool *pool, size_t nelem, size_t elsize); + +/** + * Reallocates pooled memory. + * + * If the memory to be reallocated is not contained by the specified pool, this + * function will possibly fail. In case the memory had to be moved to another + * location, this function will print out a message to stderr + * and exit the program with error code EXIT_FAILURE. + * + * @param pool the memory pool + * @param ptr a pointer to the memory that shall be reallocated + * @param n the new size of the memory + * @return a pointer to the the location of the memory + * @see ucx_allocator_realloc() + */ +void *ucx_mempool_realloc(UcxMempool *pool, void *ptr, size_t n); + +/** + * Frees pooled memory. + * + * Before freeing the memory, the specified destructor function (if any) + * is called. + * + * If you specify memory, that is not pooled by the specified memory pool, this + * is considered as a severe error and an error message is written to + * stderr and the application is shut down with code + * EXIT_FAILURE. + * + * @param pool the memory pool + * @param ptr a pointer to the memory that shall be freed + * @see ucx_mempool_set_destr() + */ +void ucx_mempool_free(UcxMempool *pool, void *ptr); + +/** + * Destroys a memory pool. + * + * For each element the destructor function (if any) is called and the element + * is freed. + * + * Each of the registered destructor function that has no corresponding element + * within the pool (namely those registered by ucx_mempool_reg_destr) is + * called interleaving with the element destruction, but with guarantee to the + * order in which they were registered (FIFO order). + * + * + * @param pool the mempool to destroy + */ +void ucx_mempool_destroy(UcxMempool *pool); + +/** + * Sets a destructor function for the specified memory. + * + * The destructor is automatically called when the memory is freed or the + * pool is destroyed. + * + * The only requirement for the specified memory is, that it MUST be + * pooled memory by an UcxMempool or an element-compatible mempool. The pointer + * to the destructor function is saved in a reserved area before the actual + * memory. + * + * @param ptr pooled memory + * @param func a pointer to the destructor function + * @see ucx_mempool_free() + * @see ucx_mempool_destroy() + */ +void ucx_mempool_set_destr(void *ptr, ucx_destructor func); + +/** + * Registers a destructor function for the specified (non-pooled) memory. + * + * This is useful, if you have memory that has not been allocated by a mempool, + * but shall be managed by a mempool. + * + * This function creates an entry in the specified mempool and the memory will + * therefore (logically) convert to pooled memory. + * + * @param pool the memory pool + * @param ptr data the destructor is registered for + * @param destr a pointer to the destructor function + */ +void ucx_mempool_reg_destr(UcxMempool *pool, void *ptr, ucx_destructor destr); + +/** + * Creates an UcxAllocator based on an UcxMempool. + * + * @param pool the mempool to create the UcxAllocator for + * @return a new UcxAllocator based on the specified pool + */ +UcxAllocator* ucx_mempool_allocator(UcxMempool *pool); + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_MEMPOOL_H */ + diff -r 279f343bbf6c -r fac51f87def0 src/ucx/properties.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/properties.c Sun Sep 08 23:27:07 2013 +0200 @@ -0,0 +1,264 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 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 +#include +#include + +#include "properties.h" + +UcxProperties *ucx_properties_new() { + UcxProperties *parser = (UcxProperties*)malloc( + sizeof(UcxProperties)); + if(!parser) { + return NULL; + } + + parser->buffer = NULL; + parser->buflen = 0; + parser->pos = 0; + parser->tmp = NULL; + parser->tmplen = 0; + parser->tmpcap = 0; + parser->error = 0; + parser->delimiter = '='; + parser->comment1 = '#'; + parser->comment2 = 0; + parser->comment3 = 0; + + return parser; +} + +void ucx_properties_free(UcxProperties *parser) { + if(parser->tmp) { + free(parser->tmp); + } + free(parser); +} + +void ucx_properties_fill(UcxProperties *parser, char *buf, size_t len) { + parser->buffer = buf; + parser->buflen = len; + parser->pos = 0; +} + +static void parser_tmp_append(UcxProperties *parser, char *buf, size_t len) { + if(parser->tmpcap - parser->tmplen < len) { + size_t newcap = parser->tmpcap + len + 64; + parser->tmp = (char*)realloc(parser->tmp, newcap); + parser->tmpcap = newcap; + } + memcpy(parser->tmp + parser->tmplen, buf, len); + parser->tmplen += len; +} + +int ucx_properties_next(UcxProperties *parser, sstr_t *name, sstr_t *value) { + if(parser->tmplen > 0) { + char *buf = parser->buffer + parser->pos; + size_t len = parser->buflen - parser->pos; + sstr_t str = sstrn(buf, len); + sstr_t nl = sstrchr(str, '\n'); + if(nl.ptr) { + size_t newlen = (size_t)(nl.ptr - buf) + 1; + parser_tmp_append(parser, buf, newlen); + // the tmp buffer contains exactly one line now + + char *orig_buf = parser->buffer; + size_t orig_len = parser->buflen; + + parser->buffer = parser->tmp; + parser->buflen = parser->tmplen; + parser->pos = 0; + parser->tmp = NULL; + parser->tmpcap = 0; + parser->tmplen = 0; + // run ucx_properties_next with the tmp buffer as main buffer + int ret = ucx_properties_next(parser, name, value); + + // restore original buffer + parser->tmp = parser->buffer; + parser->buffer = orig_buf; + parser->buflen = orig_len; + parser->pos = newlen; + + /* + * if ret == 0 the tmp buffer contained just space or a comment + * we parse again with the original buffer to get a name/value + * or a new tmp buffer + */ + return ret ? ret : ucx_properties_next(parser, name, value); + } else { + parser_tmp_append(parser, buf, len); + return 0; + } + } else if(parser->tmp) { + free(parser->tmp); + parser->tmp = NULL; + } + + char comment1 = parser->comment1; + char comment2 = parser->comment2; + char comment3 = parser->comment3; + char delimiter = parser->delimiter; + + // get one line and parse it + while(parser->pos < parser->buflen) { + char *buf = parser->buffer + parser->pos; + size_t len = parser->buflen - parser->pos; + + /* + * First we check if we have at least one line. We also get indices of + * delimiter and comment chars + */ + size_t delimiter_index = 0; + size_t comment_index = 0; + int has_comment = 0; + + size_t i = 0; + char c = 0; + for(;itmpcap = len + 128; + parser->tmp = (char*)malloc(parser->tmpcap); + parser->tmplen = len; + memcpy(parser->tmp, buf, len); + return 0; + } + + sstr_t line = has_comment ? sstrn(buf, comment_index) : sstrn(buf, i); + // check line + if(delimiter_index == 0) { + line = sstrtrim(line); + if(line.length != 0) { + parser->error = 1; + } + } else { + sstr_t n = sstrn(buf, delimiter_index); + sstr_t v = sstrn( + buf + delimiter_index + 1, + line.length - delimiter_index - 1); + n = sstrtrim(n); + v = sstrtrim(v); + if(n.length != 0 || v.length != 0) { + *name = n; + *value = v; + parser->pos += i + 1; + return 1; + } else { + parser->error = 1; + } + } + + parser->pos += i + 1; + } + + return 0; +} + +int ucx_properties2map(UcxProperties *parser, UcxMap *map) { + sstr_t name; + sstr_t value; + while(ucx_properties_next(parser, &name, &value)) { + value = sstrdup_a(map->allocator, value); + if(!value.ptr) { + return 1; + } + if(ucx_map_sstr_put(map, name, value.ptr)) { + map->allocator->free(map->allocator->pool, value.ptr); + return 1; + } + } + if (parser->error) { + return parser->error; + } else { + return 0; + } +} + +// buffer size is documented - change doc, when you change bufsize! +#define UCX_PROPLOAD_BUFSIZE 1024 +int ucx_properties_load(UcxMap *map, FILE *file) { + UcxProperties *parser = ucx_properties_new(); + if(!(parser && map && file)) { + return 1; + } + + int error = 0; + size_t r; + char buf[UCX_PROPLOAD_BUFSIZE]; + while((r = fread(buf, 1, UCX_PROPLOAD_BUFSIZE, file)) != 0) { + ucx_properties_fill(parser, buf, r); + error = ucx_properties2map(parser, map); + if (error) { + break; + } + } + ucx_properties_free(parser); + return error; +} + +int ucx_properties_store(UcxMap *map, FILE *file) { + UcxMapIterator iter = ucx_map_iterator(map); + void *v; + sstr_t value; + size_t written; + + UCX_MAP_FOREACH(k, v, iter) { + value = sstr((char*)v); + + written = 0; + written += fwrite(k.data, 1, k.len, file); + written += fwrite(" = ", 1, 3, file); + written += fwrite(value.ptr, 1, value.length, file); + written += fwrite("\n", 1, 1, file); + + if (written != k.len + value.length + 4) { + return 1; + } + } + + return 0; +} + diff -r 279f343bbf6c -r fac51f87def0 src/ucx/properties.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/properties.h Sun Sep 08 23:27:07 2013 +0200 @@ -0,0 +1,220 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 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. + */ +/** + * @file properties.h + * + * Load / store utilities for properties files. + * + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_PROPERTIES_H +#define UCX_PROPERTIES_H + +#include "ucx.h" +#include "map.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * UcxProperties object for parsing properties data. + * Most of the fields are for internal use only. You may configure the + * properties parser, e.g. by changing the used delimiter or specifying + * up to three different characters that shall introduce comments. + */ +typedef struct { + /** + * Input buffer (don't set manually). + * Automatically set by calls to ucx_properties_fill(). + */ + char *buffer; + + /** + * Length of the input buffer (don't set manually). + * Automatically set by calls to ucx_properties_fill(). + */ + size_t buflen; + + /** + * Current buffer position (don't set manually). + * Used by ucx_properties_next(). + */ + size_t pos; + + /** + * Internal temporary buffer (don't set manually). + * Used by ucx_properties_next(). + */ + char *tmp; + + /** + * Internal temporary buffer length (don't set manually). + * Used by ucx_properties_next(). + */ + size_t tmplen; + + /** + * Internal temporary buffer capacity (don't set manually). + * Used by ucx_properties_next(). + */ + size_t tmpcap; + + /** + * Parser error code. + * This is always 0 on success and a nonzero value on syntax errors. + * The value is set by ucx_properties_next(). + */ + int error; + + /** + * The delimiter that shall be used. + * This is '=' by default. + */ + char delimiter; + + /** + * The first comment character. + * This is '#' by default. + */ + char comment1; + + /** + * The second comment character. + * This is not set by default. + */ + char comment2; + + /** + * The third comment character. + * This is not set by default. + */ + char comment3; +} UcxProperties; + + +/** + * Constructs a new UcxProperties object. + * @return a pointer to the new UcxProperties object + */ +UcxProperties *ucx_properties_new(); + +/** + * Destroys an UcxProperties object. + * @param prop the UcxProperties object to destroy + */ +void ucx_properties_free(UcxProperties *prop); + +/** + * Sets the input buffer for the properties parser. + * + * After calling this function, you may parse the data by calling + * ucx_properties_next() until it returns 0. The function ucx_properties2map() + * is a convenience function that performs these successive calls of + * ucx_properties_next() within a while loop and puts the properties to a map. + * + * + * @param prop the UcxProperties object + * @param buf a pointer to the new buffer + * @param len the payload length of the buffer + * @see ucx_properties_next() + * @see ucx_properties2map() + */ +void ucx_properties_fill(UcxProperties *prop, char *buf, size_t len); + +/** + * Retrieves the next key/value-pair. + * + * This function returns a nonzero value as long as there are key/value-pairs + * found. If no more key/value-pairs are found, you may refill the input buffer + * with ucx_properties_fill(). + * + * Attention: the sstr_t.ptr pointers of the output parameters point to + * memory within the input buffer of the parser and will get invalid some time. + * If you want long term copies of the key/value-pairs, use sstrdup() after + * calling this function. + * + * @param prop the UcxProperties object + * @param name a pointer to the sstr_t that shall contain the property name + * @param value a pointer to the sstr_t that shall contain the property value + * @return Nonzero, if a key/value-pair was successfully retrieved + * @see ucx_properties_fill() + */ +int ucx_properties_next(UcxProperties *prop, sstr_t *name, sstr_t *value); + +/** + * Retrieves all available key/value-pairs and puts them into an UcxMap. + * + * This is done by successive calls to ucx_properties_next() until no more + * key/value-pairs can be retrieved. + * + * @param prop the UcxProperties object + * @param map the target map + * @return The UcxProperties.error code (i.e. 0 on success). + * @see ucx_properties_fill() + */ +int ucx_properties2map(UcxProperties *prop, UcxMap *map); + +/** + * Loads a properties file to an UcxMap. + * + * This is a convenience function that reads chunks of 1 KB from an input + * stream until the end of the stream is reached. + * + * An UcxProperties object is implicitly created and destroyed. + * + * @param map the map object to write the key/value-pairs to + * @param file the FILE* stream to read from + * @return 0 on success, or a non-zero value on error + * + * @see ucx_properties_fill() + * @see ucx_properties2map() + */ +int ucx_properties_load(UcxMap *map, FILE *file); + +/** + * Stores an UcxMap to a file. + * + * The key/value-pairs are written by using the following format: + * + * [key] = [value]\\n + * + * @param map the map to store + * @param file the FILE* stream to write to + * @return 0 on success, or a non-zero value on error + */ +int ucx_properties_store(UcxMap *map, FILE *file); + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_PROPERTIES_H */ + diff -r 279f343bbf6c -r fac51f87def0 src/ucx/string.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/string.c Sun Sep 08 23:27:07 2013 +0200 @@ -0,0 +1,313 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 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 +#include +#include + +#include "string.h" +#include "allocator.h" + +sstr_t sstr(char *cstring) { + sstr_t string; + string.ptr = cstring; + string.length = strlen(cstring); + return string; +} + +sstr_t sstrn(char *cstring, size_t length) { + sstr_t string; + string.ptr = cstring; + string.length = length; + return string; +} + +size_t sstrnlen(size_t n, sstr_t s, ...) { + va_list ap; + size_t size = s.length; + va_start(ap, s); + + for (size_t i = 1 ; i < n ; i++) { + sstr_t str = va_arg(ap, sstr_t); + size += str.length; + } + va_end(ap); + + return size; +} + +sstr_t sstrncat(sstr_t s, size_t n, 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 (size_t i = 1 ; i < n ; 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); + s.length = ptr - s.ptr; + + 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 >= s.length) { + 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 sstrchr(sstr_t s, int c) { + for(size_t i=0;i 0) { + for(size_t i=s.length;i>0;i--) { + if(s.ptr[i-1] == c) { + return sstrsubs(s, i-1); + } + } + } + sstr_t n; + n.ptr = NULL; + n.length = 0; + return n; +} + +sstr_t* sstrsplit(sstr_t s, sstr_t d, size_t *n) { + return sstrsplit_a(ucx_default_allocator(), s, d, n); +} + +sstr_t* sstrsplit_a(UcxAllocator *allocator, sstr_t s, sstr_t d, size_t *n) { + if (s.length == 0 || d.length == 0) { + *n = -1; + return NULL; + } + + sstr_t* result; + size_t nmax = *n; + *n = 1; + + /* special case: exact match - no processing needed */ + if (sstrcmp(s, d) == 0) { + *n = 0; + return NULL; + } + sstr_t sv = sstrdup(s); + if (sv.length == 0) { + *n = -2; + return NULL; + } + + for (size_t i = 0 ; i < s.length ; i++) { + if (sv.ptr[i] == d.ptr[0]) { + _Bool match = 1; + for (size_t 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 (size_t j = 0 ; j < d.length ; j++) { + sv.ptr[i+j] = 0; + } + i += d.length; + } + } + if ((*n) == nmax) break; + } + result = (sstr_t*) allocator->malloc(allocator->pool, sizeof(sstr_t)*(*n)); + + if (result) { + char *pptr = sv.ptr; + for (size_t i = 0 ; i < *n ; i++) { + size_t l = strlen(pptr); + char* ptr = (char*) allocator->malloc(allocator->pool, l + 1); + memcpy(ptr, pptr, l); + ptr[l] = 0; + + result[i] = sstrn(ptr, l); + pptr += l + d.length; + } + } else { + *n = -2; + } + + free(sv.ptr); + + return result; +} + +int sstrcmp(sstr_t s1, sstr_t s2) { + if (s1.length == s2.length) { + return memcmp(s1.ptr, s2.ptr, s1.length); + } else if (s1.length > s2.length) { + return 1; + } else { + return -1; + } +} + +int sstrcasecmp(sstr_t s1, sstr_t s2) { + if (s1.length == s2.length) { +#ifdef _WIN32 + return _strnicmp(s1.ptr, s2.ptr, s1.length); +#else + return strncasecmp(s1.ptr, s2.ptr, s1.length); +#endif + } else if (s1.length > s2.length) { + return 1; + } else { + return -1; + } +} + +sstr_t sstrdup(sstr_t s) { + return sstrdup_a(ucx_default_allocator(), s); +} + +sstr_t sstrdup_a(UcxAllocator *allocator, sstr_t s) { + sstr_t newstring; + newstring.ptr = (char*)allocator->malloc(allocator->pool, s.length + 1); + if (newstring.ptr) { + newstring.length = s.length; + newstring.ptr[newstring.length] = 0; + + memcpy(newstring.ptr, s.ptr, s.length); + } else { + newstring.length = 0; + } + + return newstring; +} + +sstr_t sstrtrim(sstr_t string) { + sstr_t newstr = string; + if (string.length == 0) { + return newstr; + } + + size_t i; + for(i=0;i 32) { + break; + } + } + newstr.ptr = &string.ptr[i]; + newstr.length = string.length - i; + + if(newstr.length == 0) { + return newstr; + } + + i = newstr.length - 1; + for(;;) { + char c = newstr.ptr[i]; + if(c > 32) { + break; + } + if(i > 0) { + i--; + } else { + break; + } + } + newstr.length = i + 1; + + return newstr; +} + +int sstrprefix(sstr_t string, sstr_t prefix) { + if (string.length == 0) { + return prefix.length == 0; + } + if (prefix.length == 0) { + return 1; + } + + if (prefix.length > string.length) { + return 0; + } else { + return memcmp(string.ptr, prefix.ptr, prefix.length) == 0; + } +} + +int sstrsuffix(sstr_t string, sstr_t suffix) { + if (string.length == 0) { + return suffix.length == 0; + } + if (suffix.length == 0) { + return 1; + } + + if (suffix.length > string.length) { + return 0; + } else { + return memcmp(string.ptr+string.length-suffix.length, + suffix.ptr, suffix.length) == 0; + } +} diff -r 279f343bbf6c -r fac51f87def0 src/ucx/string.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/string.h Sun Sep 08 23:27:07 2013 +0200 @@ -0,0 +1,392 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 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. + */ +/** + * Bounded string implementation. + * + * The UCX strings (sstr_t) provide an alternative to C strings. + * The main difference to C strings is, that sstr_t does not + * need to be NULL-terminated. Instead the length is stored + * within the structure. + * + * When using sstr_t, developers must be full aware of what type + * of string (NULL-terminated) or not) they are using, when + * accessing the char* ptr directly. + * + * The UCX string module provides some common string functions, known from + * standard libc, working with sstr_t. + * + * @file string.h + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_STRING_H +#define UCX_STRING_H + +#include "ucx.h" +#include "allocator.h" +#include + +/** Shortcut for a sstr_t struct literal. */ +#define ST(s) { (char*)s, sizeof(s)-1 } + +/** Shortcut for the conversion of a C string to a sstr_t. */ +#define S(s) sstrn((char*)s, sizeof(s)-1) + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * The UCX string structure. + */ +typedef struct { + /** A reference to the string (not necessarily NULL + * -terminated) */ + char *ptr; + /** The length of the string */ + size_t length; +} sstr_t; + +/** + * Creates a new sstr_t based on a C string. + * + * The length is implicitly inferred by using a call to strlen(). + * + * Note: the sstr_t will hold a reference to the C string. If you + * do want a copy, use sstrdup() on the return value of this function. + * + * @param cstring the C string to wrap + * @return a new sstr_t containing the C string + * + * @see sstrn() + */ +sstr_t sstr(char *cstring); + +/** + * Creates a new sstr_t of the specified length based on a C string. + * + * Note: the sstr_t will hold a reference to the C string. If you + * do want a copy, use sstrdup() on the return value of this function. + * + * @param cstring the C string to wrap + * @param length the length of the string + * @return a new sstr_t containing the C string + * + * @see sstr() + * @see S() + */ +sstr_t sstrn(char *cstring, size_t length); + + +/** + * Returns the cumulated length of all specified strings. + * + * At least one string must be specified. + * + * Attention: if the count argument does not match the count of the + * specified strings, the behavior is undefined. + * + * @param count the total number of specified strings (so at least 1) + * @param string the first string + * @param ... all other strings + * @return the cumulated length of all strings + */ +size_t sstrnlen(size_t count, sstr_t string, ...); + + +/** + * Concatenates strings. + * + * At least one string must be specified and there must be enough memory + * available referenced by the destination sstr_t.ptr for this function to + * successfully concatenate all specified strings. + * + * The sstr_t.length of the destination string specifies the capacity and + * should match the total memory available referenced by the destination + * sstr_t.ptr. This function never copies data beyond the capacity and + * does not modify any of the source strings. + * + * Attention: + *
    + *
  • Any content in the destination string will be overwritten
  • + *
  • The destination sstr_t.ptr is NOT + * NULL-terminated
  • + *
  • The destination sstr_t.length is set to the total length of the + * concatenated strings
  • + *
  • Hint: get a NULL-terminated string by performing + * mystring.ptr[mystring.length]='\0' after calling this + * function
  • + *
+ * + * @param dest new sstr_t with capacity information and allocated memory + * @param count the total number of strings to concatenate + * @param src the first string + * @param ... all other strings + * @return the argument for dest is returned + */ +sstr_t sstrncat(sstr_t dest, size_t count, sstr_t src, ...); + + +/** + * Returns a substring starting at the specified location. + * + * Attention: the new string references the same memory area as the + * input string and will NOT be NULL-terminated. + * Use sstrdup() to get a copy. + * + * @param string input string + * @param start start location of the substring + * @return a substring of string starting at start + * + * @see sstrsubsl() + * @see sstrchr() + */ +sstr_t sstrsubs(sstr_t string, size_t start); + +/** + * Returns a substring with a maximum length starting at the specified location. + * + * Attention: the new string references the same memory area as the + * input string and will NOT be NULL-terminated. + * Use sstrdup() to get a copy. + * + * @param string input string + * @param start start location of the substring + * @param length the maximum length of the substring + * @return a substring of string starting at start + * with a maximum length of length + * + * @see sstrsubs() + * @see sstrchr() + */ +sstr_t sstrsubsl(sstr_t string, size_t start, size_t length); + +/** + * Returns a substring starting at the location of the first occurrence of the + * specified character. + * + * If the string does not contain the character, an empty string is returned. + * + * @param string the string where to locate the character + * @param chr the character to locate + * @return a substring starting at the first location of chr + * + * @see sstrsubs() + */ +sstr_t sstrchr(sstr_t string, int chr); + +/** + * Returns a substring starting at the location of the last occurrence of the + * specified character. + * + * If the string does not contain the character, an empty string is returned. + * + * @param string the string where to locate the character + * @param chr the character to locate + * @return a substring starting at the last location of chr + * + * @see sstrsubs() + */ +sstr_t sstrrchr(sstr_t string, int chr); + +/** + * Splits a string into parts by using a delimiter string. + * + * This function will return NULL, if one of the following happens: + *
    + *
  • the string length is zero
  • + *
  • the delimeter length is zero
  • + *
  • the string equals the delimeter
  • + *
  • memory allocation fails
  • + *
+ * + * The integer referenced by count is used as input and determines + * the maximum size of the resulting list, i.e. the maximum count of splits to + * perform + 1. + * + * The integer referenced by count is also used as output and is + * set to + *
    + *
  • -2, on memory allocation errors
  • + *
  • -1, if either the string or the delimiter is an empty string
  • + *
  • 0, if the string equals the delimiter
  • + *
  • 1, if the string does not contain the delimiter
  • + *
  • the count of list items, otherwise
  • + *
+ * + * If the string starts with the delimiter, the first item of the resulting + * list will be an empty string. + * + * If the string ends with the delimiter and the maximum list size is not + * exceeded, the last list item will be an empty string. + * + * Attention: All list items AND all sstr_t.ptr of the list + * items must be manually passed to free(). Use sstrsplit_a() with + * an allocator to managed memory, to avoid this. + * + * @param string the string to split + * @param delim the delimiter string + * @param count IN: the maximum size of the resulting list (0 for an + * unbounded list), OUT: the actual size of the list + * @return a list of the split strings as sstr_t array or + * NULL on error + * + * @see sstrsplit_a() + */ +sstr_t* sstrsplit(sstr_t string, sstr_t delim, size_t *count); + +/** + * Performing sstrsplit() using an UcxAllocator. + * + * Read the description of sstrsplit() for details. + * + * The memory for the sstr_t.ptr pointers of the list items and the memory for + * the sstr_t array itself are allocated by using the UcxAllocator.malloc() + * function. + * + * Note: the allocator is not used for memory that is freed within the + * same call of this function (locally scoped variables). + * + * @param allocator the UcxAllocator used for allocating memory + * @param string the string to split + * @param delim the delimiter string + * @param count IN: the maximum size of the resulting list (0 for an + * unbounded list), OUT: the actual size of the list + * @return a list of the split strings as sstr_t array or + * NULL on error + * + * @see sstrsplit() + */ +sstr_t* sstrsplit_a(UcxAllocator *allocator, sstr_t string, sstr_t delim, + size_t *count); + +/** + * Compares two UCX strings with standard memcmp(). + * + * At first it compares the sstr_t.length attribute of the two strings. The + * memcmp() function is called, if and only if the lengths match. + * + * @param s1 the first string + * @param s2 the second string + * @return -1, if the length of s1 is less than the length of s2 or 1, if the + * length of s1 is greater than the length of s2 or the result of + * memcmp() otherwise (i.e. 0 if the strings match) + */ +int sstrcmp(sstr_t s1, sstr_t s2); + +/** + * Compares two UCX strings ignoring the case. + * + * At first it compares the sstr_t.length attribute of the two strings. If and + * only if the lengths match, both strings are compared char by char ignoring + * the case. + * + * @param s1 the first string + * @param s2 the second string + * @return -1, if the length of s1 is less than the length of s2 or 1, if the + * length of s1 is greater than the length of s2 or the difference between the + * first two differing characters otherwise (i.e. 0 if the strings match and + * no characters differ) + */ +int sstrcasecmp(sstr_t s1, sstr_t s2); + +/** + * Creates a duplicate of the specified string. + * + * The new sstr_t will contain a copy allocated by standard + * malloc(). So developers MUST pass the sstr_t.ptr to + * free(). + * + * The sstr_t.ptr of the return value will always be NULL- + * terminated. + * + * @param string the string to duplicate + * @return a duplicate of the string + * @see sstrdup_a() + */ +sstr_t sstrdup(sstr_t string); + +/** + * Creates a duplicate of the specified string using an UcxAllocator. + * + * The new sstr_t will contain a copy allocated by the allocators + * ucx_allocator_malloc function. So it is implementation depended, whether the + * returned sstr_t.ptr pointer must be passed to the allocators + * ucx_allocator_free function manually. + * + * The sstr_t.ptr of the return value will always be NULL- + * terminated. + * + * @param allocator a valid instance of an UcxAllocator + * @param string the string to duplicate + * @return a duplicate of the string + * @see sstrdup() + */ +sstr_t sstrdup_a(UcxAllocator *allocator, sstr_t string); + +/** + * Omits leading and trailing spaces. + * + * This function returns a new sstr_t containing a trimmed version of the + * specified string. + * + * Note: the new sstr_t references the same memory, thus you + * MUST NOT pass the sstr_t.ptr of the return value to + * free(). It is also highly recommended to avoid assignments like + * mystr = sstrtrim(mystr); as you lose the reference to the + * source string. Assignments of this type are only permitted, if the + * sstr_t.ptr of the source string does not need to be freed or if another + * reference to the source string exists. + * + * @param string the string that shall be trimmed + * @return a new sstr_t containing the trimmed string + */ +sstr_t sstrtrim(sstr_t string); + +/** + * Checks, if a string has a specific prefix. + * @param string the string to check + * @param prefix the prefix the string should have + * @return 1, if and only if the string has the specified prefix, 0 otherwise + */ +int sstrprefix(sstr_t string, sstr_t prefix); + +/** + * Checks, if a string has a specific suffix. + * @param string the string to check + * @param suffix the suffix the string should have + * @return 1, if and only if the string has the specified suffix, 0 otherwise + */ +int sstrsuffix(sstr_t string, sstr_t suffix); + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_STRING_H */ diff -r 279f343bbf6c -r fac51f87def0 src/ucx/test.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/test.c Sun Sep 08 23:27:07 2013 +0200 @@ -0,0 +1,91 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 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 "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) { + UcxTestList *l = suite->tests; + while (l != NULL) { + UcxTestList *e = l; + l = l->next; + free(e); + } + free(suite); +} + +int ucx_test_register(UcxTestSuite* suite, UcxTest test) { + if (suite->tests) { + UcxTestList *newelem = (UcxTestList*) malloc(sizeof(UcxTestList)); + if (newelem) { + newelem->test = test; + newelem->next = NULL; + + UcxTestList *last = suite->tests; + while (last->next) { + last = last->next; + } + last->next = newelem; + + return EXIT_SUCCESS; + } else { + return EXIT_FAILURE; + } + } else { + suite->tests = (UcxTestList*) malloc(sizeof(UcxTestList)); + if (suite->tests) { + suite->tests->test = test; + suite->tests->next = NULL; + + return EXIT_SUCCESS; + } else { + return EXIT_FAILURE; + } + } +} + +void ucx_test_run(UcxTestSuite* suite, FILE* output) { + suite->success = 0; + suite->failure = 0; + for (UcxTestList* elem = suite->tests ; elem ; elem = elem->next) { + elem->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); +} diff -r 279f343bbf6c -r fac51f87def0 src/ucx/test.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/test.h Sun Sep 08 23:27:07 2013 +0200 @@ -0,0 +1,241 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 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. + */ + +/** + * @file: test.h + * + * UCX Test Framework. + * + * Usage of this test framework: + * + * **** IN HEADER FILE: **** + * + *
+ * UCX_TEST(function_name)
+ * UCX_TEST_SUBROUTINE(subroutine_name, paramlist) // optional
+ * 
+ * + * **** IN SOURCE FILE: **** + *
+ * UCX_TEST_SUBROUTINE(subroutine_name, paramlist) {
+ *   // tests with UCX_TEST_ASSERT()
+ * }
+ * 
+ * UCX_TEST(function_name) {
+ *   // memory allocation and other stuff here
+ *   #UCX_TEST_BEGIN
+ *   // tests with UCX_TEST_ASSERT() and/or
+ *   // calls with UCX_TEST_CALL_SUBROUTINE() here
+ *   #UCX_TEST_END
+ *   // cleanup of memory here
+ * }
+ * 
+ * + * Note: if a test fails, a longjump is performed + * back to the #UCX_TEST_BEGIN macro! + * + * Attention: Do not call own functions within a test, that use + * UCX_TEST_ASSERT() macros and are not defined by using UCX_TEST_SUBROUTINE(). + * + * + * @author Mike Becker + * @author Olaf Wintermann + * + */ + +#ifndef UCX_TEST_H +#define UCX_TEST_H + +#include "ucx.h" +#include +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef __FUNCTION__ + +/** + * Alias for the __func__ preprocessor macro. + * Some compilers use __func__ and others use __FUNC__. + * We use __FUNC__ so we define it for those compilers which use + * __func__. + */ +#define __FUNCTION__ __func__ +#endif + +/** Type for the UcxTestSuite. */ +typedef struct UcxTestSuite UcxTestSuite; + +/** Pointer to a test function. */ +typedef void(*UcxTest)(UcxTestSuite*,FILE*); + +/** Type for the internal list of test cases. */ +typedef struct UcxTestList UcxTestList; + +/** Structure for the internal list of test cases. */ +struct UcxTestList { + + /** Test case. */ + UcxTest test; + + /** Pointer to the next list element. */ + UcxTestList *next; +}; + +/** + * A test suite containing multiple test cases. + */ +struct UcxTestSuite { + + /** The number of successful tests after the suite has been run. */ + unsigned int success; + + /** The number of failed tests after the suite has been run. */ + unsigned int failure; + + /** + * Internal list of test cases. + * Use ucx_test_register() to add tests to this list. + */ + UcxTestList *tests; +}; + +/** + * Creates a new test suite. + * @return a new test suite + */ +UcxTestSuite* ucx_test_suite_new(); + +/** + * Destroys a test suite. + * @param suite the test suite to destroy + */ +void ucx_test_suite_free(UcxTestSuite* suite); + +/** + * Registers a test function with the specified test suite. + * + * @param suite the suite, the test function shall be added to + * @param test the test function to register + * @return EXIT_SUCCESS on success or + * EXIT_FAILURE on failure + */ +int ucx_test_register(UcxTestSuite* suite, UcxTest test); + +/** + * Runs a test suite and writes the test log to the specified stream. + * @param suite the test suite to run + * @param outstream the stream the log shall be written to + */ +void ucx_test_run(UcxTestSuite* suite, FILE* outstream); + +/** + * Macro for a #UcxTest function header. + * + * Use this macro to declare and/or define an #UcxTest function. + * + * @param name the name of the test function + */ +#define UCX_TEST(name) void name(UcxTestSuite* _suite_,FILE *_output_) + +/** + * Marks the begin of a test. + * Note: Any UCX_TEST_ASSERT() calls must be performed after + * #UCX_TEST_BEGIN. + * + * @see #UCX_TEST_END + */ +#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_)) { + +/** + * Checks a test assertion. + * If the assertion is correct, the test carries on. If the assertion is not + * correct, the specified message (terminated by a dot and a line break) is + * written to the test suites output stream. + * @param condition the condition to check + * @param message the message that shall be printed out on failure + */ +#define UCX_TEST_ASSERT(condition,message) if (!(condition)) { \ + fwrite(message".\n", 1, 2+strlen(message), _output_); \ + _suite_->failure++; \ + longjmp(_env_, 1);\ + } + +/** + * Macro for a test subroutine function header. + * + * Use this to declare and/or define an subroutine that can be called by using + * UCX_TEST_CALL_SUBROUTINE(). + * + * @param name the name of the subroutine + * @param ... the parameter list + * + * @see UCX_TEST_CALL_SUBROUTINE() + */ +#define UCX_TEST_SUBROUTINE(name,...) void name(UcxTestSuite* _suite_,\ + FILE *_output_, jmp_buf _env_, __VA_ARGS__) + +/** + * Macro for calling a test subroutine. + * + * Subroutines declared with UCX_TEST_SUBROUTINE() can be called by using this + * macro. + * + * Note: You may only call subroutines within a #UCX_TEST_BEGIN- + * #UCX_TEST_END-block. + * + * @param name the name of the subroutine + * @param ... the argument list + * + * @see UCX_TEST_SUBROUTINE() + */ +#define UCX_TEST_CALL_SUBROUTINE(name,...) \ + name(_suite_,_output_,_env_,__VA_ARGS__); + +/** + * Marks the end of a test. + * Note: Any UCX_TEST_ASSERT() calls must be performed before + * #UCX_TEST_END. + * + * @see #UCX_TEST_BEGIN + */ +#define UCX_TEST_END fwrite("success.\n", 1, 9, _output_); _suite_->success++;} + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_TEST_H */ + diff -r 279f343bbf6c -r fac51f87def0 src/ucx/ucx.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/ucx.c Sun Sep 08 23:27:07 2013 +0200 @@ -0,0 +1,37 @@ +/** + * @mainpage UAP Common Extensions + * Library with common and useful functions, macros and data structures. + *

+ * Latest available source:
+ * + * https://develop.uap-core.de/hg/ucx + *

+ * + *

LICENCE

+ * + * Copyright 2013 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 "ucx.h" diff -r 279f343bbf6c -r fac51f87def0 src/ucx/ucx.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/ucx.h Sun Sep 08 23:27:07 2013 +0200 @@ -0,0 +1,130 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 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. + */ +/** + * Main UCX Header providing most common definitions. + * + * @file ucx.h + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_H +#define UCX_H + +/** Major UCX version as integer constant. */ +#define UCX_VERSION_MAJOR 1 + +/** Minor UCX version as integer constant. */ +#define UCX_VERSION_MINOR 0 + +/** The UCX version in format [major].[minor] */ +#define UCX_VERSION UCX_VERSION_MAJOR.UCX_VERSION_MINOR + +#include + +#ifdef _WIN32 +#if !(defined __ssize_t_defined || defined _SSIZE_T_) +#include +typedef SSIZE_T ssize_t; +#define __ssize_t_defined +#define _SSIZE_T_ +#endif /* __ssize_t_defined and _SSIZE_T */ +#else /* !_WIN32 */ +#include +#endif /* _WIN32 */ + +#ifdef __cplusplus +#ifndef _Bool +#define _Bool bool +#define restrict +#endif +/** Use C naming even when compiling with C++. */ +#define UCX_EXTERN extern "C" +extern "C" { +#else +/** Pointless in C. */ +#define UCX_EXTERN +#endif + +/** + * Function pointer to a compare function. + * + * The compare function shall take three arguments: the two values that shall be + * compared and optional additional data. + * The function shall then return -1 if the first argument is less than the + * second argument, 1 if the first argument is greater than the second argument + * and 0 if both arguments are equal. If the third argument is + * NULL, it shall be ignored. + */ +typedef int(*cmp_func)(void*,void*,void*); + +/** + * Function pointer to a copy function. + * + * The copy function shall create a copy of the first argument and may use + * additional data provided by the second argument. If the second argument is + * NULL, it shall be ignored. + + * Attention: if pointers returned by functions of this type may be + * passed to free() depends on the implementation of the + * respective copy_func. + */ +typedef void*(*copy_func)(void*,void*); + +/** + * Function pointer to a write function. + * + * The signature of the write function shall be compatible to the signature + * of standard fwrite, though it may use arbitrary data types for + * source and destination. + * + * The arguments shall contain (in ascending order): a pointer to the source, + * the length of one element, the element count and a pointer to the + * destination. + */ +typedef size_t(*write_func)(const void*, size_t, size_t, void*); + +/** + * Function pointer to a read function. + * + * The signature of the read function shall be compatible to the signature + * of standard fread, though it may use arbitrary data types for + * source and destination. + * + * The arguments shall contain (in ascending order): a pointer to the + * destination, the length of one element, the element count and a pointer to + * the source. + */ +typedef size_t(*read_func)(void*, size_t, size_t, void*); + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_H */ + diff -r 279f343bbf6c -r fac51f87def0 src/ucx/utils.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/utils.c Sun Sep 08 23:27:07 2013 +0200 @@ -0,0 +1,244 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 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 "utils.h" +#include +#include +#include +#include + +/* COPY FUCNTIONS */ +void* ucx_strcpy(void* s, void* data) { + char *str = (char*) s; + size_t n = 1+strlen(str); + char *cpy = (char*) malloc(n); + memcpy(cpy, str, n); + return cpy; +} + +void* ucx_memcpy(void* m, void* n) { + size_t k = *((size_t*)n); + void *cpy = malloc(k); + memcpy(cpy, m, k); + return cpy; +} + +size_t ucx_stream_copy(void *src, void *dest, read_func readfnc, + write_func writefnc, char* buf, size_t bufsize, size_t n) { + if(n == 0 || bufsize == 0) { + return 0; + } + + size_t ncp = 0; + if (!buf) { + buf = (char*)malloc(bufsize); + if(buf == NULL) { + return 0; + } + } + + size_t r; + size_t rn = bufsize > n ? n : bufsize; + while((r = readfnc(buf, 1, rn, src)) != 0) { + r = writefnc(buf, 1, r, dest); + ncp += r; + n -= r; + rn = bufsize > n ? n : bufsize; + if(r == 0 || n == 0) { + break; + } + } + + free(buf); + return ncp; +} + +/* COMPARE FUNCTIONS */ + +int ucx_strcmp(void *s1, void *s2, void *data) { + return strcmp((char*)s1, (char*)s2); +} + +int ucx_strncmp(void *s1, void *s2, void *n) { + return strncmp((char*)s1, (char*)s2, *((size_t*) n)); +} + +int ucx_intcmp(void *i1, void *i2, void *data) { + int a = *((int*) i1); + int b = *((int*) i2); + if (a == b) { + return 0; + } else { + return a < b ? -1 : 1; + } +} + +int ucx_floatcmp(void *f1, void *f2, void *epsilon) { + float a = *((float*) f1); + float b = *((float*) f2); + float e = !epsilon ? 1e-6f : *((float*)epsilon); + if (fabsf(a - b) < e) { + return 0; + } else { + return a < b ? -1 : 1; + } +} + +int ucx_doublecmp(void *d1, void *d2, void *epsilon) { + double a = *((float*) d1); + double b = *((float*) d2); + double e = !epsilon ? 1e-14 : *((double*)epsilon); + if (fabs(a - b) < e) { + return 0; + } else { + return a < b ? -1 : 1; + } +} + +int ucx_ptrcmp(void *ptr1, void *ptr2, void *data) { + if (ptr1 == ptr2) { + return 0; + } else { + return ptr1 < ptr2 ? -1 : 1; + } +} + +int ucx_memcmp(void *ptr1, void *ptr2, void *n) { + return memcmp(ptr1, ptr2, *((size_t*)n)); +} + +/* PRINTF FUNCTIONS */ + +#ifdef va_copy +#define UCX_PRINTF_BUFSIZE 256 +#else +#pragma message("WARNING: C99 va_copy macro not supported by this platform" \ + " - limiting ucx_*printf to 2 KiB") +#define UCX_PRINTF_BUFSIZE 0x800 +#endif + +int ucx_fprintf(void *stream, write_func wfc, const char *fmt, ...) { + int ret; + va_list ap; + va_start(ap, fmt); + ret = ucx_vfprintf(stream, wfc, fmt, ap); + va_end(ap); + return ret; +} + +int ucx_vfprintf(void *stream, write_func wfc, const char *fmt, va_list ap) { + char buf[UCX_PRINTF_BUFSIZE]; +#ifdef va_copy + va_list ap2; + va_copy(ap2, ap); + int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap); + if (ret < 0) { + return ret; + } else if (ret < UCX_PRINTF_BUFSIZE) { + return (int)wfc(buf, 1, ret, stream); + } else { + if (ret == INT_MAX) { + errno = ENOMEM; + return -1; + } + + int len = ret + 1; + char *newbuf = (char*)malloc(len); + if (!newbuf) { + return -1; + } + + ret = vsnprintf(newbuf, len, fmt, ap2); + if (ret > 0) { + ret = (int)wfc(newbuf, 1, ret, stream); + } + free(newbuf); + } + return ret; +#else + int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap); + if (ret < 0) { + return ret; + } else if (ret < UCX_PRINTF_BUFSIZE) { + return (int)wfc(buf, 1, ret, stream); + } else { + errno = ENOMEM; + return -1; + } +#endif +} + +sstr_t ucx_asprintf(UcxAllocator *allocator, const char *fmt, ...) { + va_list ap; + sstr_t ret; + va_start(ap, fmt); + ret = ucx_vasprintf(allocator, fmt, ap); + va_end(ap); + return ret; +} + +sstr_t ucx_vasprintf(UcxAllocator *a, const char *fmt, va_list ap) { + sstr_t s; + s.ptr = NULL; + s.length = 0; + char buf[UCX_PRINTF_BUFSIZE]; +#ifdef va_copy + va_list ap2; + va_copy(ap2, ap); + int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap); + if (ret > 0 && ret < UCX_PRINTF_BUFSIZE) { + s.ptr = (char*)a->malloc(a->pool, ret + 1); + s.length = (size_t)ret; + memcpy(s.ptr, buf, ret); + s.ptr[s.length] = '\0'; + } else if (ret == INT_MAX) { + errno = ENOMEM; + } else { + int len = ret + 1; + s.ptr = (char*)a->malloc(a->pool, len); + ret = vsnprintf(s.ptr, len, fmt, ap2); + if (ret < 0) { + free(s.ptr); + s.ptr = NULL; + } else { + s.length = (size_t)ret; + } + } +#else + int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap); + if (ret > 0 && ret < UCX_PRINTF_BUFSIZE) { + s.ptr = (char*)a->malloc(a->pool, ret + 1); + s.length = (size_t)ret; + memcpy(s.ptr, buf, ret); + s.ptr[s.length] = '\0'; + } else { + errno = ENOMEM; + } +#endif + return s; +} diff -r 279f343bbf6c -r fac51f87def0 src/ucx/utils.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/ucx/utils.h Sun Sep 08 23:27:07 2013 +0200 @@ -0,0 +1,250 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 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. + */ + +/** + * @file utils.h + * + * Compare, copy and printf functions. + * + * @author Mike Becker + * @author Olaf Wintermann + */ + +#ifndef UCX_UTILS_H +#define UCX_UTILS_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include "ucx.h" +#include "string.h" +#include "allocator.h" +#include +#include +#include + +/** + * Copies a string. + * @param s the string to copy + * @param data omitted + * @return a pointer to a copy of s1 that can be passed to free(void*) + */ +void *ucx_strcpy(void *s, void *data); + +/** + * Copies a memory area. + * @param m a pointer to the memory area + * @param n a pointer to the size_t containing the size of the memory area + * @return a pointer to a copy of the specified memory area that can + * be passed to free(void*) + */ +void *ucx_memcpy(void *m, void *n); + + +/** + * Reads data from a stream and writes it to another stream. + * + * @param src the source stream + * @param dest the destination stream + * @param rfnc the read function + * @param wfnc the write function + * @param buf a pointer to the copy buffer or NULL if a buffer + * shall be implicitly created on the heap + * @param bufsize the size of the copy buffer - if NULL was + * provided for buf, this is the size of the buffer that shall be + * implicitly created + * @param n the maximum number of bytes that shall be copied + * @return the total number of bytes copied + */ +size_t ucx_stream_copy(void *src, void *dest, read_func rfnc, write_func wfnc, + char* buf, size_t bufsize, size_t n); + +/** + * Shorthand for ucx_stream_copy using the default copy buffer. + * + * @param src the source stream + * @param dest the destination stream + * @param rfnc the read function + * @param wfnc the write function + * @return total number of bytes copied + */ +#define ucx_stream_hcopy(src,dest,rfnc,wfnc) ucx_stream_copy(\ + src, dest, (read_func)rfnc, (write_func)wfnc, NULL, 0x100, SIZE_MAX) + +/** + * Shorthand for ucx_stream_copy using the default copy buffer and a copy limit. + * + * @param src the source stream + * @param dest the destination stream + * @param rfnc the read function + * @param wfnc the write function + * @param n maximum number of bytes that shall be copied + * @return total number of bytes copied + */ +#define ucx_stream_ncopy(src,dest,rfnc,wfnc, n) ucx_stream_copy(\ + src, dest, (read_func)rfnc, (write_func)wfnc, NULL, 0x100, n) + +/** + * Wraps the strcmp function. + * @param s1 string one + * @param s2 string two + * @param data omitted + * @return the result of strcmp(s1, s2) + */ +int ucx_strcmp(void *s1, void *s2, void *data); + +/** + * Wraps the strncmp function. + * @param s1 string one + * @param s2 string two + * @param n a pointer to the size_t containing the third strncmp parameter + * @return the result of strncmp(s1, s2, *n) + */ +int ucx_strncmp(void *s1, void *s2, void *n); + +/** + * Compares two integers of type int. + * @param i1 pointer to integer one + * @param i2 pointer to integer two + * @param data omitted + * @return -1, if *i1 is less than *i2, 0 if both are equal, + * 1 if *i1 is greater than *i2 + */ +int ucx_intcmp(void *i1, void *i2, void *data); + +/** + * Compares two real numbers of type float. + * @param f1 pointer to float one + * @param f2 pointer to float two + * @param data if provided: a pointer to precision (default: 1e-6f) + * @return -1, if *f1 is less than *f2, 0 if both are equal, + * 1 if *f1 is greater than *f2 + */ + +int ucx_floatcmp(void *f1, void *f2, void *data); + +/** + * Compares two real numbers of type double. + * @param d1 pointer to double one + * @param d2 pointer to double two + * @param data if provided: a pointer to precision (default: 1e-14) + * @return -1, if *d1 is less than *d2, 0 if both are equal, + * 1 if *d1 is greater than *d2 + */ +int ucx_doublecmp(void *d1, void *d2, void *data); + +/** + * Compares two pointers. + * @param ptr1 pointer one + * @param ptr2 pointer two + * @param data omitted + * @return -1 if ptr1 is less than ptr2, 0 if both are equal, + * 1 if ptr1 is greater than ptr2 + */ +int ucx_ptrcmp(void *ptr1, void *ptr2, void *data); + +/** + * Compares two memory areas. + * @param ptr1 pointer one + * @param ptr2 pointer two + * @param n a pointer to the size_t containing the third parameter for memcmp + * @return the result of memcmp(ptr1, ptr2, *n) + */ +int ucx_memcmp(void *ptr1, void *ptr2, void *n); + +/** + * A printf() like function which writes the output to a stream by + * using a write_func(). + * @param stream the stream the data is written to + * @param wfc the write function + * @param fmt format string + * @param ... additional arguments + * @return the total number of bytes written + */ +int ucx_fprintf(void *stream, write_func wfc, const char *fmt, ...); + +/** + * va_list version of ucx_fprintf(). + * @param stream the stream the data is written to + * @param wfc the write function + * @param fmt format string + * @param ap argument list + * @return the total number of bytes written + * @see ucx_fprintf() + */ +int ucx_vfprintf(void *stream, write_func wfc, const char *fmt, va_list ap); + +/** + * A printf() like function which allocates space for a sstr_t + * the result is written to. + * + * Attention: The sstr_t data is allocated with the allocators + * ucx_allocator_malloc() function. So it is implementation dependent, if + * the returned sstr_t.ptr pointer must be passed to the allocators + * ucx_allocator_free() function manually. + * + * Note: The sstr_t.ptr of the return value will always be + * NULL-terminated. + * + * @param allocator the UcxAllocator used for allocating the result sstr_t + * @param fmt format string + * @param ... additional arguments + * @return a sstr_t containing the formatted string + */ +sstr_t ucx_asprintf(UcxAllocator *allocator, const char *fmt, ...); + +/** + * va_list version of ucx_asprintf(). + * + * @param allocator the UcxAllocator used for allocating the result sstr_t + * @param fmt format string + * @param ap argument list + * @return a sstr_t containing the formatted string + * @see ucx_asprintf() + */ +sstr_t ucx_vasprintf(UcxAllocator *allocator, const char *fmt, va_list ap); + +/** + * A printf() like function which writes the output to an + * UcxBuffer. + * + * @param buffer the buffer the data is written to + * @param ... format string and additional arguments + * @return the total number of bytes written + * @see ucx_fprintf() + */ +#define ucx_bprintf(buffer, ...) ucx_fprintf((UcxBuffer*)buffer, \ + (write_func)ucx_buffer_write, __VA_ARGS__) + +#ifdef __cplusplus +} +#endif + +#endif /* UCX_UTILS_H */ +