cdata works

This commit is contained in:
Nishi 2025-12-22 20:44:41 +09:00
commit 1113b2dbe3
Signed by: nishi
GPG key ID: 27EF69B208EB9343
7 changed files with 196 additions and 126 deletions

View file

@ -3,7 +3,7 @@ CFLAGS = -I include -fPIC -g
LDFLAGS = -shared LDFLAGS = -shared
LIBS = 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 SO = .so

View file

@ -2,17 +2,17 @@
#define INDENT 2 #define INDENT 2
void recursive(xmllib_node_t* node, int indent) { void recursive(xl_node_t* node, int indent) {
int i; int i;
xmllib_node_t* n; xl_node_t* n;
for(i = 0; i < indent; i++) printf(" "); 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); printf("<%s>\n", node->name);
if(node->text != NULL) { if(node->text != NULL) {
for(i = 0; i < indent + INDENT; i++) printf(" "); for(i = 0; i < indent + INDENT; i++) printf(" ");
printf("%s\n", node->text); 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("<!--%s-->\n", node->text); printf("<!--%s-->\n", node->text);
} }
@ -22,7 +22,7 @@ void recursive(xmllib_node_t* node, int indent) {
n = n->next; 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(" "); for(i = 0; i < indent; i++) printf(" ");
printf("</%s>\n", node->name); printf("</%s>\n", node->name);
} }
@ -32,17 +32,17 @@ int main(int argc, char** argv) {
int i; int i;
for(i = 1; i < argc; 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) { if(h != NULL) {
printf("%s:\n", argv[i]); printf("%s:\n", argv[i]);
if(xmllib_parse(h)) { if(xl_parse(h)) {
if(h->root != NULL) recursive(h->root, INDENT); if(h->root != NULL) recursive(h->root, INDENT);
} else { } else {
int j; int j;
for(j = 0; j < INDENT; j++) printf(" "); for(j = 0; j < INDENT; j++) printf(" ");
printf("Parse error\n"); printf("Parse error\n");
} }
xmllib_close(h); xl_close(h);
} }
} }
} }

View file

