cdata works
This commit is contained in:
parent
54806705c5
commit
1113b2dbe3
7 changed files with 196 additions and 126 deletions
2
Makefile
2
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
|
||||
|
||||
|
|
|
|||
18
example.c
18
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("<!--%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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
137
src/core.c
137
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);
|
||||
|
|
|
|||
20
src/file.c
20
src/file.c
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
78
src/util.c
Normal 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;
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue