From 1113b2dbe3020790c70c01049b1e58c9df55a151 Mon Sep 17 00:00:00 2001 From: NishiOwO Date: Mon, 22 Dec 2025 20:44:41 +0900 Subject: [PATCH] cdata works --- Makefile | 2 +- example.c | 18 +++---- include/xmllib.h | 59 ++++++++++---------- src/core.c | 137 +++++++++++++++++++++-------------------------- src/file.c | 20 +++---- src/unicode.c | 8 +-- src/util.c | 78 +++++++++++++++++++++++++++ 7 files changed, 196 insertions(+), 126 deletions(-) create mode 100644 src/util.c diff --git a/Makefile b/Makefile index cb01247..c73182a 100644 --- a/Makefile +++ b/Makefile @@ -3,7 +3,7 @@ CFLAGS = -I include -fPIC -g LDFLAGS = -shared LIBS = -OBJS = src/core.o src/file.o src/unicode.o src/stb_ds.o +OBJS = src/core.o src/file.o src/unicode.o src/util.o src/stb_ds.o SO = .so diff --git a/example.c b/example.c index be3e603..31e6474 100644 --- a/example.c +++ b/example.c @@ -2,17 +2,17 @@ #define INDENT 2 -void recursive(xmllib_node_t* node, int indent) { - int i; - xmllib_node_t* n; +void recursive(xl_node_t* node, int indent) { + int i; + xl_node_t* n; for(i = 0; i < indent; i++) printf(" "); - if(node->name != NULL && node->type == XMLLIB_NODE_NODE) { + if(node->name != NULL && node->type == XL_NODE_NODE) { printf("<%s>\n", node->name); if(node->text != NULL) { for(i = 0; i < indent + INDENT; i++) printf(" "); printf("%s\n", node->text); } - } else if(node->text != NULL && node->type == XMLLIB_NODE_COMMENT) { + } else if(node->text != NULL && node->type == XL_NODE_COMMENT) { printf("\n", node->text); } @@ -22,7 +22,7 @@ void recursive(xmllib_node_t* node, int indent) { n = n->next; } - if(node->name != NULL && node->type == XMLLIB_NODE_NODE) { + if(node->name != NULL && node->type == XL_NODE_NODE) { for(i = 0; i < indent; i++) printf(" "); printf("\n", node->name); } @@ -32,17 +32,17 @@ int main(int argc, char** argv) { int i; for(i = 1; i < argc; i++) { - xmllib_t* h = xmllib_open_file(argv[i]); + xmllib_t* h = xl_open_file(argv[i]); if(h != NULL) { printf("%s:\n", argv[i]); - if(xmllib_parse(h)) { + if(xl_parse(h)) { if(h->root != NULL) recursive(h->root, INDENT); } else { int j; for(j = 0; j < INDENT; j++) printf(" "); printf("Parse error\n"); } - xmllib_close(h); + xl_close(h); } } } diff --git a/include/xmllib.h b/include/xmllib.h index acd82d6..efd1d50 100644 --- a/include/xmllib.h +++ b/include/xmllib.h @@ -8,42 +8,44 @@ #define XLDECL extern -typedef struct xmllib_driver xmllib_driver_t; -typedef struct xmllib xmllib_t; -typedef struct xmllib_node xmllib_node_t; +typedef struct xl_driver xl_driver_t; +typedef struct xmllib xmllib_t; +typedef struct xl_node xl_node_t; -struct xmllib_driver { +#define XL_SKIPPABLE(x) (((x) == ' ') || ((x) == '\t') || ((x) == '\n') || ((x) == '\r')) + +struct xl_driver { int (*open)(xmllib_t* handle); int (*read)(xmllib_t* handle, void* data, int size); void (*close)(xmllib_t* handle); }; -enum XMLLIB_NODE_TYPE { - XMLLIB_NODE_COMMENT = 0, - XMLLIB_NODE_NODE, - XMLLIB_NODE_PROCESS, - XMLLIB_NODE_DOCTYPE +enum XL_NODE_TYPE { + XL_NODE_COMMENT = 0, + XL_NODE_NODE, + XL_NODE_PROCESS, + XL_NODE_DOCTYPE }; -struct xmllib_node { +struct xl_node { int type; char* name; char* text; - xmllib_node_t* root; - xmllib_node_t* parent; + xl_node_t* root; + xl_node_t* parent; - xmllib_node_t* first_child; + xl_node_t* first_child; - xmllib_node_t* prev; - xmllib_node_t* next; + xl_node_t* prev; + xl_node_t* next; }; struct xmllib { - xmllib_driver_t* driver; - void* drv_opaque; - void* drv_arg; - xmllib_node_t* root; + xl_driver_t* driver; + void* drv_opaque; + void* drv_arg; + xl_node_t* root; }; #ifdef __cplusplus @@ -51,23 +53,26 @@ extern "C" { #endif /* core.c */ -XLDECL xmllib_t* xmllib_open(xmllib_driver_t* driver, void* arg); +XLDECL xmllib_t* xl_open(xl_driver_t* driver, void* arg); -XLDECL int xmllib_parse(xmllib_t* handle); +XLDECL int xl_parse(xmllib_t* handle); -XLDECL void xmllib_close(xmllib_t* handle); +XLDECL void xl_close(xmllib_t* handle); /* file.c */ -XLDECL xmllib_driver_t* xmllib_driver_file; +XLDECL xl_driver_t* xl_driver_file; -XLDECL xmllib_t* xmllib_open_file(const char* filename); +XLDECL xmllib_t* xl_open_file(const char* filename); + +/* util.c */ +XLDECL char* xl_util_trim(const char* str); /* unicode.c */ -XLDECL int xmllib_unicode_count(unsigned char c); +XLDECL int xl_unicode_count(unsigned char c); -XLDECL int xmllib_unicode_8_to_32(const char* input, int* output); +XLDECL int xl_unicode_8_to_32(const char* input, int* output); -XLDECL int xmllib_unicode_32_to_8(const int input, char* output); +XLDECL int xl_unicode_32_to_8(const int input, char* output); #ifdef __cplusplus } diff --git a/src/core.c b/src/core.c index c3ea6b5..0ff3876 100644 --- a/src/core.c +++ b/src/core.c @@ -2,7 +2,7 @@ #include "../external/stb_ds.h" -xmllib_t* xmllib_open(xmllib_driver_t* driver, void* arg) { +xmllib_t* xl_open(xl_driver_t* driver, void* arg) { xmllib_t* handle = malloc(sizeof(*handle)); memset(handle, 0, sizeof(*handle)); @@ -23,14 +23,15 @@ enum STATES { STATE_STRING, STATE_SPECIAL, STATE_COMMENT, - STATE_DOCTYPE, + STATE_MISC, + STATE_IGNORE_TAG }; #define TAKE_AS_NODE(x) \ { \ char* old = node; \ char buf[4]; \ - int new = xmllib_unicode_32_to_8((x), &buf[0]); \ + int new = xl_unicode_32_to_8((x), &buf[0]); \ \ node = malloc(strlen(old) + new + 1); \ strcpy(node, old); \ @@ -54,17 +55,15 @@ enum STATES { longjmp(err, 1); \ } -#define SKIPPABLE(x) (((x) == ' ') || ((x) == '\t') || ((x) == '\n') || ((x) == '\r')) - #define STATE state[arrlen(state) - 1] -int xmllib_parse(xmllib_t* handle) { - jmp_buf err; - int* state = NULL; - char* node = NULL; - int node_count = 0; - int nest_level = 0; - xmllib_node_t* current = NULL; +int xl_parse(xmllib_t* handle) { + jmp_buf err; + int* state = NULL; + char* node = NULL; + int node_count = 0; + int nest_level = 0; + xl_node_t* current = NULL; if(setjmp(err)) { return 0; @@ -79,12 +78,12 @@ int xmllib_parse(xmllib_t* handle) { if(handle->driver->read(handle, &in[0], 1) < 1) ERROR; - c = xmllib_unicode_count(in[0]); + c = xl_unicode_count(in[0]); if((c > 1) && handle->driver->read(handle, &in[1], c - 1) < (c - 1)) longjmp(err, 1); - xmllib_unicode_8_to_32(in, &cp); + xl_unicode_8_to_32(in, &cp); - if(cp == '<' && STATE != STATE_COMMENT && STATE != STATE_DOCTYPE) { + if(cp == '<' && STATE != STATE_COMMENT) { if(STATE == STATE_INITIAL) { arrput(state, STATE_TAG); @@ -93,34 +92,51 @@ int xmllib_parse(xmllib_t* handle) { node_count = 0; } else if(STATE == STATE_STRING) { TAKE_AS_NODE(cp); + } else if(STATE == STATE_MISC) { + arrput(state, STATE_IGNORE_TAG); } else { ERROR; } } else if(cp == '>') { - if(STATE == STATE_TAG || STATE == STATE_DOCTYPE || STATE == STATE_COMMENT) { - if((STATE != STATE_COMMENT || node[strlen(node) - 1] == '-') && (STATE != STATE_DOCTYPE || node[strlen(node) - 1] == ']')) { + if(STATE == STATE_TAG || STATE == STATE_COMMENT || STATE == STATE_MISC || STATE == STATE_IGNORE_TAG) { + if((STATE != STATE_COMMENT || node[strlen(node) - 1] == '-')) { arrpop(state); if(STATE == STATE_INITIAL) { /* parsed tag */ - xmllib_node_t* n = NULL; - xmllib_node_t* targ = NULL; + xl_node_t* n = NULL; + xl_node_t* targ = NULL; if(node[0] == '!') { /* special tag */ - if(strlen(node) > 1 && node[1] == '-') { + if(strlen(node) > 2 && node[1] == '-') { /* comment */ - if(strlen(node) > (3 + 2) && nest_level > 0) { + if(strlen(node) > (1 + 3 + 2) && nest_level > 0) { n = malloc(sizeof(*n)); - n->type = XMLLIB_NODE_COMMENT; + n->type = XL_NODE_COMMENT; n->name = NULL; n->text = malloc(strlen(node) + 1); strcpy(n->text, node + 3); n->text[strlen(n->text) - 2] = 0; } + } else if(strlen(node) > 8 && memcmp(&node[1], "[CDATA[", 7) == 0 && node[strlen(node) - 1] == ']' && node[strlen(node) - 2] == ']') { + char* old = current->text; + + if(old == NULL) { + current->text = malloc(strlen(node)); + strcpy(current->text, node + 8); + } else { + current->text = malloc(strlen(old) + strlen(node)); + strcpy(current->text, old); + strcpy(current->text + strlen(old), node + 8); + free(old); + } + if(strlen(current->text) > 2) { + current->text[strlen(current->text) - 2] = 0; + } } else { /* doctype or something - we ignore this for now */ } @@ -130,59 +146,30 @@ int xmllib_parse(xmllib_t* handle) { /* normal tag */ if(node[0] == '/') { /* close tag */ + char* str; if(nest_level > 0) { if(strcmp(current->name, node + 1) != 0) ERROR; - if(current->text != NULL) { - int i, inc; - int* l = NULL; - char* txt = current->text; - - i = 0; - while(1) { - int icp; - int nb = xmllib_unicode_8_to_32(txt + i, &icp); - - if(icp == 0) break; - - arrput(l, nb); - - i += nb; - } - - inc = strlen(txt); - i = arrlen(l) - 1; - while(1) { - int icp; - int nb; - - inc -= l[i]; - - nb = xmllib_unicode_8_to_32(txt + inc, &icp); - - if(SKIPPABLE(icp)) { - txt[inc] = 0; - } else { - break; - } - - i--; - } - - arrfree(l); - } - targ = current->parent; } nest_level--; + + str = xl_util_trim(current->text); + free(current->text); + current->text = str; + + if(strlen(current->text) == 0) { + free(current->text); + current->text = NULL; + } } else { int i; n = malloc(sizeof(*n)); - n->type = XMLLIB_NODE_NODE; + n->type = XL_NODE_NODE; n->name = malloc(strlen(node) + 1); n->text = NULL; @@ -190,11 +177,11 @@ int xmllib_parse(xmllib_t* handle) { i = 0; while(1) { int icp; - int nb = xmllib_unicode_8_to_32(n->name + i, &icp); + int nb = xl_unicode_8_to_32(n->name + i, &icp); if(icp == 0) break; - if(SKIPPABLE(icp)) { + if(XL_SKIPPABLE(icp)) { n->name[i] = 0; break; } @@ -214,7 +201,7 @@ int xmllib_parse(xmllib_t* handle) { } if(n != NULL) { - xmllib_node_t* last = NULL; + xl_node_t* last = NULL; if(handle->root == NULL) handle->root = n; @@ -253,14 +240,14 @@ int xmllib_parse(xmllib_t* handle) { } else { ERROR; } - } else if(cp == '"' && STATE != STATE_COMMENT && STATE != STATE_DOCTYPE) { + } else if(cp == '"' && STATE != STATE_COMMENT && STATE != STATE_MISC) { if(STATE == STATE_TAG) { arrput(state, STATE_STRING); } else if(STATE == STATE_STRING) { arrpop(state); } TAKE_AS_NODE(cp); - } else if(STATE == STATE_TAG || STATE == STATE_STRING || STATE == STATE_SPECIAL || STATE == STATE_COMMENT || STATE == STATE_DOCTYPE) { + } else if(STATE == STATE_TAG || STATE == STATE_STRING || STATE == STATE_SPECIAL || STATE == STATE_COMMENT || STATE == STATE_MISC || STATE == STATE_IGNORE_TAG) { if(node_count == 0 && cp == '!') { arrpop(state); arrput(state, STATE_SPECIAL); @@ -269,7 +256,7 @@ int xmllib_parse(xmllib_t* handle) { arrput(state, STATE_COMMENT); } else if(node_count == 1 && STATE == STATE_SPECIAL) { arrpop(state); - arrput(state, STATE_DOCTYPE); + arrput(state, STATE_MISC); } TAKE_AS_NODE(cp); } else if(STATE == STATE_INITIAL) { @@ -277,7 +264,7 @@ int xmllib_parse(xmllib_t* handle) { char* old = current->text; if(old != NULL) { char buf[4]; - int new = xmllib_unicode_32_to_8(cp, &buf[0]); + int new = xl_unicode_32_to_8(cp, &buf[0]); current->text = malloc(strlen(old) + new + 1); strcpy(current->text, old); @@ -285,9 +272,9 @@ int xmllib_parse(xmllib_t* handle) { current->text[strlen(old) + new] = 0; free(old); - } else if(!SKIPPABLE(cp)) { + } else { char buf[4]; - int new = xmllib_unicode_32_to_8(cp, &buf[0]); + int new = xl_unicode_32_to_8(cp, &buf[0]); current->text = malloc(new + 1); memcpy(current->text, &buf[0], new); @@ -304,8 +291,8 @@ int xmllib_parse(xmllib_t* handle) { return 1; } -void recursive_free(xmllib_node_t* node) { - xmllib_node_t* n = node->first_child; +void recursive_free(xl_node_t* node) { + xl_node_t* n = node->first_child; while(n != NULL) { recursive_free(n); @@ -317,8 +304,8 @@ void recursive_free(xmllib_node_t* node) { free(node); } -void xmllib_close(xmllib_t* handle) { - recursive_free(handle->root); +void xl_close(xmllib_t* handle) { + if(handle->root != NULL) recursive_free(handle->root); handle->driver->close(handle); free(handle); diff --git a/src/file.c b/src/file.c index 35de8e7..8ed994d 100644 --- a/src/file.c +++ b/src/file.c @@ -1,26 +1,26 @@ #include -static int xmllib_driver_file_open(xmllib_t* handle) { +static int xl_driver_file_open(xmllib_t* handle) { if((handle->drv_opaque = fopen(handle->drv_arg, "rb")) == NULL) return 0; return 1; } -static int xmllib_driver_file_read(xmllib_t* handle, void* data, int size) { +static int xl_driver_file_read(xmllib_t* handle, void* data, int size) { return fread(data, 1, size, handle->drv_opaque); } -static void xmllib_driver_file_close(xmllib_t* handle) { +static void xl_driver_file_close(xmllib_t* handle) { fclose(handle->drv_opaque); } -xmllib_driver_t xmllib_driver_file_rec = { - xmllib_driver_file_open, - xmllib_driver_file_read, - xmllib_driver_file_close, +xl_driver_t xl_driver_file_rec = { + xl_driver_file_open, + xl_driver_file_read, + xl_driver_file_close, }; -xmllib_driver_t* xmllib_driver_file = &xmllib_driver_file_rec; +xl_driver_t* xl_driver_file = &xl_driver_file_rec; -xmllib_t* xmllib_open_file(const char* filename) { - return xmllib_open(xmllib_driver_file, (void*)filename); +xmllib_t* xl_open_file(const char* filename) { + return xl_open(xl_driver_file, (void*)filename); } diff --git a/src/unicode.c b/src/unicode.c index 0a68603..20b44db 100644 --- a/src/unicode.c +++ b/src/unicode.c @@ -2,7 +2,7 @@ #define CAST_I32(x) ((int)(x)) -int xmllib_unicode_count(unsigned char c) { +int xl_unicode_count(unsigned char c) { if(c < 0x80) { return 1; } @@ -22,9 +22,9 @@ static int unicode_later(unsigned char c) { return 0x80 <= c && c < 0xc0; } -int xmllib_unicode_8_to_32(const char* input, int* output) { +int xl_unicode_8_to_32(const char* input, int* output) { const unsigned char* inbuf = (const unsigned char*)input; - int b = xmllib_unicode_count(inbuf[0]); + int b = xl_unicode_count(inbuf[0]); if(b == 0) return 0; if(b == 1) *output = inbuf[0]; @@ -56,7 +56,7 @@ int xmllib_unicode_8_to_32(const char* input, int* output) { return b; } -int xmllib_unicode_32_to_8(const int input, char* output) { +int xl_unicode_32_to_8(const int input, char* output) { if(input < 128) { output[0] = input; return 1; diff --git a/src/util.c b/src/util.c new file mode 100644 index 0000000..e98af0b --- /dev/null +++ b/src/util.c @@ -0,0 +1,78 @@ +#include + +#include "../external/stb_ds.h" + +char* xl_util_trim(const char* str) { + char* s = malloc(strlen(str) + 1); + int nl = 1; + int i; + int inc = 0; + int* l = NULL; + + s[0] = 0; + + i = 0; + while(1) { + int cp; + int new = xl_unicode_8_to_32(str + i, &cp); + int len = 0; + char buf[4]; + + if(cp == 0) break; + + if(!nl && cp == '\n') { + len = xl_unicode_32_to_8(cp, &buf[0]); + + nl = 1; + } else if(nl && XL_SKIPPABLE(cp)) { + } else { + len = xl_unicode_32_to_8(cp, &buf[0]); + nl = 0; + } + + if(len > 0) { + memcpy(s + inc, buf, len); + inc += len; + } + + i += new; + } + + s[inc] = 0; + + i = 0; + while(1) { + int cp; + int new = xl_unicode_8_to_32(s + i, &cp); + + if(cp == 0) break; + + arrput(l, new); + + i += new; + } + + i = strlen(s); + inc = arrlen(l) - 1; + if(inc > 0) { + while(1) { + int cp, new; + + i -= l[inc]; + new = xl_unicode_8_to_32(s + i, &cp); + + if(XL_SKIPPABLE(cp)) { + s[i] = 0; + } else { + break; + } + + inc--; + if(inc < 0) break; + } + } + + arrfree(l); + + return s; +}