@ -8,42 +8,44 @@
#define XLDECL extern #define XLDECL extern
typedef struct xmllib_driver xmllib_driver_t; typedef struct xl_driver xl_driver_t;
typedef struct xmllib xmllib_t; typedef struct xmllib xmllib_t;
typedef struct xmllib_node xmllib_node_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 (*open)(xmllib_t* handle);
int (*read)(xmllib_t* handle, void* data, int size); int (*read)(xmllib_t* handle, void* data, int size);
void (*close)(xmllib_t* handle); void (*close)(xmllib_t* handle);
}; };
enum XMLLIB_NODE_TYPE { enum XL_NODE_TYPE {
XMLLIB_NODE_COMMENT = 0, XL_NODE_COMMENT = 0,
XMLLIB_NODE_NODE, XL_NODE_NODE,
XMLLIB_NODE_PROCESS, XL_NODE_PROCESS,
XMLLIB_NODE_DOCTYPE XL_NODE_DOCTYPE
}; };
struct xmllib_node { struct xl_node {
int type; int type;
char* name; char* name;
char* text; char* text;
xmllib_node_t* root; xl_node_t* root;
xmllib_node_t* parent; xl_node_t* parent;
xmllib_node_t* first_child; xl_node_t* first_child;
xmllib_node_t* prev; xl_node_t* prev;
xmllib_node_t* next; xl_node_t* next;
}; };
struct xmllib { struct xmllib {
xmllib_driver_t* driver; xl_driver_t* driver;
void* drv_opaque; void* drv_opaque;
void* drv_arg; void* drv_arg;
xmllib_node_t* root; xl_node_t* root;
}; };
#ifdef __cplusplus #ifdef __cplusplus
@ -51,23 +53,26 @@ extern "C" {
#endif #endif
/* core.c */ /* 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 */ /* 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 */ /* 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 #ifdef __cplusplus
} }

View file

@ -2,7 +2,7 @@
#include "../external/stb_ds.h" #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)); xmllib_t* handle = malloc(sizeof(*handle));
memset(handle, 0, sizeof(*handle)); memset(handle, 0, sizeof(*handle));
@ -23,14 +23,15 @@ enum STATES {
STATE_STRING, STATE_STRING,
STATE_SPECIAL, STATE_SPECIAL,
STATE_COMMENT, STATE_COMMENT,
STATE_DOCTYPE, STATE_MISC,
STATE_IGNORE_TAG
}; };
#define TAKE_AS_NODE(x) \ #define TAKE_AS_NODE(x) \
{ \ { \
char* old = node; \ char* old = node; \
char buf[4]; \ 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); \ node = malloc(strlen(old) + new + 1); \
strcpy(node, old); \ strcpy(node, old); \
@ -54,17 +55,15 @@ enum STATES {
longjmp(err, 1); \ longjmp(err, 1); \
} }
#define SKIPPABLE(x) (((x) == ' ') || ((x) == '\t') || ((x) == '\n') || ((x) == '\r'))
#define STATE state[arrlen(state) - 1] #define STATE state[arrlen(state) - 1]
int xmllib_parse(xmllib_t* handle) { int xl_parse(xmllib_t* handle) {
jmp_buf err; jmp_buf err;
int* state = NULL; int* state = NULL;
char* node = NULL; char* node = NULL;
int node_count = 0; int node_count = 0;
int nest_level = 0; int nest_level = 0;
xmllib_node_t* current = NULL; xl_node_t* current = NULL;
if(setjmp(err)) { if(setjmp(err)) {
return 0; return 0;
@ -79,12 +78,12 @@ int xmllib_parse(xmllib_t* handle) {
if(handle->driver->read(handle, &in[0], 1) < 1) ERROR; 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); 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) { if(STATE == STATE_INITIAL) {
arrput(state, STATE_TAG); arrput(state, STATE_TAG);
@ -93,34 +92,51 @@ int xmllib_parse(xmllib_t* handle) {
node_count = 0; node_count = 0;
} else if(STATE == STATE_STRING) { } else if(STATE == STATE_STRING) {
TAKE_AS_NODE(cp); TAKE_AS_NODE(cp);
} else if(STATE == STATE_MISC) {
arrput(state, STATE_IGNORE_TAG);
} else { } else {
ERROR; ERROR;
} }
} else if(cp == '>') { } else if(cp == '>') {
if(STATE == STATE_TAG || STATE == STATE_DOCTYPE || STATE == STATE_COMMENT) { if(STATE == STATE_TAG || STATE == STATE_COMMENT || STATE == STATE_MISC || STATE == STATE_IGNORE_TAG) {
if((STATE != STATE_COMMENT || node[strlen(node) - 1] == '-') && (STATE != STATE_DOCTYPE || node[strlen(node) - 1] == ']')) { if((STATE != STATE_COMMENT || node[strlen(node) - 1] == '-')) {
arrpop(state); arrpop(state);
if(STATE == STATE_INITIAL) { if(STATE == STATE_INITIAL) {
/* parsed tag */ /* parsed tag */
xmllib_node_t* n = NULL; xl_node_t* n = NULL;
xmllib_node_t* targ = NULL; xl_node_t* targ = NULL;
if(node[0] == '!') { if(node[0] == '!') {
/* special tag */ /* special tag */
if(strlen(node) > 1 && node[1] == '-') { if(strlen(node) > 2 && node[1] == '-') {
/* comment */ /* comment */
if(strlen(node) > (3 + 2) && nest_level > 0) { if(strlen(node) > (1 + 3 + 2) && nest_level > 0) {
n = malloc(sizeof(*n)); n = malloc(sizeof(*n));
n->type = XMLLIB_NODE_COMMENT; n->type = XL_NODE_COMMENT;
n->name = NULL; n->name = NULL;
n->text = malloc(strlen(node) + 1); n->text = malloc(strlen(node) + 1);
strcpy(n->text, node + 3); strcpy(n->text, node + 3);
n->text[strlen(n->text) - 2] = 0; 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 { } else {
/* doctype or something - we ignore this for now */ /* doctype or something - we ignore this for now */
} }
@ -130,59 +146,30 @@ int xmllib_parse(xmllib_t* handle) {
/* normal tag */ /* normal tag */
if(node[0] == '/') { if(node[0] == '/') {
/* close tag */ /* close tag */
char* str;
if(nest_level > 0) { if(nest_level > 0) {
if(strcmp(current->name, node + 1) != 0) ERROR; 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; targ = current->parent;
} }
nest_level--; 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 { } else {
int i; int i;
n = malloc(sizeof(*n)); n = malloc(sizeof(*n));
n->type = XMLLIB_NODE_NODE; n->type = XL_NODE_NODE;
n->name = malloc(strlen(node) + 1); n->name = malloc(strlen(node) + 1);
n->text = NULL; n->text = NULL;
@ -190,11 +177,11 @@ int xmllib_parse(xmllib_t* handle) {
i = 0; i = 0;
while(1) { while(1) {
int icp; 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(icp == 0) break;
if(SKIPPABLE(icp)) { if(XL_SKIPPABLE(icp)) {
n->name[i] = 0; n->name[i] = 0;
break; break;
} }
@ -214,7 +201,7 @@ int xmllib_parse(xmllib_t* handle) {
} }
if(n != NULL) { if(n != NULL) {
xmllib_node_t* last = NULL; xl_node_t* last = NULL;
if(handle->root == NULL) handle->root = n; if(handle->root == NULL) handle->root = n;
@ -253,14 +240,14 @@ int xmllib_parse(xmllib_t* handle) {
} else { } else {
ERROR; ERROR;
} }
} else if(cp == '"' && STATE != STATE_COMMENT && STATE != STATE_DOCTYPE) { } else if(cp == '"' && STATE != STATE_COMMENT && STATE != STATE_MISC) {
if(STATE == STATE_TAG) { if(STATE == STATE_TAG) {
arrput(state, STATE_STRING); arrput(state, STATE_STRING);
} else if(STATE == STATE_STRING) { } else if(STATE == STATE_STRING) {
arrpop(state); arrpop(state);
} }
TAKE_AS_NODE(cp); 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 == '!') { if(node_count == 0 && cp == '!') {
arrpop(state); arrpop(state);
arrput(state, STATE_SPECIAL); arrput(state, STATE_SPECIAL);
@ -269,7 +256,7 @@ int xmllib_parse(xmllib_t* handle) {
arrput(state, STATE_COMMENT); arrput(state, STATE_COMMENT);
} else if(node_count == 1 && STATE == STATE_SPECIAL) { } else if(node_count == 1 && STATE == STATE_SPECIAL) {
arrpop(state); arrpop(state);
arrput(state, STATE_DOCTYPE); arrput(state, STATE_MISC);
} }
TAKE_AS_NODE(cp); TAKE_AS_NODE(cp);
} else if(STATE == STATE_INITIAL) { } else if(STATE == STATE_INITIAL) {
@ -277,7 +264,7 @@ int xmllib_parse(xmllib_t* handle) {
char* old = current->text; char* old = current->text;
if(old != NULL) { if(old != NULL) {
char buf[4]; 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); current->text = malloc(strlen(old) + new + 1);
strcpy(current->text, old); strcpy(current->text, old);
@ -285,9 +272,9 @@ int xmllib_parse(xmllib_t* handle) {
current->text[strlen(old) + new] = 0; current->text[strlen(old) + new] = 0;
free(old); free(old);
} else if(!SKIPPABLE(cp)) { } else {
char buf[4]; 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); current->text = malloc(new + 1);
memcpy(current->text, &buf[0], new); memcpy(current->text, &buf[0], new);
@ -304,8 +291,8 @@ int xmllib_parse(xmllib_t* handle) {
return 1; return 1;
} }
void recursive_free(xmllib_node_t* node) { void recursive_free(xl_node_t* node) {
xmllib_node_t* n = node->first_child; xl_node_t* n = node->first_child;
while(n != NULL) { while(n != NULL) {
recursive_free(n); recursive_free(n);
@ -317,8 +304,8 @@ void recursive_free(xmllib_node_t* node) {
free(node); free(node);
} }
void xmllib_close(xmllib_t* handle) { void xl_close(xmllib_t* handle) {
recursive_free(handle->root); if(handle->root != NULL) recursive_free(handle->root);
handle->driver->close(handle); handle->driver->close(handle);
free(handle); free(handle);

View file

@ -1,26 +1,26 @@
#include <xmllib.h> #include <xmllib.h>
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; if((handle->drv_opaque = fopen(handle->drv_arg, "rb")) == NULL) return 0;
return 1; 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); 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); fclose(handle->drv_opaque);
} }
xmllib_driver_t xmllib_driver_file_rec = { xl_driver_t xl_driver_file_rec = {
xmllib_driver_file_open, xl_driver_file_open,
xmllib_driver_file_read, xl_driver_file_read,
xmllib_driver_file_close, 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) { xmllib_t* xl_open_file(const char* filename) {
return xmllib_open(xmllib_driver_file, (void*)filename); return xl_open(xl_driver_file, (void*)filename);
} }

View file

@ -2,7 +2,7 @@
#define CAST_I32(x) ((int)(x)) #define CAST_I32(x) ((int)(x))
int xmllib_unicode_count(unsigned char c) { int xl_unicode_count(unsigned char c) {
if(c < 0x80) { if(c < 0x80) {
return 1; return 1;
} }
@ -22,9 +22,9 @@ static int unicode_later(unsigned char c) {
return 0x80 <= c && c < 0xc0; 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; 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 == 0) return 0;
if(b == 1) *output = inbuf[0]; if(b == 1) *output = inbuf[0];
@ -56,7 +56,7 @@ int xmllib_unicode_8_to_32(const char* input, int* output) {
return b; 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) { if(input < 128) {
output[0] = input; output[0] = input;
return 1; return 1;

78
src/util.c Normal file
View file

@ -0,0 +1,78 @@
#include <xmllib.h>
#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;
}