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
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

View file

@ -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("<!--%s-->\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("</%s>\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);
}
}
}

View file

@ -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
}

View file

@ -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);

View file

@ -1,26 +1,26 @@
#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;
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);
}

View file

@ -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;

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;
}