# HG changeset patch # User Mike Becker # Date 1682362478 -7200 # Node ID 1b12cf799fee3da4ce7e21e5e27aa27eb198ca75 # Parent 9f25df78925eb911b0499a85176797204d61cb07 upgrade to ucx 3.0 diff -r 9f25df78925e -r 1b12cf799fee .hgignore --- a/.hgignore Thu Nov 10 18:44:48 2016 +0100 +++ b/.hgignore Mon Apr 24 20:54:38 2023 +0200 @@ -5,3 +5,4 @@ \.conflict\~$ ^build/.*$ ^nbproject/.*$ +^.idea/.*$ diff -r 9f25df78925e -r 1b12cf799fee Makefile --- a/Makefile Thu Nov 10 18:44:48 2016 +0100 +++ b/Makefile Mon Apr 24 20:54:38 2023 +0200 @@ -34,25 +34,17 @@ SRC = frontend.c SRC += c2html.c SRC += highlighter.c -SRC += ucx/allocator.c -SRC += ucx/buffer.c -SRC += ucx/list.c -SRC += ucx/string.c -SRC += ucx/utils.c OBJ = $(SRC:%.c=build/%$(OBJ_EXT)) -all: build/ucx build/$(BIN) +all: build build/$(BIN) build/$(BIN): $(OBJ) $(LD) -o $@ $^ $(LDFLAGS) build/%$(OBJ_EXT): src/%.c $(CC) -o $@ $(CFLAGS) -c $< - -build/ucx: build - $(MKDIR) $@ - + build: $(MKDIR) $@ @@ -65,12 +57,10 @@ -H test/header.html -F test/footer.html ./build/$(BIN) -p test/plain.csp -o build/plain.html \ -H test/header.html -F test/footer.html - -test-v2-regression: test - diff build/ctest.html test/v2-regression/ctest.html && \ - diff build/javatest.html test/v2-regression/javatest.html && \ - diff build/bigtest.html test/v2-regression/bigtest.html && \ - diff build/plain.html test/v2-regression/plain.html + diff build/ctest.html test/gs/ctest.html && \ + diff build/javatest.html test/gs/javatest.html && \ + diff build/bigtest.html test/gs/bigtest.html && \ + diff build/plain.html test/gs/plain.html clean: $(RM) $(RMFLAGS) build diff -r 9f25df78925e -r 1b12cf799fee clang.mk --- a/clang.mk Thu Nov 10 18:44:48 2016 +0100 +++ b/clang.mk Mon Apr 24 20:54:38 2023 +0200 @@ -36,5 +36,5 @@ CC = clang CFLAGS = -O2 LD = clang -LDFLAGS = +LDFLAGS = -lucx OBJ_EXT = .o diff -r 9f25df78925e -r 1b12cf799fee gcc.mk --- a/gcc.mk Thu Nov 10 18:44:48 2016 +0100 +++ b/gcc.mk Mon Apr 24 20:54:38 2023 +0200 @@ -36,5 +36,5 @@ CC = gcc CFLAGS = -O2 -std=gnu99 LD = gcc -LDFLAGS = +LDFLAGS = -lucx OBJ_EXT = .o diff -r 9f25df78925e -r 1b12cf799fee src/c2html.c --- a/src/c2html.c Thu Nov 10 18:44:48 2016 +0100 +++ b/src/c2html.c Mon Apr 24 20:54:38 2023 +0200 @@ -29,131 +29,93 @@ #include "c2html.h" -#include "ucx/list.h" -#include "ucx/utils.h" +#include +#include -#define try_write(wfnc, str, n, buf, written, maxlen) \ - { \ - size_t m = maxlen-written; \ - written += wfnc(str, 1, n > m ? m : n, buf); \ +size_t c2html_format( + CxList const *lines, + void *outbuf, + cx_write_func wfnc, + c2html_highlighter_func highlighter, + int showln +) { + /* total written bytes */ + size_t written = 0; + + /* compute width of line numbering */ + int lnw = 0; + if (showln) { + size_t no_lines = cxListSize(lines); + for (size_t p = 1; p < no_lines; p *= 10) lnw++; } -static size_t formatlines(c2html_highlighter_func highlighter, UcxList *in, - void *outbuf, write_func wfnc, size_t maxlen, int showlineno) { - /* total written bytes */ - size_t written = 0; - - /* compute width of line numbering */ - int lnw = 0; - if (showlineno) { - size_t lines = ucx_list_size(in); - for (size_t p = 1; p < lines ; p*=10) lnw++; - } - - /* start monospace formatting */ - try_write(wfnc, "
\n", 6, outbuf, written, maxlen);
+    /* start code formatting */
+    written += wfnc("
\n", 1, 26, outbuf); /* process lines */ - size_t lineno = 0; - c2html_highlighter_data* hd = malloc(sizeof(c2html_highlighter_data)); - hd->multiline_comment = 0; - hd->primary_buffer = ucx_buffer_new(NULL, 256, UCX_BUFFER_AUTOEXTEND); - hd->secondary_buffer = ucx_buffer_new(NULL, 32, UCX_BUFFER_AUTOEXTEND); - UcxBuffer *line = ucx_buffer_new(NULL, 1024, UCX_BUFFER_AUTOEXTEND); - - UCX_FOREACH(sourceline, in) { + int lineno = 0; + c2html_highlighter_data hd; + hd.multiline_comment = 0; + cxBufferInit(&hd.primary_buffer, NULL, 256, NULL, CX_BUFFER_AUTO_EXTEND); + cxBufferInit(&hd.secondary_buffer, NULL, 32, NULL, CX_BUFFER_AUTO_EXTEND); + CxBuffer out_line; + cxBufferInit(&out_line, NULL, 128, NULL, CX_BUFFER_AUTO_EXTEND); + + CxIterator in_lines = cxListIterator(lines); + cx_foreach(char*, in_line, in_lines) { /* increase line number and clean line buffer */ lineno++; - ucx_buffer_clear(line); - + cxBufferClear(&out_line); + /* write line number */ - if (showlineno) { - ucx_bprintf(line, "%*d ", - lineno, lineno, lnw, lineno); + if (showln) { + cx_bprintf(&out_line, "%*d ", + lineno, lineno, lnw, lineno); } - + /* process code line */ - highlighter(sourceline->data, line, hd); - + highlighter(in_line, &out_line, &hd); + /* write code line */ - try_write(wfnc, line->space, line->size, outbuf, written, maxlen); - - if (written == maxlen) break; + written += wfnc(out_line.space, 1, out_line.size, outbuf); } - - /* end monospace formatting */ - try_write(wfnc, "
\n", 7, outbuf, written, maxlen); - + + /* end code formatting */ + written += wfnc("\n", 1, 7, outbuf); + /* cleanup and return */ - ucx_buffer_free(hd->primary_buffer); - ucx_buffer_free(hd->secondary_buffer); - free(hd); - ucx_buffer_free(line); - + cxBufferDestroy(&hd.primary_buffer); + cxBufferDestroy(&hd.secondary_buffer); + cxBufferDestroy(&out_line); + return written; } -size_t c2html_formatn(void* inputbuffer, read_func rfnc, - char* ibuf, size_t ibuflen, void* outputbuffer, write_func wfnc, - size_t maxlen, c2html_highlighter_func hltr, int showln) { - - UcxBuffer *content = ucx_buffer_new(NULL, ibuflen*2, UCX_BUFFER_AUTOEXTEND); - ucx_stream_copy(inputbuffer, content, rfnc, (write_func) ucx_buffer_write, - ibuf, ibuflen, (size_t)-1); +size_t c2html_bformat( + char const *inputbuffer, + size_t inputbuflen, + void *outbuf, + cx_write_func wfnc, + c2html_highlighter_func highlighter, + int showln +) { + /* a rough estimate for the number of lines */ + size_t est_cap = 16 + inputbuflen / 40; - size_t n = c2html_bformatn(content->space, content->size, - outputbuffer, wfnc, maxlen, hltr, showln); - - ucx_buffer_free(content); - return n; -} - -size_t c2html_format(void* inputbuffer, read_func rfnc, - char* ibuf, size_t ibuflen, void* outputbuffer, write_func wfnc, - c2html_highlighter_func hltr, int showln) { - return c2html_formatn(inputbuffer, rfnc, ibuf, ibuflen, - outputbuffer, wfnc, (size_t)-1, hltr, showln); -} - -size_t c2html_fformat(FILE* inputfile, char *ibuf, size_t ibuflen, - void* outputbuffer, write_func wfnc, - c2html_highlighter_func hltr, int showln) { - return c2html_format(inputfile, (read_func) fread, ibuf, ibuflen, - outputbuffer, wfnc, hltr, showln); -} - -void c2html_fformatf(FILE *inputfile, char *ibuf, size_t ibuflen, - FILE* outputfile, c2html_highlighter_func hltr, int showln) { - c2html_format(inputfile, (read_func) fread, ibuf, ibuflen, - outputfile, (write_func) fwrite, hltr, showln); -} - -size_t c2html_bformatn(const char* inputbuffer, size_t inputbuflen, - void* outputbuffer, write_func wfnc, - size_t maxlen, c2html_highlighter_func hltr, int showln) { - UcxList *lines = ucx_list_append(NULL, (char*)inputbuffer); - for (size_t i = 1 ; i < inputbuflen ; i++) { - if (inputbuffer[i] == '\n' && i+1 < inputbuflen) { - ucx_list_append(lines, (char*)inputbuffer+i+1); + /* create the line pointer array */ + CxList *lines = cxArrayListCreateSimple(CX_STORE_POINTERS, est_cap); + cxListAdd(lines, inputbuffer); + for (size_t i = 1; i < inputbuflen; i++) { + if (inputbuffer[i] == '\n' && i + 1 < inputbuflen) { + cxListAdd(lines, inputbuffer + i + 1); } } - - size_t n = formatlines(hltr, lines, outputbuffer, wfnc, maxlen, showln); - - ucx_list_free(lines); + + /* invoke the other function */ + size_t n = c2html_format(lines, outbuf, wfnc, highlighter, showln); + + /* cleanup and return */ + cxListDestroy(lines); return n; -} - -size_t c2html_bformat(const char* inputbuffer, size_t inputbuflen, - void* outputbuffer, write_func wfnc, - c2html_highlighter_func hltr, int showln) { - return c2html_bformatn(inputbuffer, inputbuflen, outputbuffer, wfnc, - (size_t)-1, hltr, showln); -} - -void c2html_bformatf(const char* inputbuffer, size_t inputbuflen, - FILE* outputfile, c2html_highlighter_func hltr, int showln) { - c2html_bformatn(inputbuffer, inputbuflen, outputfile, - (write_func) fwrite, (size_t)-1, hltr, showln); -} +} \ No newline at end of file diff -r 9f25df78925e -r 1b12cf799fee src/c2html.h --- a/src/c2html.h Thu Nov 10 18:44:48 2016 +0100 +++ b/src/c2html.h Mon Apr 24 20:54:38 2023 +0200 @@ -31,61 +31,23 @@ #define C2HTML_H #include +#include #include "highlighter.h" #ifdef __cplusplus extern "C" { #endif -#define VERSION_MAJOR 2 +#define VERSION_MAJOR 3 #define VERSION_MINOR 0 #define VERSION_DEVELOP 0 /* set this to zero for release version */ /** - * Reads a source file from the input buffer and writes at most - * maxlen bytes of the formatted output to the output buffer. + * Writes the formatted source data to the output buffer. * - * The output buffer must either be large enough to hold maxlen - * bytes or the write function must trigger an automatic extension of the - * buffer. - * - * The input is copied via an intermediate buffer to an internal buffer. - * - * @param inputbuffer the input buffer - * @param rfnc a read function operating for the input buffer - * @param ibuf intermediate processing buffer - * @param ibuflen length of intermediate processing buffer - * @param outputbuffer the output buffer - * @param wfnc a write function for the output buffer - * @param maxlen the maximum amount bytes which will be written to the - * output buffer - * @param hltr the highlighter function - * @param showln zero, if line numbers shall be omitted, nonzero otherwise - * - * @return total amount of bytes written to the output buffer - * - * @see c2html_plain_highlighter() - * @see c2html_c_highlighter() - * @see c2html_java_highlighter() - */ -size_t c2html_formatn(void* inputbuffer, read_func rfnc, - char* ibuf, size_t ibuflen, void* outputbuffer, write_func wfnc, - size_t maxlen, c2html_highlighter_func hltr, int showln); - -/** - * Reads a source file from the input buffer and writes the formatted output - * to an output buffer. - * - * The output buffer must either be large enough to hold the formatted data - * or the write function must trigger an automatic extension of the buffer. - * - * The input is copied via an intermediate buffer to an internal buffer. - * - * @param inputbuffer the input buffer - * @param rfnc a read function operating for the input buffer - * @param ibuf intermediate processing buffer - * @param ibuflen length of intermediate processing buffer - * @param outputbuffer the output buffer + * @param inputbuffer the source file data as string + * @param inputbuflen the length of the source file + * @param outbuf the output buffer * @param wfnc a write function for the output buffer * @param hltr the highlighter function * @param showln zero, if line numbers shall be omitted, nonzero otherwise @@ -96,121 +58,32 @@ * @see c2html_c_highlighter() * @see c2html_java_highlighter() */ -size_t c2html_format(void* inputbuffer, read_func rfnc, - char* ibuf, size_t ibuflen, void* outputbuffer, write_func wfnc, - c2html_highlighter_func hltr, int showln); +size_t c2html_bformat(char const* inputbuffer, size_t inputbuflen, + void* outbuf, cx_write_func wfnc, + c2html_highlighter_func hltr, int showln); /** - * Reads a source file from the specified input file stream and writes the - * formatted output to an output buffer. - * - * The output buffer must either be large enough to hold the formatted data - * or the write function must trigger an automatic extension of the buffer. - * - * The input is copied via an intermediate buffer to an internal buffer. - * For files, the recommended intermediate buffer length is the file system - * block size. - * - * @param inputfile the input file stream - * @param ibuf intermediate processing buffer - * @param ibuflen length of intermediate processing buffer - * @param outputbuffer the output buffer + * Writes the formatted source data to the output buffer. + * + * This function takes a list of \c char* that point to the beginning of each + * line. These pointers may point directly into the source text and the strings + * do not need to be zero-terminated, but the line-breaks must be included. + * + * @param lines a list of pointers to the beginning of each line + * @param outbuf the output buffer * @param wfnc a write function for the output buffer * @param hltr the highlighter function * @param showln zero, if line numbers shall be omitted, nonzero otherwise - * + * * @return total amount of bytes written to the output buffer - * + * * @see c2html_plain_highlighter() * @see c2html_c_highlighter() * @see c2html_java_highlighter() */ -size_t c2html_fformat(FILE* inputfile, char *ibuf, size_t ibuflen, - void* outputbuffer, write_func wfnc, - c2html_highlighter_func hltr, int showln); - -/** - * Reads a source file from the specified input file stream and directly writes - * the formatted output to the output file stream. - * - * For files, the recommended intermediate buffer length is the file system - * block size. - * - * @param inputfile the input file stream - * @param ibuf intermediate processing buffer - * @param ibuflen length of intermediate processing buffer (recommended: 4 KB) - * @param outputfile the output file stream - * @param hltr the highlighter function - * @param showln zero, if line numbers shall be omitted, nonzero otherwise - * - * @see c2html_plain_highlighter() - * @see c2html_c_highlighter() - * @see c2html_java_highlighter() - */ -void c2html_fformatf(FILE *inputfile, char *ibuf, size_t ibuflen, - FILE* outputfile, c2html_highlighter_func hltr, int showln); - - -/** - * Writes at most maxlen bytes of formatted source data to the - * output buffer. - * - * @param inputbuffer the source file data as string - * @param inputbuflen the length of the source file - * @param outputbuffer the output buffer - * @param wfnc a write function for the output buffer - * @param maxlen the maximum amount bytes which will be written to the - * output buffer - * @param hltr the highlighter function - * @param showln zero, if line numbers shall be omitted, nonzero otherwise - * - * @return total amount of bytes written to the output buffer - * - * @see c2html_plain_highlighter() - * @see c2html_c_highlighter() - * @see c2html_java_highlighter() - */ -size_t c2html_bformatn(const char* inputbuffer, size_t inputbuflen, - void* outputbuffer, write_func wfnc, - size_t maxlen, c2html_highlighter_func hltr, int showln); - - -/** - * Writes the formatted source data to the output buffer. - * - * @param inputbuffer the source file data as string - * @param inputbuflen the length of the source file - * @param outputbuffer the output buffer - * @param wfnc a write function for the output buffer - * @param hltr the highlighter function - * @param showln zero, if line numbers shall be omitted, nonzero otherwise - * - * @return total amount of bytes written to the output buffer - * - * @see c2html_plain_highlighter() - * @see c2html_c_highlighter() - * @see c2html_java_highlighter() - */ -size_t c2html_bformat(const char* inputbuffer, size_t inputbuflen, - void* outputbuffer, write_func wfnc, - c2html_highlighter_func hltr, int showln); - - -/** - * Writes the formatted source data directly to the specified file stream. - * - * @param inputbuffer the source file data as string - * @param inputbuflen the length of the source file - * @param outputfile the output file stream - * @param hltr the highlighter function - * @param showln zero, if line numbers shall be omitted, nonzero otherwise - * - * @see c2html_plain_highlighter() - * @see c2html_c_highlighter() - * @see c2html_java_highlighter() - */ -void c2html_bformatf(const char* inputbuffer, size_t inputbuflen, - FILE* outputfile, c2html_highlighter_func hltr, int showln); +size_t c2html_format(CxList const* lines, + void* outbuf, cx_write_func wfnc, + c2html_highlighter_func hltr, int showln); #ifdef __cplusplus } diff -r 9f25df78925e -r 1b12cf799fee src/frontend.c --- a/src/frontend.c Thu Nov 10 18:44:48 2016 +0100 +++ b/src/frontend.c Mon Apr 24 20:54:38 2023 +0200 @@ -33,9 +33,7 @@ #include #include "c2html.h" -#include "ucx/utils.h" - -#define FILEBUF_SIZE 4096 +#include typedef struct { char* outfilename; @@ -45,20 +43,17 @@ int showlinenumbers; } Settings; -static int appendfile(const char *filename, FILE *fout, - char *copybuf, size_t copybuflen, const char *errmsg) { - FILE *headerfile = fopen(filename, "r"); - if (!headerfile) { +static int appendfile(const char *filename, FILE *fout, const char *errmsg) { + FILE *fin = fopen(filename, "r"); + if (!fin) { perror(errmsg); if (fout != stdout) { fclose(fout); } return 1; } - ucx_stream_copy(headerfile, fout, - (read_func) fread, (write_func) fwrite, - copybuf, copybuflen, (size_t)-1); - fclose(headerfile); + cx_stream_copy(fin, fout, (cx_read_func) fread, (cx_write_func) fwrite); + fclose(fin); return 0; } @@ -86,7 +81,7 @@ c2html_highlighter_func hltr = c2html_c_highlighter; /* Parse command line */ - char optc; + int optc; while ((optc = getopt(argc, argv, "hljo:pH:F:vV")) != -1) { switch (optc) { case 'o': @@ -142,15 +137,8 @@ fout = stdout; } - /* Allocate file buffer */ - char *filebuf = malloc(FILEBUF_SIZE); - if (!filebuf) { - perror("Error allocating file buffer"); - return EXIT_FAILURE; - } - /* Prepend header file */ - if (appendfile(settings.headerfile, fout, filebuf, FILEBUF_SIZE, + if (appendfile(settings.headerfile, fout, "Error opening header file")) { return EXIT_FAILURE; } @@ -158,11 +146,17 @@ /* Process input file */ FILE *inputfile = fopen(settings.infilename, "r"); if (inputfile) { - c2html_fformatf( - inputfile, filebuf, FILEBUF_SIZE, - fout, hltr, settings.showlinenumbers + CxBuffer fbuf; + cxBufferInit(&fbuf, NULL, 4096, NULL, CX_BUFFER_AUTO_EXTEND); + cx_stream_copy(inputfile, &fbuf, (cx_read_func) fread, + (cx_write_func) cxBufferWrite); + fclose(inputfile); + c2html_bformat( + fbuf.space, fbuf.size, + fout, (cx_write_func ) fwrite, hltr, + settings.showlinenumbers ); - fclose(inputfile); + cxBufferDestroy(&fbuf); } else { perror("Error opening input file"); if (fout != stdout) { @@ -172,12 +166,10 @@ } /* Append footer file */ - if (appendfile(settings.footerfile, fout, filebuf, FILEBUF_SIZE, + if (appendfile(settings.footerfile, fout, "Error opening footer file")) { return EXIT_FAILURE; } - - free(filebuf); return EXIT_SUCCESS; } diff -r 9f25df78925e -r 1b12cf799fee src/highlighter.c --- a/src/highlighter.c Thu Nov 10 18:44:48 2016 +0100 +++ b/src/highlighter.c Mon Apr 24 20:54:38 2023 +0200 @@ -33,35 +33,35 @@ #include #include #include -#include "ucx/string.h" -#include "ucx/utils.h" -static void put_htmlescaped(UcxBuffer *dest, char c) { +#include + +static void put_htmlescaped(CxBuffer *dest, char c) { if (c == '>') { - ucx_buffer_puts(dest, ">"); + cxBufferPutString(dest, ">"); } else if (c == '<') { - ucx_buffer_puts(dest, "<"); + cxBufferPutString(dest, "<"); } else if (c) { - ucx_buffer_putc(dest, c); + cxBufferPut(dest, c); } } -static void put_htmlescapedstr(UcxBuffer *dest, sstr_t s) { +static void put_htmlescapedstr(CxBuffer *dest, cxstring s) { for (int i = 0 ; i < s.length ; i++) { put_htmlescaped(dest, s.ptr[i]); } } -static int check_keyword(sstr_t word, const char** keywords) { +static int check_keyword(cxstring word, const char** keywords) { for (int i = 0 ; keywords[i] ; i++) { - if (sstrcmp(word, sstr((char*)keywords[i])) == 0) { + if (cx_strcmp(word, cx_str(keywords[i])) == 0) { return 1; } } return 0; } -static int check_capsonly(sstr_t word) { +static int check_capsonly(cxstring word) { for (size_t i = 0 ; i < word.length ; i++) { if (!isupper(word.ptr[i]) && !isdigit(word.ptr[i]) && word.ptr[i] != '_') { @@ -73,7 +73,7 @@ /* Plaintext Highlighter */ -void c2html_plain_highlighter(char *src, UcxBuffer *dest, +void c2html_plain_highlighter(char const *src, CxBuffer *dest, c2html_highlighter_data *hd) { while (*src && *src != '\n') { if (*src != '\r') { @@ -81,7 +81,7 @@ } src++; } - ucx_buffer_putc(dest, '\n'); + cxBufferPut(dest, '\n'); } /* C Highlighter */ @@ -94,15 +94,15 @@ "while", NULL }; -void c2html_c_highlighter(char *src, UcxBuffer *dest, +void c2html_c_highlighter(char const *src, CxBuffer *dest, c2html_highlighter_data *hd) { /* reset buffers without clearing them */ - hd->primary_buffer->size = hd->primary_buffer->pos = 0; - hd->secondary_buffer->size = hd->secondary_buffer->pos = 0; + hd->primary_buffer.size = hd->primary_buffer.pos = 0; + hd->secondary_buffer.size = hd->secondary_buffer.pos = 0; /* alias the buffers for better handling */ - UcxBuffer *wbuf = hd->primary_buffer; - UcxBuffer *ifilebuf = hd->secondary_buffer; + CxBuffer *wbuf = &hd->primary_buffer; + CxBuffer *ifilebuf = &hd->secondary_buffer; /* local information */ size_t sp = (size_t)-1; @@ -113,7 +113,7 @@ /* continue a multi line comment highlighting */ if (hd->multiline_comment) { iscomment = 1; - ucx_buffer_puts(dest, ""); + cxBufferPutString(dest, ""); } char c; @@ -126,42 +126,42 @@ if (hd->multiline_comment && sp > 0 && src[sp-1] == '*') { iscomment = 0; hd->multiline_comment = 0; - ucx_buffer_puts(dest, "/"); + cxBufferPutString(dest, "/"); continue; } else if (!iscomment && (src[sp+1] == '/' || src[sp+1] == '*')) { iscomment = 1; hd->multiline_comment = (src[sp+1] == '*'); - ucx_buffer_puts(dest, ""); + cxBufferPutString(dest, ""); } } if (iscomment) { if (c == '\n') { - ucx_buffer_puts(dest, "\n"); + cxBufferPutString(dest, "\n"); } else { put_htmlescaped(dest, c); } } else if (isinclude) { if (c == '<') { - ucx_buffer_puts(dest, + cxBufferPutString(dest, "<"); } else if (c == '\"') { if (parseinclude) { - ucx_buffer_puts(dest, "\">"); - ucx_buffer_write(ifilebuf->space, 1, ifilebuf->size, dest); - ucx_buffer_puts(dest, "\""); + cxBufferPutString(dest, "\">"); + cxBufferWrite(ifilebuf->space, 1, ifilebuf->size, dest); + cxBufferPutString(dest, "\""); parseinclude = 0; } else { - ucx_buffer_puts(dest, + cxBufferPutString(dest, "') { - ucx_buffer_puts(dest, ">"); + cxBufferPutString(dest, ">"); } else { if (parseinclude) { - ucx_buffer_putc(ifilebuf, c); + cxBufferPut(ifilebuf, c); } put_htmlescaped(dest, c); } @@ -172,14 +172,14 @@ put_htmlescaped(dest, c); if (c == quote) { isstring = 0; - ucx_buffer_puts(dest, ""); + cxBufferPutString(dest, ""); } else { put_htmlescaped(dest, c); } } else { isstring = 1; quote = c; - ucx_buffer_puts(dest, ""); + cxBufferPutString(dest, ""); put_htmlescaped(dest, c); } } else { @@ -187,32 +187,32 @@ put_htmlescaped(dest, c); } else if (isalnum(c) || c == '_' || c == '#') { /* buffer the current word */ - ucx_buffer_putc(wbuf, c); + cxBufferPut(wbuf, c); } else { /* write buffered word, if any */ if (wbuf->size > 0) { - sstr_t word = sstrn(wbuf->space, wbuf->size); + cxstring word = cx_strn(wbuf->space, wbuf->size); int closespan = 1; - sstr_t typesuffix = ST("_t"); + cxstring typesuffix = CX_STR("_t"); if (check_keyword(word, ckeywords)) { - ucx_buffer_puts(dest, + cxBufferPutString(dest, ""); - } else if (sstrsuffix(word, typesuffix)) { - ucx_buffer_puts(dest, + } else if (cx_strsuffix(word, typesuffix)) { + cxBufferPutString(dest, ""); } else if (word.ptr[0] == '#') { - isinclude = !sstrcmp(word, S("#include")); - ucx_buffer_puts(dest, + isinclude = !cx_strcmp(word, CX_STR("#include")); + cxBufferPutString(dest, ""); } else if (check_capsonly(word)) { - ucx_buffer_puts(dest, + cxBufferPutString(dest, ""); } else { closespan = 0; } put_htmlescapedstr(dest, word); if (closespan) { - ucx_buffer_puts(dest, ""); + cxBufferPutString(dest, ""); } } wbuf->pos = wbuf->size = 0; /* reset word buffer */ @@ -239,14 +239,14 @@ "volatile", "const", "float", "native", "super", "while", NULL }; -void c2html_java_highlighter(char *src, UcxBuffer *dest, +void c2html_java_highlighter(char const *src, CxBuffer *dest, c2html_highlighter_data *hd) { /* reset buffers without clearing them */ - hd->primary_buffer->size = hd->primary_buffer->pos = 0; - hd->secondary_buffer->size = hd->secondary_buffer->pos = 0; + hd->primary_buffer.size = hd->primary_buffer.pos = 0; + hd->secondary_buffer.size = hd->secondary_buffer.pos = 0; /* alias the buffers for better handling */ - UcxBuffer *wbuf = hd->primary_buffer; + CxBuffer *wbuf = &hd->primary_buffer; /* local information */ size_t sp = (size_t)-1; @@ -256,7 +256,7 @@ if (hd->multiline_comment) { iscomment = 1; - ucx_buffer_puts(dest, ""); + cxBufferPutString(dest, ""); } char c; @@ -269,18 +269,18 @@ if (hd->multiline_comment && sp > 0 && src[sp-1] == '*') { iscomment = 0; hd->multiline_comment = 0; - ucx_buffer_puts(dest, "/"); + cxBufferPutString(dest, "/"); continue; } else if (!iscomment && (src[sp+1] == '/' || src[sp+1] == '*')) { iscomment = 1; hd->multiline_comment = (src[sp+1] == '*'); - ucx_buffer_puts(dest, ""); + cxBufferPutString(dest, ""); } } if (iscomment) { if (c == '\n') { - ucx_buffer_puts(dest, "\n"); + cxBufferPutString(dest, "\n"); } else { put_htmlescaped(dest, c); } @@ -293,14 +293,14 @@ put_htmlescaped(dest, c); if (c == quote) { isstring = 0; - ucx_buffer_puts(dest, ""); + cxBufferPutString(dest, ""); } else { put_htmlescaped(dest, c); } } else { isstring = 1; quote = c; - ucx_buffer_puts(dest, + cxBufferPutString(dest, ""); put_htmlescaped(dest, c); } @@ -309,23 +309,23 @@ put_htmlescaped(dest, c); } else if (isalnum(c) || c == '_' || c == '@') { /* buffer the current word */ - ucx_buffer_putc(wbuf, c); + cxBufferPut(wbuf, c); } else { /* write buffered word, if any */ if (wbuf->size > 0) { - sstr_t word = sstrn(wbuf->space, wbuf->size); + cxstring word = cx_strn(wbuf->space, wbuf->size); int closespan = 1; if (check_keyword(word, jkeywords)) { - ucx_buffer_puts(dest, + cxBufferPutString(dest, ""); } else if (isupper(word.ptr[0])) { - ucx_buffer_puts(dest, + cxBufferPutString(dest, ""); } else if (word.ptr[0] == '@') { - ucx_buffer_puts(dest, + cxBufferPutString(dest, ""); } else if (check_capsonly(word)) { - ucx_buffer_puts(dest, + cxBufferPutString(dest, ""); } else { closespan = 0; @@ -333,7 +333,7 @@ put_htmlescapedstr(dest, word); if (closespan) { - ucx_buffer_puts(dest, ""); + cxBufferPutString(dest, ""); } } wbuf->pos = wbuf->size = 0; /* reset buffer */ diff -r 9f25df78925e -r 1b12cf799fee src/highlighter.h --- a/src/highlighter.h Thu Nov 10 18:44:48 2016 +0100 +++ b/src/highlighter.h Mon Apr 24 20:54:38 2023 +0200 @@ -30,7 +30,7 @@ #ifndef C2HTML_HIGHLIGHTER_H #define C2HTML_HIGHLIGHTER_H -#include "ucx/buffer.h" +#include #ifdef __cplusplus extern "C" { @@ -38,12 +38,12 @@ typedef struct { int multiline_comment; - UcxBuffer* primary_buffer; - UcxBuffer* secondary_buffer; + CxBuffer primary_buffer; + CxBuffer secondary_buffer; } c2html_highlighter_data; #define C2HTML_HIGHLIGHTER_SIGNATURE \ -char*,UcxBuffer*, c2html_highlighter_data* +char const*, CxBuffer*, c2html_highlighter_data* typedef void(*c2html_highlighter_func)(C2HTML_HIGHLIGHTER_SIGNATURE); diff -r 9f25df78925e -r 1b12cf799fee src/ucx/allocator.c --- a/src/ucx/allocator.c Thu Nov 10 18:44:48 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,59 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2015 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include "allocator.h" - -UcxAllocator default_allocator = { - NULL, - ucx_default_malloc, - ucx_default_calloc, - ucx_default_realloc, - ucx_default_free -}; - -UcxAllocator *ucx_default_allocator() { - UcxAllocator *allocator = &default_allocator; - return allocator; -} - -void *ucx_default_malloc(void *ignore, size_t n) { - return malloc(n); -} - -void *ucx_default_calloc(void *ignore, size_t n, size_t size) { - return calloc(n, size); -} - -void *ucx_default_realloc(void *ignore, void *data, size_t n) { - return realloc(data, n); -} - -void ucx_default_free(void *ignore, void *data) { - free(data); -} diff -r 9f25df78925e -r 1b12cf799fee src/ucx/allocator.h --- a/src/ucx/allocator.h Thu Nov 10 18:44:48 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,206 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2015 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -/** - * Allocator for custom memory management. - * - * An UCX allocator consists of a pointer to the memory area / pool and four - * function pointers to memory management functions operating on this memory - * area / pool. These functions shall behave equivalent to the standard libc - * functions malloc(), calloc(), realloc() and free(). - * - * The signature of the memory management functions is based on the signature - * of the respective libc function but each of them takes the pointer to the - * memory area / pool as first argument. - * - * As the pointer to the memory area / pool can be arbitrarily chosen, any data - * can be provided to the memory management functions. An UcxMempool is just - * one example. - * - * @see mempool.h - * @see UcxMap - * - * @file allocator.h - * @author Mike Becker - * @author Olaf Wintermann - */ - -#ifndef UCX_ALLOCATOR_H -#define UCX_ALLOCATOR_H - -#include "ucx.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * A function pointer to the allocators malloc() function. - * @see UcxAllocator - */ -typedef void*(*ucx_allocator_malloc)(void *pool, size_t n); - -/** - * A function pointer to the allocators calloc() function. - * @see UcxAllocator - */ -typedef void*(*ucx_allocator_calloc)(void *pool, size_t n, size_t size); - -/** - * A function pointer to the allocators realloc() function. - * @see UcxAllocator - */ -typedef void*(*ucx_allocator_realloc)(void *pool, void *data, size_t n); - -/** - * A function pointer to the allocators free() function. - * @see UcxAllocator - */ -typedef void(*ucx_allocator_free)(void *pool, void *data); - -/** - * UCX allocator data structure containing memory management functions. - */ -typedef struct { - /** Pointer to an area of memory or a complex memory pool. - * This pointer will be passed to any memory management function as first - * argument. - */ - void *pool; - /** - * The malloc() function for this allocator. - */ - ucx_allocator_malloc malloc; - /** - * The calloc() function for this allocator. - */ - ucx_allocator_calloc calloc; - /** - * The realloc() function for this allocator. - */ - ucx_allocator_realloc realloc; - /** - * The free() function for this allocator. - */ - ucx_allocator_free free; -} UcxAllocator; - -/** - * Returns a pointer to the default allocator. - * - * The default allocator contains wrappers to the standard libc memory - * management functions. Use this function to get a pointer to a globally - * available allocator. You may also define an own UcxAllocator by assigning - * #UCX_ALLOCATOR_DEFAULT to a variable and pass the address of this variable - * to any function that takes an UcxAllocator as argument. Note that using - * this function is the recommended way of passing a default allocator, thus - * it never runs out of scope. - * - * @return a pointer to the default allocator - * - * @see UCX_ALLOCATOR_DEFAULT - */ -UcxAllocator *ucx_default_allocator(); - -/** - * A wrapper for the standard libc malloc() function. - * @param ignore ignored (may be used by allocators for pooled memory) - * @param n argument passed to malloc() - * @return return value of malloc() - */ -void *ucx_default_malloc(void *ignore, size_t n); -/** - * A wrapper for the standard libc calloc() function. - * @param ignore ignored (may be used by allocators for pooled memory) - * @param n argument passed to calloc() - * @param size argument passed to calloc() - * @return return value of calloc() - */ -void *ucx_default_calloc(void *ignore, size_t n, size_t size); -/** - * A wrapper for the standard libc realloc() function. - * @param ignore ignored (may be used by allocators for pooled memory) - * @param data argumend passed to realloc() - * @param n argument passed to realloc() - * @return return value of realloc() - */ -void *ucx_default_realloc(void *ignore, void *data, size_t n); -/** - * A wrapper for the standard libc free() function. - * @param ignore ignored (may be used by allocators for pooled memory) - * @param data argument passed to free() - */ -void ucx_default_free(void *ignore, void *data); - -/** - * Shorthand for calling an allocators malloc function. - * @param allocator the allocator to use - * @param n size of space to allocate - * @return a pointer to the allocated memory area - */ -#define almalloc(allocator, n) ((allocator)->malloc((allocator)->pool, n)) - -/** - * Shorthand for calling an allocators calloc function. - * @param allocator the allocator to use - * @param n the count of elements the space should be allocated for - * @param size the size of each element - * @return a pointer to the allocated memory area - */ -#define alcalloc(allocator, n, size) \ - ((allocator)->calloc((allocator)->pool, n, size)) - -/** - * Shorthand for calling an allocators realloc function. - * @param allocator the allocator to use - * @param ptr the pointer to the memory area that shall be reallocated - * @param n the new size of the allocated memory area - * @return a pointer to the reallocated memory area - */ -#define alrealloc(allocator, ptr, n) \ - ((allocator)->realloc((allocator)->pool, ptr, n)) - -/** - * Shorthand for calling an allocators free function. - * @param allocator the allocator to use - * @param ptr the pointer to the memory area that shall be freed - */ -#define alfree(allocator, ptr) ((allocator)->free((allocator)->pool, ptr)) - -/** - * Convenient macro for a default allocator struct definition. - */ -#define UCX_ALLOCATOR_DEFAULT {NULL, \ - ucx_default_malloc, ucx_default_calloc, ucx_default_realloc, \ - ucx_default_free } - -#ifdef __cplusplus -} -#endif - -#endif /* UCX_ALLOCATOR_H */ - diff -r 9f25df78925e -r 1b12cf799fee src/ucx/buffer.c --- a/src/ucx/buffer.c Thu Nov 10 18:44:48 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,234 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2015 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "buffer.h" -#include -#include -#include - -UcxBuffer *ucx_buffer_new(void *space, size_t capacity, int flags) { - UcxBuffer *buffer = (UcxBuffer*) malloc(sizeof(UcxBuffer)); - if (buffer) { - buffer->flags = flags; - if (!space) { - buffer->space = (char*)malloc(capacity); - if (!buffer->space) { - free(buffer); - return NULL; - } - memset(buffer->space, 0, capacity); - buffer->flags |= UCX_BUFFER_AUTOFREE; - } else { - buffer->space = (char*)space; - } - buffer->capacity = capacity; - buffer->size = 0; - - buffer->pos = 0; - } - - return buffer; -} - -void ucx_buffer_free(UcxBuffer *buffer) { - if ((buffer->flags & UCX_BUFFER_AUTOFREE) == UCX_BUFFER_AUTOFREE) { - free(buffer->space); - } - free(buffer); -} - -UcxBuffer* ucx_buffer_extract( - UcxBuffer *src, size_t start, size_t length, int flags) { - - if (src->size == 0 || length == 0 || start+length > src->capacity) { - return NULL; - } - - UcxBuffer *dst = (UcxBuffer*) malloc(sizeof(UcxBuffer)); - if (dst) { - dst->space = (char*)malloc(length); - if (!dst->space) { - free(dst); - return NULL; - } - dst->capacity = length; - dst->size = length; - dst->flags = flags | UCX_BUFFER_AUTOFREE; - dst->pos = 0; - memcpy(dst->space, src->space+start, length); - } - return dst; -} - -int ucx_buffer_seek(UcxBuffer *buffer, off_t offset, int whence) { - size_t npos; - switch (whence) { - case SEEK_CUR: - npos = buffer->pos; - break; - case SEEK_END: - npos = buffer->size; - break; - case SEEK_SET: - npos = 0; - break; - default: - return -1; - } - - size_t opos = npos; - npos += offset; - - if ((offset > 0 && npos < opos) || (offset < 0 && npos > opos)) { - return -1; - } - - if (npos >= buffer->size) { - return -1; - } else { - buffer->pos = npos; - return 0; - } - -} - -int ucx_buffer_eof(UcxBuffer *buffer) { - return buffer->pos >= buffer->size; -} - -int ucx_buffer_extend(UcxBuffer *buffer, size_t len) { - size_t newcap = buffer->capacity; - - if (buffer->capacity + len < buffer->capacity) { - return -1; - } - - while (buffer->capacity + len > newcap) { - newcap <<= 1; - if (newcap < buffer->capacity) { - return -1; - } - } - - char *newspace = (char*)realloc(buffer->space, newcap); - if (newspace) { - memset(newspace+buffer->size, 0, newcap-buffer->size); - buffer->space = newspace; - buffer->capacity = newcap; - } else { - return -1; - } - - return 0; -} - -size_t ucx_buffer_write(const void *ptr, size_t size, size_t nitems, - UcxBuffer *buffer) { - size_t len = size * nitems; - size_t required = buffer->pos + len; - if (buffer->pos > required) { - return 0; - } - - if (required > buffer->capacity) { - if ((buffer->flags & UCX_BUFFER_AUTOEXTEND) == UCX_BUFFER_AUTOEXTEND) { - if (ucx_buffer_extend(buffer, required - buffer->capacity)) { - return 0; - } - } else { - len = buffer->capacity - buffer->pos; - if (size > 1) { - len -= len%size; - } - } - } - - if (len == 0) { - return len; - } - - memcpy(buffer->space + buffer->pos, ptr, len); - buffer->pos += len; - if(buffer->pos > buffer->size) { - buffer->size = buffer->pos; - } - - return len / size; -} - -size_t ucx_buffer_read(void *ptr, size_t size, size_t nitems, - UcxBuffer *buffer) { - size_t len = size * nitems; - if (buffer->pos + len > buffer->size) { - len = buffer->size - buffer->pos; - if (size > 1) len -= len%size; - } - - if (len <= 0) { - return len; - } - - memcpy(ptr, buffer->space + buffer->pos, len); - buffer->pos += len; - - return len / size; -} - -int ucx_buffer_putc(UcxBuffer *buffer, int c) { - if(buffer->pos >= buffer->capacity) { - if ((buffer->flags & UCX_BUFFER_AUTOEXTEND) == UCX_BUFFER_AUTOEXTEND) { - if(ucx_buffer_extend(buffer, 1)) { - return EOF; - } - } else { - return EOF; - } - } - - c &= 0xFF; - buffer->space[buffer->pos] = (char) c; - buffer->pos++; - if(buffer->pos > buffer->size) { - buffer->size = buffer->pos; - } - return c; -} - -int ucx_buffer_getc(UcxBuffer *buffer) { - if (ucx_buffer_eof(buffer)) { - return EOF; - } else { - int c = buffer->space[buffer->pos]; - buffer->pos++; - return c; - } -} - -size_t ucx_buffer_puts(UcxBuffer *buffer, char *str) { - return ucx_buffer_write((const void*)str, 1, strlen(str), buffer); -} diff -r 9f25df78925e -r 1b12cf799fee src/ucx/buffer.h --- a/src/ucx/buffer.h Thu Nov 10 18:44:48 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,270 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2015 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file buffer.h - * - * Advanced buffer implementation. - * - * Instances of UcxBuffer can be used to read from or to write to like one - * would do with a stream. This allows the use of ucx_stream_copy() to copy - * contents from one buffer to another. - * - * Some features for convenient use of the buffer - * can be enabled. See the documentation of the macro constants for more - * information. - * - * @author Mike Becker - * @author Olaf Wintermann - */ - -#ifndef UCX_BUFFER_H -#define UCX_BUFFER_H - -#include "ucx.h" -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * No buffer features enabled (all flags cleared). - */ -#define UCX_BUFFER_DEFAULT 0x00 - -/** - * If this flag is enabled, the buffer will automatically free its contents. - */ -#define UCX_BUFFER_AUTOFREE 0x01 - -/** - * If this flag is enabled, the buffer will automatically extends its capacity. - */ -#define UCX_BUFFER_AUTOEXTEND 0x02 - -/** UCX Buffer. */ -typedef struct { - /** A pointer to the buffer contents. */ - char *space; - /** Current position of the buffer. */ - size_t pos; - /** Current capacity (i.e. maximum size) of the buffer. */ - size_t capacity; - /** Current size of the buffer content. */ - size_t size; - /** - * Flag register for buffer features. - * @see #UCX_BUFFER_DEFAULT - * @see #UCX_BUFFER_AUTOFREE - * @see #UCX_BUFFER_AUTOEXTEND - */ - int flags; -} UcxBuffer; - -/** - * Creates a new buffer. - * - * Note: you may provide NULL as argument for - * space. Then this function will allocate the space and enforce - * the #UCX_BUFFER_AUTOFREE flag. - * - * @param space pointer to the memory area, or NULL to allocate - * new memory - * @param capacity the capacity of the buffer - * @param flags buffer features (see UcxBuffer.flags) - * @return the new buffer - */ -UcxBuffer *ucx_buffer_new(void *space, size_t capacity, int flags); - -/** - * Destroys a buffer. - * - * If the #UCX_BUFFER_AUTOFREE feature is enabled, the contents of the buffer - * are also freed. - * - * @param buffer the buffer to destroy - */ -void ucx_buffer_free(UcxBuffer* buffer); - -/** - * Creates a new buffer and fills it with extracted content from another buffer. - * - * Note: the #UCX_BUFFER_AUTOFREE feature is enforced for the new buffer. - * - * @param src the source buffer - * @param start the start position of extraction - * @param length the count of bytes to extract (must not be zero) - * @param flags feature mask for the new buffer - * @return a new buffer containing the extraction - */ -UcxBuffer* ucx_buffer_extract(UcxBuffer *src, - size_t start, size_t length, int flags); - -/** - * A shorthand macro for the full extraction of the buffer. - * - * @param src the source buffer - * @param flags feature mask for the new buffer - * @return a new buffer with the extracted content - */ -#define ucx_buffer_clone(src,flags) \ - ucx_buffer_extract(src, 0, (src)->capacity, flags) - -/** - * Moves the position of the buffer. - * - * The new position is relative to the whence argument. - * - * SEEK_SET marks the start of the buffer. - * SEEK_CUR marks the current position. - * SEEK_END marks the end of the buffer. - * - * With an offset of zero, this function sets the buffer position to zero - * (SEEK_SET), the buffer size (SEEK_END) or leaves the buffer position - * unchanged (SEEK_CUR). - * - * @param buffer - * @param offset position offset relative to whence - * @param whence one of SEEK_SET, SEEK_CUR or SEEK_END - * @return 0 on success, non-zero if the position is invalid - * - */ -int ucx_buffer_seek(UcxBuffer *buffer, off_t offset, int whence); - -/** - * Clears the buffer by resetting the position and deleting the data. - * - * The data is deleted by a zeroing it with call to memset(). - * - * @param buffer the buffer to be cleared - */ -#define ucx_buffer_clear(buffer) memset(buffer->space, 0, buffer->size); \ - buffer->size = 0; buffer->pos = 0; - -/** - * Tests, if the buffer position has exceeded the buffer capacity. - * - * @param buffer the buffer to test - * @return non-zero, if the current buffer position has exceeded the last - * available byte of the buffer. - */ -int ucx_buffer_eof(UcxBuffer *buffer); - - -/** - * Extends the capacity of the buffer. - * - * Note: The buffer capacity increased by a power of two. I.e. - * the buffer capacity is doubled, as long as it would not hold the current - * content plus the additional required bytes. - * - * Attention: the argument provided is the number of additional - * bytes the buffer shall hold. It is NOT the total number of bytes the - * buffer shall hold. - * - * @param buffer the buffer to extend - * @param additional_bytes the number of additional bytes the buffer shall - * at least hold - * @return 0 on success or a non-zero value on failure - */ -int ucx_buffer_extend(UcxBuffer *buffer, size_t additional_bytes); - -/** - * Writes data to an UcxBuffer. - * - * The position of the buffer is increased by the number of bytes written. - * - * @param ptr a pointer to the memory area containing the bytes to be written - * @param size the length of one element - * @param nitems the element count - * @param buffer the UcxBuffer to write to - * @return the total count of bytes written - */ -size_t ucx_buffer_write(const void *ptr, size_t size, size_t nitems, - UcxBuffer *buffer); - -/** - * Reads data from an UcxBuffer. - * - * The position of the buffer is increased by the number of bytes read. - * - * @param ptr a pointer to the memory area where to store the read data - * @param size the length of one element - * @param nitems the element count - * @param buffer the UcxBuffer to read from - * @return the total number of elements read - */ -size_t ucx_buffer_read(void *ptr, size_t size, size_t nitems, - UcxBuffer *buffer); - -/** - * Writes a character to a buffer. - * - * The least significant byte of the argument is written to the buffer. If the - * end of the buffer is reached and #UCX_BUFFER_AUTOEXTEND feature is enabled, - * the buffer capacity is extended by ucx_buffer_extend(). If the feature is - * disabled or buffer extension fails, EOF is returned. - * - * On successful write the position of the buffer is increased. - * - * @param buffer the buffer to write to - * @param c the character to write as int value - * @return the byte that has bean written as int value or - * EOF when the end of the stream is reached and automatic - * extension is not enabled or not possible - */ -int ucx_buffer_putc(UcxBuffer *buffer, int c); - -/** - * Gets a character from a buffer. - * - * The current position of the buffer is increased after a successful read. - * - * @param buffer the buffer to read from - * @return the character as int value or EOF, if the - * end of the buffer is reached - */ -int ucx_buffer_getc(UcxBuffer *buffer); - -/** - * Writes a string to a buffer. - * - * @param buffer the buffer - * @param str the string - * @return the number of bytes written - */ -size_t ucx_buffer_puts(UcxBuffer *buffer, char *str); - -#ifdef __cplusplus -} -#endif - -#endif /* UCX_BUFFER_H */ - diff -r 9f25df78925e -r 1b12cf799fee src/ucx/list.c --- a/src/ucx/list.c Thu Nov 10 18:44:48 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,335 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2015 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "list.h" - -UcxList *ucx_list_clone(UcxList *l, copy_func fnc, void *data) { - return ucx_list_clone_a(ucx_default_allocator(), l, fnc, data); -} - -UcxList *ucx_list_clone_a(UcxAllocator *alloc, UcxList *l, - copy_func fnc, void *data) { - UcxList *ret = NULL; - while (l) { - if (fnc) { - ret = ucx_list_append_a(alloc, ret, fnc(l->data, data)); - } else { - ret = ucx_list_append_a(alloc, ret, l->data); - } - l = l->next; - } - return ret; -} - -int ucx_list_equals(const UcxList *l1, const UcxList *l2, - cmp_func fnc, void* data) { - if (l1 == l2) return 1; - - while (l1 != NULL && l2 != NULL) { - if (fnc == NULL) { - if (l1->data != l2->data) return 0; - } else { - if (fnc(l1->data, l2->data, data) != 0) return 0; - } - l1 = l1->next; - l2 = l2->next; - } - - return (l1 == NULL && l2 == NULL); -} - -void ucx_list_free(UcxList *l) { - ucx_list_free_a(ucx_default_allocator(), l); -} - -void ucx_list_free_a(UcxAllocator *alloc, UcxList *l) { - UcxList *e = l, *f; - while (e != NULL) { - f = e; - e = e->next; - alfree(alloc, f); - } -} - -void ucx_list_free_content(UcxList* list, ucx_destructor destr) { - while (list != NULL) { - destr(list->data); - list = list->next; - } -} - -UcxList *ucx_list_append(UcxList *l, void *data) { - return ucx_list_append_a(ucx_default_allocator(), l, data); -} - -UcxList *ucx_list_append_a(UcxAllocator *alloc, UcxList *l, void *data) { - UcxList *nl = (UcxList*) almalloc(alloc, sizeof(UcxList)); - if (!nl) { - return NULL; - } - - nl->data = data; - nl->next = NULL; - if (l) { - UcxList *t = ucx_list_last(l); - t->next = nl; - nl->prev = t; - return l; - } else { - nl->prev = NULL; - return nl; - } -} - -UcxList *ucx_list_prepend(UcxList *l, void *data) { - return ucx_list_prepend_a(ucx_default_allocator(), l, data); -} - -UcxList *ucx_list_prepend_a(UcxAllocator *alloc, UcxList *l, void *data) { - UcxList *nl = ucx_list_append_a(alloc, NULL, data); - if (!nl) { - return NULL; - } - l = ucx_list_first(l); - - if (l) { - nl->next = l; - l->prev = nl; - } - return nl; -} - -UcxList *ucx_list_concat(UcxList *l1, UcxList *l2) { - if (l1) { - UcxList *last = ucx_list_last(l1); - last->next = l2; - if (l2) { - l2->prev = last; - } - return l1; - } else { - return l2; - } -} - -UcxList *ucx_list_last(const UcxList *l) { - if (l == NULL) return NULL; - - const UcxList *e = l; - while (e->next != NULL) { - e = e->next; - } - return (UcxList*)e; -} - -ssize_t ucx_list_indexof(const UcxList *list, const UcxList *elem) { - ssize_t index = 0; - while (list) { - if (list == elem) { - return index; - } - list = list->next; - index++; - } - return -1; -} - -UcxList *ucx_list_get(const UcxList *l, size_t index) { - if (l == NULL) return NULL; - - const UcxList *e = l; - while (e->next && index > 0) { - e = e->next; - index--; - } - - return (UcxList*)(index == 0 ? e : NULL); -} - -ssize_t ucx_list_find(UcxList *l, void *elem, cmp_func fnc, void *cmpdata) { - ssize_t index = 0; - UCX_FOREACH(e, l) { - if (fnc) { - if (fnc(elem, e->data, cmpdata) == 0) { - return index; - } - } else { - if (elem == e->data) { - return index; - } - } - index++; - } - return -1; -} - -int ucx_list_contains(UcxList *l, void *elem, cmp_func fnc, void *cmpdata) { - return ucx_list_find(l, elem, fnc, cmpdata) > -1; -} - -size_t ucx_list_size(const UcxList *l) { - if (l == NULL) return 0; - - const UcxList *e = l; - size_t s = 1; - while (e->next != NULL) { - e = e->next; - s++; - } - - return s; -} - -static UcxList *ucx_list_sort_merge(int length, - UcxList* restrict ls, UcxList* restrict le, UcxList* restrict re, - cmp_func fnc, void* data) { - - UcxList** sorted = (UcxList**) malloc(sizeof(UcxList*)*length); - UcxList *rc, *lc; - - lc = ls; rc = le; - int n = 0; - while (lc && lc != le && rc != re) { - if (fnc(lc->data, rc->data, data) <= 0) { - sorted[n] = lc; - lc = lc->next; - } else { - sorted[n] = rc; - rc = rc->next; - } - n++; - } - while (lc && lc != le) { - sorted[n] = lc; - lc = lc->next; - n++; - } - while (rc && rc != re) { - sorted[n] = rc; - rc = rc->next; - n++; - } - - // Update pointer - sorted[0]->prev = NULL; - for (int i = 0 ; i < length-1 ; i++) { - sorted[i]->next = sorted[i+1]; - sorted[i+1]->prev = sorted[i]; - } - sorted[length-1]->next = NULL; - - UcxList *ret = sorted[0]; - free(sorted); - return ret; -} - -UcxList *ucx_list_sort(UcxList *l, cmp_func fnc, void *data) { - if (l == NULL) { - return NULL; - } - - UcxList *lc; - int ln = 1; - - UcxList *restrict ls = l, *restrict le, *restrict re; - - // check how many elements are already sorted - lc = ls; - while (lc->next != NULL && fnc(lc->next->data, lc->data, data) > 0) { - lc = lc->next; - ln++; - } - le = lc->next; - - if (le == NULL) { - return l; // this list is already sorted :) - } else { - UcxList *rc; - int rn = 1; - rc = le; - // skip already sorted elements - while (rc->next != NULL && fnc(rc->next->data, rc->data, data) > 0) { - rc = rc->next; - rn++; - } - re = rc->next; - - // {ls,...,le->prev} and {rs,...,re->prev} are sorted - merge them - UcxList *sorted = ucx_list_sort_merge(ln+rn, - ls, le, re, - fnc, data); - - // Something left? Sort it! - size_t remainder_length = ucx_list_size(re); - if (remainder_length > 0) { - UcxList *remainder = ucx_list_sort(re, fnc, data); - - // merge sorted list with (also sorted) remainder - l = ucx_list_sort_merge(ln+rn+remainder_length, - sorted, remainder, NULL, fnc, data); - } else { - // no remainder - we've got our sorted list - l = sorted; - } - - return l; - } -} - -UcxList *ucx_list_first(const UcxList *l) { - if (!l) { - return NULL; - } - - const UcxList *e = l; - while (e->prev) { - e = e->prev; - } - return (UcxList *)e; -} - -UcxList *ucx_list_remove(UcxList *l, UcxList *e) { - return ucx_list_remove_a(ucx_default_allocator(), l, e); -} - -UcxList *ucx_list_remove_a(UcxAllocator *alloc, UcxList *l, UcxList *e) { - if (l == e) { - l = e->next; - } - - if (e->next) { - e->next->prev = e->prev; - } - - if (e->prev) { - e->prev->next = e->next; - } - - alfree(alloc, e); - return l; -} diff -r 9f25df78925e -r 1b12cf799fee src/ucx/list.h --- a/src/ucx/list.h Thu Nov 10 18:44:48 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,395 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2015 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -/** - * Doubly linked list implementation. - * - * @file list.h - * @author Mike Becker - * @author Olaf Wintermann - */ - -#ifndef UCX_LIST_H -#define UCX_LIST_H - -#include "ucx.h" -#include "allocator.h" - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * Loop statement for UCX lists. - * - * The first argument is the name of the iteration variable. The scope of - * this variable is limited to the UCX_FOREACH statement. - * - * The second argument is a pointer to the list. In most cases this will be the - * pointer to the first element of the list, but it may also be an arbitrary - * element of the list. The iteration will then start with that element. - * - * - * @param list The first element of the list - * @param elem The variable name of the element - */ -#define UCX_FOREACH(elem,list) \ - for (UcxList* elem = list ; elem != NULL ; elem = elem->next) - -/** - * UCX list type. - * @see UcxList - */ -typedef struct UcxList UcxList; - -/** - * UCX list structure. - */ -struct UcxList { - /** - * List element payload. - */ - void *data; - /** - * Pointer to the next list element or NULL, if this is the - * last element. - */ - UcxList *next; - /** - * Pointer to the previous list element or NULL, if this is - * the first element. - */ - UcxList *prev; -}; - -/** - * Creates an element-wise copy of a list. - * - * This function clones the specified list by creating new list elements and - * copying the data with the specified copy_func(). If no copy_func() is - * specified, a shallow copy is created and the new list will reference the - * same data as the source list. - * - * @param list the list to copy - * @param cpyfnc a pointer to the function that shall copy an element (may be - * NULL) - * @param data additional data for the copy_func() - * @return a pointer to the copy - */ -UcxList *ucx_list_clone(UcxList *list, copy_func cpyfnc, void* data); - -/** - * Creates an element-wise copy of a list using an UcxAllocator. - * - * See ucx_list_clone() for details. - * - * Keep in mind, that you might want to pass the allocator as an (part of the) - * argument for the data parameter, if you want the copy_func() to - * make use of the allocator. - * - * @param allocator the allocator to use - * @param list the list to copy - * @param cpyfnc a pointer to the function that shall copy an element (may be - * NULL) - * @param data additional data for the copy_func() - * @return a pointer to the copy - * @see ucx_list_clone() - */ -UcxList *ucx_list_clone_a(UcxAllocator *allocator, UcxList *list, - copy_func cpyfnc, void* data); - -/** - * Compares two UCX lists element-wise by using a compare function. - * - * Each element of the two specified lists are compared by using the specified - * compare function and the additional data. The type and content of this - * additional data depends on the cmp_func() used. - * - * If the list pointers denote elements within a list, the lists are compared - * starting with the denoted elements. Thus any previous elements are not taken - * into account. This might be useful to check, if certain list tails match - * each other. - * - * @param list1 the first list - * @param list2 the second list - * @param cmpfnc the compare function - * @param data additional data for the compare function - * @return 1, if and only if the two lists equal element-wise, 0 otherwise - */ -int ucx_list_equals(const UcxList *list1, const UcxList *list2, - cmp_func cmpfnc, void* data); - -/** - * Destroys the entire list. - * - * The members of the list are not automatically freed, so ensure they are - * otherwise referenced or destroyed by ucx_list_free_contents(). - * Otherwise, a memory leak is likely to occur. - * - * Caution: the argument MUST denote an entire list (i.e. a call - * to ucx_list_first() on the argument must return the argument itself) - * - * @param list the list to free - * @see ucx_list_free_contents() - */ -void ucx_list_free(UcxList *list); - -/** - * Destroys the entire list using an UcxAllocator. - * - * See ucx_list_free() for details. - * - * @param allocator the allocator to use - * @param list the list to free - * @see ucx_list_free() - */ -void ucx_list_free_a(UcxAllocator *allocator, UcxList *list); - -/** - * Destroys the contents of the specified list by calling the specified - * destructor on each of them. - * - * Note, that the contents are not usable afterwards and the list should be - * destroyed with ucx_list_free(). - * - * @param list the list for which the contents shall be freed - * @param destr the destructor function (e.g. stdlib free()) - * @see ucx_list_free() - */ -void ucx_list_free_content(UcxList* list, ucx_destructor destr); - - -/** - * Inserts an element at the end of the list. - * - * This is generally an O(n) operation, as the end of the list is retrieved with - * ucx_list_last(). - * - * @param list the list where to append the data, or NULL to - * create a new list - * @param data the data to insert - * @return list, if it is not NULL or a pointer to - * the newly created list otherwise - */ -UcxList *ucx_list_append(UcxList *list, void *data); - -/** - * Inserts an element at the end of the list using an UcxAllocator. - * - * See ucx_list_append() for details. - * - * @param allocator the allocator to use - * @param list the list where to append the data, or NULL to - * create a new list - * @param data the data to insert - * @return list, if it is not NULL or a pointer to - * the newly created list otherwise - * @see ucx_list_append() - */ -UcxList *ucx_list_append_a(UcxAllocator *allocator, UcxList *list, void *data); - -/** - * Inserts an element at the beginning of the list. - * - * You should overwrite the old list pointer by calling - * mylist = ucx_list_prepend(mylist, mydata);. However, you may - * also perform successive calls of ucx_list_prepend() on the same list pointer, - * as this function always searchs for the head of the list with - * ucx_list_first(). - * - * @param list the list where to insert the data or NULL to create - * a new list - * @param data the data to insert - * @return a pointer to the new list head - */ -UcxList *ucx_list_prepend(UcxList *list, void *data); - -/** - * Inserts an element at the beginning of the list using an UcxAllocator. - * - * See ucx_list_prepend() for details. - * - * @param allocator the allocator to use - * @param list the list where to insert the data or NULL to create - * a new list - * @param data the data to insert - * @return a pointer to the new list head - * @see ucx_list_prepend() - */ -UcxList *ucx_list_prepend_a(UcxAllocator *allocator, UcxList *list, void *data); - -/** - * Concatenates two lists. - * - * Either of the two arguments may be NULL. - * - * This function modifies the references to the next/previous element of - * the last/first element of list1/ - * list2. - * - * @param list1 first list - * @param list2 second list - * @return if list1 is NULL, list2 is - * returned, otherwise list1 is returned - */ -UcxList *ucx_list_concat(UcxList *list1, UcxList *list2); - -/** - * Returns the first element of a list. - * - * If the argument is the list pointer, it is directly returned. Otherwise - * this function traverses to the first element of the list and returns the - * list pointer. - * - * @param elem one element of the list - * @return the first element of the list, the specified element is a member of - */ -UcxList *ucx_list_first(const UcxList *elem); - -/** - * Returns the last element of a list. - * - * If the argument has no successor, it is the last element and therefore - * directly returned. Otherwise this function traverses to the last element of - * the list and returns it. - * - * @param elem one element of the list - * @return the last element of the list, the specified element is a member of - */ -UcxList *ucx_list_last(const UcxList *elem); - -/** - * Returns the list element at the specified index. - * - * @param list the list to retrieve the element from - * @param index index of the element to return - * @return the element at the specified index or NULL, if the - * index is greater than the list size - */ -UcxList *ucx_list_get(const UcxList *list, size_t index); - -/** - * Returns the index of an element. - * - * @param list the list where to search for the element - * @param elem the element to find - * @return the index of the element or -1 if the list does not contain the - * element - */ -ssize_t ucx_list_indexof(const UcxList *list, const UcxList *elem); - -/** - * Returns the element count of the list. - * - * @param list the list whose elements are counted - * @return the element count - */ -size_t ucx_list_size(const UcxList *list); - -/** - * Returns the index of an element containing the specified data. - * - * This function uses a cmp_func() to compare the data of each list element - * with the specified data. If no cmp_func is provided, the pointers are - * compared. - * - * If the list contains the data more than once, the index of the first - * occurrence is returned. - * - * @param list the list where to search for the data - * @param elem the element data - * @param cmpfnc the compare function - * @param data additional data for the compare function - * @return the index of the element containing the specified data or -1 if the - * data is not found in this list - */ -ssize_t ucx_list_find(UcxList *list, void *elem, cmp_func cmpfnc, void *data); - -/** - * Checks, if a list contains a specific element. - * - * An element is found, if ucx_list_find() returns a value greater than -1. - * - * @param list the list where to search for the data - * @param elem the element data - * @param cmpfnc the compare function - * @param data additional data for the compare function - * @return 1, if and only if the list contains the specified element data - * @see ucx_list_find() - */ -int ucx_list_contains(UcxList *list, void *elem, cmp_func cmpfnc, void *data); - -/** - * Sorts an UcxList with natural merge sort. - * - * This function uses O(n) additional temporary memory for merge operations - * that is automatically freed after each merge. - * - * As the head of the list might change, you MUST call this function - * as follows: mylist = ucx_list_sort(mylist, mycmpfnc, mydata);. - * - * @param list the list to sort - * @param cmpfnc the function that shall be used to compare the element data - * @param data additional data for the cmp_func() - * @return the sorted list - */ -UcxList *ucx_list_sort(UcxList *list, cmp_func cmpfnc, void *data); - -/** - * Removes an element from the list. - * - * If the first element is removed, the list pointer changes. So it is - * highly recommended to always update the pointer by calling - * mylist = ucx_list_remove(mylist, myelem);. - * - * @param list the list from which the element shall be removed - * @param element the element to remove - * @return returns the updated list pointer or NULL, if the list - * is now empty - */ -UcxList *ucx_list_remove(UcxList *list, UcxList *element); - -/** - * Removes an element from the list using an UcxAllocator. - * - * See ucx_list_remove() for details. - * - * @param allocator the allocator to use - * @param list the list from which the element shall be removed - * @param element the element to remove - * @return returns the updated list pointer or NULL, if the list - * @see ucx_list_remove() - */ -UcxList *ucx_list_remove_a(UcxAllocator *allocator, UcxList *list, - UcxList *element); - -#ifdef __cplusplus -} -#endif - -#endif /* UCX_LIST_H */ - diff -r 9f25df78925e -r 1b12cf799fee src/ucx/string.c --- a/src/ucx/string.c Thu Nov 10 18:44:48 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,381 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2015 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include -#include -#include -#include - -#include "string.h" -#include "allocator.h" - -sstr_t sstr(char *cstring) { - sstr_t string; - string.ptr = cstring; - string.length = strlen(cstring); - return string; -} - -sstr_t sstrn(char *cstring, size_t length) { - sstr_t string; - string.ptr = cstring; - string.length = length; - return string; -} - -size_t sstrnlen(size_t n, sstr_t s, ...) { - va_list ap; - size_t size = s.length; - va_start(ap, s); - - for (size_t i = 1 ; i < n ; i++) { - sstr_t str = va_arg(ap, sstr_t); - size += str.length; - } - va_end(ap); - - return size; -} - -static sstr_t sstrvcat_a( - UcxAllocator *a, - size_t count, - sstr_t s1, - sstr_t s2, - va_list ap) { - sstr_t str; - str.ptr = NULL; - str.length = 0; - if(count < 2) { - return str; - } - - sstr_t *strings = (sstr_t*) calloc(count, sizeof(sstr_t)); - if(!strings) { - return str; - } - - // get all args and overall length - strings[0] = s1; - strings[1] = s2; - size_t strlen = s1.length + s2.length; - for (size_t i=2;i= s.length) { - new_sstr.ptr = NULL; - new_sstr.length = 0; - } else { - if (length > s.length-start) { - length = s.length-start; - } - new_sstr.ptr = &s.ptr[start]; - new_sstr.length = length; - } - return new_sstr; -} - -sstr_t sstrchr(sstr_t s, int c) { - for(size_t i=0;i 0) { - for(size_t i=s.length;i>0;i--) { - if(s.ptr[i-1] == c) { - return sstrsubs(s, i-1); - } - } - } - sstr_t n; - n.ptr = NULL; - n.length = 0; - return n; -} - -sstr_t sstrstr(sstr_t string, sstr_t match) { - if (match.length == 0) { - return string; - } - - for (size_t i = 0 ; i < string.length ; i++) { - sstr_t substr = sstrsubs(string, i); - if (sstrprefix(substr, match)) { - return substr; - } - } - - sstr_t emptystr; - emptystr.length = 0; - emptystr.ptr = NULL; - return emptystr; -} - -sstr_t* sstrsplit(sstr_t s, sstr_t d, ssize_t *n) { - return sstrsplit_a(ucx_default_allocator(), s, d, n); -} - -sstr_t* sstrsplit_a(UcxAllocator *allocator, sstr_t s, sstr_t d, ssize_t *n) { - if (s.length == 0 || d.length == 0) { - *n = -1; - return NULL; - } - - sstr_t* result; - ssize_t nmax = *n; - *n = 1; - - /* special case: exact match - no processing needed */ - if (sstrcmp(s, d) == 0) { - *n = 0; - return NULL; - } - sstr_t sv = sstrdup(s); - if (sv.length == 0) { - *n = -2; - return NULL; - } - - for (size_t i = 0 ; i < s.length ; i++) { - sstr_t substr = sstrsubs(sv, i); - if (sstrprefix(substr, d)) { - (*n)++; - for (size_t j = 0 ; j < d.length ; j++) { - sv.ptr[i+j] = 0; - } - i += d.length - 1; // -1, because the loop will do a i++ - } - if ((*n) == nmax) break; - } - result = (sstr_t*) almalloc(allocator, sizeof(sstr_t)*(*n)); - - if (result) { - char *pptr = sv.ptr; - for (ssize_t i = 0 ; i < *n ; i++) { - size_t l = strlen(pptr); - char* ptr = (char*) almalloc(allocator, l + 1); - if (ptr) { - memcpy(ptr, pptr, l); - ptr[l] = 0; - - result[i] = sstrn(ptr, l); - pptr += l + d.length; - } else { - for (ssize_t j = i-1 ; j >= 0 ; j--) { - alfree(allocator, result[j].ptr); - } - alfree(allocator, result); - *n = -2; - break; - } - } - } else { - *n = -2; - } - - free(sv.ptr); - - return result; -} - -int sstrcmp(sstr_t s1, sstr_t s2) { - if (s1.length == s2.length) { - return memcmp(s1.ptr, s2.ptr, s1.length); - } else if (s1.length > s2.length) { - return 1; - } else { - return -1; - } -} - -int sstrcasecmp(sstr_t s1, sstr_t s2) { - if (s1.length == s2.length) { -#ifdef _WIN32 - return _strnicmp(s1.ptr, s2.ptr, s1.length); -#else - return strncasecmp(s1.ptr, s2.ptr, s1.length); -#endif - } else if (s1.length > s2.length) { - return 1; - } else { - return -1; - } -} - -sstr_t sstrdup(sstr_t s) { - return sstrdup_a(ucx_default_allocator(), s); -} - -sstr_t sstrdup_a(UcxAllocator *allocator, sstr_t s) { - sstr_t newstring; - newstring.ptr = (char*)almalloc(allocator, s.length + 1); - if (newstring.ptr) { - newstring.length = s.length; - newstring.ptr[newstring.length] = 0; - - memcpy(newstring.ptr, s.ptr, s.length); - } else { - newstring.length = 0; - } - - return newstring; -} - -sstr_t sstrtrim(sstr_t string) { - sstr_t newstr = string; - - while (newstr.length > 0 && isspace(*newstr.ptr)) { - newstr.ptr++; - newstr.length--; - } - while (newstr.length > 0 && isspace(newstr.ptr[newstr.length-1])) { - newstr.length--; - } - - return newstr; -} - -int sstrprefix(sstr_t string, sstr_t prefix) { - if (string.length == 0) { - return prefix.length == 0; - } - if (prefix.length == 0) { - return 1; - } - - if (prefix.length > string.length) { - return 0; - } else { - return memcmp(string.ptr, prefix.ptr, prefix.length) == 0; - } -} - -int sstrsuffix(sstr_t string, sstr_t suffix) { - if (string.length == 0) { - return suffix.length == 0; - } - if (suffix.length == 0) { - return 1; - } - - if (suffix.length > string.length) { - return 0; - } else { - return memcmp(string.ptr+string.length-suffix.length, - suffix.ptr, suffix.length) == 0; - } -} - -sstr_t sstrlower(sstr_t string) { - sstr_t ret = sstrdup(string); - for (size_t i = 0; i < ret.length ; i++) { - ret.ptr[i] = tolower(ret.ptr[i]); - } - return ret; -} - -sstr_t sstrlower_a(UcxAllocator *allocator, sstr_t string) { - sstr_t ret = sstrdup_a(allocator, string); - for (size_t i = 0; i < ret.length ; i++) { - ret.ptr[i] = tolower(ret.ptr[i]); - } - return ret; -} - -sstr_t sstrupper(sstr_t string) { - sstr_t ret = sstrdup(string); - for (size_t i = 0; i < ret.length ; i++) { - ret.ptr[i] = toupper(ret.ptr[i]); - } - return ret; -} - -sstr_t sstrupper_a(UcxAllocator *allocator, sstr_t string) { - sstr_t ret = sstrdup_a(allocator, string); - for (size_t i = 0; i < ret.length ; i++) { - ret.ptr[i] = toupper(ret.ptr[i]); - } - return ret; -} diff -r 9f25df78925e -r 1b12cf799fee src/ucx/string.h --- a/src/ucx/string.h Thu Nov 10 18:44:48 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,457 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2015 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -/** - * Bounded string implementation. - * - * The UCX strings (sstr_t) provide an alternative to C strings. - * The main difference to C strings is, that sstr_t does not - * need to be NULL-terminated. Instead the length is stored - * within the structure. - * - * When using sstr_t, developers must be full aware of what type - * of string (NULL-terminated) or not) they are using, when - * accessing the char* ptr directly. - * - * The UCX string module provides some common string functions, known from - * standard libc, working with sstr_t. - * - * @file string.h - * @author Mike Becker - * @author Olaf Wintermann - */ - -#ifndef UCX_STRING_H -#define UCX_STRING_H - -#include "ucx.h" -#include "allocator.h" -#include - -/** Shortcut for a sstr_t struct literal. */ -#define ST(s) { (char*)s, sizeof(s)-1 } - -/** Shortcut for the conversion of a C string to a sstr_t. */ -#define S(s) sstrn((char*)s, sizeof(s)-1) - -#ifdef __cplusplus -extern "C" { -#endif - -/** - * The UCX string structure. - */ -typedef struct { - /** A reference to the string (not necessarily NULL - * -terminated) */ - char *ptr; - /** The length of the string */ - size_t length; -} sstr_t; - -/** - * Creates a new sstr_t based on a C string. - * - * The length is implicitly inferred by using a call to strlen(). - * - * Note: the sstr_t will hold a reference to the C string. If you - * do want a copy, use sstrdup() on the return value of this function. - * - * @param cstring the C string to wrap - * @return a new sstr_t containing the C string - * - * @see sstrn() - */ -sstr_t sstr(char *cstring); - -/** - * Creates a new sstr_t of the specified length based on a C string. - * - * Note: the sstr_t will hold a reference to the C string. If you - * do want a copy, use sstrdup() on the return value of this function. - * - * @param cstring the C string to wrap - * @param length the length of the string - * @return a new sstr_t containing the C string - * - * @see sstr() - * @see S() - */ -sstr_t sstrn(char *cstring, size_t length); - - -/** - * Returns the cumulated length of all specified strings. - * - * At least one string must be specified. - * - * Attention: if the count argument does not match the count of the - * specified strings, the behavior is undefined. - * - * @param count the total number of specified strings (so at least 1) - * @param string the first string - * @param ... all other strings - * @return the cumulated length of all strings - */ -size_t sstrnlen(size_t count, sstr_t string, ...); - -/** - * Concatenates two or more strings. - * - * The resulting string will be allocated by standard malloc(). - * So developers MUST pass the sstr_t.ptr to free(). - * - * The sstr_t.ptr of the return value will always be NULL- - * terminated. - * - * @param count the total number of strings to concatenate - * @param s1 first string - * @param s2 second string - * @param ... all remaining strings - * @return the concatenated string - */ -sstr_t sstrcat(size_t count, sstr_t s1, sstr_t s2, ...); - -/** - * Concatenates two or more strings using an UcxAllocator. - * - * See sstrcat() for details. - * - * @param a the allocator to use - * @param count the total number of strings to concatenate - * @param s1 first string - * @param s2 second string - * @param ... all remaining strings - * @return the concatenated string - */ -sstr_t sstrcat_a(UcxAllocator *a, size_t count, sstr_t s1, sstr_t s2, ...); - - -/** - * Returns a substring starting at the specified location. - * - * Attention: the new string references the same memory area as the - * input string and will NOT be NULL-terminated. - * Use sstrdup() to get a copy. - * - * @param string input string - * @param start start location of the substring - * @return a substring of string starting at start - * - * @see sstrsubsl() - * @see sstrchr() - */ -sstr_t sstrsubs(sstr_t string, size_t start); - -/** - * Returns a substring with a maximum length starting at the specified location. - * - * Attention: the new string references the same memory area as the - * input string and will NOT be NULL-terminated. - * Use sstrdup() to get a copy. - * - * @param string input string - * @param start start location of the substring - * @param length the maximum length of the substring - * @return a substring of string starting at start - * with a maximum length of length - * - * @see sstrsubs() - * @see sstrchr() - */ -sstr_t sstrsubsl(sstr_t string, size_t start, size_t length); - -/** - * Returns a substring starting at the location of the first occurrence of the - * specified character. - * - * If the string does not contain the character, an empty string is returned. - * - * @param string the string where to locate the character - * @param chr the character to locate - * @return a substring starting at the first location of chr - * - * @see sstrsubs() - */ -sstr_t sstrchr(sstr_t string, int chr); - -/** - * Returns a substring starting at the location of the last occurrence of the - * specified character. - * - * If the string does not contain the character, an empty string is returned. - * - * @param string the string where to locate the character - * @param chr the character to locate - * @return a substring starting at the last location of chr - * - * @see sstrsubs() - */ -sstr_t sstrrchr(sstr_t string, int chr); - -/** - * Returns a substring starting at the location of the first occurrence of the - * specified string. - * - * If the string does not contain the other string, an empty string is returned. - * - * If match is an empty string, the complete string is - * returned. - * - * @param string the string to be scanned - * @param match string containing the sequence of characters to match - * @return a substring starting at the first occurrence of - * match, or an empty string, if the sequence is not - * present in string - */ -sstr_t sstrstr(sstr_t string, sstr_t match); - -/** - * Splits a string into parts by using a delimiter string. - * - * This function will return NULL, if one of the following happens: - *
    - *
  • the string length is zero
  • - *
  • the delimeter length is zero
  • - *
  • the string equals the delimeter
  • - *
  • memory allocation fails
  • - *
- * - * The integer referenced by count is used as input and determines - * the maximum size of the resulting array, i.e. the maximum count of splits to - * perform + 1. - * - * The integer referenced by count is also used as output and is - * set to - *
    - *
  • -2, on memory allocation errors
  • - *
  • -1, if either the string or the delimiter is an empty string
  • - *
  • 0, if the string equals the delimiter
  • - *
  • 1, if the string does not contain the delimiter
  • - *
  • the count of array items, otherwise
  • - *
- * - * If the string starts with the delimiter, the first item of the resulting - * array will be an empty string. - * - * If the string ends with the delimiter and the maximum list size is not - * exceeded, the last array item will be an empty string. - * - * Attention: The array pointer AND all sstr_t.ptr of the array - * items must be manually passed to free(). Use sstrsplit_a() with - * an allocator to managed memory, to avoid this. - * - * @param string the string to split - * @param delim the delimiter string - * @param count IN: the maximum size of the resulting array (0 = no limit), - * OUT: the actual size of the array - * @return a sstr_t array containing the split strings or - * NULL on error - * - * @see sstrsplit_a() - */ -sstr_t* sstrsplit(sstr_t string, sstr_t delim, ssize_t *count); - -/** - * Performing sstrsplit() using an UcxAllocator. - * - * Read the description of sstrsplit() for details. - * - * The memory for the sstr_t.ptr pointers of the array items and the memory for - * the sstr_t array itself are allocated by using the UcxAllocator.malloc() - * function. - * - * Note: the allocator is not used for memory that is freed within the - * same call of this function (locally scoped variables). - * - * @param allocator the UcxAllocator used for allocating memory - * @param string the string to split - * @param delim the delimiter string - * @param count IN: the maximum size of the resulting array (0 = no limit), - * OUT: the actual size of the array - * @return a sstr_t array containing the split strings or - * NULL on error - * - * @see sstrsplit() - */ -sstr_t* sstrsplit_a(UcxAllocator *allocator, sstr_t string, sstr_t delim, - ssize_t *count); - -/** - * Compares two UCX strings with standard memcmp(). - * - * At first it compares the sstr_t.length attribute of the two strings. The - * memcmp() function is called, if and only if the lengths match. - * - * @param s1 the first string - * @param s2 the second string - * @return -1, if the length of s1 is less than the length of s2 or 1, if the - * length of s1 is greater than the length of s2 or the result of - * memcmp() otherwise (i.e. 0 if the strings match) - */ -int sstrcmp(sstr_t s1, sstr_t s2); - -/** - * Compares two UCX strings ignoring the case. - * - * At first it compares the sstr_t.length attribute of the two strings. If and - * only if the lengths match, both strings are compared char by char ignoring - * the case. - * - * @param s1 the first string - * @param s2 the second string - * @return -1, if the length of s1 is less than the length of s2 or 1, if the - * length of s1 is greater than the length of s2 or the difference between the - * first two differing characters otherwise (i.e. 0 if the strings match and - * no characters differ) - */ -int sstrcasecmp(sstr_t s1, sstr_t s2); - -/** - * Creates a duplicate of the specified string. - * - * The new sstr_t will contain a copy allocated by standard - * malloc(). So developers MUST pass the sstr_t.ptr to - * free(). - * - * The sstr_t.ptr of the return value will always be NULL- - * terminated. - * - * @param string the string to duplicate - * @return a duplicate of the string - * @see sstrdup_a() - */ -sstr_t sstrdup(sstr_t string); - -/** - * Creates a duplicate of the specified string using an UcxAllocator. - * - * The new sstr_t will contain a copy allocated by the allocators - * ucx_allocator_malloc function. So it is implementation depended, whether the - * returned sstr_t.ptr pointer must be passed to the allocators - * ucx_allocator_free function manually. - * - * The sstr_t.ptr of the return value will always be NULL- - * terminated. - * - * @param allocator a valid instance of an UcxAllocator - * @param string the string to duplicate - * @return a duplicate of the string - * @see sstrdup() - */ -sstr_t sstrdup_a(UcxAllocator *allocator, sstr_t string); - -/** - * Omits leading and trailing spaces. - * - * This function returns a new sstr_t containing a trimmed version of the - * specified string. - * - * Note: the new sstr_t references the same memory, thus you - * MUST NOT pass the sstr_t.ptr of the return value to - * free(). It is also highly recommended to avoid assignments like - * mystr = sstrtrim(mystr); as you lose the reference to the - * source string. Assignments of this type are only permitted, if the - * sstr_t.ptr of the source string does not need to be freed or if another - * reference to the source string exists. - * - * @param string the string that shall be trimmed - * @return a new sstr_t containing the trimmed string - */ -sstr_t sstrtrim(sstr_t string); - -/** - * Checks, if a string has a specific prefix. - * @param string the string to check - * @param prefix the prefix the string should have - * @return 1, if and only if the string has the specified prefix, 0 otherwise - */ -int sstrprefix(sstr_t string, sstr_t prefix); - -/** - * Checks, if a string has a specific suffix. - * @param string the string to check - * @param suffix the suffix the string should have - * @return 1, if and only if the string has the specified suffix, 0 otherwise - */ -int sstrsuffix(sstr_t string, sstr_t suffix); - -/** - * Returns a lower case version of a string. - * - * This function creates a duplicate of the input string, first. See the - * documentation of sstrdup() for the implications. - * - * @param string the input string - * @return the resulting lower case string - * @see sstrdup() - */ -sstr_t sstrlower(sstr_t string); - -/** - * Returns a lower case version of a string. - * - * This function creates a duplicate of the input string, first. See the - * documentation of sstrdup_a() for the implications. - * - * @param allocator the allocator used for duplicating the string - * @param string the input string - * @return the resulting lower case string - * @see sstrdup_a() - */ -sstr_t sstrlower_a(UcxAllocator *allocator, sstr_t string); - -/** - * Returns a upper case version of a string. - * - * This function creates a duplicate of the input string, first. See the - * documentation of sstrdup() for the implications. - * - * @param string the input string - * @return the resulting upper case string - * @see sstrdup() - */ -sstr_t sstrupper(sstr_t string); - -/** - * Returns a upper case version of a string. - * - * This function creates a duplicate of the input string, first. See the - * documentation of sstrdup_a() for the implications. - * - * @param allocator the allocator used for duplicating the string - * @param string the input string - * @return the resulting upper case string - * @see sstrdup_a() - */ -sstr_t sstrupper_a(UcxAllocator *allocator, sstr_t string); - -#ifdef __cplusplus -} -#endif - -#endif /* UCX_STRING_H */ diff -r 9f25df78925e -r 1b12cf799fee src/ucx/ucx.h --- a/src/ucx/ucx.h Thu Nov 10 18:44:48 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,138 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2015 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ -/** - * Main UCX Header providing most common definitions. - * - * @file ucx.h - * @author Mike Becker - * @author Olaf Wintermann - */ - -#ifndef UCX_H -#define UCX_H - -/** Major UCX version as integer constant. */ -#define UCX_VERSION_MAJOR 0 - -/** Minor UCX version as integer constant. */ -#define UCX_VERSION_MINOR 9 - -/** The UCX version in format [major].[minor] */ -#define UCX_VERSION UCX_VERSION_MAJOR.UCX_VERSION_MINOR - -#include - -#ifdef _WIN32 -#if !(defined __ssize_t_defined || defined _SSIZE_T_) -#include -typedef SSIZE_T ssize_t; -#define __ssize_t_defined -#define _SSIZE_T_ -#endif /* __ssize_t_defined and _SSIZE_T */ -#else /* !_WIN32 */ -#include -#endif /* _WIN32 */ - -#ifdef __cplusplus -#ifndef _Bool -#define _Bool bool -#define restrict -#endif -/** Use C naming even when compiling with C++. */ -#define UCX_EXTERN extern "C" -extern "C" { -#else -/** Pointless in C. */ -#define UCX_EXTERN -#endif - - -/** - * A function pointer to a destructor function. - * @see ucx_mempool_setdestr() - * @see ucx_mempool_regdestr() - */ -typedef void(*ucx_destructor)(void*); - -/** - * Function pointer to a compare function. - * - * The compare function shall take three arguments: the two values that shall be - * compared and optional additional data. - * The function shall then return -1 if the first argument is less than the - * second argument, 1 if the first argument is greater than the second argument - * and 0 if both arguments are equal. If the third argument is - * NULL, it shall be ignored. - */ -typedef int(*cmp_func)(void*,void*,void*); - -/** - * Function pointer to a copy function. - * - * The copy function shall create a copy of the first argument and may use - * additional data provided by the second argument. If the second argument is - * NULL, it shall be ignored. - - * Attention: if pointers returned by functions of this type may be - * passed to free() depends on the implementation of the - * respective copy_func. - */ -typedef void*(*copy_func)(void*,void*); - -/** - * Function pointer to a write function. - * - * The signature of the write function shall be compatible to the signature - * of standard fwrite, though it may use arbitrary data types for - * source and destination. - * - * The arguments shall contain (in ascending order): a pointer to the source, - * the length of one element, the element count and a pointer to the - * destination. - */ -typedef size_t(*write_func)(const void*, size_t, size_t, void*); - -/** - * Function pointer to a read function. - * - * The signature of the read function shall be compatible to the signature - * of standard fread, though it may use arbitrary data types for - * source and destination. - * - * The arguments shall contain (in ascending order): a pointer to the - * destination, the length of one element, the element count and a pointer to - * the source. - */ -typedef size_t(*read_func)(void*, size_t, size_t, void*); - -#ifdef __cplusplus -} -#endif - -#endif /* UCX_H */ - diff -r 9f25df78925e -r 1b12cf799fee src/ucx/utils.c --- a/src/ucx/utils.c Thu Nov 10 18:44:48 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,259 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2015 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -#include "utils.h" -#include -#include -#include -#include - -/* COPY FUCNTIONS */ -void* ucx_strcpy(void* s, void* data) { - char *str = (char*) s; - size_t n = 1+strlen(str); - char *cpy = (char*) malloc(n); - memcpy(cpy, str, n); - return cpy; -} - -void* ucx_memcpy(void* m, void* n) { - size_t k = *((size_t*)n); - void *cpy = malloc(k); - memcpy(cpy, m, k); - return cpy; -} - -size_t ucx_stream_copy(void *src, void *dest, read_func readfnc, - write_func writefnc, char* buf, size_t bufsize, size_t n) { - if(n == 0 || bufsize == 0) { - return 0; - } - - char *lbuf; - size_t ncp = 0; - - if(buf) { - lbuf = buf; - } else { - lbuf = (char*)malloc(bufsize); - if(lbuf == NULL) { - return 0; - } - } - - size_t r; - size_t rn = bufsize > n ? n : bufsize; - while((r = readfnc(lbuf, 1, rn, src)) != 0) { - r = writefnc(lbuf, 1, r, dest); - ncp += r; - n -= r; - rn = bufsize > n ? n : bufsize; - if(r == 0 || n == 0) { - break; - } - } - - if (lbuf != buf) { - free(lbuf); - } - - return ncp; -} - -/* COMPARE FUNCTIONS */ - -int ucx_strcmp(void *s1, void *s2, void *data) { - return strcmp((char*)s1, (char*)s2); -} - -int ucx_strncmp(void *s1, void *s2, void *n) { - return strncmp((char*)s1, (char*)s2, *((size_t*) n)); -} - -int ucx_intcmp(void *i1, void *i2, void *data) { - int a = *((int*) i1); - int b = *((int*) i2); - if (a == b) { - return 0; - } else { - return a < b ? -1 : 1; - } -} - -int ucx_floatcmp(void *f1, void *f2, void *epsilon) { - float a = *((float*) f1); - float b = *((float*) f2); - float e = !epsilon ? 1e-6f : *((float*)epsilon); - if (fabsf(a - b) < e) { - return 0; - } else { - return a < b ? -1 : 1; - } -} - -int ucx_doublecmp(void *d1, void *d2, void *epsilon) { - double a = *((float*) d1); - double b = *((float*) d2); - double e = !epsilon ? 1e-14 : *((double*)epsilon); - if (fabs(a - b) < e) { - return 0; - } else { - return a < b ? -1 : 1; - } -} - -int ucx_ptrcmp(void *ptr1, void *ptr2, void *data) { - intptr_t p1 = (intptr_t) ptr1; - intptr_t p2 = (intptr_t) ptr2; - if (p1 == p2) { - return 0; - } else { - return p1 < p2 ? -1 : 1; - } -} - -int ucx_memcmp(void *ptr1, void *ptr2, void *n) { - return memcmp(ptr1, ptr2, *((size_t*)n)); -} - -/* PRINTF FUNCTIONS */ - -#ifdef va_copy -#define UCX_PRINTF_BUFSIZE 256 -#else -#pragma message("WARNING: C99 va_copy macro not supported by this platform" \ - " - limiting ucx_*printf to 2 KiB") -#define UCX_PRINTF_BUFSIZE 0x800 -#endif - -int ucx_fprintf(void *stream, write_func wfc, const char *fmt, ...) { - int ret; - va_list ap; - va_start(ap, fmt); - ret = ucx_vfprintf(stream, wfc, fmt, ap); - va_end(ap); - return ret; -} - -int ucx_vfprintf(void *stream, write_func wfc, const char *fmt, va_list ap) { - char buf[UCX_PRINTF_BUFSIZE]; -#ifdef va_copy - va_list ap2; - va_copy(ap2, ap); - int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap); - if (ret < 0) { - return ret; - } else if (ret < UCX_PRINTF_BUFSIZE) { - return (int)wfc(buf, 1, ret, stream); - } else { - if (ret == INT_MAX) { - errno = ENOMEM; - return -1; - } - - int len = ret + 1; - char *newbuf = (char*)malloc(len); - if (!newbuf) { - return -1; - } - - ret = vsnprintf(newbuf, len, fmt, ap2); - if (ret > 0) { - ret = (int)wfc(newbuf, 1, ret, stream); - } - free(newbuf); - } - return ret; -#else - int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap); - if (ret < 0) { - return ret; - } else if (ret < UCX_PRINTF_BUFSIZE) { - return (int)wfc(buf, 1, ret, stream); - } else { - errno = ENOMEM; - return -1; - } -#endif -} - -sstr_t ucx_asprintf(UcxAllocator *allocator, const char *fmt, ...) { - va_list ap; - sstr_t ret; - va_start(ap, fmt); - ret = ucx_vasprintf(allocator, fmt, ap); - va_end(ap); - return ret; -} - -sstr_t ucx_vasprintf(UcxAllocator *a, const char *fmt, va_list ap) { - sstr_t s; - s.ptr = NULL; - s.length = 0; - char buf[UCX_PRINTF_BUFSIZE]; -#ifdef va_copy - va_list ap2; - va_copy(ap2, ap); - int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap); - if (ret > 0 && ret < UCX_PRINTF_BUFSIZE) { - s.ptr = (char*)almalloc(a, ret + 1); - if (s.ptr) { - s.length = (size_t)ret; - memcpy(s.ptr, buf, ret); - s.ptr[s.length] = '\0'; - } - } else if (ret == INT_MAX) { - errno = ENOMEM; - } else { - int len = ret + 1; - s.ptr = (char*)almalloc(a, len); - if (s.ptr) { - ret = vsnprintf(s.ptr, len, fmt, ap2); - if (ret < 0) { - free(s.ptr); - s.ptr = NULL; - } else { - s.length = (size_t)ret; - } - } - } -#else - int ret = vsnprintf(buf, UCX_PRINTF_BUFSIZE, fmt, ap); - if (ret > 0 && ret < UCX_PRINTF_BUFSIZE) { - s.ptr = (char*)almalloc(a, ret + 1); - if (s.ptr) { - s.length = (size_t)ret; - memcpy(s.ptr, buf, ret); - s.ptr[s.length] = '\0'; - } - } else { - errno = ENOMEM; - } -#endif - return s; -} diff -r 9f25df78925e -r 1b12cf799fee src/ucx/utils.h --- a/src/ucx/utils.h Thu Nov 10 18:44:48 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,254 +0,0 @@ -/* - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. - * - * Copyright 2015 Olaf Wintermann. All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions are met: - * - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" - * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE - * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE - * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR - * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF - * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS - * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN - * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) - * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE - * POSSIBILITY OF SUCH DAMAGE. - */ - -/** - * @file utils.h - * - * Compare, copy and printf functions. - * - * @author Mike Becker - * @author Olaf Wintermann - */ - -#ifndef UCX_UTILS_H -#define UCX_UTILS_H - -#ifdef __cplusplus -extern "C" { -#endif - -#include "ucx.h" -#include "string.h" -#include "allocator.h" -#include -#include -#include - -/** - * Copies a string. - * @param s the string to copy - * @param data omitted - * @return a pointer to a copy of s1 that can be passed to free(void*) - */ -void *ucx_strcpy(void *s, void *data); - -/** - * Copies a memory area. - * @param m a pointer to the memory area - * @param n a pointer to the size_t containing the size of the memory area - * @return a pointer to a copy of the specified memory area that can - * be passed to free(void*) - */ -void *ucx_memcpy(void *m, void *n); - - -/** - * Reads data from a stream and writes it to another stream. - * - * @param src the source stream - * @param dest the destination stream - * @param rfnc the read function - * @param wfnc the write function - * @param buf a pointer to the copy buffer or NULL if a buffer - * shall be implicitly created on the heap - * @param bufsize the size of the copy buffer - if NULL was - * provided for buf, this is the size of the buffer that shall be - * implicitly created - * @param n the maximum number of bytes that shall be copied - * @return the total number of bytes copied - */ -size_t ucx_stream_copy(void *src, void *dest, read_func rfnc, write_func wfnc, - char* buf, size_t bufsize, size_t n); - -/** - * Shorthand for ucx_stream_copy using the default copy buffer. - * - * @param src the source stream - * @param dest the destination stream - * @param rfnc the read function - * @param wfnc the write function - * @return total number of bytes copied - */ -#define ucx_stream_hcopy(src,dest,rfnc,wfnc) ucx_stream_copy(\ - src, dest, (read_func)rfnc, (write_func)wfnc, NULL, 0x100, (size_t)-1) - -/** - * Shorthand for ucx_stream_copy using the default copy buffer and a copy limit. - * - * @param src the source stream - * @param dest the destination stream - * @param rfnc the read function - * @param wfnc the write function - * @param n maximum number of bytes that shall be copied - * @return total number of bytes copied - */ -#define ucx_stream_ncopy(src,dest,rfnc,wfnc, n) ucx_stream_copy(\ - src, dest, (read_func)rfnc, (write_func)wfnc, NULL, 0x100, n) - -/** - * Wraps the strcmp function. - * @param s1 string one - * @param s2 string two - * @param data omitted - * @return the result of strcmp(s1, s2) - */ -int ucx_strcmp(void *s1, void *s2, void *data); - -/** - * Wraps the strncmp function. - * @param s1 string one - * @param s2 string two - * @param n a pointer to the size_t containing the third strncmp parameter - * @return the result of strncmp(s1, s2, *n) - */ -int ucx_strncmp(void *s1, void *s2, void *n); - -/** - * Compares two integers of type int. - * @param i1 pointer to integer one - * @param i2 pointer to integer two - * @param data omitted - * @return -1, if *i1 is less than *i2, 0 if both are equal, - * 1 if *i1 is greater than *i2 - */ -int ucx_intcmp(void *i1, void *i2, void *data); - -/** - * Compares two real numbers of type float. - * @param f1 pointer to float one - * @param f2 pointer to float two - * @param data if provided: a pointer to precision (default: 1e-6f) - * @return -1, if *f1 is less than *f2, 0 if both are equal, - * 1 if *f1 is greater than *f2 - */ - -int ucx_floatcmp(void *f1, void *f2, void *data); - -/** - * Compares two real numbers of type double. - * @param d1 pointer to double one - * @param d2 pointer to double two - * @param data if provided: a pointer to precision (default: 1e-14) - * @return -1, if *d1 is less than *d2, 0 if both are equal, - * 1 if *d1 is greater than *d2 - */ -int ucx_doublecmp(void *d1, void *d2, void *data); - -/** - * Compares two pointers. - * @param ptr1 pointer one - * @param ptr2 pointer two - * @param data omitted - * @return -1 if ptr1 is less than ptr2, 0 if both are equal, - * 1 if ptr1 is greater than ptr2 - */ -int ucx_ptrcmp(void *ptr1, void *ptr2, void *data); - -/** - * Compares two memory areas. - * @param ptr1 pointer one - * @param ptr2 pointer two - * @param n a pointer to the size_t containing the third parameter for memcmp - * @return the result of memcmp(ptr1, ptr2, *n) - */ -int ucx_memcmp(void *ptr1, void *ptr2, void *n); - -/** - * A printf() like function which writes the output to a stream by - * using a write_func(). - * @param stream the stream the data is written to - * @param wfc the write function - * @param fmt format string - * @param ... additional arguments - * @return the total number of bytes written - */ -int ucx_fprintf(void *stream, write_func wfc, const char *fmt, ...); - -/** - * va_list version of ucx_fprintf(). - * @param stream the stream the data is written to - * @param wfc the write function - * @param fmt format string - * @param ap argument list - * @return the total number of bytes written - * @see ucx_fprintf() - */ -int ucx_vfprintf(void *stream, write_func wfc, const char *fmt, va_list ap); - -/** - * A printf() like function which allocates space for a sstr_t - * the result is written to. - * - * Attention: The sstr_t data is allocated with the allocators - * ucx_allocator_malloc() function. So it is implementation dependent, if - * the returned sstr_t.ptr pointer must be passed to the allocators - * ucx_allocator_free() function manually. - * - * Note: The sstr_t.ptr of the return value will always be - * NULL-terminated. - * - * @param allocator the UcxAllocator used for allocating the result sstr_t - * @param fmt format string - * @param ... additional arguments - * @return a sstr_t containing the formatted string - */ -sstr_t ucx_asprintf(UcxAllocator *allocator, const char *fmt, ...); - -/** Shortcut for ucx_asprintf() with default allocator. */ -#define ucx_sprintf(fmt, ...) \ - ucx_asprintf(ucx_default_allocator(), fmt, __VA_ARGS__) - -/** - * va_list version of ucx_asprintf(). - * - * @param allocator the UcxAllocator used for allocating the result sstr_t - * @param fmt format string - * @param ap argument list - * @return a sstr_t containing the formatted string - * @see ucx_asprintf() - */ -sstr_t ucx_vasprintf(UcxAllocator *allocator, const char *fmt, va_list ap); - -/** - * A printf() like function which writes the output to an - * UcxBuffer. - * - * @param buffer the buffer the data is written to - * @param ... format string and additional arguments - * @return the total number of bytes written - * @see ucx_fprintf() - */ -#define ucx_bprintf(buffer, ...) ucx_fprintf((UcxBuffer*)buffer, \ - (write_func)ucx_buffer_write, __VA_ARGS__) - -#ifdef __cplusplus -} -#endif - -#endif /* UCX_UTILS_H */ - diff -r 9f25df78925e -r 1b12cf799fee test/ctestfile.c --- a/test/ctestfile.c Thu Nov 10 18:44:48 2016 +0100 +++ b/test/ctestfile.c Mon Apr 24 20:54:38 2023 +0200 @@ -199,7 +199,7 @@ char* util_path_to_url(DavSession *sn, char *path) { char *space = malloc(256); - UcxBuffer *url = ucx_buffer_new(space, 256, UCX_BUFFER_AUTOEXTEND); + UcxBuffer *url = ucx_buffer_new(space, 256, CX_BUFFER_AUTO_EXTEND); // add base url ucx_buffer_write(sn->base_url, 1, strlen(sn->base_url), url); diff -r 9f25df78925e -r 1b12cf799fee test/gs/bigtest.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gs/bigtest.html Mon Apr 24 20:54:38 2023 +0200 @@ -0,0 +1,865 @@ + + + + c2html + + + + +
+ 1 /* + 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + 3 * + 4 * Copyright 2014 Mike Becker. All rights reserved. + 5 * + 6 * Redistribution and use in source and binary forms, with or without + 7 * modification, are permitted provided that the following conditions are met: + 8 * + 9 * 1. Redistributions of source code must retain the above copyright + 10 * notice, this list of conditions and the following disclaimer. + 11 * + 12 * 2. Redistributions in binary form must reproduce the above copyright + 13 * notice, this list of conditions and the following disclaimer in the + 14 * documentation and/or other materials provided with the distribution. + 15 * + 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + 26 * POSSIBILITY OF SUCH DAMAGE. + 27 * + 28 */ + 29 + 30 #include "rules.h" + 31 #include "chess.h" + 32 #include <string.h> + 33 #include <stdlib.h> + 34 #include <sys/time.h> + 35 + 36 static GameState gamestate_copy_sim(GameState *gamestate) { + 37 GameState simulation = *gamestate; + 38 if (simulation.lastmove) { + 39 MoveList *lastmovecopy = malloc(sizeof(MoveList)); + 40 *lastmovecopy = *(simulation.lastmove); + 41 simulation.movelist = simulation.lastmove = lastmovecopy; + 42 } + 43 + 44 return simulation; + 45 } + 46 + 47 void gamestate_init(GameState *gamestate) { + 48 memset(gamestate, 0, sizeof(GameState)); + 49 + 50 Board initboard = { + 51 {WROOK, WKNIGHT, WBISHOP, WQUEEN, WKING, WBISHOP, WKNIGHT, WROOK}, + 52 {WPAWN, WPAWN, WPAWN, WPAWN, WPAWN, WPAWN, WPAWN, WPAWN}, + 53 {0, 0, 0, 0, 0, 0, 0, 0}, + 54 {0, 0, 0, 0, 0, 0, 0, 0}, + 55 {0, 0, 0, 0, 0, 0, 0, 0}, + 56 {0, 0, 0, 0, 0, 0, 0, 0}, + 57 {BPAWN, BPAWN, BPAWN, BPAWN, BPAWN, BPAWN, BPAWN, BPAWN}, + 58 {BROOK, BKNIGHT, BBISHOP, BQUEEN, BKING, BBISHOP, BKNIGHT, BROOK} + 59 }; + 60 memcpy(gamestate->board, initboard, sizeof(Board)); + 61 } + 62 + 63 void gamestate_cleanup(GameState *gamestate) { + 64 MoveList *elem; + 65 elem = gamestate->movelist; + 66 while (elem) { + 67 MoveList *cur = elem; + 68 elem = elem->next; + 69 free(cur); + 70 }; + 71 } + 72 + 73 /* MUST be called IMMEDIATLY after applying a move to work correctly */ + 74 static void format_move(GameState *gamestate, Move *move) { + 75 char *string = move->string; + 76 + 77 /* at least 8 characters should be available, wipe them out */ + 78 memset(string, 0, 8); + 79 + 80 /* special formats for castling */ + 81 if ((move->piece&PIECE_MASK) == KING && + 82 abs(move->tofile-move->fromfile) == 2) { + 83 if (move->tofile==fileidx('c')) { + 84 memcpy(string, "O-O-O", 5); + 85 } else { + 86 memcpy(string, "O-O", 3); + 87 } + 88 } + 89 + 90 /* start by notating the piece character */ + 91 string[0] = getpiecechr(move->piece); + 92 int idx = string[0] ? 1 : 0; + 93 + 94 /* find out how many source information we do need */ + 95 uint8_t piece = move->piece & PIECE_MASK; + 96 if (piece == PAWN) { + 97 if (move->capture) { + 98 string[idx++] = filechr(move->fromfile); + 99 } +100 } else if (piece != KING) { +101 Move threats[16]; +102 uint8_t threatcount; +103 get_real_threats(gamestate, move->torow, move->tofile, +104 move->piece&COLOR_MASK, threats, &threatcount); +105 if (threatcount > 1) { +106 int ambrows = 0, ambfiles = 0; +107 for (uint8_t i = 0 ; i < threatcount ; i++) { +108 if (threats[i].fromrow == move->fromrow) { +109 ambrows++; +110 } +111 if (threats[i].fromfile == move->fromfile) { +112 ambfiles++; +113 } +114 } +115 /* ambiguous row, name file */ +116 if (ambrows > 1) { +117 string[idx++] = filechr(move->fromfile); +118 } +119 /* ambiguous file, name row */ +120 if (ambfiles > 1) { +121 string[idx++] = filechr(move->fromrow); +122 } +123 } +124 } +125 +126 /* capturing? */ +127 if (move->capture) { +128 string[idx++] = 'x'; +129 } +130 +131 /* destination */ +132 string[idx++] = filechr(move->tofile); +133 string[idx++] = rowchr(move->torow); +134 +135 /* promotion? */ +136 if (move->promotion) { +137 string[idx++] = '='; +138 string[idx++] = getpiecechr(move->promotion); +139 } +140 +141 /* check? */ +142 if (move->check) { +143 /* works only, if this function is called when applying the move */ +144 string[idx++] = gamestate->checkmate?'#':'+'; +145 } +146 } +147 +148 static void addmove(GameState* gamestate, Move *move) { +149 MoveList *elem = malloc(sizeof(MoveList)); +150 elem->next = NULL; +151 elem->move = *move; +152 +153 struct timeval curtimestamp; +154 gettimeofday(&curtimestamp, NULL); +155 elem->move.timestamp.tv_sec = curtimestamp.tv_sec; +156 elem->move.timestamp.tv_usec = curtimestamp.tv_usec; +157 +158 if (gamestate->lastmove) { +159 struct movetimeval *lasttstamp = &(gamestate->lastmove->move.timestamp); +160 uint64_t sec = curtimestamp.tv_sec - lasttstamp->tv_sec; +161 suseconds_t micros; +162 if (curtimestamp.tv_usec < lasttstamp->tv_usec) { +163 micros = 1e6L-(lasttstamp->tv_usec - curtimestamp.tv_usec); +164 sec--; +165 } else { +166 micros = curtimestamp.tv_usec - lasttstamp->tv_usec; +167 } +168 +169 elem->move.movetime.tv_sec = sec; +170 elem->move.movetime.tv_usec = micros; +171 +172 gamestate->lastmove->next = elem; +173 gamestate->lastmove = elem; +174 } else { +175 elem->move.movetime.tv_usec = 0; +176 elem->move.movetime.tv_sec = 0; +177 gamestate->movelist = gamestate->lastmove = elem; +178 } +179 } +180 +181 char getpiecechr(uint8_t piece) { +182 switch (piece & PIECE_MASK) { +183 case ROOK: return 'R'; +184 case KNIGHT: return 'N'; +185 case BISHOP: return 'B'; +186 case QUEEN: return 'Q'; +187 case KING: return 'K'; +188 default: return '\0'; +189 } +190 } +191 +192 uint8_t getpiece(char c) { +193 switch (c) { +194 case 'R': return ROOK; +195 case 'N': return KNIGHT; +196 case 'B': return BISHOP; +197 case 'Q': return QUEEN; +198 case 'K': return KING; +199 default: return 0; +200 } +201 } +202 +203 static void apply_move_impl(GameState *gamestate, Move *move, _Bool simulate) { +204 uint8_t piece = move->piece & PIECE_MASK; +205 uint8_t color = move->piece & COLOR_MASK; +206 +207 /* en passant capture */ +208 if (move->capture && piece == PAWN && +209 mdst(gamestate->board, move) == 0) { +210 gamestate->board[move->fromrow][move->tofile] = 0; +211 } +212 +213 /* remove old en passant threats */ +214 for (uint8_t file = 0 ; file < 8 ; file++) { +215 gamestate->board[3][file] &= ~ENPASSANT_THREAT; +216 gamestate->board[4][file] &= ~ENPASSANT_THREAT; +217 } +218 +219 /* add new en passant threat */ +220 if (piece == PAWN && ( +221 (move->fromrow == 1 && move->torow == 3) || +222 (move->fromrow == 6 && move->torow == 4))) { +223 move->piece |= ENPASSANT_THREAT; +224 } +225 +226 /* move (and maybe capture or promote) */ +227 msrc(gamestate->board, move) = 0; +228 if (move->promotion) { +229 mdst(gamestate->board, move) = move->promotion; +230 } else { +231 mdst(gamestate->board, move) = move->piece; +232 } +233 +234 /* castling */ +235 if (piece == KING && move->fromfile == fileidx('e')) { +236 +237 if (move->tofile == fileidx('g')) { +238 gamestate->board[move->torow][fileidx('h')] = 0; +239 gamestate->board[move->torow][fileidx('f')] = color|ROOK; +240 } else if (move->tofile == fileidx('c')) { +241 gamestate->board[move->torow][fileidx('a')] = 0; +242 gamestate->board[move->torow][fileidx('d')] = color|ROOK; +243 } +244 } +245 +246 if (!simulate) { +247 if (!move->string[0]) { +248 format_move(gamestate, move); +249 } +250 } +251 /* add move, even in simulation (checkmate test needs it) */ +252 addmove(gamestate, move); +253 } +254 +255 void apply_move(GameState *gamestate, Move *move) { +256 apply_move_impl(gamestate, move, 0); +257 } +258 +259 static int validate_move_rules(GameState *gamestate, Move *move) { +260 /* validate indices (don't trust opponent) */ +261 if (!chkidx(move)) { +262 return INVALID_POSITION; +263 } +264 +265 /* must move */ +266 if (move->fromfile == move->tofile && move->fromrow == move->torow) { +267 return INVALID_MOVE_SYNTAX; +268 } +269 +270 /* does piece exist */ +271 if ((msrc(gamestate->board, move)&(PIECE_MASK|COLOR_MASK)) +272 != (move->piece&(PIECE_MASK|COLOR_MASK))) { +273 return INVALID_POSITION; +274 } +275 +276 /* can't capture own pieces */ +277 if ((mdst(gamestate->board, move) & COLOR_MASK) +278 == (move->piece & COLOR_MASK)) { +279 return RULES_VIOLATED; +280 } +281 +282 /* must capture, if and only if destination is occupied */ +283 if ((mdst(gamestate->board, move) == 0 && move->capture) || +284 (mdst(gamestate->board, move) != 0 && !move->capture)) { +285 return INVALID_MOVE_SYNTAX; +286 } +287 +288 /* validate individual rules */ +289 _Bool chkrules; +290 switch (move->piece & PIECE_MASK) { +291 case PAWN: +292 chkrules = pawn_chkrules(gamestate, move) && +293 !pawn_isblocked(gamestate, move); +294 break; +295 case ROOK: +296 chkrules = rook_chkrules(move) && +297 !rook_isblocked(gamestate, move); +298 break; +299 case KNIGHT: +300 chkrules = knight_chkrules(move); /* knight is never blocked */ +301 break; +302 case BISHOP: +303 chkrules = bishop_chkrules(move) && +304 !bishop_isblocked(gamestate, move); +305 break; +306 case QUEEN: +307 chkrules = queen_chkrules(move) && +308 !queen_isblocked(gamestate, move); +309 break; +310 case KING: +311 chkrules = king_chkrules(gamestate, move) && +312 !king_isblocked(gamestate, move); +313 break; +314 default: +315 return INVALID_MOVE_SYNTAX; +316 } +317 +318 return chkrules ? VALID_MOVE_SEMANTICS : RULES_VIOLATED; +319 } +320 +321 int validate_move(GameState *gamestate, Move *move) { +322 +323 int result = validate_move_rules(gamestate, move); +324 +325 /* cancel processing to save resources */ +326 if (result != VALID_MOVE_SEMANTICS) { +327 return result; +328 } +329 +330 /* find kings for check validation */ +331 uint8_t piececolor = (move->piece & COLOR_MASK); +332 +333 uint8_t mykingfile = 0, mykingrow = 0, opkingfile = 0, opkingrow = 0; +334 for (uint8_t row = 0 ; row < 8 ; row++) { +335 for (uint8_t file = 0 ; file < 8 ; file++) { +336 if (gamestate->board[row][file] == +337 (piececolor == WHITE?WKING:BKING)) { +338 mykingfile = file; +339 mykingrow = row; +340 } else if (gamestate->board[row][file] == +341 (piececolor == WHITE?BKING:WKING)) { +342 opkingfile = file; +343 opkingrow = row; +344 } +345 } +346 } +347 +348 /* simulate move for check validation */ +349 GameState simulation = gamestate_copy_sim(gamestate); +350 Move simmove = *move; +351 apply_move_impl(&simulation, &simmove, 1); +352 +353 /* don't move into or stay in check position */ +354 if (is_covered(&simulation, mykingrow, mykingfile, +355 opponent_color(piececolor))) { +356 +357 gamestate_cleanup(&simulation); +358 if ((move->piece & PIECE_MASK) == KING) { +359 return KING_MOVES_INTO_CHECK; +360 } else { +361 /* last move is always not null in this case */ +362 return gamestate->lastmove->move.check ? +363 KING_IN_CHECK : PIECE_PINNED; +364 } +365 } +366 +367 /* correct check and checkmate flags (move is still valid) */ +368 Move threats[16]; +369 uint8_t threatcount; +370 move->check = get_threats(&simulation, opkingrow, opkingfile, +371 piececolor, threats, &threatcount); +372 +373 if (move->check) { +374 /* determine possible escape fields */ +375 _Bool canescape = 0; +376 for (int dr = -1 ; dr <= 1 && !canescape ; dr++) { +377 for (int df = -1 ; df <= 1 && !canescape ; df++) { +378 if (!(dr == 0 && df == 0) && +379 isidx(opkingrow + dr) && isidx(opkingfile + df)) { +380 +381 /* escape field neither blocked nor covered */ +382 if ((simulation.board[opkingrow + dr][opkingfile + df] +383 & COLOR_MASK) != opponent_color(piececolor)) { +384 canescape |= !is_covered(&simulation, +385 opkingrow + dr, opkingfile + df, piececolor); +386 } +387 } +388 } +389 } +390 /* can't escape, can he capture? */ +391 if (!canescape && threatcount == 1) { +392 canescape = is_attacked(&simulation, threats[0].fromrow, +393 threats[0].fromfile, opponent_color(piececolor)); +394 } +395 +396 /* can't capture, can he block? */ +397 if (!canescape && threatcount == 1) { +398 Move *threat = &(threats[0]); +399 uint8_t threatpiece = threat->piece & PIECE_MASK; +400 +401 /* knight, pawns and the king cannot be blocked */ +402 if (threatpiece == BISHOP || threatpiece == ROOK +403 || threatpiece == QUEEN) { +404 if (threat->fromrow == threat->torow) { +405 /* rook aspect (on row) */ +406 int d = threat->tofile > threat->fromfile ? 1 : -1; +407 uint8_t file = threat->fromfile; +408 while (!canescape && file != threat->tofile - d) { +409 file += d; +410 canescape |= is_protected(&simulation, +411 threat->torow, file, opponent_color(piececolor)); +412 } +413 } else if (threat->fromfile == threat->tofile) { +414 /* rook aspect (on file) */ +415 int d = threat->torow > threat->fromrow ? 1 : -1; +416 uint8_t row = threat->fromrow; +417 while (!canescape && row != threat->torow - d) { +418 row += d; +419 canescape |= is_protected(&simulation, +420 row, threat->tofile, opponent_color(piececolor)); +421 } +422 } else { +423 /* bishop aspect */ +424 int dr = threat->torow > threat->fromrow ? 1 : -1; +425 int df = threat->tofile > threat->fromfile ? 1 : -1; +426 +427 uint8_t row = threat->fromrow; +428 uint8_t file = threat->fromfile; +429 while (!canescape && file != threat->tofile - df +430 && row != threat->torow - dr) { +431 row += dr; +432 file += df; +433 canescape |= is_protected(&simulation, row, file, +434 opponent_color(piececolor)); +435 } +436 } +437 } +438 } +439 +440 if (!canescape) { +441 gamestate->checkmate = 1; +442 } +443 } +444 +445 gamestate_cleanup(&simulation); +446 +447 return VALID_MOVE_SEMANTICS; +448 } +449 +450 _Bool get_threats(GameState *gamestate, uint8_t row, uint8_t file, +451 uint8_t color, Move *threats, uint8_t *threatcount) { +452 Move candidates[32]; +453 int candidatecount = 0; +454 for (uint8_t r = 0 ; r < 8 ; r++) { +455 for (uint8_t f = 0 ; f < 8 ; f++) { +456 if ((gamestate->board[r][f] & COLOR_MASK) == color) { +457 // non-capturing move +458 memset(&(candidates[candidatecount]), 0, sizeof(Move)); +459 candidates[candidatecount].piece = gamestate->board[r][f]; +460 candidates[candidatecount].fromrow = r; +461 candidates[candidatecount].fromfile = f; +462 candidates[candidatecount].torow = row; +463 candidates[candidatecount].tofile = file; +464 candidatecount++; +465 +466 // capturing move +467 memcpy(&(candidates[candidatecount]), +468 &(candidates[candidatecount-1]), sizeof(Move)); +469 candidates[candidatecount].capture = 1; +470 candidatecount++; +471 } +472 } +473 } +474 +475 if (threatcount) { +476 *threatcount = 0; +477 } +478 +479 +480 _Bool result = 0; +481 +482 for (int i = 0 ; i < candidatecount ; i++) { +483 if (validate_move_rules(gamestate, &(candidates[i])) +484 == VALID_MOVE_SEMANTICS) { +485 result = 1; +486 if (threats && threatcount) { +487 threats[(*threatcount)++] = candidates[i]; +488 } +489 } +490 } +491 +492 return result; +493 } +494 +495 _Bool is_pinned(GameState *gamestate, Move *move) { +496 uint8_t color = move->piece & COLOR_MASK; +497 +498 uint8_t kingfile = 0, kingrow = 0; +499 for (uint8_t row = 0 ; row < 8 ; row++) { +500 for (uint8_t file = 0 ; file < 8 ; file++) { +501 if (gamestate->board[row][file] == (color|KING)) { +502 kingfile = file; +503 kingrow = row; +504 } +505 } +506 } +507 +508 GameState simulation = gamestate_copy_sim(gamestate); +509 Move simmove = *move; +510 apply_move(&simulation, &simmove); +511 _Bool covered = is_covered(&simulation, +512 kingrow, kingfile, opponent_color(color)); +513 gamestate_cleanup(&simulation); +514 +515 return covered; +516 } +517 +518 _Bool get_real_threats(GameState *gamestate, uint8_t row, uint8_t file, +519 uint8_t color, Move *threats, uint8_t *threatcount) { +520 +521 if (threatcount) { +522 *threatcount = 0; +523 } +524 +525 Move candidates[16]; +526 uint8_t candidatecount; +527 if (get_threats(gamestate, row, file, color, candidates, &candidatecount)) { +528 +529 _Bool result = 0; +530 uint8_t kingfile = 0, kingrow = 0; +531 for (uint8_t row = 0 ; row < 8 ; row++) { +532 for (uint8_t file = 0 ; file < 8 ; file++) { +533 if (gamestate->board[row][file] == (color|KING)) { +534 kingfile = file; +535 kingrow = row; +536 } +537 } +538 } +539 +540 for (uint8_t i = 0 ; i < candidatecount ; i++) { +541 GameState simulation = gamestate_copy_sim(gamestate); +542 Move simmove = candidates[i]; +543 apply_move(&simulation, &simmove); +544 if (!is_covered(&simulation, kingrow, kingfile, +545 opponent_color(color))) { +546 result = 1; +547 if (threats && threatcount) { +548 threats[(*threatcount)++] = candidates[i]; +549 } +550 } +551 } +552 +553 return result; +554 } else { +555 return 0; +556 } +557 } +558 +559 static int getlocation(GameState *gamestate, Move *move) { +560 +561 uint8_t color = move->piece & COLOR_MASK; +562 _Bool incheck = gamestate->lastmove?gamestate->lastmove->move.check:0; +563 +564 Move threats[16], *threat = NULL; +565 uint8_t threatcount; +566 +567 if (get_threats(gamestate, move->torow, move->tofile, color, +568 threats, &threatcount)) { +569 +570 int reason = INVALID_POSITION; +571 +572 // find threats for the specified position +573 for (uint8_t i = 0 ; i < threatcount ; i++) { +574 if ((threats[i].piece & (PIECE_MASK | COLOR_MASK)) +575 == move->piece && +576 (move->fromrow == POS_UNSPECIFIED || +577 move->fromrow == threats[i].fromrow) && +578 (move->fromfile == POS_UNSPECIFIED || +579 move->fromfile == threats[i].fromfile)) { +580 +581 if (threat) { +582 return AMBIGUOUS_MOVE; +583 } else { +584 // found threat is no real threat +585 if (is_pinned(gamestate, &(threats[i]))) { +586 reason = incheck?KING_IN_CHECK:PIECE_PINNED; +587 } else { +588 threat = &(threats[i]); +589 } +590 } +591 } +592 } +593 +594 // can't threaten specified position +595 if (!threat) { +596 return reason; +597 } +598 +599 memcpy(move, threat, sizeof(Move)); +600 return VALID_MOVE_SYNTAX; +601 } else { +602 return INVALID_POSITION; +603 } +604 } +605 +606 int eval_move(GameState *gamestate, char *mstr, Move *move, uint8_t color) { +607 memset(move, 0, sizeof(Move)); +608 move->fromfile = POS_UNSPECIFIED; +609 move->fromrow = POS_UNSPECIFIED; +610 +611 size_t len = strlen(mstr); +612 if (len < 1 || len > 6) { +613 return INVALID_MOVE_SYNTAX; +614 } +615 +616 /* evaluate check/checkmate flags */ +617 if (mstr[len-1] == '+') { +618 len--; mstr[len] = '\0'; +619 move->check = 1; +620 } else if (mstr[len-1] == '#') { +621 len--; mstr[len] = '\0'; +622 /* ignore - validation should set game state */ +623 } +624 +625 /* evaluate promotion */ +626 if (len > 3 && mstr[len-2] == '=') { +627 move->promotion = getpiece(mstr[len-1]); +628 if (!move->promotion) { +629 return INVALID_MOVE_SYNTAX; +630 } else { +631 move->promotion |= color; +632 len -= 2; +633 mstr[len] = 0; +634 } +635 } +636 +637 if (len == 2) { +638 /* pawn move (e.g. "e4") */ +639 move->piece = PAWN; +640 move->tofile = fileidx(mstr[0]); +641 move->torow = rowidx(mstr[1]); +642 } else if (len == 3) { +643 if (strcmp(mstr, "O-O") == 0) { +644 /* king side castling */ +645 move->piece = KING; +646 move->fromfile = fileidx('e'); +647 move->tofile = fileidx('g'); +648 move->fromrow = move->torow = color == WHITE ? 0 : 7; +649 } else { +650 /* move (e.g. "Nf3") */ +651 move->piece = getpiece(mstr[0]); +652 move->tofile = fileidx(mstr[1]); +653 move->torow = rowidx(mstr[2]); +654 } +655 } else if (len == 4) { +656 move->piece = getpiece(mstr[0]); +657 if (!move->piece) { +658 move->piece = PAWN; +659 move->fromfile = fileidx(mstr[0]); +660 } +661 if (mstr[1] == 'x') { +662 /* capture (e.g. "Nxf3", "dxe5") */ +663 move->capture = 1; +664 } else { +665 /* move (e.g. "Ndf3", "N2c3", "e2e4") */ +666 if (isfile(mstr[1])) { +667 move->fromfile = fileidx(mstr[1]); +668 if (move->piece == PAWN) { +669 move->piece = 0; +670 } +671 } else { +672 move->fromrow = rowidx(mstr[1]); +673 } +674 } +675 move->tofile = fileidx(mstr[2]); +676 move->torow = rowidx(mstr[3]); +677 } else if (len == 5) { +678 if (strcmp(mstr, "O-O-O") == 0) { +679 /* queen side castling "O-O-O" */ +680 move->piece = KING; +681 move->fromfile = fileidx('e'); +682 move->tofile = fileidx('c'); +683 move->fromrow = move->torow = color == WHITE ? 0 : 7; +684 } else { +685 move->piece = getpiece(mstr[0]); +686 if (mstr[2] == 'x') { +687 move->capture = 1; +688 if (move->piece) { +689 /* capture (e.g. "Ndxf3") */ +690 move->fromfile = fileidx(mstr[1]); +691 } else { +692 /* long notation capture (e.g. "e5xf6") */ +693 move->piece = PAWN; +694 move->fromfile = fileidx(mstr[0]); +695 move->fromrow = rowidx(mstr[1]); +696 } +697 } else { +698 /* long notation move (e.g. "Nc5a4") */ +699 move->fromfile = fileidx(mstr[1]); +700 move->fromrow = rowidx(mstr[2]); +701 } +702 move->tofile = fileidx(mstr[3]); +703 move->torow = rowidx(mstr[4]); +704 } +705 } else if (len == 6) { +706 /* long notation capture (e.g. "Nc5xf3") */ +707 if (mstr[3] == 'x') { +708 move->capture = 1; +709 move->piece = getpiece(mstr[0]); +710 move->fromfile = fileidx(mstr[1]); +711 move->fromrow = rowidx(mstr[2]); +712 move->tofile = fileidx(mstr[4]); +713 move->torow = rowidx(mstr[5]); +714 } +715 } +716 +717 +718 if (move->piece) { +719 if (move->piece == PAWN +720 && move->torow == (color==WHITE?7:0) +721 && !move->promotion) { +722 return NEED_PROMOTION; +723 } +724 +725 move->piece |= color; +726 if (move->fromfile == POS_UNSPECIFIED +727 || move->fromrow == POS_UNSPECIFIED) { +728 return getlocation(gamestate, move); +729 } else { +730 return chkidx(move) ? VALID_MOVE_SYNTAX : INVALID_POSITION; +731 } +732 } else { +733 return INVALID_MOVE_SYNTAX; +734 } +735 } +736 +737 _Bool is_protected(GameState *gamestate, uint8_t row, uint8_t file, +738 uint8_t color) { +739 +740 Move threats[16]; +741 uint8_t threatcount; +742 if (get_real_threats(gamestate, row, file, color, threats, &threatcount)) { +743 for (int i = 0 ; i < threatcount ; i++) { +744 if (threats[i].piece != (color|KING)) { +745 return 1; +746 } +747 } +748 return 0; +749 } else { +750 return 0; +751 } +752 } +753 +754 uint16_t remaining_movetime(GameInfo *gameinfo, GameState *gamestate, +755 uint8_t color) { +756 if (!gameinfo->timecontrol) { +757 return 0; +758 } +759 +760 if (gamestate->movelist) { +761 uint16_t time = gameinfo->time; +762 suseconds_t micros = 0; +763 +764 MoveList *movelist = color == WHITE ? +765 gamestate->movelist : gamestate->movelist->next; +766 +767 while (movelist) { +768 time += gameinfo->addtime; +769 +770 struct movetimeval *movetime = &(movelist->move.movetime); +771 if (movetime->tv_sec >= time) { +772 return 0; +773 } +774 +775 time -= movetime->tv_sec; +776 micros += movetime->tv_usec; +777 +778 movelist = movelist->next ? movelist->next->next : NULL; +779 } +780 +781 time_t sec; +782 movelist = gamestate->lastmove; +783 if ((movelist->move.piece & COLOR_MASK) != color) { +784 struct movetimeval *lastmovetstamp = &(movelist->move.timestamp); +785 struct timeval currenttstamp; +786 gettimeofday(¤ttstamp, NULL); +787 micros += currenttstamp.tv_usec - lastmovetstamp->tv_usec; +788 sec = currenttstamp.tv_sec - lastmovetstamp->tv_sec; +789 if (sec >= time) { +790 return 0; +791 } +792 +793 time -= sec; +794 } +795 +796 sec = micros / 1e6L; +797 +798 if (sec >= time) { +799 return 0; +800 } +801 +802 time -= sec; +803 +804 return time; +805 } else { +806 return gameinfo->time; +807 } +808 } +
+ + + diff -r 9f25df78925e -r 1b12cf799fee test/gs/ctest.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gs/ctest.html Mon Apr 24 20:54:38 2023 +0200 @@ -0,0 +1,448 @@ + + + + c2html + + + + +
+ 1 /* + 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + 3 * + 4 * Copyright 2015 Olaf Wintermann. All rights reserved. + 5 * + 6 * Redistribution and use in source and binary forms, with or without + 7 * modification, are permitted provided that the following conditions are met: + 8 * + 9 * 1. Redistributions of source code must retain the above copyright + 10 * notice, this list of conditions and the following disclaimer. + 11 * + 12 * 2. Redistributions in binary form must reproduce the above copyright + 13 * notice, this list of conditions and the following disclaimer in the + 14 * documentation and/or other materials provided with the distribution. + 15 * + 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + 26 * POSSIBILITY OF SUCH DAMAGE. + 27 */ + 28 + 29 #include <time.h> + 30 #include <stdio.h> + 31 #include <stdlib.h> + 32 #include <string.h> + 33 #include <ucx/string.h> + 34 #include <ucx/buffer.h> + 35 #include <ucx/utils.h> + 36 #include <libxml/tree.h> + 37 #include <curl/curl.h> + 38 + 39 #include <openssl/sha.h> + 40 #include <openssl/hmac.h> + 41 #include <openssl/evp.h> + 42 #include <openssl/bio.h> + 43 #include <openssl/buffer.h> + 44 #include <openssl/rand.h> + 45 + 46 #include "utils.h" + 47 #include "crypto.h" + 48 #include "webdav.h" + 49 + 50 #define MACRO1337 1337L + 51 + 52 /* -------------------- This is a testing file. -------------------------- */ + 53 /* + 54 time_t util_parse_creationdate(char *str) { + 55 // example: 2012-11-29T21:35:35Z + 56 if(!str) { + 57 return 0; + 58 } + 59 // TODO + 60 return 0; + 61 } + 62 */ + 63 time_t util_parse_lastmodified(char *str) { + 64 // example: Thu, 29 Nov 2012 21:35:35 GMT + 65 if(!str) { + 66 return 0; + 67 } else { + 68 return curl_getdate(str, NULL); + 69 } + 70 } + 71 + 72 int util_getboolean(char *v) { + 73 if(v[0] == 'T' || v[0] == 't') { + 74 return 1; + 75 } + 76 return 0; + 77 } + 78 + 79 int util_strtoint(char *str, int64_t *value) { + 80 char *end; + 81 int64_t val = strtoll(str, &end, 0); + 82 if(strlen(end) == 0) { + 83 *value = val; + 84 return 1; + 85 } else { + 86 return 0; + 87 } + 88 } + 89 + 90 char* util_url_path(char *url) { + 91 char *path = NULL; + 92 size_t len = strlen(url); + 93 int slashcount = 0; + 94 int slmax; + 95 if(len > 7 && !strncasecmp(url, "http://", 7)) { + 96 slmax = 3; + 97 } else if(len > 8 && !strncasecmp(url, "https://", 8)) { + 98 slmax = 3; + 99 } else { +100 slmax = 1; +101 } +102 char c; +103 for(int i=0;i<len;i++) { +104 c = url[i]; +105 if(c == '/') { +106 slashcount++; +107 if(slashcount == slmax) { +108 path = url + i; +109 break; +110 } +111 } +112 } +113 return path; +114 } +115 +116 char* util_url_decode(DavSession *sn, char *url) { +117 char *unesc = curl_easy_unescape(sn->handle, url, strlen(url), NULL); +118 char *ret = strdup(unesc); +119 curl_free(unesc); +120 return ret; +121 } +122 +123 char* util_resource_name(char *url) { +124 int si = 0; +125 int osi = 0; +126 int i = 0; +127 int p = 0; +128 char c; +129 while((c = url[i]) != 0) { +130 if(c == '/') { +131 osi = si; +132 si = i; +133 p = 1; +134 } +135 i++; +136 } +137 +138 char *name = url + si + p; +139 if(name[0] == 0) { +140 name = url + osi + p; +141 if(name[0] == 0) { +142 return url; +143 } +144 } +145 +146 return name; +147 } +148 +149 int util_mkdir(char *path, mode_t mode) { +150 #ifdef _WIN32 +151 return mkdir(path); +152 #else +153 return mkdir(path, mode); +154 #endif +155 } +156 +157 char* util_concat_path(char *url_base, char *p) { +158 sstr_t base = sstr(url_base); +159 sstr_t path; +160 if(p) { +161 path = sstr(p); +162 } else { +163 path = sstrn("", 0); +164 } +165 +166 int add_separator = 0; +167 if(base.ptr[base.length-1] == '/') { +168 if(path.ptr[0] == '/') { +169 base.length--; +170 } +171 } else { +172 if(path.length == 0 || path.ptr[0] != '/') { +173 add_separator = 1; +174 } +175 } +176 +177 sstr_t url; +178 if(add_separator) { +179 url = sstrcat(3, base, sstr("/"), path); +180 } else { +181 url = sstrcat(2, base, path); +182 } +183 +184 return url.ptr; +185 } +186 +187 void util_set_url(DavSession *sn, char *href) { +188 sstr_t base = sstr(sn->base_url); +189 sstr_t href_str = sstr(href); +190 +191 char *base_path = util_url_path(sn->base_url); +192 base.length -= strlen(base_path); +193 +194 sstr_t url = sstrcat(2, base, href_str); +195 +196 curl_easy_setopt(sn->handle, CURLOPT_URL, url.ptr); +197 free(url.ptr); +198 } +199 +200 char* util_path_to_url(DavSession *sn, char *path) { +201 char *space = malloc(256); +202 UcxBuffer *url = ucx_buffer_new(space, 256, CX_BUFFER_AUTO_EXTEND); +203 +204 // add base url +205 ucx_buffer_write(sn->base_url, 1, strlen(sn->base_url), url); +206 // remove trailing slash +207 ucx_buffer_seek(url, -1, SEEK_CUR); +208 +209 sstr_t p = sstr(path); +210 ssize_t ntk = 0; +211 sstr_t *tks = sstrsplit(p, S("/"), &ntk); +212 +213 for(int i=0;i<ntk;i++) { +214 sstr_t node = tks[i]; +215 if(node.length > 0) { +216 char *esc = curl_easy_escape(sn->handle, node.ptr, node.length); +217 ucx_buffer_putc(url, '/'); +218 ucx_buffer_write(esc, 1, strlen(esc), url); +219 curl_free(esc); +220 } +221 free(node.ptr); +222 } +223 free(tks); +224 if(path[p.length-1] == '/') { +225 ucx_buffer_putc(url, '/'); +226 } +227 ucx_buffer_putc(url, 0); +228 +229 space = url->space; +230 ucx_buffer_free(url); +231 +232 return space; +233 } +234 +235 char* util_parent_path(char *path) { +236 char *name = util_resource_name(path); +237 size_t namelen = strlen(name); +238 size_t pathlen = strlen(path); +239 size_t parentlen = pathlen - namelen; +240 char *parent = malloc(parentlen + 1); +241 memcpy(parent, path, parentlen); +242 parent[parentlen] = '\0'; +243 return parent; +244 } +245 +246 +247 char* util_xml_get_text(xmlNode *elm) { +248 xmlNode *node = elm->children; +249 while(node) { +250 if(node->type == XML_TEXT_NODE) { +251 return (char*)node->content; +252 } +253 node = node->next; +254 } +255 return NULL; +256 } +257 +258 +259 char* util_base64decode(char *in) { +260 int len = 0; +261 return util_base64decode_len(in, &len); +262 } +263 +264 char* util_base64decode_len(char* in, int *outlen) { +265 size_t len = strlen(in); +266 char *out = calloc(1, len); +267 +268 BIO* b = BIO_new_mem_buf(in, len); +269 BIO *d = BIO_new(BIO_f_base64()); +270 BIO_set_flags(d, BIO_FLAGS_BASE64_NO_NL); +271 b = BIO_push(d, b); +272 +273 *outlen = BIO_read(b, out, len); +274 BIO_free_all(b); +275 +276 return out; +277 } +278 +279 char* util_base64encode(char *in, size_t len) { +280 BIO *b; +281 BIO *e; +282 BUF_MEM *mem; +283 +284 e = BIO_new(BIO_f_base64()); +285 b = BIO_new(BIO_s_mem()); +286 +287 e = BIO_push(e, b); +288 BIO_write(e, in, len); +289 BIO_flush(e); +290 +291 BIO_get_mem_ptr(e, &mem); +292 char *out = malloc(mem->length); +293 memcpy(out, mem->data, mem->length -1); +294 out[mem->length - 1] = '\0'; +295 +296 BIO_free_all(e); +297 +298 return out; +299 } +300 +301 char* util_encrypt_str(DavSession *sn, char *str, char *key) { +302 DavKey *k = dav_context_get_key(sn->context, key); +303 if(!k) { +304 // TODO: session error +305 return NULL; +306 } +307 +308 char *enc_str = aes_encrypt(str, k); +309 char *ret_str = dav_session_strdup(sn, enc_str); +310 free(enc_str); +311 return ret_str; +312 } +313 +314 /* commented out for testing reasons */ +315 /* +316 char* util_decrypt_str(DavSession *sn, char *str, char *key) { +317 DavKey *k = dav_context_get_key(sn->context, key); +318 if(!k) { +319 // TODO: session error +320 return NULL; +321 } +322 +323 char *dec_str = aes_decrypt(str, k); +324 char *ret_str = dav_session_strdup(sn, dec_str); +325 free(dec_str); +326 return ret_str; +327 } +328 */ +329 char* util_random_str() { +330 unsigned char *str = malloc(25); +331 str[24] = '\0'; +332 +333 sstr_t t = S( +334 "01234567890" +335 "abcdefghijklmnopqrstuvwxyz" +336 "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); +337 const unsigned char *table = (const unsigned char*)t.ptr; +338 +339 RAND_pseudo_bytes(str, 24); +340 for(int i=0;i<24;i++) { +341 int c = str[i] % t.length; +342 str[i] = table[c]; +343 } +344 +345 return (char*)str; +346 } +347 +348 /* +349 * gets a substring from 0 to the appearance of the token +350 * tokens are separated by space +351 * sets sub to the substring and returns the remaining string +352 */ +353 sstr_t util_getsubstr_until_token(sstr_t str, sstr_t token, sstr_t *sub) { +354 int i; +355 int token_start = -1; +356 int token_end = -1; +357 for(i=0;i<=str.length;i++) { +358 int c; +359 if(i == str.length) { +360 c = ' '; +361 } else { +362 c = str.ptr[i]; +363 } +364 if(c < 33) { +365 if(token_start != -1) { +366 token_end = i; +367 size_t len = token_end - token_start; +368 sstr_t tk = sstrsubsl(str, token_start, len); +369 //printf("token: {%.*s}\n", token.length, token.ptr); +370 if(!sstrcmp(tk, token)) { +371 *sub = sstrtrim(sstrsubsl(str, 0, token_start)); +372 break; +373 } +374 token_start = -1; +375 token_end = -1; +376 } +377 } else { +378 if(token_start == -1) { +379 token_start = i; +380 } +381 } +382 } +383 +384 if(i < str.length) { +385 return sstrtrim(sstrsubs(str, i)); +386 } else { +387 str.ptr = NULL; +388 str.length = 0; +389 return str; +390 } +391 } +
+ + + diff -r 9f25df78925e -r 1b12cf799fee test/gs/javatest.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gs/javatest.html Mon Apr 24 20:54:38 2023 +0200 @@ -0,0 +1,225 @@ + + + + c2html + + + + +
+ 1 /* + 2 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + 3 * + 4 * Copyright 2014 Mike Becker. All rights reserved. + 5 * + 6 * Redistribution and use in source and binary forms, with or without + 7 * modification, are permitted provided that the following conditions are met: + 8 * + 9 * 1. Redistributions of source code must retain the above copyright + 10 * notice, this list of conditions and the following disclaimer. + 11 * + 12 * 2. Redistributions in binary form must reproduce the above copyright + 13 * notice, this list of conditions and the following disclaimer in the + 14 * documentation and/or other materials provided with the distribution. + 15 * + 16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + 17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + 20 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + 21 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + 22 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + 23 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + 24 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + 25 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + 26 * POSSIBILITY OF SUCH DAMAGE. + 27 * + 28 */ + 29 + 30 package de.uapcore.sigred.doc.base; + 31 + 32 import de.uapcore.sigred.doc.Resources; + 33 import de.uapcore.sigrapi.impl.Digraph; + 34 import de.uapcore.sigrapi.impl.Graph; + 35 import de.uapcore.sigrapi.IGraph; + 36 import java.io.IOException; + 37 import java.io.InputStream; + 38 import java.io.OutputStream; + 39 import java.util.concurrent.atomic.AtomicBoolean; + 40 import java.util.concurrent.atomic.AtomicReference; + 41 import org.apache.xerces.impl.Constants; + 42 import org.dom4j.Document; + 43 import org.dom4j.DocumentException; + 44 import org.dom4j.DocumentHelper; + 45 import org.dom4j.Element; + 46 import org.dom4j.Namespace; + 47 import org.dom4j.QName; + 48 import org.dom4j.io.OutputFormat; + 49 import org.dom4j.io.SAXReader; + 50 import org.dom4j.io.XMLWriter; + 51 import org.xml.sax.ErrorHandler; + 52 import org.xml.sax.SAXException; + 53 import org.xml.sax.SAXParseException; + 54 + 55 public abstract class AbstractGraphDocument<T extends IGraph> + 56 extends FileBackedDocument { + 57 + 58 protected static final Namespace NAMESPACE = Namespace.get("sigred", + 59 "http://develop.uap-core.de/sigred/"); + 60 + 61 private static final + 62 QName TAG_GRAPHDOC = QName.get("graph-document", NAMESPACE); + 63 private static final + 64 QName TAG_GRAPH = QName.get("graph", NAMESPACE); + 65 private static final + 66 QName TAG_DIGRAPH = QName.get("digraph", NAMESPACE); + 67 private static final + 68 QName TAG_METADATA = QName.get("metadata", NAMESPACE); + 69 + 70 protected final T graph; + 71 + 72 private final GraphDocumentMetadata metadata; + 73 + 74 public AbstractGraphDocument(Class<T> graphType) { + 75 T g; + 76 try { + 77 g = graphType.newInstance(); + 78 } catch (ReflectiveOperationException e) { + 79 assert false; + 80 g = null; // for the compiler + 81 } + 82 graph = g; + 83 metadata = new GraphDocumentMetadata(); + 84 } + 85 + 86 public T getGraph() { + 87 return graph; + 88 } + 89 + 90 public GraphDocumentMetadata getMetadata() { + 91 return metadata; + 92 } + 93 + 94 protected abstract void writeGraph(Element rootNode) throws IOException; + 95 protected abstract void readGraph(Element rootNode) throws IOException; + 96 + 97 @Override + 98 public void writeTo(OutputStream out) throws IOException { + 99 Document doc = DocumentHelper.createDocument(); +100 +101 Element rootNode = doc.addElement(TAG_GRAPHDOC); +102 +103 Element metadataNode = rootNode.addElement(TAG_METADATA); +104 +105 metadata.write(metadataNode); +106 +107 if (graph instanceof Graph) { +108 writeGraph(rootNode.addElement(TAG_GRAPH)); +109 } else if (graph instanceof Digraph) { +110 writeGraph(rootNode.addElement(TAG_DIGRAPH)); +111 } else { +112 throw new IOException("unsupported graph type"); +113 } +114 +115 XMLWriter writer = new XMLWriter(out, OutputFormat.createPrettyPrint()); +116 writer.write(doc); +117 writer.flush(); +118 } +119 +120 @Override +121 public void readFrom(InputStream in) throws IOException { +122 try { +123 SAXReader reader = new SAXReader(true); +124 reader.setStripWhitespaceText(true); +125 +126 reader.setFeature(Constants.XERCES_FEATURE_PREFIX+ +127 Constants.SCHEMA_VALIDATION_FEATURE, true); +128 reader.setProperty(Constants.XERCES_PROPERTY_PREFIX + +129 Constants.SCHEMA_LOCATION, String.format("%s %s", +130 NAMESPACE.getURI(), Resources.class.getResource( +131 "graph-document.xsd").toExternalForm())); +132 +133 final AtomicBoolean passed = new AtomicBoolean(true); +134 final AtomicReference<SAXParseException> xmlerror = new AtomicReference<>(); +135 // TODO: we should do more detailed error handling here +136 reader.setErrorHandler(new ErrorHandler() { +137 @Override +138 public void warning(SAXParseException exception) throws SAXException { +139 } +140 +141 @Override +142 public void error(SAXParseException exception) throws SAXException { +143 xmlerror.set(exception); +144 passed.set(false); +145 } +146 +147 @Override +148 public void fatalError(SAXParseException exception) throws SAXException { +149 xmlerror.set(exception); +150 passed.set(false); +151 } +152 +153 }); +154 Document doc = reader.read(in); +155 if (!passed.get()) { +156 // TODO: provide details (maybe via separate error object?) +157 throw xmlerror.get(); +158 } +159 +160 doc.normalize(); +161 +162 Element root = doc.getRootElement(); +163 metadata.read(root.element(TAG_METADATA)); +164 +165 if (graph instanceof Graph) { +166 readGraph(root.element(TAG_GRAPH)); +167 } else if (graph instanceof Digraph) { +168 readGraph(root.element(TAG_DIGRAPH)); +169 } else { +170 throw new IOException("unsupported graph type"); +171 } +172 } catch (DocumentException | SAXException ex) { +173 throw new IOException(ex); +174 } +175 } +176 } +
+ + + diff -r 9f25df78925e -r 1b12cf799fee test/gs/plain.html --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/test/gs/plain.html Mon Apr 24 20:54:38 2023 +0200 @@ -0,0 +1,63 @@ + + + + c2html + + + + +
+1 </body> +2 </html> +3 <!c +4 pblock_free(q); +5 !> +6 +
+ + + diff -r 9f25df78925e -r 1b12cf799fee test/header.html --- a/test/header.html Thu Nov 10 18:44:48 2016 +0100 +++ b/test/header.html Mon Apr 24 20:54:38 2023 +0200 @@ -3,6 +3,10 @@ c2html - - - -
-  1  /*
-  2   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
-  3   *
-  4   * Copyright 2014 Mike Becker. All rights reserved.
-  5   *
-  6   * Redistribution and use in source and binary forms, with or without
-  7   * modification, are permitted provided that the following conditions are met:
-  8   *
-  9   *   1. Redistributions of source code must retain the above copyright
- 10   *      notice, this list of conditions and the following disclaimer.
- 11   *
- 12   *   2. Redistributions in binary form must reproduce the above copyright
- 13   *      notice, this list of conditions and the following disclaimer in the
- 14   *      documentation and/or other materials provided with the distribution.
- 15   *
- 16   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- 17   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- 18   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- 19   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- 20   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- 21   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- 22   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- 23   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- 24   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- 25   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- 26   * POSSIBILITY OF SUCH DAMAGE.
- 27   *
- 28   */
- 29  
- 30  #include "rules.h"
- 31  #include "chess.h"
- 32  #include <string.h>
- 33  #include <stdlib.h>
- 34  #include <sys/time.h>
- 35  
- 36  static GameState gamestate_copy_sim(GameState *gamestate) {
- 37      GameState simulation = *gamestate;
- 38      if (simulation.lastmove) {
- 39          MoveList *lastmovecopy = malloc(sizeof(MoveList));
- 40          *lastmovecopy = *(simulation.lastmove);
- 41          simulation.movelist = simulation.lastmove = lastmovecopy;
- 42      }
- 43  
- 44      return simulation;
- 45  }
- 46  
- 47  void gamestate_init(GameState *gamestate) {
- 48      memset(gamestate, 0, sizeof(GameState));
- 49      
- 50      Board initboard = {
- 51          {WROOK, WKNIGHT, WBISHOP, WQUEEN, WKING, WBISHOP, WKNIGHT, WROOK},
- 52          {WPAWN, WPAWN,   WPAWN,   WPAWN,  WPAWN, WPAWN,   WPAWN,   WPAWN},
- 53          {0,     0,       0,       0,      0,     0,       0,       0},
- 54          {0,     0,       0,       0,      0,     0,       0,       0},
- 55          {0,     0,       0,       0,      0,     0,       0,       0},
- 56          {0,     0,       0,       0,      0,     0,       0,       0},
- 57          {BPAWN, BPAWN,   BPAWN,   BPAWN,  BPAWN, BPAWN,   BPAWN,   BPAWN},
- 58          {BROOK, BKNIGHT, BBISHOP, BQUEEN, BKING, BBISHOP, BKNIGHT, BROOK}
- 59      };
- 60      memcpy(gamestate->board, initboard, sizeof(Board));
- 61  }
- 62  
- 63  void gamestate_cleanup(GameState *gamestate) {
- 64      MoveList *elem;
- 65      elem = gamestate->movelist;
- 66      while (elem) {
- 67          MoveList *cur = elem;
- 68          elem = elem->next;
- 69          free(cur);
- 70      };
- 71  }
- 72  
- 73  /* MUST be called IMMEDIATLY after applying a move to work correctly */
- 74  static void format_move(GameState *gamestate, Move *move) {
- 75      char *string = move->string;
- 76      
- 77      /* at least 8 characters should be available, wipe them out */
- 78      memset(string, 0, 8);
- 79      
- 80      /* special formats for castling */
- 81      if ((move->piece&PIECE_MASK) == KING &&
- 82              abs(move->tofile-move->fromfile) == 2) {
- 83          if (move->tofile==fileidx('c')) {
- 84              memcpy(string, "O-O-O", 5);
- 85          } else {
- 86              memcpy(string, "O-O", 3);
- 87          }
- 88      }
- 89  
- 90      /* start by notating the piece character */
- 91      string[0] = getpiecechr(move->piece);
- 92      int idx = string[0] ? 1 : 0;
- 93      
- 94      /* find out how many source information we do need */
- 95      uint8_t piece = move->piece & PIECE_MASK;
- 96      if (piece == PAWN) {
- 97          if (move->capture) {
- 98              string[idx++] = filechr(move->fromfile);
- 99          }
-100      } else if (piece != KING) {
-101          Move threats[16];
-102          uint8_t threatcount;
-103          get_real_threats(gamestate, move->torow, move->tofile,
-104              move->piece&COLOR_MASK, threats, &threatcount);
-105          if (threatcount > 1) {
-106              int ambrows = 0, ambfiles = 0;
-107              for (uint8_t i = 0 ; i < threatcount ; i++) {
-108                  if (threats[i].fromrow == move->fromrow) {
-109                      ambrows++;
-110                  }
-111                  if (threats[i].fromfile == move->fromfile) {
-112                      ambfiles++;
-113                  }
-114              }
-115              /* ambiguous row, name file */
-116              if (ambrows > 1) {
-117                  string[idx++] = filechr(move->fromfile);
-118              }
-119              /* ambiguous file, name row */
-120              if (ambfiles > 1) {
-121                  string[idx++] = filechr(move->fromrow);
-122              }
-123          }
-124      }
-125      
-126      /* capturing? */
-127      if (move->capture) {
-128          string[idx++] = 'x';
-129      }
-130      
-131      /* destination */
-132      string[idx++] = filechr(move->tofile);
-133      string[idx++] = rowchr(move->torow);
-134      
-135      /* promotion? */
-136      if (move->promotion) {
-137          string[idx++] = '=';
-138          string[idx++] = getpiecechr(move->promotion);
-139      }
-140      
-141      /* check? */
-142      if (move->check) {
-143          /* works only, if this function is called when applying the move */
-144          string[idx++] = gamestate->checkmate?'#':'+';
-145      }
-146  }
-147  
-148  static void addmove(GameState* gamestate, Move *move) {
-149      MoveList *elem = malloc(sizeof(MoveList));
-150      elem->next = NULL;
-151      elem->move = *move;
-152      
-153      struct timeval curtimestamp;
-154      gettimeofday(&curtimestamp, NULL);
-155      elem->move.timestamp.tv_sec = curtimestamp.tv_sec;
-156      elem->move.timestamp.tv_usec = curtimestamp.tv_usec;
-157      
-158      if (gamestate->lastmove) {
-159          struct movetimeval *lasttstamp = &(gamestate->lastmove->move.timestamp);
-160          uint64_t sec = curtimestamp.tv_sec - lasttstamp->tv_sec;
-161          suseconds_t micros;
-162          if (curtimestamp.tv_usec < lasttstamp->tv_usec) {
-163              micros = 1e6L-(lasttstamp->tv_usec - curtimestamp.tv_usec);
-164              sec--;
-165          } else {
-166              micros = curtimestamp.tv_usec - lasttstamp->tv_usec;
-167          }
-168          
-169          elem->move.movetime.tv_sec = sec;
-170          elem->move.movetime.tv_usec = micros;
-171          
-172          gamestate->lastmove->next = elem;
-173          gamestate->lastmove = elem;
-174      } else {
-175          elem->move.movetime.tv_usec = 0;
-176          elem->move.movetime.tv_sec = 0;
-177          gamestate->movelist = gamestate->lastmove = elem;
-178      }
-179  }
-180  
-181  char getpiecechr(uint8_t piece) {
-182      switch (piece & PIECE_MASK) {
-183      case ROOK: return 'R';
-184      case KNIGHT: return 'N';
-185      case BISHOP: return 'B';
-186      case QUEEN: return 'Q';
-187      case KING: return 'K';
-188      default: return '\0';
-189      }
-190  }
-191  
-192  uint8_t getpiece(char c) {
-193      switch (c) {
-194          case 'R': return ROOK;
-195          case 'N': return KNIGHT;
-196          case 'B': return BISHOP;
-197          case 'Q': return QUEEN;
-198          case 'K': return KING;
-199          default: return 0;
-200      }
-201  }
-202  
-203  static void apply_move_impl(GameState *gamestate, Move *move, _Bool simulate) {
-204      uint8_t piece = move->piece & PIECE_MASK;
-205      uint8_t color = move->piece & COLOR_MASK;
-206      
-207      /* en passant capture */
-208      if (move->capture && piece == PAWN &&
-209          mdst(gamestate->board, move) == 0) {
-210          gamestate->board[move->fromrow][move->tofile] = 0;
-211      }
-212      
-213      /* remove old en passant threats */
-214      for (uint8_t file = 0 ; file < 8 ; file++) {
-215          gamestate->board[3][file] &= ~ENPASSANT_THREAT;
-216          gamestate->board[4][file] &= ~ENPASSANT_THREAT;
-217      }
-218      
-219      /* add new en passant threat */
-220      if (piece == PAWN && (
-221          (move->fromrow == 1 && move->torow == 3) ||
-222          (move->fromrow == 6 && move->torow == 4))) {
-223          move->piece |= ENPASSANT_THREAT;
-224      }
-225      
-226      /* move (and maybe capture or promote) */
-227      msrc(gamestate->board, move) = 0;
-228      if (move->promotion) {
-229          mdst(gamestate->board, move) = move->promotion;
-230      } else {
-231          mdst(gamestate->board, move) = move->piece;
-232      }
-233      
-234      /* castling */
-235      if (piece == KING && move->fromfile == fileidx('e')) {
-236          
-237          if (move->tofile == fileidx('g')) {
-238              gamestate->board[move->torow][fileidx('h')] = 0;
-239              gamestate->board[move->torow][fileidx('f')] = color|ROOK;
-240          } else if (move->tofile == fileidx('c')) {
-241              gamestate->board[move->torow][fileidx('a')] = 0;
-242              gamestate->board[move->torow][fileidx('d')] = color|ROOK;
-243          }
-244      }
-245  
-246      if (!simulate) {
-247          if (!move->string[0]) {
-248              format_move(gamestate, move);
-249          }
-250      }
-251      /* add move, even in simulation (checkmate test needs it) */
-252      addmove(gamestate, move);
-253  }
-254  
-255  void apply_move(GameState *gamestate, Move *move) {
-256      apply_move_impl(gamestate, move, 0);
-257  }
-258  
-259  static int validate_move_rules(GameState *gamestate, Move *move) {
-260      /* validate indices (don't trust opponent) */
-261      if (!chkidx(move)) {
-262          return INVALID_POSITION;
-263      }
-264      
-265      /* must move */
-266      if (move->fromfile == move->tofile && move->fromrow == move->torow) {
-267          return INVALID_MOVE_SYNTAX;
-268      }
-269      
-270      /* does piece exist */
-271      if ((msrc(gamestate->board, move)&(PIECE_MASK|COLOR_MASK))
-272             != (move->piece&(PIECE_MASK|COLOR_MASK))) {
-273          return INVALID_POSITION;
-274      }
-275      
-276      /* can't capture own pieces */
-277      if ((mdst(gamestate->board, move) & COLOR_MASK)
-278              == (move->piece & COLOR_MASK)) {
-279          return RULES_VIOLATED;
-280      }
-281      
-282      /* must capture, if and only if destination is occupied */
-283      if ((mdst(gamestate->board, move) == 0 && move->capture) ||
-284              (mdst(gamestate->board, move) != 0 && !move->capture)) {
-285          return INVALID_MOVE_SYNTAX;
-286      }
-287      
-288      /* validate individual rules */
-289      _Bool chkrules;
-290      switch (move->piece & PIECE_MASK) {
-291      case PAWN:
-292          chkrules = pawn_chkrules(gamestate, move) &&
-293              !pawn_isblocked(gamestate, move);
-294          break;
-295      case ROOK:
-296          chkrules = rook_chkrules(move) &&
-297              !rook_isblocked(gamestate, move);
-298          break;
-299      case KNIGHT:
-300          chkrules = knight_chkrules(move); /* knight is never blocked */
-301          break;
-302      case BISHOP:
-303          chkrules = bishop_chkrules(move) &&
-304              !bishop_isblocked(gamestate, move);
-305          break;
-306      case QUEEN:
-307          chkrules = queen_chkrules(move) &&
-308              !queen_isblocked(gamestate, move);
-309          break;
-310      case KING:
-311          chkrules = king_chkrules(gamestate, move) &&
-312              !king_isblocked(gamestate, move);
-313          break;
-314      default:
-315          return INVALID_MOVE_SYNTAX;
-316      }
-317      
-318      return chkrules ? VALID_MOVE_SEMANTICS : RULES_VIOLATED;
-319  }
-320  
-321  int validate_move(GameState *gamestate, Move *move) {
-322      
-323      int result = validate_move_rules(gamestate, move);
-324      
-325      /* cancel processing to save resources */
-326      if (result != VALID_MOVE_SEMANTICS) {
-327          return result;
-328      }
-329      
-330      /* find kings for check validation */
-331      uint8_t piececolor = (move->piece & COLOR_MASK);
-332      
-333      uint8_t mykingfile = 0, mykingrow = 0, opkingfile = 0, opkingrow = 0;
-334      for (uint8_t row = 0 ; row < 8 ; row++) {
-335          for (uint8_t file = 0 ; file < 8 ; file++) {
-336              if (gamestate->board[row][file] ==
-337                      (piececolor == WHITE?WKING:BKING)) {
-338                  mykingfile = file;
-339                  mykingrow = row;
-340              } else if (gamestate->board[row][file] ==
-341                      (piececolor == WHITE?BKING:WKING)) {
-342                  opkingfile = file;
-343                  opkingrow = row;
-344              }
-345          }
-346      }
-347      
-348      /* simulate move for check validation */
-349      GameState simulation = gamestate_copy_sim(gamestate);
-350      Move simmove = *move;
-351      apply_move_impl(&simulation, &simmove, 1);
-352      
-353      /* don't move into or stay in check position */
-354      if (is_covered(&simulation, mykingrow, mykingfile,
-355          opponent_color(piececolor))) {
-356          
-357          gamestate_cleanup(&simulation);
-358          if ((move->piece & PIECE_MASK) == KING) {
-359              return KING_MOVES_INTO_CHECK;
-360          } else {
-361              /* last move is always not null in this case */
-362              return gamestate->lastmove->move.check ?
-363                  KING_IN_CHECK : PIECE_PINNED;
-364          }
-365      }
-366      
-367      /* correct check and checkmate flags (move is still valid) */
-368      Move threats[16];
-369      uint8_t threatcount;
-370      move->check = get_threats(&simulation, opkingrow, opkingfile,
-371          piececolor, threats, &threatcount);
-372      
-373      if (move->check) {
-374          /* determine possible escape fields */
-375          _Bool canescape = 0;
-376          for (int dr = -1 ; dr <= 1 && !canescape ; dr++) {
-377              for (int df = -1 ; df <= 1 && !canescape ; df++) {
-378                  if (!(dr == 0 && df == 0)  &&
-379                          isidx(opkingrow + dr) && isidx(opkingfile + df)) {
-380                      
-381                      /* escape field neither blocked nor covered */
-382                      if ((simulation.board[opkingrow + dr][opkingfile + df]
-383                              & COLOR_MASK) != opponent_color(piececolor)) {
-384                          canescape |= !is_covered(&simulation,
-385                              opkingrow + dr, opkingfile + df, piececolor);
-386                      }
-387                  }
-388              }
-389          }
-390          /* can't escape, can he capture? */
-391          if (!canescape && threatcount == 1) {
-392              canescape = is_attacked(&simulation, threats[0].fromrow,
-393                  threats[0].fromfile, opponent_color(piececolor));
-394          }
-395          
-396          /* can't capture, can he block? */
-397          if (!canescape && threatcount == 1) {
-398              Move *threat = &(threats[0]);
-399              uint8_t threatpiece = threat->piece & PIECE_MASK;
-400              
-401              /* knight, pawns and the king cannot be blocked */
-402              if (threatpiece == BISHOP || threatpiece == ROOK
-403                  || threatpiece == QUEEN) {
-404                  if (threat->fromrow == threat->torow) {
-405                      /* rook aspect (on row) */
-406                      int d = threat->tofile > threat->fromfile ? 1 : -1;
-407                      uint8_t file = threat->fromfile;
-408                      while (!canescape && file != threat->tofile - d) {
-409                          file += d;
-410                          canescape |= is_protected(&simulation,
-411                              threat->torow, file, opponent_color(piececolor));
-412                      }
-413                  } else if (threat->fromfile == threat->tofile) {
-414                      /* rook aspect (on file) */
-415                      int d = threat->torow > threat->fromrow ? 1 : -1;
-416                      uint8_t row = threat->fromrow;
-417                      while (!canescape && row != threat->torow - d) {
-418                          row += d;
-419                          canescape |= is_protected(&simulation,
-420                              row, threat->tofile, opponent_color(piececolor));
-421                      }
-422                  } else {
-423                      /* bishop aspect */
-424                      int dr = threat->torow > threat->fromrow ? 1 : -1;
-425                      int df = threat->tofile > threat->fromfile ? 1 : -1;
-426  
-427                      uint8_t row = threat->fromrow;
-428                      uint8_t file = threat->fromfile;
-429                      while (!canescape && file != threat->tofile - df
-430                          && row != threat->torow - dr) {
-431                          row += dr;
-432                          file += df;
-433                          canescape |= is_protected(&simulation, row, file,
-434                              opponent_color(piececolor));
-435                      }
-436                  }
-437              }
-438          }
-439              
-440          if (!canescape) {
-441              gamestate->checkmate = 1;
-442          }
-443      }
-444      
-445      gamestate_cleanup(&simulation);
-446      
-447      return VALID_MOVE_SEMANTICS;
-448  }
-449  
-450  _Bool get_threats(GameState *gamestate, uint8_t row, uint8_t file,
-451          uint8_t color, Move *threats, uint8_t *threatcount) {
-452      Move candidates[32];
-453      int candidatecount = 0;
-454      for (uint8_t r = 0 ; r < 8 ; r++) {
-455          for (uint8_t f = 0 ; f < 8 ; f++) {
-456              if ((gamestate->board[r][f] & COLOR_MASK) == color) {
-457                  // non-capturing move
-458                  memset(&(candidates[candidatecount]), 0, sizeof(Move));
-459                  candidates[candidatecount].piece = gamestate->board[r][f];
-460                  candidates[candidatecount].fromrow = r;
-461                  candidates[candidatecount].fromfile = f;
-462                  candidates[candidatecount].torow = row;
-463                  candidates[candidatecount].tofile = file;
-464                  candidatecount++;
-465  
-466                  // capturing move
-467                  memcpy(&(candidates[candidatecount]),
-468                      &(candidates[candidatecount-1]), sizeof(Move));
-469                  candidates[candidatecount].capture = 1;
-470                  candidatecount++;
-471              }
-472          }
-473      }
-474  
-475      if (threatcount) {
-476          *threatcount = 0;
-477      }
-478      
-479      
-480      _Bool result = 0;
-481      
-482      for (int i = 0 ; i < candidatecount ; i++) {
-483          if (validate_move_rules(gamestate, &(candidates[i]))
-484                  == VALID_MOVE_SEMANTICS) {
-485              result = 1;
-486              if (threats && threatcount) {
-487                  threats[(*threatcount)++] = candidates[i];
-488              }
-489          }
-490      }
-491      
-492      return result;
-493  }
-494  
-495  _Bool is_pinned(GameState *gamestate, Move *move) {
-496      uint8_t color = move->piece & COLOR_MASK;
-497  
-498      uint8_t kingfile = 0, kingrow = 0;
-499      for (uint8_t row = 0 ; row < 8 ; row++) {
-500          for (uint8_t file = 0 ; file < 8 ; file++) {
-501              if (gamestate->board[row][file] == (color|KING)) {
-502                  kingfile = file;
-503                  kingrow = row;
-504              }
-505          }
-506      }
-507  
-508      GameState simulation = gamestate_copy_sim(gamestate);
-509      Move simmove = *move;
-510      apply_move(&simulation, &simmove);
-511      _Bool covered = is_covered(&simulation,
-512          kingrow, kingfile, opponent_color(color));
-513      gamestate_cleanup(&simulation);
-514      
-515      return covered;
-516  }
-517  
-518  _Bool get_real_threats(GameState *gamestate, uint8_t row, uint8_t file,
-519          uint8_t color, Move *threats, uint8_t *threatcount) {
-520      
-521      if (threatcount) {
-522          *threatcount = 0;
-523      }
-524  
-525      Move candidates[16];
-526      uint8_t candidatecount;
-527      if (get_threats(gamestate, row, file, color, candidates, &candidatecount)) {
-528          
-529          _Bool result = 0;
-530          uint8_t kingfile = 0, kingrow = 0;
-531          for (uint8_t row = 0 ; row < 8 ; row++) {
-532              for (uint8_t file = 0 ; file < 8 ; file++) {
-533                  if (gamestate->board[row][file] == (color|KING)) {
-534                      kingfile = file;
-535                      kingrow = row;
-536                  }
-537              }
-538          }
-539  
-540          for (uint8_t i = 0 ; i < candidatecount ; i++) {
-541              GameState simulation = gamestate_copy_sim(gamestate);
-542              Move simmove = candidates[i];
-543              apply_move(&simulation, &simmove);
-544              if (!is_covered(&simulation, kingrow, kingfile,
-545                      opponent_color(color))) {
-546                  result = 1;
-547                  if (threats && threatcount) {
-548                      threats[(*threatcount)++] = candidates[i];
-549                  }
-550              }
-551          }
-552          
-553          return result;
-554      } else {
-555          return 0;
-556      }
-557  }
-558  
-559  static int getlocation(GameState *gamestate, Move *move) {   
-560  
-561      uint8_t color = move->piece & COLOR_MASK;
-562      _Bool incheck = gamestate->lastmove?gamestate->lastmove->move.check:0;
-563      
-564      Move threats[16], *threat = NULL;
-565      uint8_t threatcount;
-566      
-567      if (get_threats(gamestate, move->torow, move->tofile, color,
-568              threats, &threatcount)) {
-569          
-570          int reason = INVALID_POSITION;
-571          
-572          // find threats for the specified position
-573          for (uint8_t i = 0 ; i < threatcount ; i++) {
-574              if ((threats[i].piece & (PIECE_MASK | COLOR_MASK))
-575                      == move->piece &&
-576                      (move->fromrow == POS_UNSPECIFIED ||
-577                      move->fromrow == threats[i].fromrow) &&
-578                      (move->fromfile == POS_UNSPECIFIED ||
-579                      move->fromfile == threats[i].fromfile)) {
-580  
-581                  if (threat) {
-582                      return AMBIGUOUS_MOVE;
-583                  } else {
-584                      // found threat is no real threat
-585                      if (is_pinned(gamestate, &(threats[i]))) {
-586                          reason = incheck?KING_IN_CHECK:PIECE_PINNED;
-587                      } else {
-588                          threat = &(threats[i]);
-589                      }
-590                  }
-591              }
-592          }
-593          
-594          // can't threaten specified position
-595          if (!threat) {
-596              return reason;
-597          }
-598  
-599          memcpy(move, threat, sizeof(Move));
-600          return VALID_MOVE_SYNTAX;
-601      } else {
-602          return INVALID_POSITION;
-603      }
-604  }
-605  
-606  int eval_move(GameState *gamestate, char *mstr, Move *move, uint8_t color) {
-607      memset(move, 0, sizeof(Move));
-608      move->fromfile = POS_UNSPECIFIED;
-609      move->fromrow = POS_UNSPECIFIED;
-610  
-611      size_t len = strlen(mstr);
-612      if (len < 1 || len > 6) {
-613          return INVALID_MOVE_SYNTAX;
-614      }
-615      
-616      /* evaluate check/checkmate flags */
-617      if (mstr[len-1] == '+') {
-618          len--; mstr[len] = '\0';
-619          move->check = 1;
-620      } else if (mstr[len-1] == '#') {
-621          len--; mstr[len] = '\0';
-622          /* ignore - validation should set game state */
-623      }
-624      
-625      /* evaluate promotion */
-626      if (len > 3 && mstr[len-2] == '=') {
-627          move->promotion = getpiece(mstr[len-1]);
-628          if (!move->promotion) {
-629              return INVALID_MOVE_SYNTAX;
-630          } else {
-631              move->promotion |= color;
-632              len -= 2;
-633              mstr[len] = 0;
-634          }
-635      }
-636      
-637      if (len == 2) {
-638          /* pawn move (e.g. "e4") */
-639          move->piece = PAWN;
-640          move->tofile = fileidx(mstr[0]);
-641          move->torow = rowidx(mstr[1]);
-642      } else if (len == 3) {
-643          if (strcmp(mstr, "O-O") == 0) {
-644              /* king side castling */
-645              move->piece = KING;
-646              move->fromfile = fileidx('e');
-647              move->tofile = fileidx('g');
-648              move->fromrow = move->torow = color == WHITE ? 0 : 7;
-649          } else {
-650              /* move (e.g. "Nf3") */
-651              move->piece = getpiece(mstr[0]);
-652              move->tofile = fileidx(mstr[1]);
-653              move->torow = rowidx(mstr[2]);
-654          }
-655      } else if (len == 4) {
-656          move->piece = getpiece(mstr[0]);
-657          if (!move->piece) {
-658              move->piece = PAWN;
-659              move->fromfile = fileidx(mstr[0]);
-660          }
-661          if (mstr[1] == 'x') {
-662              /* capture (e.g. "Nxf3", "dxe5") */
-663              move->capture = 1;
-664          } else {
-665              /* move (e.g. "Ndf3", "N2c3", "e2e4") */
-666              if (isfile(mstr[1])) {
-667                  move->fromfile = fileidx(mstr[1]);
-668                  if (move->piece == PAWN) {
-669                      move->piece = 0;
-670                  }
-671              } else {
-672                  move->fromrow = rowidx(mstr[1]);
-673              }
-674          }
-675          move->tofile = fileidx(mstr[2]);
-676          move->torow = rowidx(mstr[3]);
-677      } else if (len == 5) {
-678          if (strcmp(mstr, "O-O-O") == 0) {
-679              /* queen side castling "O-O-O" */
-680              move->piece = KING;
-681              move->fromfile = fileidx('e');
-682              move->tofile = fileidx('c');
-683              move->fromrow = move->torow = color == WHITE ? 0 : 7;
-684          } else {
-685              move->piece = getpiece(mstr[0]);
-686              if (mstr[2] == 'x') {
-687                  move->capture = 1;
-688                  if (move->piece) {
-689                      /* capture (e.g. "Ndxf3") */
-690                      move->fromfile = fileidx(mstr[1]);
-691                  } else {
-692                      /* long notation capture (e.g. "e5xf6") */
-693                      move->piece = PAWN;
-694                      move->fromfile = fileidx(mstr[0]);
-695                      move->fromrow = rowidx(mstr[1]);
-696                  }
-697              } else {
-698                  /* long notation move (e.g. "Nc5a4") */
-699                  move->fromfile = fileidx(mstr[1]);
-700                  move->fromrow = rowidx(mstr[2]);
-701              }
-702              move->tofile = fileidx(mstr[3]);
-703              move->torow = rowidx(mstr[4]);
-704          }
-705      } else if (len == 6) {
-706          /* long notation capture (e.g. "Nc5xf3") */
-707          if (mstr[3] == 'x') {
-708              move->capture = 1;
-709              move->piece = getpiece(mstr[0]);
-710              move->fromfile = fileidx(mstr[1]);
-711              move->fromrow = rowidx(mstr[2]);
-712              move->tofile = fileidx(mstr[4]);
-713              move->torow = rowidx(mstr[5]);
-714          }
-715      }
-716  
-717      
-718      if (move->piece) {
-719          if (move->piece == PAWN
-720              && move->torow == (color==WHITE?7:0)
-721              && !move->promotion) {
-722              return NEED_PROMOTION;
-723          }
-724          
-725          move->piece |= color;
-726          if (move->fromfile == POS_UNSPECIFIED
-727              || move->fromrow == POS_UNSPECIFIED) {
-728              return getlocation(gamestate, move);
-729          } else {
-730              return chkidx(move) ? VALID_MOVE_SYNTAX : INVALID_POSITION;
-731          }
-732      } else {
-733          return INVALID_MOVE_SYNTAX;
-734      }
-735  }
-736  
-737  _Bool is_protected(GameState *gamestate, uint8_t row, uint8_t file,
-738          uint8_t color) {
-739      
-740      Move threats[16];
-741      uint8_t threatcount;
-742      if (get_real_threats(gamestate, row, file, color, threats, &threatcount)) {
-743          for (int i = 0 ; i < threatcount ; i++) {
-744              if (threats[i].piece != (color|KING)) {
-745                  return 1;
-746              }
-747          }
-748          return 0;
-749      } else {
-750          return 0;
-751      }
-752  }
-753  
-754  uint16_t remaining_movetime(GameInfo *gameinfo, GameState *gamestate,
-755          uint8_t color) {
-756      if (!gameinfo->timecontrol) {
-757          return 0;
-758      }
-759      
-760      if (gamestate->movelist) {
-761          uint16_t time = gameinfo->time;
-762          suseconds_t micros = 0;
-763          
-764          MoveList *movelist = color == WHITE ?
-765              gamestate->movelist : gamestate->movelist->next;
-766          
-767          while (movelist) {
-768              time += gameinfo->addtime;
-769              
-770              struct movetimeval *movetime = &(movelist->move.movetime);
-771              if (movetime->tv_sec >= time) {
-772                  return 0;
-773              }
-774              
-775              time -= movetime->tv_sec;
-776              micros += movetime->tv_usec;
-777              
-778              movelist = movelist->next ? movelist->next->next : NULL;
-779          }
-780          
-781          time_t sec;
-782          movelist = gamestate->lastmove;
-783          if ((movelist->move.piece & COLOR_MASK) != color) {
-784              struct movetimeval *lastmovetstamp = &(movelist->move.timestamp);
-785              struct timeval currenttstamp;
-786              gettimeofday(¤ttstamp, NULL);
-787              micros += currenttstamp.tv_usec - lastmovetstamp->tv_usec;
-788              sec = currenttstamp.tv_sec - lastmovetstamp->tv_sec;
-789              if (sec >= time) {
-790                  return 0;
-791              }
-792              
-793              time -= sec;
-794          }
-795          
-796          sec = micros / 1e6L;
-797          
-798          if (sec >= time) {
-799              return 0;
-800          }
-801  
-802          time -= sec;
-803          
-804          return time;
-805      } else {
-806          return gameinfo->time;
-807      }
-808  }
-
- - - diff -r 9f25df78925e -r 1b12cf799fee test/v2-regression/ctest.html --- a/test/v2-regression/ctest.html Thu Nov 10 18:44:48 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,438 +0,0 @@ - - - - c2html - - - - -
-  1  /*
-  2   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
-  3   *
-  4   * Copyright 2015 Olaf Wintermann. All rights reserved.
-  5   *
-  6   * Redistribution and use in source and binary forms, with or without
-  7   * modification, are permitted provided that the following conditions are met:
-  8   *
-  9   *   1. Redistributions of source code must retain the above copyright
- 10   *      notice, this list of conditions and the following disclaimer.
- 11   *
- 12   *   2. Redistributions in binary form must reproduce the above copyright
- 13   *      notice, this list of conditions and the following disclaimer in the
- 14   *      documentation and/or other materials provided with the distribution.
- 15   *
- 16   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- 17   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- 18   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- 19   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- 20   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- 21   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- 22   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- 23   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- 24   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- 25   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- 26   * POSSIBILITY OF SUCH DAMAGE.
- 27   */
- 28  
- 29  #include <time.h>
- 30  #include <stdio.h>
- 31  #include <stdlib.h>
- 32  #include <string.h>
- 33  #include <ucx/string.h>
- 34  #include <ucx/buffer.h>
- 35  #include <ucx/utils.h>
- 36  #include <libxml/tree.h>
- 37  #include <curl/curl.h>
- 38  
- 39  #include <openssl/sha.h>
- 40  #include <openssl/hmac.h>
- 41  #include <openssl/evp.h>
- 42  #include <openssl/bio.h>
- 43  #include <openssl/buffer.h>
- 44  #include <openssl/rand.h>
- 45  
- 46  #include "utils.h"
- 47  #include "crypto.h"
- 48  #include "webdav.h"
- 49  
- 50  #define MACRO1337 1337L
- 51  
- 52  /* -------------------- This is a testing file. -------------------------- */
- 53  /*
- 54  time_t util_parse_creationdate(char *str) {
- 55      // example: 2012-11-29T21:35:35Z
- 56      if(!str) {
- 57          return 0;
- 58      }
- 59      // TODO
- 60      return 0;
- 61  }
- 62  */
- 63  time_t util_parse_lastmodified(char *str) {
- 64      // example: Thu, 29 Nov 2012 21:35:35 GMT
- 65      if(!str) {
- 66          return 0;
- 67      } else {
- 68          return curl_getdate(str, NULL);
- 69      }
- 70  }
- 71  
- 72  int util_getboolean(char *v) {
- 73      if(v[0] == 'T' || v[0] == 't') {
- 74          return 1;
- 75      }
- 76      return 0;
- 77  }
- 78  
- 79  int util_strtoint(char *str, int64_t *value) {
- 80      char *end;
- 81      int64_t val = strtoll(str, &end, 0);
- 82      if(strlen(end) == 0) {
- 83          *value = val;
- 84          return 1;
- 85      } else {
- 86          return 0;
- 87      }
- 88  }
- 89  
- 90  char* util_url_path(char *url) { 
- 91      char *path = NULL;
- 92      size_t len = strlen(url);
- 93      int slashcount = 0;
- 94      int slmax;
- 95      if(len > 7 && !strncasecmp(url, "http://", 7)) {
- 96          slmax = 3;
- 97      } else if(len > 8 && !strncasecmp(url, "https://", 8)) {
- 98          slmax = 3;
- 99      } else {
-100          slmax = 1;
-101      }
-102      char c;
-103      for(int i=0;i<len;i++) {
-104          c = url[i];
-105          if(c == '/') {
-106              slashcount++;
-107              if(slashcount == slmax) {
-108                  path = url + i;
-109                  break;
-110              }
-111          }
-112      } 
-113      return path;
-114  }
-115  
-116  char* util_url_decode(DavSession *sn, char *url) {
-117      char *unesc = curl_easy_unescape(sn->handle, url, strlen(url), NULL);
-118      char *ret = strdup(unesc);
-119      curl_free(unesc);
-120      return ret;
-121  }
-122  
-123  char* util_resource_name(char *url) {
-124      int si = 0;
-125      int osi = 0;
-126      int i = 0;
-127      int p = 0;
-128      char c;
-129      while((c = url[i]) != 0) {
-130          if(c == '/') {
-131              osi = si;
-132              si = i;
-133              p = 1;
-134          }
-135          i++;
-136      }
-137      
-138      char *name = url + si + p;
-139      if(name[0] == 0) {
-140          name = url + osi + p;
-141          if(name[0] == 0) {
-142              return url;
-143          }
-144      }
-145      
-146      return name;
-147  }
-148  
-149  int util_mkdir(char *path, mode_t mode) {
-150  #ifdef _WIN32
-151      return mkdir(path);
-152  #else
-153      return mkdir(path, mode);
-154  #endif
-155  }
-156  
-157  char* util_concat_path(char *url_base, char *p) {
-158      sstr_t base = sstr(url_base);
-159      sstr_t path;
-160      if(p) {
-161          path = sstr(p);
-162      } else {
-163          path = sstrn("", 0);
-164      }
-165      
-166      int add_separator = 0;
-167      if(base.ptr[base.length-1] == '/') {
-168          if(path.ptr[0] == '/') {
-169              base.length--;
-170          }
-171      } else {
-172          if(path.length == 0 || path.ptr[0] != '/') {
-173              add_separator = 1;
-174          }
-175      }
-176      
-177      sstr_t url;
-178      if(add_separator) {
-179          url = sstrcat(3, base, sstr("/"), path);
-180      } else {
-181          url = sstrcat(2, base, path);
-182      }
-183      
-184      return url.ptr;
-185  }
-186  
-187  void util_set_url(DavSession *sn, char *href) {
-188      sstr_t base = sstr(sn->base_url);
-189      sstr_t href_str = sstr(href);
-190      
-191      char *base_path = util_url_path(sn->base_url);
-192      base.length -= strlen(base_path);
-193      
-194      sstr_t url = sstrcat(2, base, href_str);
-195      
-196      curl_easy_setopt(sn->handle, CURLOPT_URL, url.ptr);
-197      free(url.ptr);
-198  }
-199  
-200  char* util_path_to_url(DavSession *sn, char *path) {
-201      char *space = malloc(256);
-202      UcxBuffer *url = ucx_buffer_new(space, 256, UCX_BUFFER_AUTOEXTEND);
-203      
-204      // add base url
-205      ucx_buffer_write(sn->base_url, 1, strlen(sn->base_url), url);
-206      // remove trailing slash
-207      ucx_buffer_seek(url, -1, SEEK_CUR);
-208      
-209      sstr_t p = sstr(path);
-210      ssize_t ntk = 0;
-211      sstr_t *tks = sstrsplit(p, S("/"), &ntk);
-212      
-213      for(int i=0;i<ntk;i++) {
-214          sstr_t node = tks[i];
-215          if(node.length > 0) {
-216              char *esc = curl_easy_escape(sn->handle, node.ptr, node.length);
-217              ucx_buffer_putc(url, '/');
-218              ucx_buffer_write(esc, 1, strlen(esc), url);
-219              curl_free(esc);
-220          }
-221          free(node.ptr);
-222      }
-223      free(tks);
-224      if(path[p.length-1] == '/') {
-225          ucx_buffer_putc(url, '/');
-226      }
-227      ucx_buffer_putc(url, 0);
-228      
-229      space = url->space;
-230      ucx_buffer_free(url);
-231      
-232      return space;
-233  }
-234  
-235  char* util_parent_path(char *path) {
-236      char *name = util_resource_name(path);
-237      size_t namelen = strlen(name);
-238      size_t pathlen = strlen(path);
-239      size_t parentlen = pathlen - namelen;
-240      char *parent = malloc(parentlen + 1);
-241      memcpy(parent, path, parentlen);
-242      parent[parentlen] = '\0';
-243      return parent;
-244  }
-245  
-246  
-247  char* util_xml_get_text(xmlNode *elm) {
-248      xmlNode *node = elm->children;
-249      while(node) {
-250          if(node->type == XML_TEXT_NODE) {
-251              return (char*)node->content;
-252          }
-253          node = node->next;
-254      }
-255      return NULL;
-256  }
-257  
-258  
-259  char* util_base64decode(char *in) {
-260      int len = 0;
-261      return util_base64decode_len(in, &len);
-262  }
-263  
-264  char* util_base64decode_len(char* in, int *outlen) {
-265      size_t len = strlen(in);
-266      char *out = calloc(1, len);
-267      
-268      BIO* b = BIO_new_mem_buf(in, len);
-269      BIO *d = BIO_new(BIO_f_base64());
-270      BIO_set_flags(d, BIO_FLAGS_BASE64_NO_NL);
-271      b = BIO_push(d, b);
-272  
-273      *outlen = BIO_read(b, out, len);
-274      BIO_free_all(b);
-275      
-276      return out;
-277  }
-278  
-279  char* util_base64encode(char *in, size_t len) { 
-280      BIO *b;
-281      BIO *e;
-282      BUF_MEM *mem;
-283  
-284      e = BIO_new(BIO_f_base64());
-285      b = BIO_new(BIO_s_mem());
-286      
-287      e = BIO_push(e, b);
-288      BIO_write(e, in, len);
-289      BIO_flush(e);
-290      
-291      BIO_get_mem_ptr(e, &mem);
-292      char *out = malloc(mem->length);
-293      memcpy(out, mem->data, mem->length -1);
-294      out[mem->length - 1] = '\0';
-295  
-296      BIO_free_all(e);
-297  
-298      return out;
-299  }
-300  
-301  char* util_encrypt_str(DavSession *sn, char *str, char *key) {
-302      DavKey *k = dav_context_get_key(sn->context, key);
-303      if(!k) {
-304          // TODO: session error
-305          return NULL;
-306      }
-307      
-308      char *enc_str = aes_encrypt(str, k);
-309      char *ret_str = dav_session_strdup(sn, enc_str);
-310      free(enc_str);
-311      return ret_str;
-312  }
-313  
-314  /* commented out for testing reasons */
-315  /*
-316  char* util_decrypt_str(DavSession *sn, char *str, char *key) {
-317      DavKey *k = dav_context_get_key(sn->context, key);
-318      if(!k) {
-319          // TODO: session error
-320          return NULL;
-321      }
-322      
-323      char *dec_str = aes_decrypt(str, k);
-324      char *ret_str = dav_session_strdup(sn, dec_str);
-325      free(dec_str);
-326      return ret_str;
-327  }
-328  */
-329  char* util_random_str() {
-330      unsigned char *str = malloc(25);
-331      str[24] = '\0';
-332      
-333      sstr_t t = S(
-334              "01234567890"
-335              "abcdefghijklmnopqrstuvwxyz"
-336              "ABCDEFGHIJKLMNOPQRSTUVWXYZ");
-337      const unsigned char *table = (const unsigned char*)t.ptr;
-338      
-339      RAND_pseudo_bytes(str, 24);
-340      for(int i=0;i<24;i++) {
-341          int c = str[i] % t.length;
-342          str[i] = table[c];
-343      }
-344      
-345      return (char*)str;
-346  }
-347  
-348  /*
-349   * gets a substring from 0 to the appearance of the token
-350   * tokens are separated by space
-351   * sets sub to the substring and returns the remaining string
-352   */
-353  sstr_t util_getsubstr_until_token(sstr_t str, sstr_t token, sstr_t *sub) {  
-354      int i;
-355      int token_start = -1;
-356      int token_end = -1;
-357      for(i=0;i<=str.length;i++) {
-358          int c;
-359          if(i == str.length) {
-360              c = ' ';
-361          } else {
-362              c = str.ptr[i];
-363          }
-364          if(c < 33) {
-365              if(token_start != -1) {
-366                  token_end = i;
-367                  size_t len = token_end - token_start;
-368                  sstr_t tk = sstrsubsl(str, token_start, len);
-369                  //printf("token: {%.*s}\n", token.length, token.ptr);
-370                  if(!sstrcmp(tk, token)) {
-371                      *sub = sstrtrim(sstrsubsl(str, 0, token_start));
-372                      break;
-373                  }
-374                  token_start = -1;
-375                  token_end = -1;
-376              }
-377          } else {
-378              if(token_start == -1) {
-379                  token_start = i;
-380              }
-381          }
-382      }
-383      
-384      if(i < str.length) {
-385          return sstrtrim(sstrsubs(str, i));
-386      } else {
-387          str.ptr = NULL;
-388          str.length = 0;
-389          return str;
-390      }
-391  }
-
- - - diff -r 9f25df78925e -r 1b12cf799fee test/v2-regression/javatest.html --- a/test/v2-regression/javatest.html Thu Nov 10 18:44:48 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,215 +0,0 @@ - - - - c2html - - - - -
-  1  /*
-  2   * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
-  3   *
-  4   * Copyright 2014 Mike Becker. All rights reserved.
-  5   *
-  6   * Redistribution and use in source and binary forms, with or without
-  7   * modification, are permitted provided that the following conditions are met:
-  8   *
-  9   *   1. Redistributions of source code must retain the above copyright
- 10   *      notice, this list of conditions and the following disclaimer.
- 11   *
- 12   *   2. Redistributions in binary form must reproduce the above copyright
- 13   *      notice, this list of conditions and the following disclaimer in the
- 14   *      documentation and/or other materials provided with the distribution.
- 15   *
- 16   * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
- 17   * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- 18   * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- 19   * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
- 20   * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
- 21   * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
- 22   * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
- 23   * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
- 24   * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
- 25   * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
- 26   * POSSIBILITY OF SUCH DAMAGE.
- 27   *
- 28   */
- 29  
- 30  package de.uapcore.sigred.doc.base;
- 31  
- 32  import de.uapcore.sigred.doc.Resources;
- 33  import de.uapcore.sigrapi.impl.Digraph;
- 34  import de.uapcore.sigrapi.impl.Graph;
- 35  import de.uapcore.sigrapi.IGraph;
- 36  import java.io.IOException;
- 37  import java.io.InputStream;
- 38  import java.io.OutputStream;
- 39  import java.util.concurrent.atomic.AtomicBoolean;
- 40  import java.util.concurrent.atomic.AtomicReference;
- 41  import org.apache.xerces.impl.Constants;
- 42  import org.dom4j.Document;
- 43  import org.dom4j.DocumentException;
- 44  import org.dom4j.DocumentHelper;
- 45  import org.dom4j.Element;
- 46  import org.dom4j.Namespace;
- 47  import org.dom4j.QName;
- 48  import org.dom4j.io.OutputFormat;
- 49  import org.dom4j.io.SAXReader;
- 50  import org.dom4j.io.XMLWriter;
- 51  import org.xml.sax.ErrorHandler;
- 52  import org.xml.sax.SAXException;
- 53  import org.xml.sax.SAXParseException;
- 54  
- 55  public abstract class AbstractGraphDocument<T extends IGraph>
- 56          extends FileBackedDocument {
- 57      
- 58      protected static final Namespace NAMESPACE = Namespace.get("sigred",
- 59          "http://develop.uap-core.de/sigred/");
- 60      
- 61      private static final
- 62          QName TAG_GRAPHDOC = QName.get("graph-document", NAMESPACE);
- 63      private static final
- 64          QName TAG_GRAPH = QName.get("graph", NAMESPACE);
- 65      private static final
- 66          QName TAG_DIGRAPH = QName.get("digraph", NAMESPACE);
- 67      private static final
- 68          QName TAG_METADATA = QName.get("metadata", NAMESPACE);
- 69      
- 70      protected final T graph;
- 71      
- 72      private final GraphDocumentMetadata metadata;
- 73      
- 74      public AbstractGraphDocument(Class<T> graphType) {
- 75          T g;
- 76          try {
- 77              g = graphType.newInstance();
- 78          } catch (ReflectiveOperationException e) {
- 79              assert false;
- 80              g = null; // for the compiler
- 81          }
- 82          graph = g;
- 83          metadata = new GraphDocumentMetadata();
- 84      }
- 85  
- 86      public T getGraph() {
- 87          return graph;
- 88      }
- 89      
- 90      public GraphDocumentMetadata getMetadata() {
- 91          return metadata;
- 92      }
- 93  
- 94      protected abstract void writeGraph(Element rootNode) throws IOException;
- 95      protected abstract void readGraph(Element rootNode) throws IOException;
- 96  
- 97      @Override
- 98      public void writeTo(OutputStream out) throws IOException {
- 99          Document doc = DocumentHelper.createDocument();
-100  
-101          Element rootNode = doc.addElement(TAG_GRAPHDOC);
-102  
-103          Element metadataNode = rootNode.addElement(TAG_METADATA);
-104  
-105          metadata.write(metadataNode);
-106  
-107          if (graph instanceof Graph) {
-108              writeGraph(rootNode.addElement(TAG_GRAPH));
-109          } else if (graph instanceof Digraph) {
-110              writeGraph(rootNode.addElement(TAG_DIGRAPH));
-111          } else {
-112              throw new IOException("unsupported graph type");
-113          }
-114  
-115          XMLWriter writer = new XMLWriter(out, OutputFormat.createPrettyPrint());
-116          writer.write(doc);
-117          writer.flush();
-118      }
-119  
-120      @Override
-121      public void readFrom(InputStream in) throws IOException {
-122          try {
-123              SAXReader reader = new SAXReader(true);
-124              reader.setStripWhitespaceText(true);
-125              
-126              reader.setFeature(Constants.XERCES_FEATURE_PREFIX+
-127                  Constants.SCHEMA_VALIDATION_FEATURE, true);
-128              reader.setProperty(Constants.XERCES_PROPERTY_PREFIX +
-129                  Constants.SCHEMA_LOCATION, String.format("%s %s",
-130                      NAMESPACE.getURI(), Resources.class.getResource(
-131                          "graph-document.xsd").toExternalForm()));
-132              
-133              final AtomicBoolean passed = new AtomicBoolean(true);
-134              final AtomicReference<SAXParseException> xmlerror = new AtomicReference<>();
-135              // TODO: we should do more detailed error handling here
-136              reader.setErrorHandler(new ErrorHandler() {
-137                  @Override
-138                  public void warning(SAXParseException exception) throws SAXException {
-139                  }
-140  
-141                  @Override
-142                  public void error(SAXParseException exception) throws SAXException {
-143                      xmlerror.set(exception);
-144                      passed.set(false);
-145                  }
-146  
-147                  @Override
-148                  public void fatalError(SAXParseException exception) throws SAXException {
-149                      xmlerror.set(exception);
-150                      passed.set(false);
-151                  }
-152                  
-153              });
-154              Document doc = reader.read(in);
-155              if (!passed.get()) {
-156                  // TODO: provide details (maybe via separate error object?)
-157                  throw xmlerror.get();
-158              }
-159              
-160              doc.normalize();
-161              
-162              Element root = doc.getRootElement();
-163              metadata.read(root.element(TAG_METADATA));
-164              
-165              if (graph instanceof Graph) {
-166                  readGraph(root.element(TAG_GRAPH));
-167              } else if (graph instanceof Digraph) {
-168                  readGraph(root.element(TAG_DIGRAPH));
-169              } else {
-170                  throw new IOException("unsupported graph type");
-171              }
-172          } catch (DocumentException | SAXException ex) {
-173              throw new IOException(ex);
-174          }
-175      }
-176  }
-
- - - diff -r 9f25df78925e -r 1b12cf799fee test/v2-regression/plain.html --- a/test/v2-regression/plain.html Thu Nov 10 18:44:48 2016 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,53 +0,0 @@ - - - - c2html - - - - -
-1  </body>
-2  </html>
-3  <!c
-4  pblock_free(q);
-5  !>
-6  
-
- - -