adds UCX + changes how the input file is read (uses an consecutive memory area now)

Tue, 23 Aug 2016 13:49:38 +0200

author
Mike Becker <universe@uap-core.de>
date
Tue, 23 Aug 2016 13:49:38 +0200
changeset 39
ac35daceb24c
parent 38
77c158821738
child 40
903b46fc4214

adds UCX + changes how the input file is read (uses an consecutive memory area now)

Makefile file | annotate | diff | comparison | revisions
clang.mk file | annotate | diff | comparison | revisions
gcc.mk file | annotate | diff | comparison | revisions
src/c2html.c file | annotate | diff | comparison | revisions
src/c2html.h file | annotate | diff | comparison | revisions
src/ccodegen.c file | annotate | diff | comparison | revisions
src/javacodegen.c file | annotate | diff | comparison | revisions
src/ucx/allocator.c file | annotate | diff | comparison | revisions
src/ucx/allocator.h file | annotate | diff | comparison | revisions
src/ucx/buffer.c file | annotate | diff | comparison | revisions
src/ucx/buffer.h file | annotate | diff | comparison | revisions
src/ucx/list.c file | annotate | diff | comparison | revisions
src/ucx/list.h file | annotate | diff | comparison | revisions
src/ucx/string.c file | annotate | diff | comparison | revisions
src/ucx/string.h file | annotate | diff | comparison | revisions
src/ucx/ucx.h file | annotate | diff | comparison | revisions
src/ucx/utils.c file | annotate | diff | comparison | revisions
src/ucx/utils.h file | annotate | diff | comparison | revisions
     1.1 --- a/Makefile	Tue Aug 23 12:06:46 2016 +0200
     1.2 +++ b/Makefile	Tue Aug 23 13:49:38 2016 +0200
     1.3 @@ -36,10 +36,15 @@
     1.4  SRC += codegens.c
     1.5  SRC += ccodegen.c
     1.6  SRC += javacodegen.c
     1.7 +SRC += ucx/allocator.c
     1.8 +SRC += ucx/buffer.c
     1.9 +SRC += ucx/list.c
    1.10 +SRC += ucx/string.c
    1.11 +SRC += ucx/utils.c
    1.12  
    1.13  OBJ = $(SRC:%.c=build/%$(OBJ_EXT))
    1.14  
    1.15 -all: build build/$(BIN)
    1.16 +all: build/ucx build/$(BIN)
    1.17  	
    1.18  build/$(BIN): $(OBJ)
    1.19  	$(LD) -o $@ $^ $(LDFLAGS)
    1.20 @@ -47,8 +52,11 @@
    1.21  build/%$(OBJ_EXT): src/%.c
    1.22  	$(CC) -o $@ $(CFLAGS) -c $<
    1.23  	
    1.24 +build/ucx: build
    1.25 +	$(MKDIR) $@
    1.26 +	
    1.27  build:
    1.28 -	$(MKDIR) build
    1.29 +	$(MKDIR) $@
    1.30  	
    1.31  test: build/$(BIN)
    1.32  	./build/$(BIN) test/ctestfile.c -o build/ctest.html \
     2.1 --- a/clang.mk	Tue Aug 23 12:06:46 2016 +0200
     2.2 +++ b/clang.mk	Tue Aug 23 13:49:38 2016 +0200
     2.3 @@ -27,7 +27,7 @@
     2.4  #
     2.5  
     2.6  # system related
     2.7 -MKDIR   = mkdir
     2.8 +MKDIR   = mkdir -p
     2.9  RM      = rm
    2.10  RMFLAGS = -fR
    2.11  
     3.1 --- a/gcc.mk	Tue Aug 23 12:06:46 2016 +0200
     3.2 +++ b/gcc.mk	Tue Aug 23 13:49:38 2016 +0200
     3.3 @@ -27,7 +27,7 @@
     3.4  #
     3.5  
     3.6  # system related
     3.7 -MKDIR   = mkdir
     3.8 +MKDIR   = mkdir -p
     3.9  RM      = rm
    3.10  RMFLAGS = -fR
    3.11  
     4.1 --- a/src/c2html.c	Tue Aug 23 12:06:46 2016 +0200
     4.2 +++ b/src/c2html.c	Tue Aug 23 13:49:38 2016 +0200
     4.3 @@ -28,77 +28,9 @@
     4.4   */
     4.5  #include "c2html.h"
     4.6  
     4.7 -inputfile_t *inputfilebuffer(size_t capacity) {
     4.8 -    inputfile_t *inputfile = (inputfile_t*) malloc(sizeof(inputfile_t));
     4.9 -    inputfile->lines = (char**) malloc(capacity * sizeof(char*));
    4.10 -    inputfile->capacity = capacity;
    4.11 -    inputfile->count = 0;
    4.12 -    inputfile->maxlinewidth = 0;
    4.13 -
    4.14 -    return inputfile;
    4.15 -}
    4.16 -
    4.17 -void addline(inputfile_t *inputfile, char* line, size_t width) {
    4.18 -    char *l = (char*) malloc(width+1);
    4.19 -    memcpy(l, line, width);
    4.20 -    l[width] = 0;
    4.21 -    if (inputfile->count >= inputfile->capacity) {
    4.22 -        inputfile->capacity <<= 1;
    4.23 -        inputfile->lines = realloc(inputfile->lines,
    4.24 -            sizeof(char*)*inputfile->capacity);
    4.25 -    }
    4.26 -    inputfile->lines[inputfile->count] = l;
    4.27 -    inputfile->maxlinewidth =
    4.28 -        width > inputfile->maxlinewidth ? width : inputfile->maxlinewidth;
    4.29 -    inputfile->count++;
    4.30 -}
    4.31 -
    4.32 -void freeinputfilebuffer(inputfile_t *inputfile) {
    4.33 -    for (int i = 0 ; i < inputfile->count ; i++) {
    4.34 -        free(inputfile->lines[i]);
    4.35 -    }
    4.36 -    free(inputfile->lines);
    4.37 -    free(inputfile);
    4.38 -}
    4.39 -
    4.40 -inputfile_t *readinput(char *filename) {
    4.41 -
    4.42 -    int fd = open(filename, O_RDONLY);
    4.43 -    if (fd == -1) return NULL;
    4.44 -
    4.45 -    inputfile_t *inputfile = inputfilebuffer(512);
    4.46 -
    4.47 -    char buf[INPUTBUF_SIZE];
    4.48 -    ssize_t r;
    4.49 -
    4.50 -    size_t maxlinewidth = 256;
    4.51 -    char *line = (char*) malloc(maxlinewidth);
    4.52 -    size_t col = 0;
    4.53 -
    4.54 -    while ((r = read(fd, buf, INPUTBUF_SIZE)) > 0) {
    4.55 -        for (size_t i = 0 ; i < r ; i++) {
    4.56 -            if (col >= maxlinewidth-4) {
    4.57 -                maxlinewidth <<= 1;
    4.58 -                line = realloc(line, maxlinewidth);
    4.59 -            }
    4.60 -
    4.61 -            if (buf[i] == '\n') {
    4.62 -                line[col++] = '\n';
    4.63 -                line[col] = 0;
    4.64 -                addline(inputfile, line, col);
    4.65 -                col = 0;
    4.66 -            } else {
    4.67 -                line[col++] = buf[i];
    4.68 -            }
    4.69 -        }
    4.70 -    }
    4.71 -
    4.72 -    free(line);
    4.73 -
    4.74 -    close(fd);
    4.75 -
    4.76 -    return inputfile;
    4.77 -}
    4.78 +#include "ucx/buffer.h"
    4.79 +#include "ucx/list.h"
    4.80 +#include "ucx/utils.h"
    4.81  
    4.82  void printhelp() {
    4.83      printf("Formats source code using HTML.\n\nUsage:\n"
    4.84 @@ -115,12 +47,6 @@
    4.85          "\n");
    4.86  }
    4.87  
    4.88 -int lnint(size_t lnc) {
    4.89 -    int w = 1, p = 1;
    4.90 -    while ((p*=10) < lnc) w++;
    4.91 -    return w;
    4.92 -}
    4.93 -
    4.94  int copyfile(char *filename, FILE *dest) {
    4.95      if (!filename) {
    4.96          return 0;
    4.97 @@ -136,60 +62,71 @@
    4.98          fclose(src);
    4.99          return 0;
   4.100      } else {
   4.101 -        return -1;
   4.102 +        return 1;
   4.103      }
   4.104  }
   4.105  
   4.106  #define WRITECONST(stream, out, cstr) out(cstr, 1, sizeof(cstr)-1, stream)
   4.107  int formatfile(
   4.108          highlighter_t *highlighter,
   4.109 -        inputfile_t *in,
   4.110 -        fmt_write_func out,
   4.111 +        UcxList *in,
   4.112 +        write_func out,
   4.113          void *stream,
   4.114 -        _Bool showln) {
   4.115 -    // formats an input file and writes the result to out
   4.116 +        int showlineno) {
   4.117 +    size_t lines = ucx_list_size(in);
   4.118      
   4.119 -    char *line = malloc(in->maxlinewidth*64);
   4.120 +    UcxBuffer *line = ucx_buffer_new(NULL, 1024, UCX_BUFFER_AUTOEXTEND);
   4.121      if(!line) {
   4.122          return 1;
   4.123      }
   4.124      WRITECONST(stream, out, "<pre>\n");
   4.125      
   4.126 -    int lnw = lnint(in->count);
   4.127 -    for (int i = 0 ; i < in->count ; i++) {
   4.128 +    int lnw;
   4.129 +    {
   4.130 +        lnw = 1;
   4.131 +        int p = 1;
   4.132 +        while ((p*=10) < lines) lnw++;
   4.133 +    }
   4.134 +
   4.135 +    size_t lineno = 0;
   4.136 +    UCX_FOREACH(sourceline, in) {
   4.137 +        lineno++;
   4.138 +        /* TODO: backwards compatibility: replace line->space in all occasions
   4.139 +         * and use UcxBuffer functions
   4.140 +         */
   4.141          if (highlighter) {
   4.142 -            highlighter->parser(in->lines[i], line, highlighter);
   4.143 +            highlighter->parser(sourceline->data, line->space, highlighter);
   4.144          } else {
   4.145 -            char *c = in->lines[i];
   4.146 +            char *c = sourceline->data;
   4.147              size_t dp = 0;
   4.148              while (*c) {
   4.149 -                dp = writeescapedchar(line, dp, *c);
   4.150 +                dp = writeescapedchar(line->space, dp, *c);
   4.151                  c++;
   4.152              }
   4.153 -            line[dp] = '\0';
   4.154 +            line->space[dp] = '\0';
   4.155          }
   4.156  
   4.157          // write line number
   4.158 -        if (showln) {
   4.159 +        if (showlineno) {
   4.160              WRITECONST(stream, out, "<span class=\"c2html-lineno\">");
   4.161              char lnbuf[128];
   4.162              int len;
   4.163              // line number link
   4.164              len = snprintf(lnbuf, 128, "<a name=\"l%d\" href=\"#l%d\">",
   4.165 -                i+1, i+1);
   4.166 +                lineno, lineno);
   4.167              out(lnbuf, 1, len, stream);
   4.168              // justified line number
   4.169 -            len = snprintf(lnbuf, 128, "%*d ", lnw, i+1);
   4.170 +            len = snprintf(lnbuf, 128, "%*d ", lnw, lineno);
   4.171              out(lnbuf, 1, len, stream);
   4.172              WRITECONST(stream, out, "</a></span> ");
   4.173          }
   4.174          
   4.175          // write formated (or plain) code line
   4.176 -        out(line, 1, strlen(line), stream);
   4.177 +        out(line->space, 1, strlen(line->space), stream);
   4.178      }
   4.179      
   4.180      WRITECONST(stream, out, "</pre>\n");
   4.181 -    free(line);
   4.182 +    ucx_buffer_free(line);
   4.183      return 0;
   4.184  }
   4.185  
   4.186 @@ -209,15 +146,20 @@
   4.187      highlighter->parser = jparseline;
   4.188  }
   4.189  
   4.190 +enum source_type {
   4.191 +    SOURCE_C,
   4.192 +    SOURCE_JAVA,
   4.193 +    SOURCE_PLAIN
   4.194 +};
   4.195 +
   4.196  int main(int argc, char** argv) {
   4.197      int retcode = EXIT_SUCCESS;
   4.198      
   4.199 -    settings_t settings;
   4.200 +    Settings settings;
   4.201      memset(&settings, 0, sizeof(settings));
   4.202 -    settings.highlight = 1;
   4.203      settings.showlinenumbers = 1;
   4.204      
   4.205 -    int lang = C2HTML_C;
   4.206 +    enum source_type sourcetype = SOURCE_C;
   4.207  
   4.208      char optc;
   4.209      while ((optc = getopt(argc, argv, "hljo:pH:F:vV")) != -1) {
   4.210 @@ -234,10 +176,10 @@
   4.211                  settings.headerfile = optarg;
   4.212                  break;
   4.213              case 'j':
   4.214 -                lang = C2HTML_JAVA;
   4.215 +                sourcetype = SOURCE_JAVA;
   4.216                  break;
   4.217              case 'p':
   4.218 -                settings.highlight = 0;
   4.219 +                sourcetype = SOURCE_PLAIN;
   4.220                  break;
   4.221              case 'l':
   4.222                  settings.showlinenumbers = 0;
   4.223 @@ -282,30 +224,53 @@
   4.224          
   4.225          highlighter_t highlighter;
   4.226          highlighter_t *hptr = &highlighter;
   4.227 -        switch (lang) {
   4.228 -            case C2HTML_C:
   4.229 +        switch (sourcetype) {
   4.230 +            case SOURCE_C:
   4.231                  init_c_highlighter(&highlighter);
   4.232                  break;
   4.233 -            case C2HTML_JAVA:
   4.234 +            case SOURCE_JAVA:
   4.235                  init_java_highlighter(&highlighter);
   4.236                  break;
   4.237 -            default:
   4.238 +            case SOURCE_PLAIN:
   4.239                  hptr = NULL;
   4.240                  break;
   4.241 -        }
   4.242 -        if (!settings.highlight) {
   4.243 -            hptr = NULL;
   4.244 +            default: /* should be unreachable */
   4.245 +                fprintf(stderr, "error in enum source_type\n");
   4.246 +                retcode = EXIT_FAILURE;
   4.247 +                goto prog_end;
   4.248          }
   4.249  
   4.250 -        inputfile_t *inputfile = readinput(settings.infilename);
   4.251 +        FILE *inputfile = fopen(settings.infilename, "r");
   4.252          if (inputfile) {
   4.253 +            UcxBuffer *filebuf = ucx_buffer_new(NULL,
   4.254 +                    2048, UCX_BUFFER_AUTOEXTEND);
   4.255 +            {
   4.256 +                const size_t tmpbufsize = 512;
   4.257 +                char *tmpbuf = malloc(tmpbufsize);
   4.258 +                ucx_stream_copy(inputfile, filebuf, (read_func) fread,
   4.259 +                        (write_func) ucx_buffer_write,
   4.260 +                        tmpbuf, tmpbufsize, (size_t)-1);
   4.261 +                free(tmpbuf);
   4.262 +            }
   4.263 +            fclose(inputfile);
   4.264 +            
   4.265 +            UcxList *inputlines = ucx_list_append(NULL, filebuf->space);
   4.266 +            for (size_t i = 1 ; i < filebuf->size ; i++) {
   4.267 +                if (filebuf->space[i] == '\r') {
   4.268 +                    filebuf->space[i] = '\n'; i++;
   4.269 +                }
   4.270 +                if (filebuf->space[i] == '\n' && i+1 < filebuf->size) {
   4.271 +                    ucx_list_append(inputlines, filebuf->space+i+1);
   4.272 +                }
   4.273 +            }
   4.274 +            
   4.275              formatfile(
   4.276                      hptr,
   4.277 -                    inputfile,
   4.278 -                    (fmt_write_func)fwrite,
   4.279 +                    inputlines,
   4.280 +                    (write_func) fwrite,
   4.281                      fout,
   4.282                      settings.showlinenumbers);
   4.283 -            freeinputfilebuffer(inputfile);
   4.284 +            ucx_buffer_free(filebuf);
   4.285          } else {
   4.286              perror("Error opening input file");
   4.287              retcode = EXIT_FAILURE;
     5.1 --- a/src/c2html.h	Tue Aug 23 12:06:46 2016 +0200
     5.2 +++ b/src/c2html.h	Tue Aug 23 13:49:38 2016 +0200
     5.3 @@ -46,31 +46,16 @@
     5.4      
     5.5  #define VERSION_MAJOR   2
     5.6  #define VERSION_MINOR   0
     5.7 -#define VERSION_DEVELOP 1 // set this to zero for release version
     5.8 +#define VERSION_DEVELOP 1 /* set this to zero for release version */
     5.9  
    5.10 -
    5.11 -#define INPUTBUF_SIZE 2048
    5.12 -
    5.13 -#define C2HTML_C    0
    5.14 -#define C2HTML_JAVA 1
    5.15 -    
    5.16  typedef struct {
    5.17      char* outfilename;
    5.18      char* headerfile;
    5.19      char* footerfile;
    5.20      char* infilename;
    5.21 -    int highlight;
    5.22      int showlinenumbers;
    5.23 -} settings_t;
    5.24 +} Settings;
    5.25  
    5.26 -typedef struct {
    5.27 -    size_t count;
    5.28 -    size_t capacity;
    5.29 -    size_t maxlinewidth;
    5.30 -    char** lines;
    5.31 -} inputfile_t;
    5.32 -
    5.33 -typedef size_t(*fmt_write_func)(const void*, size_t, size_t, void*);
    5.34  
    5.35  #ifdef	__cplusplus
    5.36  }
     6.1 --- a/src/ccodegen.c	Tue Aug 23 12:06:46 2016 +0200
     6.2 +++ b/src/ccodegen.c	Tue Aug 23 13:49:38 2016 +0200
     6.3 @@ -53,7 +53,7 @@
     6.4  void cparseline(char *src, char *dest, highlighter_t *hltr) {
     6.5  
     6.6      memset(hltr->word, 0, WORDBUF_SIZE);
     6.7 -    size_t wp = 0, ifp = 0, sp = 0, dp = 0;
     6.8 +    size_t wp = 0, ifp = 0, sp = (size_t)-1, dp = 0;
     6.9      int isstring = 0, iscomment = 0, isinclude = 0, parseinclude = 0;
    6.10      char quote = '\0';
    6.11      int isescaping = 0;
    6.12 @@ -64,7 +64,11 @@
    6.13          memcpy_const(dest, dp, "<span class=\"c2html-comment\">");
    6.14      }
    6.15  
    6.16 -    for (char c = src[sp] ; c ; c=src[++sp]) {
    6.17 +    char c;
    6.18 +    do {
    6.19 +        c = src[++sp];
    6.20 +        if (!c) break;
    6.21 +        
    6.22          /* comments */
    6.23          if (!isstring && c == '/') {
    6.24              if (hltr->iscommentml && sp > 0 && src[sp-1] == '*') {
    6.25 @@ -185,6 +189,6 @@
    6.26  
    6.27              isescaping = !isescaping & (c == '\\');
    6.28          }
    6.29 -    }
    6.30 +    } while (c != '\n');
    6.31      dest[dp] = 0;
    6.32  }
     7.1 --- a/src/javacodegen.c	Tue Aug 23 12:06:46 2016 +0200
     7.2 +++ b/src/javacodegen.c	Tue Aug 23 13:49:38 2016 +0200
     7.3 @@ -54,7 +54,7 @@
     7.4  
     7.5  void jparseline(char *src, char *dest, highlighter_t *hltr) {
     7.6      memset(hltr->word, 0, WORDBUF_SIZE);
     7.7 -    size_t wp = 0, sp = 0, dp = 0;
     7.8 +    size_t wp = 0, sp = (size_t)-1, dp = 0;
     7.9      int isstring = 0, iscomment = 0, isimport = 0;
    7.10      char quote = '\0';
    7.11      int isescaping = 0;
    7.12 @@ -64,7 +64,11 @@
    7.13          memcpy_const(dest, dp, "<span class=\"c2html-comment\">");
    7.14      }
    7.15  
    7.16 -    for (char c = src[sp] ; c ; c=src[++sp]) {
    7.17 +    char c;
    7.18 +    do {
    7.19 +        c = src[++sp];
    7.20 +        if (!c) break;
    7.21 +        
    7.22          /* comments */
    7.23          if (!isstring && c == '/') {
    7.24              if (hltr->iscommentml && sp > 0 && src[sp-1] == '*') {
    7.25 @@ -155,6 +159,6 @@
    7.26  
    7.27              isescaping = !isescaping & (c == '\\');
    7.28          }
    7.29 -    }
    7.30 +    } while (c != '\n');
    7.31      dest[dp] = 0;
    7.32  }
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/src/ucx/allocator.c	Tue Aug 23 13:49:38 2016 +0200
     8.3 @@ -0,0 +1,59 @@
     8.4 +/*
     8.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     8.6 + *
     8.7 + * Copyright 2015 Olaf Wintermann. All rights reserved.
     8.8 + *
     8.9 + * Redistribution and use in source and binary forms, with or without
    8.10 + * modification, are permitted provided that the following conditions are met:
    8.11 + *
    8.12 + *   1. Redistributions of source code must retain the above copyright
    8.13 + *      notice, this list of conditions and the following disclaimer.
    8.14 + *
    8.15 + *   2. Redistributions in binary form must reproduce the above copyright
    8.16 + *      notice, this list of conditions and the following disclaimer in the
    8.17 + *      documentation and/or other materials provided with the distribution.
    8.18 + *
    8.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    8.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    8.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    8.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    8.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    8.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    8.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    8.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    8.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    8.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    8.29 + * POSSIBILITY OF SUCH DAMAGE.
    8.30 + */
    8.31 +
    8.32 +#include <stdlib.h>
    8.33 +#include "allocator.h"
    8.34 +
    8.35 +UcxAllocator default_allocator = {
    8.36 +    NULL,
    8.37 +    ucx_default_malloc,
    8.38 +    ucx_default_calloc,
    8.39 +    ucx_default_realloc,
    8.40 +    ucx_default_free
    8.41 +};
    8.42 +
    8.43 +UcxAllocator *ucx_default_allocator() {
    8.44 +    UcxAllocator *allocator = &default_allocator;
    8.45 +    return allocator;
    8.46 +}
    8.47 +
    8.48 +void *ucx_default_malloc(void *ignore, size_t n) {
    8.49 +    return malloc(n);
    8.50 +}
    8.51 +
    8.52 +void *ucx_default_calloc(void *ignore, size_t n, size_t size) {
    8.53 +    return calloc(n, size);
    8.54 +}
    8.55 +
    8.56 +void *ucx_default_realloc(void *ignore, void *data, size_t n) {
    8.57 +    return realloc(data, n);
    8.58 +}
    8.59 +
    8.60 +void ucx_default_free(void *ignore, void *data) {
    8.61 +    free(data);
    8.62 +}
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/src/ucx/allocator.h	Tue Aug 23 13:49:38 2016 +0200
     9.3 @@ -0,0 +1,206 @@
     9.4 +/*
     9.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
     9.6 + *
     9.7 + * Copyright 2015 Olaf Wintermann. All rights reserved.
     9.8 + *
     9.9 + * Redistribution and use in source and binary forms, with or without
    9.10 + * modification, are permitted provided that the following conditions are met:
    9.11 + *
    9.12 + *   1. Redistributions of source code must retain the above copyright
    9.13 + *      notice, this list of conditions and the following disclaimer.
    9.14 + *
    9.15 + *   2. Redistributions in binary form must reproduce the above copyright
    9.16 + *      notice, this list of conditions and the following disclaimer in the
    9.17 + *      documentation and/or other materials provided with the distribution.
    9.18 + *
    9.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
    9.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
    9.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
    9.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
    9.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
    9.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
    9.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
    9.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
    9.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
    9.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
    9.29 + * POSSIBILITY OF SUCH DAMAGE.
    9.30 + */
    9.31 +/**
    9.32 + * Allocator for custom memory management.
    9.33 + * 
    9.34 + * An UCX allocator consists of a pointer to the memory area / pool and four
    9.35 + * function pointers to memory management functions operating on this memory
    9.36 + * area / pool. These functions shall behave equivalent to the standard libc
    9.37 + * functions <code>malloc(), calloc(), realloc()</code> and <code>free()</code>.
    9.38 + * 
    9.39 + * The signature of the memory management functions is based on the signature
    9.40 + * of the respective libc function but each of them takes the pointer to the
    9.41 + * memory area / pool as first argument.
    9.42 + * 
    9.43 + * As the pointer to the memory area / pool can be arbitrarily chosen, any data
    9.44 + * can be provided to the memory management functions. An UcxMempool is just
    9.45 + * one example.
    9.46 + * 
    9.47 + * @see mempool.h
    9.48 + * @see UcxMap
    9.49 + * 
    9.50 + * @file   allocator.h
    9.51 + * @author Mike Becker
    9.52 + * @author Olaf Wintermann
    9.53 + */
    9.54 +
    9.55 +#ifndef UCX_ALLOCATOR_H
    9.56 +#define	UCX_ALLOCATOR_H
    9.57 +
    9.58 +#include "ucx.h"
    9.59 +
    9.60 +#ifdef	__cplusplus
    9.61 +extern "C" {
    9.62 +#endif
    9.63 +
    9.64 +/**
    9.65 + * A function pointer to the allocators <code>malloc()</code> function.
    9.66 + * @see UcxAllocator
    9.67 + */
    9.68 +typedef void*(*ucx_allocator_malloc)(void *pool, size_t n);
    9.69 +
    9.70 +/**
    9.71 + * A function pointer to the allocators <code>calloc()</code> function.
    9.72 + * @see UcxAllocator
    9.73 + */
    9.74 +typedef void*(*ucx_allocator_calloc)(void *pool, size_t n, size_t size);
    9.75 +
    9.76 +/**
    9.77 + * A function pointer to the allocators <code>realloc()</code> function.
    9.78 + * @see UcxAllocator
    9.79 + */
    9.80 +typedef void*(*ucx_allocator_realloc)(void *pool, void *data, size_t n);
    9.81 +
    9.82 +/**
    9.83 + * A function pointer to the allocators <code>free()</code> function.
    9.84 + * @see UcxAllocator
    9.85 + */
    9.86 +typedef void(*ucx_allocator_free)(void *pool, void *data);
    9.87 +
    9.88 +/**
    9.89 + * UCX allocator data structure containing memory management functions.
    9.90 + */
    9.91 +typedef struct {
    9.92 +    /** Pointer to an area of memory or a complex memory pool.
    9.93 +     * This pointer will be passed to any memory management function as first
    9.94 +     * argument.
    9.95 +     */
    9.96 +    void *pool;
    9.97 +    /**
    9.98 +     * The <code>malloc()</code> function for this allocator.
    9.99 +     */
   9.100 +    ucx_allocator_malloc  malloc;
   9.101 +    /**
   9.102 +     * The <code>calloc()</code> function for this allocator.
   9.103 +     */
   9.104 +    ucx_allocator_calloc  calloc;
   9.105 +    /**
   9.106 +     * The <code>realloc()</code> function for this allocator.
   9.107 +     */
   9.108 +    ucx_allocator_realloc realloc;
   9.109 +    /**
   9.110 +     * The <code>free()</code> function for this allocator.
   9.111 +     */
   9.112 +    ucx_allocator_free    free;
   9.113 +} UcxAllocator;
   9.114 +
   9.115 +/**
   9.116 + * Returns a pointer to the default allocator.
   9.117 + * 
   9.118 + * The default allocator contains wrappers to the standard libc memory
   9.119 + * management functions. Use this function to get a pointer to a globally
   9.120 + * available allocator. You may also define an own UcxAllocator by assigning
   9.121 + * #UCX_ALLOCATOR_DEFAULT to a variable and pass the address of this variable
   9.122 + * to any function that takes an UcxAllocator as argument. Note that using
   9.123 + * this function is the recommended way of passing a default allocator, thus
   9.124 + * it never runs out of scope.
   9.125 + * 
   9.126 + * @return a pointer to the default allocator
   9.127 + * 
   9.128 + * @see UCX_ALLOCATOR_DEFAULT
   9.129 + */
   9.130 +UcxAllocator *ucx_default_allocator();
   9.131 +
   9.132 +/**
   9.133 + * A wrapper for the standard libc <code>malloc()</code> function.
   9.134 + * @param ignore ignored (may be used by allocators for pooled memory)
   9.135 + * @param n argument passed to <code>malloc()</code>
   9.136 + * @return return value of <code>malloc()</code>
   9.137 + */
   9.138 +void *ucx_default_malloc(void *ignore, size_t n);
   9.139 +/**
   9.140 + * A wrapper for the standard libc <code>calloc()</code> function.
   9.141 + * @param ignore ignored (may be used by allocators for pooled memory)
   9.142 + * @param n argument passed to <code>calloc()</code>
   9.143 + * @param size  argument passed to <code>calloc()</code>
   9.144 + * @return return value of <code>calloc()</code>
   9.145 + */
   9.146 +void *ucx_default_calloc(void *ignore, size_t n, size_t size);
   9.147 +/**
   9.148 + * A wrapper for the standard libc <code>realloc()</code> function.
   9.149 + * @param ignore ignored (may be used by allocators for pooled memory)
   9.150 + * @param data argumend passed to <code>realloc()</code>
   9.151 + * @param n argument passed to <code>realloc()</code>
   9.152 + * @return return value of <code>realloc()</code>
   9.153 + */
   9.154 +void *ucx_default_realloc(void *ignore, void *data, size_t n);
   9.155 +/**
   9.156 + * A wrapper for the standard libc <code>free()</code> function.
   9.157 + * @param ignore ignored (may be used by allocators for pooled memory)
   9.158 + * @param data argument passed to <code>free()</code>
   9.159 + */
   9.160 +void ucx_default_free(void *ignore, void *data);
   9.161 +
   9.162 +/**
   9.163 + * Shorthand for calling an allocators malloc function.
   9.164 + * @param allocator the allocator to use
   9.165 + * @param n size of space to allocate
   9.166 + * @return a pointer to the allocated memory area
   9.167 + */
   9.168 +#define almalloc(allocator, n) ((allocator)->malloc((allocator)->pool, n))
   9.169 +
   9.170 +/**
   9.171 + * Shorthand for calling an allocators calloc function.
   9.172 + * @param allocator the allocator to use
   9.173 + * @param n the count of elements the space should be allocated for
   9.174 + * @param size the size of each element
   9.175 + * @return a pointer to the allocated memory area
   9.176 + */
   9.177 +#define alcalloc(allocator, n, size) \
   9.178 +        ((allocator)->calloc((allocator)->pool, n, size))
   9.179 +
   9.180 +/**
   9.181 + * Shorthand for calling an allocators realloc function.
   9.182 + * @param allocator the allocator to use
   9.183 + * @param ptr the pointer to the memory area that shall be reallocated
   9.184 + * @param n the new size of the allocated memory area
   9.185 + * @return a pointer to the reallocated memory area
   9.186 + */
   9.187 +#define alrealloc(allocator, ptr, n) \
   9.188 +        ((allocator)->realloc((allocator)->pool, ptr, n))
   9.189 +
   9.190 +/**
   9.191 + * Shorthand for calling an allocators free function.
   9.192 + * @param allocator the allocator to use
   9.193 + * @param ptr the pointer to the memory area that shall be freed
   9.194 + */
   9.195 +#define alfree(allocator, ptr) ((allocator)->free((allocator)->pool, ptr))
   9.196 +
   9.197 +/**
   9.198 + * Convenient macro for a default allocator <code>struct</code> definition.
   9.199 + */
   9.200 +#define UCX_ALLOCATOR_DEFAULT {NULL, \
   9.201 +        ucx_default_malloc, ucx_default_calloc, ucx_default_realloc, \
   9.202 +        ucx_default_free }
   9.203 +
   9.204 +#ifdef	__cplusplus
   9.205 +}
   9.206 +#endif
   9.207 +
   9.208 +#endif	/* UCX_ALLOCATOR_H */
   9.209 +
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/src/ucx/buffer.c	Tue Aug 23 13:49:38 2016 +0200
    10.3 @@ -0,0 +1,234 @@
    10.4 +/*
    10.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    10.6 + *
    10.7 + * Copyright 2015 Olaf Wintermann. All rights reserved.
    10.8 + *
    10.9 + * Redistribution and use in source and binary forms, with or without
   10.10 + * modification, are permitted provided that the following conditions are met:
   10.11 + *
   10.12 + *   1. Redistributions of source code must retain the above copyright
   10.13 + *      notice, this list of conditions and the following disclaimer.
   10.14 + *
   10.15 + *   2. Redistributions in binary form must reproduce the above copyright
   10.16 + *      notice, this list of conditions and the following disclaimer in the
   10.17 + *      documentation and/or other materials provided with the distribution.
   10.18 + *
   10.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   10.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   10.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   10.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   10.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   10.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   10.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   10.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   10.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   10.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   10.29 + * POSSIBILITY OF SUCH DAMAGE.
   10.30 + */
   10.31 +
   10.32 +#include "buffer.h"
   10.33 +#include <stdarg.h>
   10.34 +#include <stdlib.h>
   10.35 +#include <string.h>
   10.36 +
   10.37 +UcxBuffer *ucx_buffer_new(void *space, size_t capacity, int flags) {
   10.38 +    UcxBuffer *buffer = (UcxBuffer*) malloc(sizeof(UcxBuffer));
   10.39 +    if (buffer) {
   10.40 +        buffer->flags = flags;
   10.41 +        if (!space) {
   10.42 +            buffer->space = (char*)malloc(capacity);
   10.43 +            if (!buffer->space) {
   10.44 +                free(buffer);
   10.45 +                return NULL;
   10.46 +            }
   10.47 +            memset(buffer->space, 0, capacity);
   10.48 +            buffer->flags |= UCX_BUFFER_AUTOFREE;
   10.49 +        } else {
   10.50 +            buffer->space = (char*)space;
   10.51 +        }
   10.52 +        buffer->capacity = capacity;
   10.53 +        buffer->size = 0;
   10.54 +
   10.55 +        buffer->pos = 0;
   10.56 +    }
   10.57 +
   10.58 +    return buffer;
   10.59 +}
   10.60 +
   10.61 +void ucx_buffer_free(UcxBuffer *buffer) {
   10.62 +    if ((buffer->flags & UCX_BUFFER_AUTOFREE) == UCX_BUFFER_AUTOFREE) {
   10.63 +        free(buffer->space);
   10.64 +    }
   10.65 +    free(buffer);
   10.66 +}
   10.67 +
   10.68 +UcxBuffer* ucx_buffer_extract(
   10.69 +        UcxBuffer *src, size_t start, size_t length, int flags) {
   10.70 +    
   10.71 +    if (src->size == 0 || length == 0 || start+length > src->capacity) {
   10.72 +        return NULL;
   10.73 +    }
   10.74 +
   10.75 +    UcxBuffer *dst = (UcxBuffer*) malloc(sizeof(UcxBuffer));
   10.76 +    if (dst) {
   10.77 +        dst->space = (char*)malloc(length);
   10.78 +        if (!dst->space) {
   10.79 +            free(dst);
   10.80 +            return NULL;
   10.81 +        }
   10.82 +        dst->capacity = length;
   10.83 +        dst->size = length;
   10.84 +        dst->flags = flags | UCX_BUFFER_AUTOFREE;
   10.85 +        dst->pos = 0;
   10.86 +        memcpy(dst->space, src->space+start, length);
   10.87 +    }
   10.88 +    return dst;
   10.89 +}
   10.90 +
   10.91 +int ucx_buffer_seek(UcxBuffer *buffer, off_t offset, int whence) {
   10.92 +    size_t npos;
   10.93 +    switch (whence) {
   10.94 +    case SEEK_CUR:
   10.95 +        npos = buffer->pos;
   10.96 +        break;
   10.97 +    case SEEK_END:
   10.98 +        npos = buffer->size;
   10.99 +        break;
  10.100 +    case SEEK_SET:
  10.101 +        npos = 0;
  10.102 +        break;
  10.103 +    default:
  10.104 +        return -1;
  10.105 +    }
  10.106 +
  10.107 +    size_t opos = npos;
  10.108 +    npos += offset;
  10.109 +    
  10.110 +    if ((offset > 0 && npos < opos) || (offset < 0 && npos > opos)) {
  10.111 +        return -1;
  10.112 +    }
  10.113 +    
  10.114 +    if (npos >= buffer->size) {
  10.115 +        return -1;
  10.116 +    } else {
  10.117 +        buffer->pos = npos;
  10.118 +        return 0;
  10.119 +    }
  10.120 +
  10.121 +}
  10.122 +
  10.123 +int ucx_buffer_eof(UcxBuffer *buffer) {
  10.124 +    return buffer->pos >= buffer->size;
  10.125 +}
  10.126 +
  10.127 +int ucx_buffer_extend(UcxBuffer *buffer, size_t len) {
  10.128 +    size_t newcap = buffer->capacity;
  10.129 +    
  10.130 +    if (buffer->capacity + len < buffer->capacity) {
  10.131 +        return -1;
  10.132 +    }
  10.133 +    
  10.134 +    while (buffer->capacity + len > newcap) {
  10.135 +        newcap <<= 1;
  10.136 +        if (newcap < buffer->capacity) {
  10.137 +            return -1;
  10.138 +        }
  10.139 +    }
  10.140 +    
  10.141 +    char *newspace = (char*)realloc(buffer->space, newcap);
  10.142 +    if (newspace) {
  10.143 +        memset(newspace+buffer->size, 0, newcap-buffer->size);
  10.144 +        buffer->space = newspace;
  10.145 +        buffer->capacity = newcap;
  10.146 +    } else {
  10.147 +        return -1;
  10.148 +    }
  10.149 +    
  10.150 +    return 0;
  10.151 +}
  10.152 +
  10.153 +size_t ucx_buffer_write(const void *ptr, size_t size, size_t nitems,
  10.154 +        UcxBuffer *buffer) {
  10.155 +    size_t len = size * nitems;
  10.156 +    size_t required = buffer->pos + len;
  10.157 +    if (buffer->pos > required) {
  10.158 +        return 0;
  10.159 +    }
  10.160 +    
  10.161 +    if (required > buffer->capacity) {
  10.162 +        if ((buffer->flags & UCX_BUFFER_AUTOEXTEND) == UCX_BUFFER_AUTOEXTEND) {
  10.163 +            if (ucx_buffer_extend(buffer, required - buffer->capacity)) {
  10.164 +                return 0;
  10.165 +            }
  10.166 +        } else {
  10.167 +            len = buffer->capacity - buffer->pos;
  10.168 +            if (size > 1) {
  10.169 +                len -= len%size;
  10.170 +            }
  10.171 +        }
  10.172 +    }
  10.173 +    
  10.174 +    if (len == 0) {
  10.175 +        return len;
  10.176 +    }
  10.177 +    
  10.178 +    memcpy(buffer->space + buffer->pos, ptr, len);
  10.179 +    buffer->pos += len;
  10.180 +    if(buffer->pos > buffer->size) {
  10.181 +        buffer->size = buffer->pos;
  10.182 +    }
  10.183 +    
  10.184 +    return len / size;
  10.185 +}
  10.186 +
  10.187 +size_t ucx_buffer_read(void *ptr, size_t size, size_t nitems,
  10.188 +        UcxBuffer *buffer) {
  10.189 +    size_t len = size * nitems;
  10.190 +    if (buffer->pos + len > buffer->size) {
  10.191 +        len = buffer->size - buffer->pos;
  10.192 +        if (size > 1) len -= len%size;
  10.193 +    }
  10.194 +    
  10.195 +    if (len <= 0) {
  10.196 +        return len;
  10.197 +    }
  10.198 +    
  10.199 +    memcpy(ptr, buffer->space + buffer->pos, len);
  10.200 +    buffer->pos += len;
  10.201 +    
  10.202 +    return len / size;
  10.203 +}
  10.204 +
  10.205 +int ucx_buffer_putc(UcxBuffer *buffer, int c) {
  10.206 +    if(buffer->pos >= buffer->capacity) {
  10.207 +        if ((buffer->flags & UCX_BUFFER_AUTOEXTEND) == UCX_BUFFER_AUTOEXTEND) {
  10.208 +            if(ucx_buffer_extend(buffer, 1)) {
  10.209 +                return EOF;
  10.210 +            }
  10.211 +        } else {
  10.212 +            return EOF;
  10.213 +        }
  10.214 +    }
  10.215 +    
  10.216 +    c &= 0xFF;
  10.217 +    buffer->space[buffer->pos] = (char) c;
  10.218 +    buffer->pos++;
  10.219 +    if(buffer->pos > buffer->size) {
  10.220 +        buffer->size = buffer->pos;
  10.221 +    }
  10.222 +    return c;
  10.223 +}
  10.224 +
  10.225 +int ucx_buffer_getc(UcxBuffer *buffer) {
  10.226 +    if (ucx_buffer_eof(buffer)) {
  10.227 +        return EOF;
  10.228 +    } else {
  10.229 +        int c = buffer->space[buffer->pos];
  10.230 +        buffer->pos++;
  10.231 +        return c;
  10.232 +    }
  10.233 +}
  10.234 +
  10.235 +size_t ucx_buffer_puts(UcxBuffer *buffer, char *str) {
  10.236 +    return ucx_buffer_write((const void*)str, 1, strlen(str), buffer);
  10.237 +}
    11.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    11.2 +++ b/src/ucx/buffer.h	Tue Aug 23 13:49:38 2016 +0200
    11.3 @@ -0,0 +1,270 @@
    11.4 +/*
    11.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    11.6 + *
    11.7 + * Copyright 2015 Olaf Wintermann. All rights reserved.
    11.8 + *
    11.9 + * Redistribution and use in source and binary forms, with or without
   11.10 + * modification, are permitted provided that the following conditions are met:
   11.11 + *
   11.12 + *   1. Redistributions of source code must retain the above copyright
   11.13 + *      notice, this list of conditions and the following disclaimer.
   11.14 + *
   11.15 + *   2. Redistributions in binary form must reproduce the above copyright
   11.16 + *      notice, this list of conditions and the following disclaimer in the
   11.17 + *      documentation and/or other materials provided with the distribution.
   11.18 + *
   11.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   11.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   11.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   11.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   11.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   11.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   11.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   11.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   11.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   11.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   11.29 + * POSSIBILITY OF SUCH DAMAGE.
   11.30 + */
   11.31 +
   11.32 +/**
   11.33 + * @file buffer.h
   11.34 + * 
   11.35 + * Advanced buffer implementation.
   11.36 + * 
   11.37 + * Instances of UcxBuffer can be used to read from or to write to like one
   11.38 + * would do with a stream. This allows the use of ucx_stream_copy() to copy
   11.39 + * contents from one buffer to another.
   11.40 + * 
   11.41 + * Some features for convenient use of the buffer
   11.42 + * can be enabled. See the documentation of the macro constants for more
   11.43 + * information.
   11.44 + * 
   11.45 + * @author Mike Becker
   11.46 + * @author Olaf Wintermann
   11.47 + */
   11.48 +
   11.49 +#ifndef UCX_BUFFER_H
   11.50 +#define	UCX_BUFFER_H
   11.51 +
   11.52 +#include "ucx.h"
   11.53 +#include <sys/types.h>
   11.54 +#include <stdio.h>
   11.55 +
   11.56 +#ifdef	__cplusplus
   11.57 +extern "C" {
   11.58 +#endif
   11.59 +
   11.60 +/**
   11.61 + * No buffer features enabled (all flags cleared).
   11.62 + */
   11.63 +#define UCX_BUFFER_DEFAULT      0x00
   11.64 +
   11.65 +/**
   11.66 + * If this flag is enabled, the buffer will automatically free its contents.
   11.67 + */
   11.68 +#define UCX_BUFFER_AUTOFREE     0x01
   11.69 +
   11.70 +/**
   11.71 + * If this flag is enabled, the buffer will automatically extends its capacity.
   11.72 + */
   11.73 +#define UCX_BUFFER_AUTOEXTEND   0x02
   11.74 +
   11.75 +/** UCX Buffer. */
   11.76 +typedef struct {
   11.77 +    /** A pointer to the buffer contents. */
   11.78 +    char *space;
   11.79 +    /** Current position of the buffer. */
   11.80 +    size_t pos;
   11.81 +    /** Current capacity (i.e. maximum size) of the buffer. */
   11.82 +    size_t capacity;
   11.83 +    /** Current size of the buffer content. */
   11.84 +    size_t size;
   11.85 +    /**
   11.86 +     * Flag register for buffer features.
   11.87 +     * @see #UCX_BUFFER_DEFAULT
   11.88 +     * @see #UCX_BUFFER_AUTOFREE
   11.89 +     * @see #UCX_BUFFER_AUTOEXTEND
   11.90 +     */
   11.91 +    int flags;
   11.92 +} UcxBuffer;
   11.93 +
   11.94 +/**
   11.95 + * Creates a new buffer.
   11.96 + * 
   11.97 + * <b>Note:</b> you may provide <code>NULL</code> as argument for
   11.98 + * <code>space</code>. Then this function will allocate the space and enforce
   11.99 + * the #UCX_BUFFER_AUTOFREE flag.
  11.100 + * 
  11.101 + * @param space pointer to the memory area, or <code>NULL</code> to allocate
  11.102 + * new memory
  11.103 + * @param capacity the capacity of the buffer
  11.104 + * @param flags buffer features (see UcxBuffer.flags)
  11.105 + * @return the new buffer
  11.106 + */
  11.107 +UcxBuffer *ucx_buffer_new(void *space, size_t capacity, int flags);
  11.108 +
  11.109 +/**
  11.110 + * Destroys a buffer.
  11.111 + * 
  11.112 + * If the #UCX_BUFFER_AUTOFREE feature is enabled, the contents of the buffer
  11.113 + * are also freed.
  11.114 + * 
  11.115 + * @param buffer the buffer to destroy
  11.116 + */
  11.117 +void ucx_buffer_free(UcxBuffer* buffer);
  11.118 +
  11.119 +/**
  11.120 + * Creates a new buffer and fills it with extracted content from another buffer.
  11.121 + * 
  11.122 + * <b>Note:</b> the #UCX_BUFFER_AUTOFREE feature is enforced for the new buffer.
  11.123 + * 
  11.124 + * @param src the source buffer
  11.125 + * @param start the start position of extraction
  11.126 + * @param length the count of bytes to extract (must not be zero)
  11.127 + * @param flags feature mask for the new buffer
  11.128 + * @return a new buffer containing the extraction
  11.129 + */
  11.130 +UcxBuffer* ucx_buffer_extract(UcxBuffer *src,
  11.131 +        size_t start, size_t length, int flags);
  11.132 +
  11.133 +/**
  11.134 + * A shorthand macro for the full extraction of the buffer.
  11.135 + * 
  11.136 + * @param src the source buffer
  11.137 + * @param flags feature mask for the new buffer
  11.138 + * @return a new buffer with the extracted content
  11.139 + */
  11.140 +#define ucx_buffer_clone(src,flags) \
  11.141 +    ucx_buffer_extract(src, 0, (src)->capacity, flags)
  11.142 +
  11.143 +/**
  11.144 + * Moves the position of the buffer.
  11.145 + * 
  11.146 + * The new position is relative to the <code>whence</code> argument.
  11.147 + *
  11.148 + * SEEK_SET marks the start of the buffer.
  11.149 + * SEEK_CUR marks the current position.
  11.150 + * SEEK_END marks the end of the buffer.
  11.151 + * 
  11.152 + * With an offset of zero, this function sets the buffer position to zero
  11.153 + * (SEEK_SET), the buffer size (SEEK_END) or leaves the buffer position
  11.154 + * unchanged (SEEK_CUR).
  11.155 + * 
  11.156 + * @param buffer
  11.157 + * @param offset position offset relative to <code>whence</code>
  11.158 + * @param whence one of SEEK_SET, SEEK_CUR or SEEK_END
  11.159 + * @return 0 on success, non-zero if the position is invalid
  11.160 + *
  11.161 + */
  11.162 +int ucx_buffer_seek(UcxBuffer *buffer, off_t offset, int whence);
  11.163 +
  11.164 +/**
  11.165 + * Clears the buffer by resetting the position and deleting the data.
  11.166 + * 
  11.167 + * The data is deleted by a zeroing it with call to <code>memset()</code>.
  11.168 + * 
  11.169 + * @param buffer the buffer to be cleared
  11.170 + */
  11.171 +#define ucx_buffer_clear(buffer) memset(buffer->space, 0, buffer->size); \
  11.172 +        buffer->size = 0; buffer->pos = 0;
  11.173 +
  11.174 +/**
  11.175 + * Tests, if the buffer position has exceeded the buffer capacity.
  11.176 + * 
  11.177 + * @param buffer the buffer to test
  11.178 + * @return non-zero, if the current buffer position has exceeded the last
  11.179 + * available byte of the buffer.
  11.180 + */
  11.181 +int ucx_buffer_eof(UcxBuffer *buffer);
  11.182 +
  11.183 +
  11.184 +/**
  11.185 + * Extends the capacity of the buffer.
  11.186 + * 
  11.187 + * <b>Note:</b> The buffer capacity increased by a power of two. I.e.
  11.188 + * the buffer capacity is doubled, as long as it would not hold the current
  11.189 + * content plus the additional required bytes.
  11.190 + * 
  11.191 + * <b>Attention:</b> the argument provided is the number of <i>additional</i>
  11.192 + * bytes the buffer shall hold. It is <b>NOT</b> the total number of bytes the
  11.193 + * buffer shall hold.
  11.194 + * 
  11.195 + * @param buffer the buffer to extend
  11.196 + * @param additional_bytes the number of additional bytes the buffer shall
  11.197 + * <i>at least</i> hold
  11.198 + * @return 0 on success or a non-zero value on failure
  11.199 + */
  11.200 +int ucx_buffer_extend(UcxBuffer *buffer, size_t additional_bytes);
  11.201 +
  11.202 +/**
  11.203 + * Writes data to an UcxBuffer.
  11.204 + * 
  11.205 + * The position of the buffer is increased by the number of bytes written.
  11.206 + * 
  11.207 + * @param ptr a pointer to the memory area containing the bytes to be written
  11.208 + * @param size the length of one element
  11.209 + * @param nitems the element count
  11.210 + * @param buffer the UcxBuffer to write to
  11.211 + * @return the total count of bytes written
  11.212 + */
  11.213 +size_t ucx_buffer_write(const void *ptr, size_t size, size_t nitems,
  11.214 +        UcxBuffer *buffer);
  11.215 +
  11.216 +/**
  11.217 + * Reads data from an UcxBuffer.
  11.218 + * 
  11.219 + * The position of the buffer is increased by the number of bytes read.
  11.220 + * 
  11.221 + * @param ptr a pointer to the memory area where to store the read data
  11.222 + * @param size the length of one element
  11.223 + * @param nitems the element count
  11.224 + * @param buffer the UcxBuffer to read from
  11.225 + * @return the total number of elements read
  11.226 + */
  11.227 +size_t ucx_buffer_read(void *ptr, size_t size, size_t nitems,
  11.228 +        UcxBuffer *buffer);
  11.229 +
  11.230 +/**
  11.231 + * Writes a character to a buffer.
  11.232 + * 
  11.233 + * The least significant byte of the argument is written to the buffer. If the
  11.234 + * end of the buffer is reached and #UCX_BUFFER_AUTOEXTEND feature is enabled,
  11.235 + * the buffer capacity is extended by ucx_buffer_extend(). If the feature is
  11.236 + * disabled or buffer extension fails, <code>EOF</code> is returned.
  11.237 + * 
  11.238 + * On successful write the position of the buffer is increased.
  11.239 + * 
  11.240 + * @param buffer the buffer to write to
  11.241 + * @param c the character to write as <code>int</code> value
  11.242 + * @return the byte that has bean written as <code>int</code> value or
  11.243 + * <code>EOF</code> when the end of the stream is reached and automatic
  11.244 + * extension is not enabled or not possible
  11.245 + */
  11.246 +int ucx_buffer_putc(UcxBuffer *buffer, int c);
  11.247 +
  11.248 +/**
  11.249 + * Gets a character from a buffer.
  11.250 + * 
  11.251 + * The current position of the buffer is increased after a successful read.
  11.252 + * 
  11.253 + * @param buffer the buffer to read from
  11.254 + * @return the character as <code>int</code> value or <code>EOF</code>, if the
  11.255 + * end of the buffer is reached
  11.256 + */
  11.257 +int ucx_buffer_getc(UcxBuffer *buffer);
  11.258 +
  11.259 +/**
  11.260 + * Writes a string to a buffer.
  11.261 + * 
  11.262 + * @param buffer the buffer
  11.263 + * @param str the string
  11.264 + * @return the number of bytes written
  11.265 + */
  11.266 +size_t ucx_buffer_puts(UcxBuffer *buffer, char *str);
  11.267 +
  11.268 +#ifdef	__cplusplus
  11.269 +}
  11.270 +#endif
  11.271 +
  11.272 +#endif	/* UCX_BUFFER_H */
  11.273 +
    12.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    12.2 +++ b/src/ucx/list.c	Tue Aug 23 13:49:38 2016 +0200
    12.3 @@ -0,0 +1,335 @@
    12.4 +/*
    12.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    12.6 + *
    12.7 + * Copyright 2015 Olaf Wintermann. All rights reserved.
    12.8 + *
    12.9 + * Redistribution and use in source and binary forms, with or without
   12.10 + * modification, are permitted provided that the following conditions are met:
   12.11 + *
   12.12 + *   1. Redistributions of source code must retain the above copyright
   12.13 + *      notice, this list of conditions and the following disclaimer.
   12.14 + *
   12.15 + *   2. Redistributions in binary form must reproduce the above copyright
   12.16 + *      notice, this list of conditions and the following disclaimer in the
   12.17 + *      documentation and/or other materials provided with the distribution.
   12.18 + *
   12.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   12.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   12.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   12.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   12.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   12.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   12.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   12.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   12.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   12.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   12.29 + * POSSIBILITY OF SUCH DAMAGE.
   12.30 + */
   12.31 +
   12.32 +#include "list.h"
   12.33 +
   12.34 +UcxList *ucx_list_clone(UcxList *l, copy_func fnc, void *data) {
   12.35 +    return ucx_list_clone_a(ucx_default_allocator(), l, fnc, data);
   12.36 +}
   12.37 +
   12.38 +UcxList *ucx_list_clone_a(UcxAllocator *alloc, UcxList *l,
   12.39 +        copy_func fnc, void *data) {
   12.40 +    UcxList *ret = NULL;
   12.41 +    while (l) {
   12.42 +        if (fnc) {
   12.43 +            ret = ucx_list_append_a(alloc, ret, fnc(l->data, data));
   12.44 +        } else {
   12.45 +            ret = ucx_list_append_a(alloc, ret, l->data);
   12.46 +        }
   12.47 +        l = l->next;
   12.48 +    }
   12.49 +    return ret;
   12.50 +}
   12.51 +
   12.52 +int ucx_list_equals(const UcxList *l1, const UcxList *l2,
   12.53 +        cmp_func fnc, void* data) {
   12.54 +    if (l1 == l2) return 1;
   12.55 +    
   12.56 +    while (l1 != NULL && l2 != NULL) {
   12.57 +        if (fnc == NULL) {
   12.58 +            if (l1->data != l2->data) return 0;
   12.59 +        } else {
   12.60 +            if (fnc(l1->data, l2->data, data) != 0) return 0;
   12.61 +        }
   12.62 +        l1 = l1->next;
   12.63 +        l2 = l2->next;
   12.64 +    }
   12.65 +    
   12.66 +    return (l1 == NULL && l2 == NULL);
   12.67 +}
   12.68 +
   12.69 +void ucx_list_free(UcxList *l) {
   12.70 +    ucx_list_free_a(ucx_default_allocator(), l);
   12.71 +}
   12.72 +
   12.73 +void ucx_list_free_a(UcxAllocator *alloc, UcxList *l) {
   12.74 +    UcxList *e = l, *f;
   12.75 +    while (e != NULL) {
   12.76 +        f = e;
   12.77 +        e = e->next;
   12.78 +        alfree(alloc, f);
   12.79 +    }
   12.80 +}
   12.81 +
   12.82 +void ucx_list_free_content(UcxList* list, ucx_destructor destr) {
   12.83 +    while (list != NULL) {
   12.84 +        destr(list->data);
   12.85 +        list = list->next;
   12.86 +    }
   12.87 +}
   12.88 +
   12.89 +UcxList *ucx_list_append(UcxList *l, void *data)  {
   12.90 +    return ucx_list_append_a(ucx_default_allocator(), l, data);
   12.91 +}
   12.92 +
   12.93 +UcxList *ucx_list_append_a(UcxAllocator *alloc, UcxList *l, void *data)  {
   12.94 +    UcxList *nl = (UcxList*) almalloc(alloc, sizeof(UcxList));
   12.95 +    if (!nl) {
   12.96 +        return NULL;
   12.97 +    }
   12.98 +    
   12.99 +    nl->data = data;
  12.100 +    nl->next = NULL;
  12.101 +    if (l) {
  12.102 +        UcxList *t = ucx_list_last(l);
  12.103 +        t->next = nl;
  12.104 +        nl->prev = t;
  12.105 +        return l;
  12.106 +    } else {
  12.107 +        nl->prev = NULL;
  12.108 +        return nl;
  12.109 +    }
  12.110 +}
  12.111 +
  12.112 +UcxList *ucx_list_prepend(UcxList *l, void *data) {
  12.113 +    return ucx_list_prepend_a(ucx_default_allocator(), l, data);
  12.114 +}
  12.115 +
  12.116 +UcxList *ucx_list_prepend_a(UcxAllocator *alloc, UcxList *l, void *data) {
  12.117 +    UcxList *nl = ucx_list_append_a(alloc, NULL, data);
  12.118 +    if (!nl) {
  12.119 +        return NULL;
  12.120 +    }
  12.121 +    l = ucx_list_first(l);
  12.122 +    
  12.123 +    if (l) {
  12.124 +        nl->next = l;
  12.125 +        l->prev = nl;
  12.126 +    }
  12.127 +    return nl;
  12.128 +}
  12.129 +
  12.130 +UcxList *ucx_list_concat(UcxList *l1, UcxList *l2) {
  12.131 +    if (l1) {
  12.132 +        UcxList *last = ucx_list_last(l1);
  12.133 +        last->next = l2;
  12.134 +        if (l2) {
  12.135 +            l2->prev = last;
  12.136 +        }
  12.137 +        return l1;
  12.138 +    } else {
  12.139 +        return l2;
  12.140 +    }
  12.141 +}
  12.142 +
  12.143 +UcxList *ucx_list_last(const UcxList *l) {
  12.144 +    if (l == NULL) return NULL;
  12.145 +    
  12.146 +    const UcxList *e = l;
  12.147 +    while (e->next != NULL) {
  12.148 +        e = e->next;
  12.149 +    }
  12.150 +    return (UcxList*)e;
  12.151 +}
  12.152 +
  12.153 +ssize_t ucx_list_indexof(const UcxList *list, const UcxList *elem) {
  12.154 +    ssize_t index = 0;
  12.155 +    while (list) {
  12.156 +        if (list == elem) {
  12.157 +            return index;
  12.158 +        }
  12.159 +        list = list->next;
  12.160 +        index++;
  12.161 +    }
  12.162 +    return -1;
  12.163 +}
  12.164 +
  12.165 +UcxList *ucx_list_get(const UcxList *l, size_t index) {
  12.166 +    if (l == NULL) return NULL;
  12.167 +
  12.168 +    const UcxList *e = l;
  12.169 +    while (e->next && index > 0) {
  12.170 +        e = e->next;
  12.171 +        index--;
  12.172 +    }
  12.173 +    
  12.174 +    return (UcxList*)(index == 0 ? e : NULL);
  12.175 +}
  12.176 +
  12.177 +ssize_t ucx_list_find(UcxList *l, void *elem, cmp_func fnc, void *cmpdata) {
  12.178 +    ssize_t index = 0;
  12.179 +    UCX_FOREACH(e, l) {
  12.180 +        if (fnc) {
  12.181 +            if (fnc(elem, e->data, cmpdata) == 0) {
  12.182 +                return index;
  12.183 +            }
  12.184 +        } else {
  12.185 +            if (elem == e->data) {
  12.186 +                return index;
  12.187 +            }
  12.188 +        }
  12.189 +        index++;
  12.190 +    }
  12.191 +    return -1;
  12.192 +}
  12.193 +
  12.194 +int ucx_list_contains(UcxList *l, void *elem, cmp_func fnc, void *cmpdata) {
  12.195 +    return ucx_list_find(l, elem, fnc, cmpdata) > -1;
  12.196 +}
  12.197 +
  12.198 +size_t ucx_list_size(const UcxList *l) {
  12.199 +    if (l == NULL) return 0;
  12.200 +    
  12.201 +    const UcxList *e = l;
  12.202 +    size_t s = 1;
  12.203 +    while (e->next != NULL) {
  12.204 +        e = e->next;
  12.205 +        s++;
  12.206 +    }
  12.207 +
  12.208 +    return s;
  12.209 +}
  12.210 +
  12.211 +static UcxList *ucx_list_sort_merge(int length,
  12.212 +        UcxList* restrict ls, UcxList* restrict le, UcxList* restrict re,
  12.213 +        cmp_func fnc, void* data) {
  12.214 +
  12.215 +    UcxList** sorted = (UcxList**) malloc(sizeof(UcxList*)*length);
  12.216 +    UcxList *rc, *lc;
  12.217 +
  12.218 +    lc = ls; rc = le;
  12.219 +    int n = 0;
  12.220 +    while (lc && lc != le && rc != re) {
  12.221 +        if (fnc(lc->data, rc->data, data) <= 0) {
  12.222 +            sorted[n] = lc;
  12.223 +            lc = lc->next;
  12.224 +        } else {
  12.225 +            sorted[n] = rc;
  12.226 +            rc = rc->next;
  12.227 +        }
  12.228 +        n++;
  12.229 +    }
  12.230 +    while (lc && lc != le) {
  12.231 +        sorted[n] = lc;
  12.232 +        lc = lc->next;
  12.233 +        n++;
  12.234 +    }
  12.235 +    while (rc && rc != re) {
  12.236 +        sorted[n] = rc;
  12.237 +        rc = rc->next;
  12.238 +        n++;
  12.239 +    }
  12.240 +
  12.241 +    // Update pointer
  12.242 +    sorted[0]->prev = NULL;
  12.243 +    for (int i = 0 ; i < length-1 ; i++) {
  12.244 +        sorted[i]->next = sorted[i+1];
  12.245 +        sorted[i+1]->prev = sorted[i];
  12.246 +    }
  12.247 +    sorted[length-1]->next = NULL;
  12.248 +
  12.249 +    UcxList *ret = sorted[0];
  12.250 +    free(sorted);
  12.251 +    return ret;
  12.252 +}
  12.253 +
  12.254 +UcxList *ucx_list_sort(UcxList *l, cmp_func fnc, void *data) {
  12.255 +    if (l == NULL) {
  12.256 +        return NULL;
  12.257 +    }
  12.258 +
  12.259 +    UcxList *lc;
  12.260 +    int ln = 1;
  12.261 +
  12.262 +    UcxList *restrict ls = l, *restrict le, *restrict re;
  12.263 +    
  12.264 +    // check how many elements are already sorted
  12.265 +    lc = ls;
  12.266 +    while (lc->next != NULL && fnc(lc->next->data, lc->data, data) > 0) {
  12.267 +        lc = lc->next;
  12.268 +        ln++;
  12.269 +    }
  12.270 +    le = lc->next;
  12.271 +
  12.272 +    if (le == NULL) {
  12.273 +        return l; // this list is already sorted :)
  12.274 +    } else {
  12.275 +        UcxList *rc;
  12.276 +        int rn = 1;
  12.277 +        rc = le;
  12.278 +        // skip already sorted elements
  12.279 +        while (rc->next != NULL && fnc(rc->next->data, rc->data, data) > 0) {
  12.280 +            rc = rc->next;
  12.281 +            rn++;
  12.282 +        }
  12.283 +        re = rc->next;
  12.284 +
  12.285 +        // {ls,...,le->prev} and {rs,...,re->prev} are sorted - merge them
  12.286 +        UcxList *sorted = ucx_list_sort_merge(ln+rn,
  12.287 +                ls, le, re,
  12.288 +                fnc, data);
  12.289 +        
  12.290 +        // Something left? Sort it!
  12.291 +        size_t remainder_length = ucx_list_size(re);
  12.292 +        if (remainder_length > 0) {
  12.293 +            UcxList *remainder = ucx_list_sort(re, fnc, data);
  12.294 +
  12.295 +            // merge sorted list with (also sorted) remainder
  12.296 +            l = ucx_list_sort_merge(ln+rn+remainder_length,
  12.297 +                    sorted, remainder, NULL, fnc, data);
  12.298 +        } else {
  12.299 +            // no remainder - we've got our sorted list
  12.300 +            l = sorted;
  12.301 +        }
  12.302 +
  12.303 +        return l;
  12.304 +    }
  12.305 +}
  12.306 +
  12.307 +UcxList *ucx_list_first(const UcxList *l) {
  12.308 +    if (!l) {
  12.309 +        return NULL;
  12.310 +    }
  12.311 +    
  12.312 +    const UcxList *e = l;
  12.313 +    while (e->prev) {
  12.314 +        e = e->prev;
  12.315 +    }
  12.316 +    return (UcxList *)e;
  12.317 +}
  12.318 +
  12.319 +UcxList *ucx_list_remove(UcxList *l, UcxList *e) {
  12.320 +    return ucx_list_remove_a(ucx_default_allocator(), l, e);
  12.321 +}
  12.322 +    
  12.323 +UcxList *ucx_list_remove_a(UcxAllocator *alloc, UcxList *l, UcxList *e) {
  12.324 +    if (l == e) {
  12.325 +        l = e->next;
  12.326 +    }
  12.327 +    
  12.328 +    if (e->next) {
  12.329 +        e->next->prev = e->prev;
  12.330 +    }
  12.331 +    
  12.332 +    if (e->prev) {
  12.333 +        e->prev->next = e->next;
  12.334 +    }
  12.335 +    
  12.336 +    alfree(alloc, e);
  12.337 +    return l;
  12.338 +}
    13.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    13.2 +++ b/src/ucx/list.h	Tue Aug 23 13:49:38 2016 +0200
    13.3 @@ -0,0 +1,395 @@
    13.4 +/*
    13.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    13.6 + *
    13.7 + * Copyright 2015 Olaf Wintermann. All rights reserved.
    13.8 + *
    13.9 + * Redistribution and use in source and binary forms, with or without
   13.10 + * modification, are permitted provided that the following conditions are met:
   13.11 + *
   13.12 + *   1. Redistributions of source code must retain the above copyright
   13.13 + *      notice, this list of conditions and the following disclaimer.
   13.14 + *
   13.15 + *   2. Redistributions in binary form must reproduce the above copyright
   13.16 + *      notice, this list of conditions and the following disclaimer in the
   13.17 + *      documentation and/or other materials provided with the distribution.
   13.18 + *
   13.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   13.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   13.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   13.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   13.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   13.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   13.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   13.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   13.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   13.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   13.29 + * POSSIBILITY OF SUCH DAMAGE.
   13.30 + */
   13.31 +/**
   13.32 + * Doubly linked list implementation.
   13.33 + * 
   13.34 + * @file   list.h
   13.35 + * @author Mike Becker
   13.36 + * @author Olaf Wintermann
   13.37 + */
   13.38 +
   13.39 +#ifndef UCX_LIST_H
   13.40 +#define	UCX_LIST_H
   13.41 +
   13.42 +#include "ucx.h"
   13.43 +#include "allocator.h"
   13.44 +
   13.45 +#ifdef	__cplusplus
   13.46 +extern "C" {
   13.47 +#endif
   13.48 +
   13.49 +/**
   13.50 + * Loop statement for UCX lists.
   13.51 + * 
   13.52 + * The first argument is the name of the iteration variable. The scope of
   13.53 + * this variable is limited to the <code>UCX_FOREACH</code> statement.
   13.54 + * 
   13.55 + * The second argument is a pointer to the list. In most cases this will be the
   13.56 + * pointer to the first element of the list, but it may also be an arbitrary
   13.57 + * element of the list. The iteration will then start with that element.
   13.58 + * 
   13.59 + * 
   13.60 + * @param list The first element of the list
   13.61 + * @param elem The variable name of the element
   13.62 + */
   13.63 +#define UCX_FOREACH(elem,list) \
   13.64 +        for (UcxList* elem = list ; elem != NULL ; elem = elem->next)
   13.65 +
   13.66 +/**
   13.67 + * UCX list type.
   13.68 + * @see UcxList
   13.69 + */
   13.70 +typedef struct UcxList UcxList;
   13.71 +
   13.72 +/**
   13.73 + * UCX list structure.
   13.74 + */
   13.75 +struct UcxList {
   13.76 +    /**
   13.77 +     * List element payload.
   13.78 +     */
   13.79 +    void    *data;
   13.80 +    /**
   13.81 +     * Pointer to the next list element or <code>NULL</code>, if this is the
   13.82 +     * last element.
   13.83 +     */
   13.84 +    UcxList *next;
   13.85 +    /**
   13.86 +     * Pointer to the previous list element or <code>NULL</code>, if this is
   13.87 +     * the first element.
   13.88 +     */
   13.89 +    UcxList *prev;
   13.90 +};
   13.91 +
   13.92 +/**
   13.93 + * Creates an element-wise copy of a list.
   13.94 + * 
   13.95 + * This function clones the specified list by creating new list elements and
   13.96 + * copying the data with the specified copy_func(). If no copy_func() is
   13.97 + * specified, a shallow copy is created and the new list will reference the
   13.98 + * same data as the source list.
   13.99 + * 
  13.100 + * @param list the list to copy
  13.101 + * @param cpyfnc a pointer to the function that shall copy an element (may be
  13.102 + * <code>NULL</code>)
  13.103 + * @param data additional data for the copy_func()
  13.104 + * @return a pointer to the copy
  13.105 + */
  13.106 +UcxList *ucx_list_clone(UcxList *list, copy_func cpyfnc, void* data);
  13.107 +
  13.108 +/**
  13.109 + * Creates an element-wise copy of a list using an UcxAllocator.
  13.110 + * 
  13.111 + * See ucx_list_clone() for details.
  13.112 + * 
  13.113 + * Keep in mind, that you might want to pass the allocator as an (part of the)
  13.114 + * argument for the <code>data</code> parameter, if you want the copy_func() to
  13.115 + * make use of the allocator.
  13.116 + * 
  13.117 + * @param allocator the allocator to use
  13.118 + * @param list the list to copy
  13.119 + * @param cpyfnc a pointer to the function that shall copy an element (may be
  13.120 + * <code>NULL</code>)
  13.121 + * @param data additional data for the copy_func()
  13.122 + * @return a pointer to the copy
  13.123 + * @see ucx_list_clone()
  13.124 + */
  13.125 +UcxList *ucx_list_clone_a(UcxAllocator *allocator, UcxList *list,
  13.126 +        copy_func cpyfnc, void* data);
  13.127 +
  13.128 +/**
  13.129 + * Compares two UCX lists element-wise by using a compare function.
  13.130 + * 
  13.131 + * Each element of the two specified lists are compared by using the specified
  13.132 + * compare function and the additional data. The type and content of this
  13.133 + * additional data depends on the cmp_func() used.
  13.134 + * 
  13.135 + * If the list pointers denote elements within a list, the lists are compared
  13.136 + * starting with the denoted elements. Thus any previous elements are not taken
  13.137 + * into account. This might be useful to check, if certain list tails match
  13.138 + * each other.
  13.139 + * 
  13.140 + * @param list1 the first list
  13.141 + * @param list2 the second list
  13.142 + * @param cmpfnc the compare function
  13.143 + * @param data additional data for the compare function
  13.144 + * @return 1, if and only if the two lists equal element-wise, 0 otherwise
  13.145 + */
  13.146 +int ucx_list_equals(const UcxList *list1, const UcxList *list2,
  13.147 +        cmp_func cmpfnc, void* data);
  13.148 +
  13.149 +/**
  13.150 + * Destroys the entire list.
  13.151 + * 
  13.152 + * The members of the list are not automatically freed, so ensure they are
  13.153 + * otherwise referenced or destroyed by ucx_list_free_contents().
  13.154 + * Otherwise, a memory leak is likely to occur.
  13.155 + * 
  13.156 + * <b>Caution:</b> the argument <b>MUST</b> denote an entire list (i.e. a call
  13.157 + * to ucx_list_first() on the argument must return the argument itself)
  13.158 + * 
  13.159 + * @param list the list to free
  13.160 + * @see ucx_list_free_contents()
  13.161 + */
  13.162 +void ucx_list_free(UcxList *list);
  13.163 +
  13.164 +/**
  13.165 + * Destroys the entire list using an UcxAllocator.
  13.166 + * 
  13.167 + * See ucx_list_free() for details.
  13.168 + * 
  13.169 + * @param allocator the allocator to use
  13.170 + * @param list the list to free
  13.171 + * @see ucx_list_free()
  13.172 + */
  13.173 +void ucx_list_free_a(UcxAllocator *allocator, UcxList *list);
  13.174 +
  13.175 +/**
  13.176 + * Destroys the contents of the specified list by calling the specified
  13.177 + * destructor on each of them.
  13.178 + * 
  13.179 + * Note, that the contents are not usable afterwards and the list should be
  13.180 + * destroyed with ucx_list_free().
  13.181 + * 
  13.182 + * @param list the list for which the contents shall be freed
  13.183 + * @param destr the destructor function (e.g. stdlib free())
  13.184 + * @see ucx_list_free()
  13.185 + */
  13.186 +void ucx_list_free_content(UcxList* list, ucx_destructor destr);
  13.187 +
  13.188 +
  13.189 +/**
  13.190 + * Inserts an element at the end of the list.
  13.191 + * 
  13.192 + * This is generally an O(n) operation, as the end of the list is retrieved with
  13.193 + * ucx_list_last().
  13.194 + * 
  13.195 + * @param list the list where to append the data, or <code>NULL</code> to
  13.196 + * create a new list
  13.197 + * @param data the data to insert
  13.198 + * @return <code>list</code>, if it is not <code>NULL</code> or a pointer to
  13.199 + * the newly created list otherwise
  13.200 + */
  13.201 +UcxList *ucx_list_append(UcxList *list, void *data);
  13.202 +
  13.203 +/**
  13.204 + * Inserts an element at the end of the list using an UcxAllocator.
  13.205 + * 
  13.206 + * See ucx_list_append() for details.
  13.207 + * 
  13.208 + * @param allocator the allocator to use
  13.209 + * @param list the list where to append the data, or <code>NULL</code> to
  13.210 + * create a new list
  13.211 + * @param data the data to insert
  13.212 + * @return <code>list</code>, if it is not <code>NULL</code> or a pointer to
  13.213 + * the newly created list otherwise
  13.214 + * @see ucx_list_append()
  13.215 + */
  13.216 +UcxList *ucx_list_append_a(UcxAllocator *allocator, UcxList *list, void *data);
  13.217 +
  13.218 +/**
  13.219 + * Inserts an element at the beginning of the list.
  13.220 + * 
  13.221 + * You <i>should</i> overwrite the old list pointer by calling
  13.222 + * <code>mylist = ucx_list_prepend(mylist, mydata);</code>. However, you may
  13.223 + * also perform successive calls of ucx_list_prepend() on the same list pointer,
  13.224 + * as this function always searchs for the head of the list with
  13.225 + * ucx_list_first().
  13.226 + * 
  13.227 + * @param list the list where to insert the data or <code>NULL</code> to create
  13.228 + * a new list
  13.229 + * @param data the data to insert
  13.230 + * @return a pointer to the new list head
  13.231 + */
  13.232 +UcxList *ucx_list_prepend(UcxList *list, void *data);
  13.233 +
  13.234 +/**
  13.235 + * Inserts an element at the beginning of the list using an UcxAllocator.
  13.236 + * 
  13.237 + * See ucx_list_prepend() for details.
  13.238 + * 
  13.239 + * @param allocator the allocator to use
  13.240 + * @param list the list where to insert the data or <code>NULL</code> to create
  13.241 + * a new list
  13.242 + * @param data the data to insert
  13.243 + * @return a pointer to the new list head
  13.244 + * @see ucx_list_prepend()
  13.245 + */
  13.246 +UcxList *ucx_list_prepend_a(UcxAllocator *allocator, UcxList *list, void *data);
  13.247 +
  13.248 +/**
  13.249 + * Concatenates two lists.
  13.250 + * 
  13.251 + * Either of the two arguments may be <code>NULL</code>.
  13.252 + * 
  13.253 + * This function modifies the references to the next/previous element of
  13.254 + * the last/first element of <code>list1</code>/<code>
  13.255 + * list2</code>.
  13.256 + * 
  13.257 + * @param list1 first list
  13.258 + * @param list2 second list
  13.259 + * @return if <code>list1</code> is <code>NULL</code>, <code>list2</code> is
  13.260 + * returned, otherwise <code>list1</code> is returned
  13.261 + */
  13.262 +UcxList *ucx_list_concat(UcxList *list1, UcxList *list2);
  13.263 +
  13.264 +/**
  13.265 + * Returns the first element of a list.
  13.266 + * 
  13.267 + * If the argument is the list pointer, it is directly returned. Otherwise
  13.268 + * this function traverses to the first element of the list and returns the
  13.269 + * list pointer.
  13.270 + * 
  13.271 + * @param elem one element of the list
  13.272 + * @return the first element of the list, the specified element is a member of
  13.273 + */
  13.274 +UcxList *ucx_list_first(const UcxList *elem);
  13.275 +
  13.276 +/**
  13.277 + * Returns the last element of a list.
  13.278 + * 
  13.279 + * If the argument has no successor, it is the last element and therefore
  13.280 + * directly returned. Otherwise this function traverses to the last element of
  13.281 + * the list and returns it.
  13.282 + * 
  13.283 + * @param elem one element of the list
  13.284 + * @return the last element of the list, the specified element is a member of
  13.285 + */
  13.286 +UcxList *ucx_list_last(const UcxList *elem);
  13.287 +
  13.288 +/**
  13.289 + * Returns the list element at the specified index.
  13.290 + * 
  13.291 + * @param list the list to retrieve the element from
  13.292 + * @param index index of the element to return
  13.293 + * @return the element at the specified index or <code>NULL</code>, if the
  13.294 + * index is greater than the list size
  13.295 + */
  13.296 +UcxList *ucx_list_get(const UcxList *list, size_t index);
  13.297 +
  13.298 +/**
  13.299 + * Returns the index of an element.
  13.300 + * 
  13.301 + * @param list the list where to search for the element
  13.302 + * @param elem the element to find
  13.303 + * @return the index of the element or -1 if the list does not contain the
  13.304 + * element
  13.305 + */
  13.306 +ssize_t ucx_list_indexof(const UcxList *list, const UcxList *elem);
  13.307 +
  13.308 +/**
  13.309 + * Returns the element count of the list.
  13.310 + * 
  13.311 + * @param list the list whose elements are counted
  13.312 + * @return the element count
  13.313 + */
  13.314 +size_t ucx_list_size(const UcxList *list);
  13.315 +
  13.316 +/**
  13.317 + * Returns the index of an element containing the specified data.
  13.318 + *
  13.319 + * This function uses a cmp_func() to compare the data of each list element
  13.320 + * with the specified data. If no cmp_func is provided, the pointers are
  13.321 + * compared.
  13.322 + * 
  13.323 + * If the list contains the data more than once, the index of the first
  13.324 + * occurrence is returned.
  13.325 + *  
  13.326 + * @param list the list where to search for the data
  13.327 + * @param elem the element data
  13.328 + * @param cmpfnc the compare function
  13.329 + * @param data additional data for the compare function
  13.330 + * @return the index of the element containing the specified data or -1 if the
  13.331 + * data is not found in this list
  13.332 + */
  13.333 +ssize_t ucx_list_find(UcxList *list, void *elem, cmp_func cmpfnc, void *data);
  13.334 +
  13.335 +/**
  13.336 + * Checks, if a list contains a specific element.
  13.337 + * 
  13.338 + * An element is found, if ucx_list_find() returns a value greater than -1.
  13.339 + * 
  13.340 + * @param list the list where to search for the data
  13.341 + * @param elem the element data
  13.342 + * @param cmpfnc the compare function
  13.343 + * @param data additional data for the compare function
  13.344 + * @return 1, if and only if the list contains the specified element data
  13.345 + * @see ucx_list_find()
  13.346 + */
  13.347 +int ucx_list_contains(UcxList *list, void *elem, cmp_func cmpfnc, void *data);
  13.348 +
  13.349 +/**
  13.350 + * Sorts an UcxList with natural merge sort.
  13.351 + * 
  13.352 + * This function uses O(n) additional temporary memory for merge operations
  13.353 + * that is automatically freed after each merge.
  13.354 + * 
  13.355 + * As the head of the list might change, you <b>MUST</b> call this function
  13.356 + * as follows: <code>mylist = ucx_list_sort(mylist, mycmpfnc, mydata);</code>.
  13.357 + * 
  13.358 + * @param list the list to sort
  13.359 + * @param cmpfnc the function that shall be used to compare the element data
  13.360 + * @param data additional data for the cmp_func()
  13.361 + * @return the sorted list
  13.362 + */
  13.363 +UcxList *ucx_list_sort(UcxList *list, cmp_func cmpfnc, void *data);
  13.364 +
  13.365 +/**
  13.366 + * Removes an element from the list.
  13.367 + * 
  13.368 + * If the first element is removed, the list pointer changes. So it is
  13.369 + * <i>highly recommended</i> to <i>always</i> update the pointer by calling
  13.370 + * <code>mylist = ucx_list_remove(mylist, myelem);</code>.
  13.371 + * 
  13.372 + * @param list the list from which the element shall be removed
  13.373 + * @param element the element to remove
  13.374 + * @return returns the updated list pointer or <code>NULL</code>, if the list
  13.375 + * is now empty
  13.376 + */
  13.377 +UcxList *ucx_list_remove(UcxList *list, UcxList *element);
  13.378 +
  13.379 +/**
  13.380 + * Removes an element from the list using an UcxAllocator.
  13.381 + * 
  13.382 + * See ucx_list_remove() for details.
  13.383 + * 
  13.384 + * @param allocator the allocator to use
  13.385 + * @param list the list from which the element shall be removed
  13.386 + * @param element the element to remove
  13.387 + * @return returns the updated list pointer or <code>NULL</code>, if the list
  13.388 + * @see ucx_list_remove()
  13.389 + */
  13.390 +UcxList *ucx_list_remove_a(UcxAllocator *allocator, UcxList *list,
  13.391 +        UcxList *element);
  13.392 +
  13.393 +#ifdef	__cplusplus
  13.394 +}
  13.395 +#endif
  13.396 +
  13.397 +#endif	/* UCX_LIST_H */
  13.398 +
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/src/ucx/string.c	Tue Aug 23 13:49:38 2016 +0200
    14.3 @@ -0,0 +1,381 @@
    14.4 +/*
    14.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    14.6 + *
    14.7 + * Copyright 2015 Olaf Wintermann. All rights reserved.
    14.8 + *
    14.9 + * Redistribution and use in source and binary forms, with or without
   14.10 + * modification, are permitted provided that the following conditions are met:
   14.11 + *
   14.12 + *   1. Redistributions of source code must retain the above copyright
   14.13 + *      notice, this list of conditions and the following disclaimer.
   14.14 + *
   14.15 + *   2. Redistributions in binary form must reproduce the above copyright
   14.16 + *      notice, this list of conditions and the following disclaimer in the
   14.17 + *      documentation and/or other materials provided with the distribution.
   14.18 + *
   14.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   14.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   14.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   14.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   14.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   14.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   14.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   14.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   14.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   14.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   14.29 + * POSSIBILITY OF SUCH DAMAGE.
   14.30 + */
   14.31 +
   14.32 +#include <stdlib.h>
   14.33 +#include <string.h>
   14.34 +#include <stdarg.h>
   14.35 +#include <ctype.h>
   14.36 +
   14.37 +#include "string.h"
   14.38 +#include "allocator.h"
   14.39 +
   14.40 +sstr_t sstr(char *cstring) {
   14.41 +    sstr_t string;
   14.42 +    string.ptr = cstring;
   14.43 +    string.length = strlen(cstring);
   14.44 +    return string;
   14.45 +}
   14.46 +
   14.47 +sstr_t sstrn(char *cstring, size_t length) {
   14.48 +    sstr_t string;
   14.49 +    string.ptr = cstring;
   14.50 +    string.length = length;
   14.51 +    return string;
   14.52 +}
   14.53 +
   14.54 +size_t sstrnlen(size_t n, sstr_t s, ...) {
   14.55 +    va_list ap;
   14.56 +    size_t size = s.length;
   14.57 +    va_start(ap, s);
   14.58 +
   14.59 +    for (size_t i = 1 ; i < n ; i++) {
   14.60 +        sstr_t str = va_arg(ap, sstr_t);
   14.61 +        size += str.length;
   14.62 +    }
   14.63 +    va_end(ap);
   14.64 +
   14.65 +    return size;
   14.66 +}
   14.67 +
   14.68 +static sstr_t sstrvcat_a(
   14.69 +        UcxAllocator *a,
   14.70 +        size_t count,
   14.71 +        sstr_t s1,
   14.72 +        sstr_t s2,
   14.73 +        va_list ap) {
   14.74 +    sstr_t str;
   14.75 +    str.ptr = NULL;
   14.76 +    str.length = 0;
   14.77 +    if(count < 2) {
   14.78 +        return str;
   14.79 +    }
   14.80 +    
   14.81 +    sstr_t *strings = (sstr_t*) calloc(count, sizeof(sstr_t));
   14.82 +    if(!strings) {
   14.83 +        return str;
   14.84 +    }
   14.85 +    
   14.86 +    // get all args and overall length
   14.87 +    strings[0] = s1;
   14.88 +    strings[1] = s2;
   14.89 +    size_t strlen = s1.length + s2.length;
   14.90 +    for (size_t i=2;i<count;i++) {
   14.91 +        sstr_t s = va_arg (ap, sstr_t);
   14.92 +        strings[i] = s;
   14.93 +        strlen += s.length;
   14.94 +    }
   14.95 +    
   14.96 +    // create new string
   14.97 +    str.ptr = (char*) almalloc(a, strlen + 1);
   14.98 +    str.length = strlen;
   14.99 +    if(!str.ptr) {
  14.100 +        free(strings);
  14.101 +        str.length = 0;
  14.102 +        return str;
  14.103 +    }
  14.104 +    
  14.105 +    // concatenate strings
  14.106 +    size_t pos = 0;
  14.107 +    for (size_t i=0;i<count;i++) {
  14.108 +        sstr_t s = strings[i];
  14.109 +        memcpy(str.ptr + pos, s.ptr, s.length);
  14.110 +        pos += s.length;
  14.111 +    }
  14.112 +    
  14.113 +    str.ptr[str.length] = '\0';
  14.114 +    
  14.115 +    free(strings);
  14.116 +    
  14.117 +    return str;
  14.118 +}
  14.119 +
  14.120 +sstr_t sstrcat(size_t count, sstr_t s1, sstr_t s2, ...) {
  14.121 +    va_list ap;
  14.122 +    va_start(ap, s2);
  14.123 +    sstr_t s = sstrvcat_a(ucx_default_allocator(), count, s1, s2, ap);
  14.124 +    va_end(ap);
  14.125 +    return s;
  14.126 +}
  14.127 +
  14.128 +sstr_t sstrcat_a(UcxAllocator *a, size_t count, sstr_t s1, sstr_t s2, ...) {
  14.129 +    va_list ap;
  14.130 +    va_start(ap, s2);
  14.131 +    sstr_t s = sstrvcat_a(a, count, s1, s2, ap);
  14.132 +    va_end(ap);
  14.133 +    return s;
  14.134 +}
  14.135 +
  14.136 +sstr_t sstrsubs(sstr_t s, size_t start) {
  14.137 +    return sstrsubsl (s, start, s.length-start);
  14.138 +}
  14.139 +
  14.140 +sstr_t sstrsubsl(sstr_t s, size_t start, size_t length) {
  14.141 +    sstr_t new_sstr;
  14.142 +    if (start >= s.length) {
  14.143 +        new_sstr.ptr = NULL;
  14.144 +        new_sstr.length = 0;
  14.145 +    } else {
  14.146 +        if (length > s.length-start) {
  14.147 +            length = s.length-start;
  14.148 +        }
  14.149 +        new_sstr.ptr = &s.ptr[start];
  14.150 +        new_sstr.length = length;
  14.151 +    }
  14.152 +    return new_sstr;
  14.153 +}
  14.154 +
  14.155 +sstr_t sstrchr(sstr_t s, int c) {
  14.156 +    for(size_t i=0;i<s.length;i++) {
  14.157 +        if(s.ptr[i] == c) {
  14.158 +            return sstrsubs(s, i);
  14.159 +        }
  14.160 +    }
  14.161 +    sstr_t n;
  14.162 +    n.ptr = NULL;
  14.163 +    n.length = 0;
  14.164 +    return n;
  14.165 +}
  14.166 +
  14.167 +sstr_t sstrrchr(sstr_t s, int c) {
  14.168 +    if (s.length > 0) {
  14.169 +        for(size_t i=s.length;i>0;i--) {
  14.170 +            if(s.ptr[i-1] == c) {
  14.171 +                return sstrsubs(s, i-1);
  14.172 +            }
  14.173 +        }
  14.174 +    }
  14.175 +    sstr_t n;
  14.176 +    n.ptr = NULL;
  14.177 +    n.length = 0;
  14.178 +    return n;
  14.179 +}
  14.180 +
  14.181 +sstr_t sstrstr(sstr_t string, sstr_t match) {
  14.182 +    if (match.length == 0) {
  14.183 +        return string;
  14.184 +    }
  14.185 +    
  14.186 +    for (size_t i = 0 ; i < string.length ; i++) {
  14.187 +        sstr_t substr = sstrsubs(string, i);
  14.188 +        if (sstrprefix(substr, match)) {
  14.189 +            return substr;
  14.190 +        }
  14.191 +    }
  14.192 +    
  14.193 +    sstr_t emptystr;
  14.194 +    emptystr.length = 0;
  14.195 +    emptystr.ptr = NULL;
  14.196 +    return emptystr;
  14.197 +}
  14.198 +
  14.199 +sstr_t* sstrsplit(sstr_t s, sstr_t d, ssize_t *n) {
  14.200 +    return sstrsplit_a(ucx_default_allocator(), s, d, n);
  14.201 +}
  14.202 +
  14.203 +sstr_t* sstrsplit_a(UcxAllocator *allocator, sstr_t s, sstr_t d, ssize_t *n) {
  14.204 +    if (s.length == 0 || d.length == 0) {
  14.205 +        *n = -1;
  14.206 +        return NULL;
  14.207 +    }
  14.208 +
  14.209 +    sstr_t* result;
  14.210 +    ssize_t nmax = *n;
  14.211 +    *n = 1;
  14.212 +
  14.213 +    /* special case: exact match - no processing needed */
  14.214 +    if (sstrcmp(s, d) == 0) {
  14.215 +        *n = 0;
  14.216 +        return NULL;
  14.217 +    }
  14.218 +    sstr_t sv = sstrdup(s);
  14.219 +    if (sv.length == 0) {
  14.220 +        *n = -2;
  14.221 +        return NULL;
  14.222 +    }
  14.223 +
  14.224 +    for (size_t i = 0 ; i < s.length ; i++) {
  14.225 +        sstr_t substr = sstrsubs(sv, i);
  14.226 +        if (sstrprefix(substr, d)) {
  14.227 +            (*n)++;
  14.228 +            for (size_t j = 0 ; j < d.length ; j++) {
  14.229 +                sv.ptr[i+j] = 0;
  14.230 +            }
  14.231 +            i += d.length - 1; // -1, because the loop will do a i++
  14.232 +        }
  14.233 +        if ((*n) == nmax) break;
  14.234 +    }
  14.235 +    result = (sstr_t*) almalloc(allocator, sizeof(sstr_t)*(*n));
  14.236 +
  14.237 +    if (result) {
  14.238 +        char *pptr = sv.ptr;
  14.239 +        for (ssize_t i = 0 ; i < *n ; i++) {
  14.240 +            size_t l = strlen(pptr);
  14.241 +            char* ptr = (char*) almalloc(allocator, l + 1);
  14.242 +            if (ptr) {
  14.243 +                memcpy(ptr, pptr, l);
  14.244 +                ptr[l] = 0;
  14.245 +
  14.246 +                result[i] = sstrn(ptr, l);
  14.247 +                pptr += l + d.length;
  14.248 +            } else {
  14.249 +                for (ssize_t j = i-1 ; j >= 0 ; j--) {
  14.250 +                    alfree(allocator, result[j].ptr);
  14.251 +                }
  14.252 +                alfree(allocator, result);
  14.253 +                *n = -2;
  14.254 +                break;
  14.255 +            }
  14.256 +        }
  14.257 +    } else {
  14.258 +        *n = -2;
  14.259 +    }
  14.260 +    
  14.261 +    free(sv.ptr);
  14.262 +
  14.263 +    return result;
  14.264 +}
  14.265 +
  14.266 +int sstrcmp(sstr_t s1, sstr_t s2) {
  14.267 +    if (s1.length == s2.length) {
  14.268 +        return memcmp(s1.ptr, s2.ptr, s1.length);
  14.269 +    } else if (s1.length > s2.length) {
  14.270 +        return 1;
  14.271 +    } else {
  14.272 +        return -1;
  14.273 +    }
  14.274 +}
  14.275 +
  14.276 +int sstrcasecmp(sstr_t s1, sstr_t s2) {
  14.277 +    if (s1.length == s2.length) {
  14.278 +#ifdef _WIN32
  14.279 +        return _strnicmp(s1.ptr, s2.ptr, s1.length);
  14.280 +#else
  14.281 +        return strncasecmp(s1.ptr, s2.ptr, s1.length);
  14.282 +#endif
  14.283 +    } else if (s1.length > s2.length) {
  14.284 +        return 1;
  14.285 +    } else {
  14.286 +        return -1;
  14.287 +    }
  14.288 +}
  14.289 +
  14.290 +sstr_t sstrdup(sstr_t s) {
  14.291 +    return sstrdup_a(ucx_default_allocator(), s);
  14.292 +}
  14.293 +
  14.294 +sstr_t sstrdup_a(UcxAllocator *allocator, sstr_t s) {
  14.295 +    sstr_t newstring;
  14.296 +    newstring.ptr = (char*)almalloc(allocator, s.length + 1);
  14.297 +    if (newstring.ptr) {
  14.298 +        newstring.length = s.length;
  14.299 +        newstring.ptr[newstring.length] = 0;
  14.300 +        
  14.301 +        memcpy(newstring.ptr, s.ptr, s.length);
  14.302 +    } else {
  14.303 +        newstring.length = 0;
  14.304 +    }
  14.305 +    
  14.306 +    return newstring;
  14.307 +}
  14.308 +
  14.309 +sstr_t sstrtrim(sstr_t string) {
  14.310 +    sstr_t newstr = string;
  14.311 +    
  14.312 +    while (newstr.length > 0 && isspace(*newstr.ptr)) {
  14.313 +        newstr.ptr++;
  14.314 +        newstr.length--;
  14.315 +    }
  14.316 +    while (newstr.length > 0 && isspace(newstr.ptr[newstr.length-1])) {
  14.317 +        newstr.length--;
  14.318 +    }
  14.319 +    
  14.320 +    return newstr;
  14.321 +}
  14.322 +
  14.323 +int sstrprefix(sstr_t string, sstr_t prefix) {
  14.324 +    if (string.length == 0) {
  14.325 +        return prefix.length == 0;
  14.326 +    }
  14.327 +    if (prefix.length == 0) {
  14.328 +        return 1;
  14.329 +    }
  14.330 +    
  14.331 +    if (prefix.length > string.length) {
  14.332 +        return 0;
  14.333 +    } else {
  14.334 +        return memcmp(string.ptr, prefix.ptr, prefix.length) == 0;
  14.335 +    }
  14.336 +}
  14.337 +
  14.338 +int sstrsuffix(sstr_t string, sstr_t suffix) {
  14.339 +    if (string.length == 0) {
  14.340 +        return suffix.length == 0;
  14.341 +    }
  14.342 +    if (suffix.length == 0) {
  14.343 +        return 1;
  14.344 +    }
  14.345 +    
  14.346 +    if (suffix.length > string.length) {
  14.347 +        return 0;
  14.348 +    } else {
  14.349 +        return memcmp(string.ptr+string.length-suffix.length,
  14.350 +            suffix.ptr, suffix.length) == 0;
  14.351 +    }
  14.352 +}
  14.353 +
  14.354 +sstr_t sstrlower(sstr_t string) {
  14.355 +    sstr_t ret = sstrdup(string);
  14.356 +    for (size_t i = 0; i < ret.length ; i++) {
  14.357 +        ret.ptr[i] = tolower(ret.ptr[i]);
  14.358 +    }
  14.359 +    return ret;
  14.360 +}
  14.361 +
  14.362 +sstr_t sstrlower_a(UcxAllocator *allocator, sstr_t string) {
  14.363 +    sstr_t ret = sstrdup_a(allocator, string);
  14.364 +    for (size_t i = 0; i < ret.length ; i++) {
  14.365 +        ret.ptr[i] = tolower(ret.ptr[i]);
  14.366 +    }
  14.367 +    return ret;
  14.368 +}
  14.369 +
  14.370 +sstr_t sstrupper(sstr_t string) {
  14.371 +    sstr_t ret = sstrdup(string);
  14.372 +    for (size_t i = 0; i < ret.length ; i++) {
  14.373 +        ret.ptr[i] = toupper(ret.ptr[i]);
  14.374 +    }
  14.375 +    return ret;
  14.376 +}
  14.377 +
  14.378 +sstr_t sstrupper_a(UcxAllocator *allocator, sstr_t string) {
  14.379 +    sstr_t ret = sstrdup_a(allocator, string);
  14.380 +    for (size_t i = 0; i < ret.length ; i++) {
  14.381 +        ret.ptr[i] = toupper(ret.ptr[i]);
  14.382 +    }
  14.383 +    return ret;
  14.384 +}
    15.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    15.2 +++ b/src/ucx/string.h	Tue Aug 23 13:49:38 2016 +0200
    15.3 @@ -0,0 +1,457 @@
    15.4 +/*
    15.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    15.6 + *
    15.7 + * Copyright 2015 Olaf Wintermann. All rights reserved.
    15.8 + *
    15.9 + * Redistribution and use in source and binary forms, with or without
   15.10 + * modification, are permitted provided that the following conditions are met:
   15.11 + *
   15.12 + *   1. Redistributions of source code must retain the above copyright
   15.13 + *      notice, this list of conditions and the following disclaimer.
   15.14 + *
   15.15 + *   2. Redistributions in binary form must reproduce the above copyright
   15.16 + *      notice, this list of conditions and the following disclaimer in the
   15.17 + *      documentation and/or other materials provided with the distribution.
   15.18 + *
   15.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   15.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   15.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   15.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   15.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   15.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   15.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   15.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   15.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   15.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   15.29 + * POSSIBILITY OF SUCH DAMAGE.
   15.30 + */
   15.31 +/**
   15.32 + * Bounded string implementation.
   15.33 + * 
   15.34 + * The UCX strings (<code>sstr_t</code>) provide an alternative to C strings.
   15.35 + * The main difference to C strings is, that <code>sstr_t</code> does <b>not
   15.36 + * need to be <code>NULL</code>-terminated</b>. Instead the length is stored
   15.37 + * within the structure.
   15.38 + * 
   15.39 + * When using <code>sstr_t</code>, developers must be full aware of what type
   15.40 + * of string (<code>NULL</code>-terminated) or not) they are using, when 
   15.41 + * accessing the <code>char* ptr</code> directly.
   15.42 + * 
   15.43 + * The UCX string module provides some common string functions, known from
   15.44 + * standard libc, working with <code>sstr_t</code>.
   15.45 + * 
   15.46 + * @file   string.h
   15.47 + * @author Mike Becker
   15.48 + * @author Olaf Wintermann
   15.49 + */
   15.50 +
   15.51 +#ifndef UCX_STRING_H
   15.52 +#define	UCX_STRING_H
   15.53 +
   15.54 +#include "ucx.h"
   15.55 +#include "allocator.h"
   15.56 +#include <stddef.h>
   15.57 +
   15.58 +/** Shortcut for a <code>sstr_t struct</code> literal. */
   15.59 +#define ST(s) { (char*)s, sizeof(s)-1 }
   15.60 +
   15.61 +/** Shortcut for the conversion of a C string to a <code>sstr_t</code>. */
   15.62 +#define S(s) sstrn((char*)s, sizeof(s)-1)
   15.63 +
   15.64 +#ifdef	__cplusplus
   15.65 +extern "C" {
   15.66 +#endif
   15.67 +
   15.68 +/**
   15.69 + * The UCX string structure.
   15.70 + */
   15.71 +typedef struct {
   15.72 +   /** A reference to the string (<b>not necessarily  <code>NULL</code>
   15.73 +    * -terminated</b>) */
   15.74 +    char   *ptr;
   15.75 +    /** The length of the string */
   15.76 +    size_t length;
   15.77 +} sstr_t;
   15.78 +
   15.79 +/**
   15.80 + * Creates a new sstr_t based on a C string.
   15.81 + * 
   15.82 + * The length is implicitly inferred by using a call to <code>strlen()</code>.
   15.83 + *
   15.84 + * <b>Note:</b> the sstr_t will hold a <i>reference</i> to the C string. If you
   15.85 + * do want a copy, use sstrdup() on the return value of this function.
   15.86 + * 
   15.87 + * @param cstring the C string to wrap
   15.88 + * @return a new sstr_t containing the C string
   15.89 + * 
   15.90 + * @see sstrn()
   15.91 + */
   15.92 +sstr_t sstr(char *cstring);
   15.93 +
   15.94 +/**
   15.95 + * Creates a new sstr_t of the specified length based on a C string.
   15.96 + *
   15.97 + * <b>Note:</b> the sstr_t will hold a <i>reference</i> to the C string. If you
   15.98 + * do want a copy, use sstrdup() on the return value of this function.
   15.99 + * 
  15.100 + * @param cstring  the C string to wrap
  15.101 + * @param length   the length of the string
  15.102 + * @return a new sstr_t containing the C string
  15.103 + * 
  15.104 + * @see sstr()
  15.105 + * @see S()
  15.106 + */
  15.107 +sstr_t sstrn(char *cstring, size_t length);
  15.108 +
  15.109 +
  15.110 +/**
  15.111 + * Returns the cumulated length of all specified strings.
  15.112 + *
  15.113 + * At least one string must be specified.
  15.114 + * 
  15.115 + * <b>Attention:</b> if the count argument does not match the count of the
  15.116 + * specified strings, the behavior is undefined.
  15.117 + *
  15.118 + * @param count    the total number of specified strings (so at least 1)
  15.119 + * @param string   the first string
  15.120 + * @param ...      all other strings
  15.121 + * @return the cumulated length of all strings
  15.122 + */
  15.123 +size_t sstrnlen(size_t count, sstr_t string, ...);
  15.124 +
  15.125 +/**
  15.126 + * Concatenates two or more strings.
  15.127 + * 
  15.128 + * The resulting string will be allocated by standard <code>malloc()</code>. 
  15.129 + * So developers <b>MUST</b> pass the sstr_t.ptr to <code>free()</code>.
  15.130 + * 
  15.131 + * The sstr_t.ptr of the return value will <i>always</i> be <code>NULL</code>-
  15.132 + * terminated.
  15.133 + *
  15.134 + * @param count   the total number of strings to concatenate
  15.135 + * @param s1      first string
  15.136 + * @param s2      second string
  15.137 + * @param ...     all remaining strings
  15.138 + * @return the concatenated string
  15.139 + */
  15.140 +sstr_t sstrcat(size_t count, sstr_t s1, sstr_t s2, ...);
  15.141 +
  15.142 +/**
  15.143 + * Concatenates two or more strings using an UcxAllocator.
  15.144 + * 
  15.145 + * See sstrcat() for details.
  15.146 + *
  15.147 + * @param a       the allocator to use
  15.148 + * @param count   the total number of strings to concatenate
  15.149 + * @param s1      first string
  15.150 + * @param s2      second string
  15.151 + * @param ...     all remaining strings
  15.152 + * @return the concatenated string
  15.153 + */
  15.154 +sstr_t sstrcat_a(UcxAllocator *a, size_t count, sstr_t s1, sstr_t s2, ...);
  15.155 +
  15.156 +
  15.157 +/**
  15.158 + * Returns a substring starting at the specified location.
  15.159 + * 
  15.160 + * <b>Attention:</b> the new string references the same memory area as the
  15.161 + * input string and will <b>NOT</b> be <code>NULL</code>-terminated.
  15.162 + * Use sstrdup() to get a copy.
  15.163 + * 
  15.164 + * @param string input string
  15.165 + * @param start  start location of the substring
  15.166 + * @return a substring of <code>string</code> starting at <code>start</code>
  15.167 + * 
  15.168 + * @see sstrsubsl()
  15.169 + * @see sstrchr()
  15.170 + */
  15.171 +sstr_t sstrsubs(sstr_t string, size_t start);
  15.172 +
  15.173 +/**
  15.174 + * Returns a substring with a maximum length starting at the specified location.
  15.175 + * 
  15.176 + * <b>Attention:</b> the new string references the same memory area as the
  15.177 + * input string and will <b>NOT</b> be <code>NULL</code>-terminated.
  15.178 + * Use sstrdup() to get a copy.
  15.179 + * 
  15.180 + * @param string input string
  15.181 + * @param start  start location of the substring
  15.182 + * @param length the maximum length of the substring
  15.183 + * @return a substring of <code>string</code> starting at <code>start</code>
  15.184 + * with a maximum length of <code>length</code>
  15.185 + * 
  15.186 + * @see sstrsubs()
  15.187 + * @see sstrchr()
  15.188 + */
  15.189 +sstr_t sstrsubsl(sstr_t string, size_t start, size_t length);
  15.190 +
  15.191 +/**
  15.192 + * Returns a substring starting at the location of the first occurrence of the
  15.193 + * specified character.
  15.194 + * 
  15.195 + * If the string does not contain the character, an empty string is returned.
  15.196 + * 
  15.197 + * @param string the string where to locate the character
  15.198 + * @param chr    the character to locate
  15.199 + * @return       a substring starting at the first location of <code>chr</code>
  15.200 + * 
  15.201 + * @see sstrsubs()
  15.202 + */
  15.203 +sstr_t sstrchr(sstr_t string, int chr);
  15.204 +
  15.205 +/**
  15.206 + * Returns a substring starting at the location of the last occurrence of the
  15.207 + * specified character.
  15.208 + * 
  15.209 + * If the string does not contain the character, an empty string is returned.
  15.210 + * 
  15.211 + * @param string the string where to locate the character
  15.212 + * @param chr    the character to locate
  15.213 + * @return       a substring starting at the last location of <code>chr</code>
  15.214 + * 
  15.215 + * @see sstrsubs()
  15.216 + */
  15.217 +sstr_t sstrrchr(sstr_t string, int chr);
  15.218 +
  15.219 +/**
  15.220 + * Returns a substring starting at the location of the first occurrence of the
  15.221 + * specified string.
  15.222 + * 
  15.223 + * If the string does not contain the other string, an empty string is returned.
  15.224 + * 
  15.225 + * If <code>match</code> is an empty string, the complete <code>string</code> is
  15.226 + * returned.
  15.227 + * 
  15.228 + * @param string the string to be scanned
  15.229 + * @param match  string containing the sequence of characters to match
  15.230 + * @return       a substring starting at the first occurrence of
  15.231 + *               <code>match</code>, or an empty string, if the sequence is not
  15.232 + *               present in <code>string</code>
  15.233 + */
  15.234 +sstr_t sstrstr(sstr_t string, sstr_t match);
  15.235 +
  15.236 +/**
  15.237 + * Splits a string into parts by using a delimiter string.
  15.238 + * 
  15.239 + * This function will return <code>NULL</code>, if one of the following happens:
  15.240 + * <ul>
  15.241 + *   <li>the string length is zero</li>
  15.242 + *   <li>the delimeter length is zero</li>
  15.243 + *   <li>the string equals the delimeter</li>
  15.244 + *   <li>memory allocation fails</li>
  15.245 + * </ul>
  15.246 + * 
  15.247 + * The integer referenced by <code>count</code> is used as input and determines
  15.248 + * the maximum size of the resulting array, i.e. the maximum count of splits to
  15.249 + * perform + 1.
  15.250 + * 
  15.251 + * The integer referenced by <code>count</code> is also used as output and is
  15.252 + * set to
  15.253 + * <ul>
  15.254 + *   <li>-2, on memory allocation errors</li>
  15.255 + *   <li>-1, if either the string or the delimiter is an empty string</li>
  15.256 + *   <li>0, if the string equals the delimiter</li>
  15.257 + *   <li>1, if the string does not contain the delimiter</li>
  15.258 + *   <li>the count of array items, otherwise</li>
  15.259 + * </ul>
  15.260 + * 
  15.261 + * If the string starts with the delimiter, the first item of the resulting
  15.262 + * array will be an empty string.
  15.263 + * 
  15.264 + * If the string ends with the delimiter and the maximum list size is not
  15.265 + * exceeded, the last array item will be an empty string.
  15.266 + * 
  15.267 + * <b>Attention:</b> The array pointer <b>AND</b> all sstr_t.ptr of the array
  15.268 + * items must be manually passed to <code>free()</code>. Use sstrsplit_a() with
  15.269 + * an allocator to managed memory, to avoid this.
  15.270 + *
  15.271 + * @param string the string to split
  15.272 + * @param delim  the delimiter string
  15.273 + * @param count  IN: the maximum size of the resulting array (0 = no limit),
  15.274 + *               OUT: the actual size of the array
  15.275 + * @return a sstr_t array containing the split strings or
  15.276 + *         <code>NULL</code> on error
  15.277 + * 
  15.278 + * @see sstrsplit_a()
  15.279 + */
  15.280 +sstr_t* sstrsplit(sstr_t string, sstr_t delim, ssize_t *count);
  15.281 +
  15.282 +/**
  15.283 + * Performing sstrsplit() using an UcxAllocator.
  15.284 + * 
  15.285 + * <i>Read the description of sstrsplit() for details.</i>
  15.286 + * 
  15.287 + * The memory for the sstr_t.ptr pointers of the array items and the memory for
  15.288 + * the sstr_t array itself are allocated by using the UcxAllocator.malloc()
  15.289 + * function.
  15.290 + * 
  15.291 + * <b>Note:</b> the allocator is not used for memory that is freed within the
  15.292 + * same call of this function (locally scoped variables).
  15.293 + * 
  15.294 + * @param allocator the UcxAllocator used for allocating memory
  15.295 + * @param string the string to split
  15.296 + * @param delim  the delimiter string
  15.297 + * @param count  IN: the maximum size of the resulting array (0 = no limit),
  15.298 + *               OUT: the actual size of the array
  15.299 + * @return a sstr_t array containing the split strings or
  15.300 + *         <code>NULL</code> on error
  15.301 + * 
  15.302 + * @see sstrsplit()
  15.303 + */
  15.304 +sstr_t* sstrsplit_a(UcxAllocator *allocator, sstr_t string, sstr_t delim,
  15.305 +        ssize_t *count);
  15.306 +
  15.307 +/**
  15.308 + * Compares two UCX strings with standard <code>memcmp()</code>.
  15.309 + * 
  15.310 + * At first it compares the sstr_t.length attribute of the two strings. The
  15.311 + * <code>memcmp()</code> function is called, if and only if the lengths match.
  15.312 + * 
  15.313 + * @param s1 the first string
  15.314 + * @param s2 the second string
  15.315 + * @return -1, if the length of s1 is less than the length of s2 or 1, if the 
  15.316 + * length of s1 is greater than the length of s2 or the result of
  15.317 + * <code>memcmp()</code> otherwise (i.e. 0 if the strings match)
  15.318 + */
  15.319 +int sstrcmp(sstr_t s1, sstr_t s2);
  15.320 +
  15.321 +/**
  15.322 + * Compares two UCX strings ignoring the case.
  15.323 + * 
  15.324 + * At first it compares the sstr_t.length attribute of the two strings. If and
  15.325 + * only if the lengths match, both strings are compared char by char ignoring
  15.326 + * the case.
  15.327 + * 
  15.328 + * @param s1 the first string
  15.329 + * @param s2 the second string
  15.330 + * @return -1, if the length of s1 is less than the length of s2 or 1, if the 
  15.331 + * length of s1 is greater than the length of s2 or the difference between the
  15.332 + * first two differing characters otherwise (i.e. 0 if the strings match and
  15.333 + * no characters differ)
  15.334 + */
  15.335 +int sstrcasecmp(sstr_t s1, sstr_t s2);
  15.336 +
  15.337 +/**
  15.338 + * Creates a duplicate of the specified string.
  15.339 + * 
  15.340 + * The new sstr_t will contain a copy allocated by standard
  15.341 + * <code>malloc()</code>. So developers <b>MUST</b> pass the sstr_t.ptr to
  15.342 + * <code>free()</code>.
  15.343 + * 
  15.344 + * The sstr_t.ptr of the return value will <i>always</i> be <code>NULL</code>-
  15.345 + * terminated.
  15.346 + * 
  15.347 + * @param string the string to duplicate
  15.348 + * @return a duplicate of the string
  15.349 + * @see sstrdup_a()
  15.350 + */
  15.351 +sstr_t sstrdup(sstr_t string);
  15.352 +
  15.353 +/**
  15.354 + * Creates a duplicate of the specified string using an UcxAllocator.
  15.355 + * 
  15.356 + * The new sstr_t will contain a copy allocated by the allocators
  15.357 + * ucx_allocator_malloc function. So it is implementation depended, whether the
  15.358 + * returned sstr_t.ptr pointer must be passed to the allocators
  15.359 + * ucx_allocator_free function manually.
  15.360 + * 
  15.361 + * The sstr_t.ptr of the return value will <i>always</i> be <code>NULL</code>-
  15.362 + * terminated.
  15.363 + * 
  15.364 + * @param allocator a valid instance of an UcxAllocator
  15.365 + * @param string the string to duplicate
  15.366 + * @return a duplicate of the string
  15.367 + * @see sstrdup()
  15.368 + */
  15.369 +sstr_t sstrdup_a(UcxAllocator *allocator, sstr_t string);
  15.370 +
  15.371 +/**
  15.372 + * Omits leading and trailing spaces.
  15.373 + * 
  15.374 + * This function returns a new sstr_t containing a trimmed version of the
  15.375 + * specified string.
  15.376 + * 
  15.377 + * <b>Note:</b> the new sstr_t references the same memory, thus you
  15.378 + * <b>MUST NOT</b> pass the sstr_t.ptr of the return value to
  15.379 + * <code>free()</code>. It is also highly recommended to avoid assignments like
  15.380 + * <code>mystr = sstrtrim(mystr);</code> as you lose the reference to the
  15.381 + * source string. Assignments of this type are only permitted, if the
  15.382 + * sstr_t.ptr of the source string does not need to be freed or if another
  15.383 + * reference to the source string exists.
  15.384 + * 
  15.385 + * @param string the string that shall be trimmed
  15.386 + * @return a new sstr_t containing the trimmed string
  15.387 + */
  15.388 +sstr_t sstrtrim(sstr_t string);
  15.389 +
  15.390 +/**
  15.391 + * Checks, if a string has a specific prefix.
  15.392 + * @param string the string to check
  15.393 + * @param prefix the prefix the string should have
  15.394 + * @return 1, if and only if the string has the specified prefix, 0 otherwise
  15.395 + */
  15.396 +int sstrprefix(sstr_t string, sstr_t prefix);
  15.397 +
  15.398 +/**
  15.399 + * Checks, if a string has a specific suffix.
  15.400 + * @param string the string to check
  15.401 + * @param suffix the suffix the string should have
  15.402 + * @return 1, if and only if the string has the specified suffix, 0 otherwise
  15.403 + */
  15.404 +int sstrsuffix(sstr_t string, sstr_t suffix);
  15.405 +
  15.406 +/**
  15.407 + * Returns a lower case version of a string.
  15.408 + * 
  15.409 + * This function creates a duplicate of the input string, first. See the
  15.410 + * documentation of sstrdup() for the implications.
  15.411 + * 
  15.412 + * @param string the input string
  15.413 + * @return the resulting lower case string
  15.414 + * @see sstrdup()
  15.415 + */
  15.416 +sstr_t sstrlower(sstr_t string);
  15.417 +
  15.418 +/**
  15.419 + * Returns a lower case version of a string.
  15.420 + * 
  15.421 + * This function creates a duplicate of the input string, first. See the
  15.422 + * documentation of sstrdup_a() for the implications.
  15.423 + * 
  15.424 + * @param allocator the allocator used for duplicating the string
  15.425 + * @param string the input string
  15.426 + * @return the resulting lower case string
  15.427 + * @see sstrdup_a()
  15.428 + */
  15.429 +sstr_t sstrlower_a(UcxAllocator *allocator, sstr_t string);
  15.430 +
  15.431 +/**
  15.432 + * Returns a upper case version of a string.
  15.433 + * 
  15.434 + * This function creates a duplicate of the input string, first. See the
  15.435 + * documentation of sstrdup() for the implications.
  15.436 + * 
  15.437 + * @param string the input string
  15.438 + * @return the resulting upper case string
  15.439 + * @see sstrdup()
  15.440 + */
  15.441 +sstr_t sstrupper(sstr_t string);
  15.442 +
  15.443 +/**
  15.444 + * Returns a upper case version of a string.
  15.445 + * 
  15.446 + * This function creates a duplicate of the input string, first. See the
  15.447 + * documentation of sstrdup_a() for the implications.
  15.448 + * 
  15.449 + * @param allocator the allocator used for duplicating the string
  15.450 + * @param string the input string
  15.451 + * @return the resulting upper case string
  15.452 + * @see sstrdup_a()
  15.453 + */
  15.454 +sstr_t sstrupper_a(UcxAllocator *allocator, sstr_t string);
  15.455 +
  15.456 +#ifdef	__cplusplus
  15.457 +}
  15.458 +#endif
  15.459 +
  15.460 +#endif	/* UCX_STRING_H */
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/src/ucx/ucx.h	Tue Aug 23 13:49:38 2016 +0200
    16.3 @@ -0,0 +1,138 @@
    16.4 +/*
    16.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    16.6 + *
    16.7 + * Copyright 2015 Olaf Wintermann. All rights reserved.
    16.8 + *
    16.9 + * Redistribution and use in source and binary forms, with or without
   16.10 + * modification, are permitted provided that the following conditions are met:
   16.11 + *
   16.12 + *   1. Redistributions of source code must retain the above copyright
   16.13 + *      notice, this list of conditions and the following disclaimer.
   16.14 + *
   16.15 + *   2. Redistributions in binary form must reproduce the above copyright
   16.16 + *      notice, this list of conditions and the following disclaimer in the
   16.17 + *      documentation and/or other materials provided with the distribution.
   16.18 + *
   16.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   16.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   16.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   16.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   16.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   16.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   16.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   16.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   16.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   16.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   16.29 + * POSSIBILITY OF SUCH DAMAGE.
   16.30 + */
   16.31 +/**
   16.32 + * Main UCX Header providing most common definitions.
   16.33 + * 
   16.34 + * @file   ucx.h
   16.35 + * @author Mike Becker
   16.36 + * @author Olaf Wintermann
   16.37 + */
   16.38 +
   16.39 +#ifndef UCX_H
   16.40 +#define	UCX_H
   16.41 +
   16.42 +/** Major UCX version as integer constant. */
   16.43 +#define UCX_VERSION_MAJOR   0
   16.44 +
   16.45 +/** Minor UCX version as integer constant. */
   16.46 +#define UCX_VERSION_MINOR   9
   16.47 +
   16.48 +/** The UCX version in format [major].[minor] */
   16.49 +#define UCX_VERSION UCX_VERSION_MAJOR.UCX_VERSION_MINOR
   16.50 +
   16.51 +#include <stdlib.h>
   16.52 +
   16.53 +#ifdef _WIN32
   16.54 +#if !(defined __ssize_t_defined || defined _SSIZE_T_)
   16.55 +#include <BaseTsd.h>
   16.56 +typedef SSIZE_T ssize_t;
   16.57 +#define __ssize_t_defined
   16.58 +#define _SSIZE_T_
   16.59 +#endif /* __ssize_t_defined and _SSIZE_T */
   16.60 +#else /* !_WIN32 */
   16.61 +#include <sys/types.h>
   16.62 +#endif /* _WIN32 */
   16.63 +
   16.64 +#ifdef	__cplusplus
   16.65 +#ifndef _Bool
   16.66 +#define _Bool bool
   16.67 +#define restrict
   16.68 +#endif
   16.69 +/** Use C naming even when compiling with C++.  */
   16.70 +#define UCX_EXTERN extern "C"
   16.71 +extern "C" {
   16.72 +#else
   16.73 +/** Pointless in C. */
   16.74 +#define UCX_EXTERN
   16.75 +#endif
   16.76 +    
   16.77 +
   16.78 +/**
   16.79 + * A function pointer to a destructor function.
   16.80 + * @see ucx_mempool_setdestr()
   16.81 + * @see ucx_mempool_regdestr()
   16.82 + */
   16.83 +typedef void(*ucx_destructor)(void*);
   16.84 +
   16.85 +/**
   16.86 + * Function pointer to a compare function.
   16.87 + * 
   16.88 + * The compare function shall take three arguments: the two values that shall be
   16.89 + * compared and optional additional data.
   16.90 + * The function shall then return -1 if the first argument is less than the
   16.91 + * second argument, 1 if the first argument is greater than the second argument
   16.92 + * and 0 if both arguments are equal. If the third argument is
   16.93 + * <code>NULL</code>, it shall be ignored.
   16.94 + */
   16.95 +typedef int(*cmp_func)(void*,void*,void*);
   16.96 +
   16.97 +/**
   16.98 + * Function pointer to a copy function.
   16.99 + * 
  16.100 + * The copy function shall create a copy of the first argument and may use
  16.101 + * additional data provided by the second argument. If the second argument is
  16.102 + * <code>NULL</code>, it shall be ignored.
  16.103 +
  16.104 + * <b>Attention:</b> if pointers returned by functions of this type may be
  16.105 + * passed to <code>free()</code> depends on the implementation of the
  16.106 + * respective <code>copy_func</code>.
  16.107 + */
  16.108 +typedef void*(*copy_func)(void*,void*);
  16.109 +
  16.110 +/**
  16.111 + * Function pointer to a write function.
  16.112 + * 
  16.113 + * The signature of the write function shall be compatible to the signature
  16.114 + * of standard <code>fwrite</code>, though it may use arbitrary data types for
  16.115 + * source and destination.
  16.116 + * 
  16.117 + * The arguments shall contain (in ascending order): a pointer to the source,
  16.118 + * the length of one element, the element count and a pointer to the
  16.119 + * destination.
  16.120 + */
  16.121 +typedef size_t(*write_func)(const void*, size_t, size_t, void*);
  16.122 +
  16.123 +/**
  16.124 + * Function pointer to a read function.
  16.125 + * 
  16.126 + * The signature of the read function shall be compatible to the signature
  16.127 + * of standard <code>fread</code>, though it may use arbitrary data types for
  16.128 + * source and destination.
  16.129 + * 
  16.130 + * The arguments shall contain (in ascending order): a pointer to the
  16.131 + * destination, the length of one element, the element count and a pointer to
  16.132 + * the source.
  16.133 + */
  16.134 +typedef size_t(*read_func)(void*, size_t, size_t, void*);
  16.135 +
  16.136 +#ifdef	__cplusplus
  16.137 +}
  16.138 +#endif
  16.139 +
  16.140 +#endif	/* UCX_H */
  16.141 +
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/src/ucx/utils.c	Tue Aug 23 13:49:38 2016 +0200
    17.3 @@ -0,0 +1,259 @@
    17.4 +/*
    17.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    17.6 + *
    17.7 + * Copyright 2015 Olaf Wintermann. All rights reserved.
    17.8 + *
    17.9 + * Redistribution and use in source and binary forms, with or without
   17.10 + * modification, are permitted provided that the following conditions are met:
   17.11 + *
   17.12 + *   1. Redistributions of source code must retain the above copyright
   17.13 + *      notice, this list of conditions and the following disclaimer.
   17.14 + *
   17.15 + *   2. Redistributions in binary form must reproduce the above copyright
   17.16 + *      notice, this list of conditions and the following disclaimer in the
   17.17 + *      documentation and/or other materials provided with the distribution.
   17.18 + *
   17.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   17.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   17.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   17.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   17.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   17.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   17.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   17.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   17.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   17.29 + * POSSIBILITY OF SUCH DAMAGE.
   17.30 + */
   17.31 +
   17.32 +#include "utils.h"
   17.33 +#include <math.h>
   17.34 +#include <stdio.h>
   17.35 +#include <limits.h>
   17.36 +#include <errno.h>
   17.37 +
   17.38 +/* COPY FUCNTIONS */
   17.39 +void* ucx_strcpy(void* s, void* data) {
   17.40 +    char *str = (char*) s;
   17.41 +    size_t n = 1+strlen(str);
   17.42 +    char *cpy = (char*) malloc(n);
   17.43 +    memcpy(cpy, str, n);
   17.44 +    return cpy;
   17.45 +}
   17.46 +
   17.47 +void* ucx_memcpy(void* m, void* n) {
   17.48 +    size_t k = *((size_t*)n);
   17.49 +    void *cpy = malloc(k);
   17.50 +    memcpy(cpy, m, k);
   17.51 +    return cpy;
   17.52 +}
   17.53 +
   17.54 +size_t ucx_stream_copy(void *src, void *dest, read_func readfnc,
   17.55 +        write_func writefnc, char* buf, size_t bufsize, size_t n) {
   17.56 +    if(n == 0 || bufsize == 0) {
   17.57 +        return 0;
   17.58 +    }
   17.59 +    
   17.60 +    char *lbuf;    
   17.61 +    size_t ncp = 0;
   17.62 +    
   17.63 +    if(buf) {
   17.64 +        lbuf = buf;
   17.65 +    } else {
   17.66 +        lbuf = (char*)malloc(bufsize);
   17.67 +        if(lbuf == NULL) {
   17.68 +            return 0;
   17.69 +        }
   17.70 +    }
   17.71 +    
   17.72 +    size_t r;
   17.73 +    size_t rn = bufsize > n ? n : bufsize;
   17.74 +    while((r = readfnc(lbuf, 1, rn, src)) != 0) {
   17.75 +        r = writefnc(lbuf, 1, r, dest);
   17.76 +        ncp += r;
   17.77 +        n -= r;
   17.78 +        rn = bufsize > n ? n : bufsize;
   17.79 +        if(r == 0 || n == 0) {
   17.80 +            break;
   17.81 +        }
   17.82 +    }
   17.83 +    
   17.84 +    if (lbuf != buf) {
   17.85 +        free(lbuf);
   17.86 +    }
   17.87 +    
   17.88 +    return ncp;
   17.89 +}
   17.90 +
   17.91 +/* COMPARE FUNCTIONS */
   17.92 +
   17.93 +int ucx_strcmp(void *s1, void *s2, void *data) {
   17.94 +    return strcmp((char*)s1, (char*)s2);
   17.95 +}
   17.96 +
   17.97 +int ucx_strncmp(void *s1, void *s2, void *n) {
   17.98 +    return strncmp((char*)s1, (char*)s2, *((size_t*) n));
   17.99 +}
  17.100 +
  17.101 +int ucx_intcmp(void *i1, void *i2, void *data) {
  17.102 +   int a = *((int*) i1);
  17.103 +   int b = *((int*) i2);
  17.104 +   if (a == b) {
  17.105 +       return 0;
  17.106 +   } else {
  17.107 +       return a < b ? -1 : 1;
  17.108 +   }
  17.109 +}
  17.110 +
  17.111 +int ucx_floatcmp(void *f1, void *f2, void *epsilon) {
  17.112 +   float a = *((float*) f1);
  17.113 +   float b = *((float*) f2);
  17.114 +   float e = !epsilon ? 1e-6f : *((float*)epsilon);
  17.115 +   if (fabsf(a - b) < e) {
  17.116 +       return 0;
  17.117 +   } else {
  17.118 +       return a < b ? -1 : 1;
  17.119 +   }
  17.120 +}
  17.121 +
  17.122 +int ucx_doublecmp(void *d1, void *d2, void *epsilon) {
  17.123 +   double a = *((float*) d1);
  17.124 +   double b = *((float*) d2);
  17.125 +   double e = !epsilon ? 1e-14 : *((double*)epsilon);
  17.126 +   if (fabs(a - b) < e) {
  17.127 +       return 0;
  17.128 +   } else {
  17.129 +       return a < b ? -1 : 1;
  17.130 +   }
  17.131 +}
  17.132 +
  17.133 +int ucx_ptrcmp(void *ptr1, void *ptr2, void *data) {
  17.134 +    intptr_t p1 = (intptr_t) ptr1;
  17.135 +    intptr_t p2 = (intptr_t) ptr2;
  17.136 +    if (p1 == p2) {
  17.137 +        return 0;
  17.138 +    } else {
  17.139 +        return p1  < p2 ? -1 : 1;
  17.140 +    }
  17.141 +}
  17.142 +
  17.143 +int ucx_memcmp(void *ptr1, void *ptr2, void *n) {
  17.144 +    return memcmp(ptr1, ptr2, *((size_t*)n));
  17.145 +}
  17.146 +
  17.147 +/* PRINTF FUNCTIONS */
  17.148 +
  17.149 +#ifdef va_copy
  17.150 +#define UCX_PRINTF_BUFSIZE 256
  17.151 +#else
  17.152 +#pragma message("WARNING: C99 va_copy macro not supported by this platform" \
  17.153 +                " - limiting ucx_*printf to 2 KiB")
  17.154 +#define UCX_PRINTF_BUFSIZE 0x800
  17.155 +#endif
  17.156 +
  17.157 +int ucx_fprintf(void *stream, write_func wfc, const char *fmt, ...) {
  17.158 +    int ret;
  17.159 +    va_list ap;
  17.160 +    va_start(ap, fmt);
  17.161 +    ret = ucx_vfprintf(stream, wfc, fmt, ap);
  17.162 +    va_end(ap);
  17.163 +    return ret;
  17.164 +}
  17.165 +
  17.166 +int ucx_vfprintf(void *stream, write_func wfc, const char *fmt, va_list ap) {
  17.167 +    char buf[UCX_PRINTF_BUFSIZE];
  17.168 +#ifdef va_copy
  17.169 +    va_list ap2;
  17.170 +    va_copy(ap2, ap);
  17.171 +    int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap);
  17.172 +    if (ret < 0) {
  17.173 +        return ret;
  17.174 +    } else if (ret < UCX_PRINTF_BUFSIZE) {
  17.175 +        return (int)wfc(buf, 1, ret, stream);
  17.176 +    } else {
  17.177 +        if (ret == INT_MAX) {
  17.178 +            errno = ENOMEM;
  17.179 +            return -1;
  17.180 +        }
  17.181 +        
  17.182 +        int len = ret + 1;
  17.183 +        char *newbuf = (char*)malloc(len);
  17.184 +        if (!newbuf) {
  17.185 +            return -1;
  17.186 +        }
  17.187 +        
  17.188 +        ret = vsnprintf(newbuf, len, fmt, ap2);
  17.189 +        if (ret > 0) {
  17.190 +            ret = (int)wfc(newbuf, 1, ret, stream);
  17.191 +        }
  17.192 +        free(newbuf);
  17.193 +    }
  17.194 +    return ret;
  17.195 +#else
  17.196 +    int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap);
  17.197 +    if (ret < 0) {
  17.198 +        return ret;
  17.199 +    } else if (ret < UCX_PRINTF_BUFSIZE) {
  17.200 +        return (int)wfc(buf, 1, ret, stream);
  17.201 +    } else {
  17.202 +        errno = ENOMEM;
  17.203 +        return -1;
  17.204 +    }
  17.205 +#endif
  17.206 +}
  17.207 +
  17.208 +sstr_t ucx_asprintf(UcxAllocator *allocator, const char *fmt, ...) {
  17.209 +    va_list ap;
  17.210 +    sstr_t ret;
  17.211 +    va_start(ap, fmt);
  17.212 +    ret = ucx_vasprintf(allocator, fmt, ap);
  17.213 +    va_end(ap);
  17.214 +    return ret;
  17.215 +}
  17.216 +
  17.217 +sstr_t ucx_vasprintf(UcxAllocator *a, const char *fmt, va_list ap) {
  17.218 +    sstr_t s;
  17.219 +    s.ptr = NULL;
  17.220 +    s.length = 0;
  17.221 +    char buf[UCX_PRINTF_BUFSIZE];
  17.222 +#ifdef va_copy
  17.223 +    va_list ap2;
  17.224 +    va_copy(ap2, ap);
  17.225 +    int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap);
  17.226 +    if (ret > 0 && ret < UCX_PRINTF_BUFSIZE) {
  17.227 +        s.ptr = (char*)almalloc(a, ret + 1);
  17.228 +        if (s.ptr) {
  17.229 +            s.length = (size_t)ret;
  17.230 +            memcpy(s.ptr, buf, ret);
  17.231 +            s.ptr[s.length] = '\0';
  17.232 +        }
  17.233 +    } else if (ret == INT_MAX) {
  17.234 +        errno = ENOMEM;
  17.235 +    } else  {
  17.236 +        int len = ret + 1;
  17.237 +        s.ptr = (char*)almalloc(a, len);
  17.238 +        if (s.ptr) {
  17.239 +            ret = vsnprintf(s.ptr, len, fmt, ap2);
  17.240 +            if (ret < 0) {
  17.241 +                free(s.ptr);
  17.242 +                s.ptr = NULL;
  17.243 +            } else {
  17.244 +                s.length = (size_t)ret;
  17.245 +            }
  17.246 +        }
  17.247 +    }
  17.248 +#else
  17.249 +    int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap);
  17.250 +    if (ret > 0 && ret < UCX_PRINTF_BUFSIZE) {
  17.251 +        s.ptr = (char*)almalloc(a, ret + 1);
  17.252 +        if (s.ptr) {
  17.253 +            s.length = (size_t)ret;
  17.254 +            memcpy(s.ptr, buf, ret);
  17.255 +            s.ptr[s.length] = '\0';
  17.256 +        }
  17.257 +    } else {
  17.258 +        errno = ENOMEM;
  17.259 +    }
  17.260 +#endif
  17.261 +    return s;
  17.262 +}
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/src/ucx/utils.h	Tue Aug 23 13:49:38 2016 +0200
    18.3 @@ -0,0 +1,254 @@
    18.4 +/*
    18.5 + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    18.6 + *
    18.7 + * Copyright 2015 Olaf Wintermann. All rights reserved.
    18.8 + *
    18.9 + * Redistribution and use in source and binary forms, with or without
   18.10 + * modification, are permitted provided that the following conditions are met:
   18.11 + *
   18.12 + *   1. Redistributions of source code must retain the above copyright
   18.13 + *      notice, this list of conditions and the following disclaimer.
   18.14 + *
   18.15 + *   2. Redistributions in binary form must reproduce the above copyright
   18.16 + *      notice, this list of conditions and the following disclaimer in the
   18.17 + *      documentation and/or other materials provided with the distribution.
   18.18 + *
   18.19 + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
   18.20 + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   18.21 + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18.22 + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
   18.23 + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   18.24 + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   18.25 + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   18.26 + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   18.27 + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   18.28 + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   18.29 + * POSSIBILITY OF SUCH DAMAGE.
   18.30 + */
   18.31 +
   18.32 +/**
   18.33 + * @file utils.h
   18.34 + * 
   18.35 + * Compare, copy and printf functions.
   18.36 + * 
   18.37 + * @author Mike Becker
   18.38 + * @author Olaf Wintermann
   18.39 + */
   18.40 +
   18.41 +#ifndef UCX_UTILS_H
   18.42 +#define UCX_UTILS_H
   18.43 +
   18.44 +#ifdef __cplusplus
   18.45 +extern "C" {
   18.46 +#endif
   18.47 +
   18.48 +#include "ucx.h"
   18.49 +#include "string.h"
   18.50 +#include "allocator.h"
   18.51 +#include <inttypes.h>
   18.52 +#include <string.h>
   18.53 +#include <stdarg.h>
   18.54 +
   18.55 +/**
   18.56 + * Copies a string.
   18.57 + * @param s the string to copy
   18.58 + * @param data omitted
   18.59 + * @return a pointer to a copy of s1 that can be passed to free(void*)
   18.60 + */
   18.61 +void *ucx_strcpy(void *s, void *data);
   18.62 +
   18.63 +/**
   18.64 + * Copies a memory area.
   18.65 + * @param m a pointer to the memory area
   18.66 + * @param n a pointer to the size_t containing the size of the memory area
   18.67 + * @return a pointer to a copy of the specified memory area that can
   18.68 + * be passed to free(void*)
   18.69 + */
   18.70 +void *ucx_memcpy(void *m, void *n);
   18.71 +
   18.72 +
   18.73 +/**
   18.74 + * Reads data from a stream and writes it to another stream.
   18.75 + * 
   18.76 + * @param src the source stream
   18.77 + * @param dest the destination stream
   18.78 + * @param rfnc the read function
   18.79 + * @param wfnc the write function
   18.80 + * @param buf a pointer to the copy buffer or <code>NULL</code> if a buffer
   18.81 + * shall be implicitly created on the heap
   18.82 + * @param bufsize the size of the copy buffer - if <code>NULL</code> was
   18.83 + * provided for <code>buf</code>, this is the size of the buffer that shall be
   18.84 + * implicitly created
   18.85 + * @param n the maximum number of bytes that shall be copied
   18.86 + * @return the total number of bytes copied
   18.87 +  */
   18.88 +size_t ucx_stream_copy(void *src, void *dest, read_func rfnc, write_func wfnc,
   18.89 +        char* buf, size_t bufsize, size_t n);
   18.90 +
   18.91 +/**
   18.92 + * Shorthand for ucx_stream_copy using the default copy buffer.
   18.93 + * 
   18.94 + * @param src the source stream
   18.95 + * @param dest the destination stream
   18.96 + * @param rfnc the read function
   18.97 + * @param wfnc the write function
   18.98 + * @return total number of bytes copied
   18.99 + */
  18.100 +#define ucx_stream_hcopy(src,dest,rfnc,wfnc) ucx_stream_copy(\
  18.101 +        src, dest, (read_func)rfnc, (write_func)wfnc, NULL, 0x100, (size_t)-1)
  18.102 +
  18.103 +/**
  18.104 + * Shorthand for ucx_stream_copy using the default copy buffer and a copy limit.
  18.105 + * 
  18.106 + * @param src the source stream
  18.107 + * @param dest the destination stream
  18.108 + * @param rfnc the read function
  18.109 + * @param wfnc the write function
  18.110 + * @param n maximum number of bytes that shall be copied
  18.111 + * @return total number of bytes copied
  18.112 + */
  18.113 +#define ucx_stream_ncopy(src,dest,rfnc,wfnc, n) ucx_stream_copy(\
  18.114 +        src, dest, (read_func)rfnc, (write_func)wfnc, NULL, 0x100, n)
  18.115 +
  18.116 +/**
  18.117 + * Wraps the strcmp function.
  18.118 + * @param s1 string one
  18.119 + * @param s2 string two
  18.120 + * @param data omitted
  18.121 + * @return the result of strcmp(s1, s2)
  18.122 + */
  18.123 +int ucx_strcmp(void *s1, void *s2, void *data);
  18.124 +
  18.125 +/**
  18.126 + * Wraps the strncmp function.
  18.127 + * @param s1 string one
  18.128 + * @param s2 string two
  18.129 + * @param n a pointer to the size_t containing the third strncmp parameter
  18.130 + * @return the result of strncmp(s1, s2, *n)
  18.131 + */
  18.132 +int ucx_strncmp(void *s1, void *s2, void *n);
  18.133 +
  18.134 +/**
  18.135 + * Compares two integers of type int.
  18.136 + * @param i1 pointer to integer one
  18.137 + * @param i2 pointer to integer two
  18.138 + * @param data omitted
  18.139 + * @return -1, if *i1 is less than *i2, 0 if both are equal,
  18.140 + * 1 if *i1 is greater than *i2
  18.141 + */
  18.142 +int ucx_intcmp(void *i1, void *i2, void *data);
  18.143 +
  18.144 +/**
  18.145 + * Compares two real numbers of type float.
  18.146 + * @param f1 pointer to float one
  18.147 + * @param f2 pointer to float two
  18.148 + * @param data if provided: a pointer to precision (default: 1e-6f)
  18.149 + * @return -1, if *f1 is less than *f2, 0 if both are equal,
  18.150 + * 1 if *f1 is greater than *f2
  18.151 + */
  18.152 +
  18.153 +int ucx_floatcmp(void *f1, void *f2, void *data);
  18.154 +
  18.155 +/**
  18.156 + * Compares two real numbers of type double.
  18.157 + * @param d1 pointer to double one
  18.158 + * @param d2 pointer to double two
  18.159 + * @param data if provided: a pointer to precision (default: 1e-14)
  18.160 + * @return -1, if *d1 is less than *d2, 0 if both are equal,
  18.161 + * 1 if *d1 is greater than *d2
  18.162 + */
  18.163 +int ucx_doublecmp(void *d1, void *d2, void *data);
  18.164 +
  18.165 +/**
  18.166 + * Compares two pointers.
  18.167 + * @param ptr1 pointer one
  18.168 + * @param ptr2 pointer two
  18.169 + * @param data omitted
  18.170 + * @return -1 if ptr1 is less than ptr2, 0 if both are equal,
  18.171 + * 1 if ptr1 is greater than ptr2
  18.172 + */
  18.173 +int ucx_ptrcmp(void *ptr1, void *ptr2, void *data);
  18.174 +
  18.175 +/**
  18.176 + * Compares two memory areas.
  18.177 + * @param ptr1 pointer one
  18.178 + * @param ptr2 pointer two
  18.179 + * @param n a pointer to the size_t containing the third parameter for memcmp
  18.180 + * @return the result of memcmp(ptr1, ptr2, *n)
  18.181 + */
  18.182 +int ucx_memcmp(void *ptr1, void *ptr2, void *n);
  18.183 +
  18.184 +/**
  18.185 + * A <code>printf()</code> like function which writes the output to a stream by
  18.186 + * using a write_func().
  18.187 + * @param stream the stream the data is written to
  18.188 + * @param wfc the write function
  18.189 + * @param fmt format string
  18.190 + * @param ... additional arguments
  18.191 + * @return the total number of bytes written
  18.192 + */
  18.193 +int ucx_fprintf(void *stream, write_func wfc, const char *fmt, ...);
  18.194 +
  18.195 +/**
  18.196 + * <code>va_list</code> version of ucx_fprintf().
  18.197 + * @param stream the stream the data is written to
  18.198 + * @param wfc the write function
  18.199 + * @param fmt format string
  18.200 + * @param ap argument list
  18.201 + * @return the total number of bytes written
  18.202 + * @see ucx_fprintf()
  18.203 + */
  18.204 +int ucx_vfprintf(void *stream, write_func wfc, const char *fmt, va_list ap);
  18.205 +
  18.206 +/**
  18.207 + * A <code>printf()</code> like function which allocates space for a sstr_t
  18.208 + * the result is written to.
  18.209 + * 
  18.210 + * <b>Attention</b>: The sstr_t data is allocated with the allocators
  18.211 + * ucx_allocator_malloc() function. So it is implementation dependent, if
  18.212 + * the returned sstr_t.ptr pointer must be passed to the allocators
  18.213 + * ucx_allocator_free() function manually.
  18.214 + * 
  18.215 + * <b>Note</b>: The sstr_t.ptr of the return value will <i>always</i> be
  18.216 + * <code>NULL</code>-terminated.
  18.217 + * 
  18.218 + * @param allocator the UcxAllocator used for allocating the result sstr_t
  18.219 + * @param fmt format string
  18.220 + * @param ... additional arguments
  18.221 + * @return a sstr_t containing the formatted string
  18.222 + */
  18.223 +sstr_t ucx_asprintf(UcxAllocator *allocator, const char *fmt, ...);
  18.224 +
  18.225 +/** Shortcut for ucx_asprintf() with default allocator. */
  18.226 +#define ucx_sprintf(fmt, ...) \
  18.227 +    ucx_asprintf(ucx_default_allocator(), fmt, __VA_ARGS__)
  18.228 +
  18.229 +/**
  18.230 + * <code>va_list</code> version of ucx_asprintf().
  18.231 + * 
  18.232 + * @param allocator the UcxAllocator used for allocating the result sstr_t
  18.233 + * @param fmt format string
  18.234 + * @param ap argument list
  18.235 + * @return a sstr_t containing the formatted string
  18.236 + * @see ucx_asprintf()
  18.237 + */
  18.238 +sstr_t ucx_vasprintf(UcxAllocator *allocator, const char *fmt, va_list ap);
  18.239 +
  18.240 +/**
  18.241 + * A <code>printf()</code> like function which writes the output to an
  18.242 + * UcxBuffer.
  18.243 + * 
  18.244 + * @param buffer the buffer the data is written to
  18.245 + * @param ... format string and additional arguments
  18.246 + * @return the total number of bytes written
  18.247 + * @see ucx_fprintf()
  18.248 + */
  18.249 +#define ucx_bprintf(buffer, ...) ucx_fprintf((UcxBuffer*)buffer, \
  18.250 +        (write_func)ucx_buffer_write, __VA_ARGS__)
  18.251 +
  18.252 +#ifdef __cplusplus
  18.253 +}
  18.254 +#endif
  18.255 +
  18.256 +#endif /* UCX_UTILS_H */
  18.257 +

mercurial