30 #if defined(WIN32) || defined(_WIN32)
41 #if !defined(WIN32) && !defined(_WIN32)
45 #include <sys/types.h>
56 #if defined(WIN32) || defined(_WIN32)
57 #define snprintf _snprintf
64 #define EZXML_WS "\t\r\n "
73 static int ezxml_ent_ok(
char *name,
char *s,
char **ent);
80 size_t * dlen,
size_t *
max,
short a);
82 size_t start,
char ***attr);
86 xml = (xml) ? xml->
child : NULL;
87 while (xml && strcmp(name, xml->
name))
95 for (; xml && idx; idx--)
106 if (!xml || !xml->
attr)
108 while (xml->
attr[i] && strcmp(attr, xml->
attr[i]))
111 return xml->
attr[i + 1];
115 for (i = 0; root->
attr[i] && strcmp(xml->
name, root->
attr[i][0]); i++)
119 while (root->
attr[i][j] && strcmp(attr, root->
attr[i][j]))
121 return (root->
attr[i][j]) ? root->
attr[i][j + 1] : NULL;
126 char *name = va_arg(ap,
char *);
130 idx = va_arg(ap,
int);
164 while (root->
pi[i] && strcmp(target, root->
pi[i][0]))
175 for (t = root->
s; t < s; t++)
178 snprintf(fmt,
EZXML_ERRL,
"[error near line %d]: %s", line, err);
196 char *e, *r = s, *m = s;
203 memmove(s, (s + 1), strlen(s));
209 while (*s && *s !=
'&' && (*s !=
'%' || t !=
'%') && !isspace(*s))
213 else if (t !=
'c' && !strncmp(s,
"&#", 2)) {
215 c = strtol(s + 3, &e, 16);
217 c = strtol(s + 2, &e, 10);
218 if (!c || *e !=
';') {
226 for (b = 0, d = c; d; d /= 2)
229 *(s++) = (
char)((0xFF << (7 - b)) | (c >> (6 * b)));
231 *(s++) = 0x80 | ((c >> (6 * --b)) & 0x3F);
234 memmove(s, strchr(s,
';') + 1, strlen(strchr(s,
';')));
235 }
else if ((*s ==
'&' && (t ==
'&' || t ==
' ' || t ==
'*'))
236 || (*s ==
'%' && t ==
'%')) {
237 for (b = 0; ent[b] && strncmp(s + 1, ent[b], strlen(ent[b])); b +=
242 if ((c = strlen(ent[b])) - 1 > (e = strchr(s,
';')) - s) {
243 l = (d = (s - r)) + c + strlen(e);
244 r = (r == m) ? strcpy((
char*)malloc(l), r) : (
char*)realloc(r, l);
245 e = strchr((s = r + d),
';');
248 memmove(s + c, e + 1, strlen(e));
249 strncpy(s, ent[b], c);
252 }
else if ((t ==
' ' || t ==
'*') && isspace(*s))
259 for (s = r; *s; s++) {
263 memmove(s, s + l, strlen(s + l) + 1);
264 while (*s && *s !=
' ')
267 if (--s >= r && *s ==
' ')
291 size_t len,
char t) {
296 if (!xml || !xml->
name || !len)
306 ? (
char*)realloc(xml->
txt, (l = strlen(xml->
txt)) + len) : strcpy((
char*)malloc((l =
307 strlen(xml->
txt)) + len), xml->
txt);
308 strcpy(xml->
txt + l, s);
320 return ezxml_err(root, s,
"unexpected closing tag </%s>", name);
332 while (*s && *s !=
'&')
336 if (!strncmp(s + 1, name, strlen(name)))
338 for (i = 0; ent[i] && strncmp(ent[i], s + 1, strlen(ent[i])); i += 2)
356 if (!strcmp(target,
"xml")) {
358 s = strstr(s,
"standalone");
359 if (s && !strncmp(s + strspn(s + 10,
EZXML_WS "='\"") + 10,
"yes", 3))
365 *(root->
pi = (
char***)malloc(
sizeof(
char **))) = NULL;
367 while (root->
pi[i] && strcmp(target, root->
pi[i][0]))
370 root->
pi = (
char***)realloc(root->
pi,
sizeof(
char **) * (i + 2));
371 root->
pi[i] = (
char**)malloc(
sizeof(
char *) * 3);
372 root->
pi[i][0] = target;
373 root->
pi[i][1] = (
char *) (root->
pi[i + 1] = NULL);
378 while (root->
pi[i][j])
380 root->
pi[i] = (
char**)realloc(root->
pi[i],
sizeof(
char *) * (j + 3));
381 root->
pi[i][j + 2] = (
char*)realloc(root->
pi[i][j + 1], j + 1);
382 strcpy(root->
pi[i][j + 2] + j - 1, (root->
xml.
name) ?
">" :
"<");
383 root->
pi[i][j + 1] = NULL;
391 char q, *c, *t, *n = NULL, *v, **ent, **pe;
392 char temp[] = {
'\0',
'\0',
'\0'};
397 for (s[len] =
'\0'; s;) {
398 while (*s && *s !=
'<' && *s !=
'%')
403 else if (!strncmp(s,
"<!ENTITY", 8)) {
404 c = s += strspn(s + 8,
EZXML_WS) + 8;
406 *(s = n + strcspn(n,
EZXML_WS)) =
';';
408 v = s + strspn(s + 1,
EZXML_WS) + 1;
409 if ((q = *(v++)) !=
'"' && q !=
'\'') {
414 for (i = 0, ent = (*c ==
'%') ? pe : root->
ent; ent[i]; i++)
416 ent = (
char**)realloc(ent, (i + 3) *
sizeof(
char *));
432 ezxml_err(root, v,
"circular entity declaration &%s", n);
436 }
else if (!strncmp(s,
"<!ATTLIST", 9)) {
437 t = s + strspn(s + 9,
EZXML_WS) + 9;
439 ezxml_err(root, t,
"unclosed <!ATTLIST");
442 if (*(s = t + strcspn(t,
EZXML_WS ">")) ==
'>')
446 for (i = 0; root->
attr[i] && strcmp(n, root->
attr[i][0]); i++)
450 while (*(n = s + strspn(s,
EZXML_WS)) && *n !=
'>') {
451 if (*(s = n + strcspn(n,
EZXML_WS)))
454 ezxml_err(root, t,
"malformed <!ATTLIST");
459 if ((strncmp(s,
"CDATA", 5))) {
465 if (!strncmp(s,
"NOTATION", 8))
467 s = (*s ==
'(') ? strchr(s,
')') : s + strcspn(s,
EZXML_WS);
469 ezxml_err(root, t,
"malformed <!ATTLIST");
474 if (!strncmp(s,
"#FIXED", 6))
483 s = strchr(v = s + 1, *s);
484 if ((*s ==
'"' || *s ==
'\'') &&
488 ezxml_err(root, t,
"malformed <!ATTLIST");
493 if (!root->
attr[i]) {
495 (!i) ? (
char***)malloc(2 *
sizeof(
char **)) : (
char***)realloc(
497 (i + 2) *
sizeof(
char **));
498 root->
attr[i] = (
char**)malloc(2 *
sizeof(
char *));
499 root->
attr[i][0] = t;
500 root->
attr[i][1] = (
char *) (root->
attr[i + 1] = NULL);
503 for (j = 1; root->
attr[i][j]; j += 3)
505 root->
attr[i] = (
char**)realloc(root->
attr[i],
506 (j + 4) *
sizeof(
char *));
508 root->
attr[i][j + 3] = NULL;
509 root->
attr[i][j + 2] = c;
510 root->
attr[i][j + 1] =
512 root->
attr[i][j] = n;
516 }
else if (!strncmp(s,
"<!--", 4)) {
517 s = strstr(s + 4,
"-->");
519 else if (!strncmp(s,
"<?", 2)) {
521 s = strstr(c = s + 2,
"?>");
524 }
else if (*s ==
'<')
539 size_t l = 0, sl,
max = *len;
541 int b, be = (**s ==
'\xFE') ? 1 : (**s ==
'\xFF') ? 0 : -1;
546 u = (
char*)malloc(max);
547 for (sl = 2; sl < *len - 1; sl += 2) {
548 c = (be) ? (((*s)[sl] & 0xFF) << 8) | ((*s)[sl + 1] & 0xFF)
550 (((*s)[sl + 1] & 0xFF) << 8) | ((*s)[sl] & 0xFF);
551 if (c >= 0xD800 && c <= 0xDFFF && (sl += 2) < *len - 1) {
553 (((*s)[sl] & 0xFF) << 8) | ((*s)[sl + 1] & 0xFF) :
554 (((*s)[sl + 1] & 0xFF) << 8) | ((*s)[sl] & 0xFF);
555 c = (((c & 0x3FF) << 10) | (d & 0x3FF)) + 0x10000;
563 for (b = 0, d = c; d; d /= 2)
566 u[l++] = (char)((0xFF << (7 - b)) | (c >> (6 * b)));
568 u[l++] = 0x80 | ((c >> (6 * --b)) & 0x3F);
571 return *s = (
char*)realloc(u, *len = l);
584 for (i = 0; m[i]; i++) {
588 free(attr[(i * 2) + 1]);
598 char q, e, *d, *temp, **attr, **a = NULL;
604 return ezxml_err(root, NULL,
"root tag missing");
606 root->
e = (root->
s = s) + len;
611 while (*s && *s !=
'<')
614 return ezxml_err(root, s,
"root tag missing");
620 if (isalpha(*s) || *s ==
'_' || *s ==
':' || *s <
'\0') {
622 return ezxml_err(root, d,
"markup outside of root element");
625 while (isspace(*s)) {
631 if (*s && *s !=
'/' && *s !=
'>') {
634 for (i = 0; a && strcmp(a[0], d); i++) {
639 for (l = 0; *s && *s !=
'/' && *s !=
'>'; l += 2) {
641 (
char**)realloc(attr, (l + 4) *
sizeof(
char *)) :
642 (
char**)malloc(4 *
sizeof(
char *));
644 (l) ? (
char*)realloc(attr[l + 1], (l / 2) + 2) : (
char*)malloc(2);
645 strcpy(attr[l + 3] + (l / 2),
" ");
651 if (*s ==
'=' || isspace(*s)) {
655 q = *(s += strspn(s,
EZXML_WS "="));
656 if (q ==
'"' || q ==
'\'') {
658 while (*s && *s != q)
664 return ezxml_err(root, d,
"missing %c", q);
667 for (j = 1; a && a[j] && strcmp(a[j], attr[l]); j += 3)
670 root->
ent, (a && a[j]) ? *a[j + 2] :
' ');
671 if (attr[l + 1] < d || attr[l + 1] > s)
675 while (isspace(*s)) {
684 if ((*s && *s !=
'>') || (!*s && e !=
'>')) {
691 }
else if ((q = *s) ==
'>' || (!*s && e ==
'>')) {
700 }
else if (*s ==
'/') {
701 s += strcspn(d = s + 1,
EZXML_WS ">") + 1;
709 if (isspace(*s = q)) {
714 }
else if (!strncmp(s,
"!--", 3)) {
716 s = strstr(s + 3,
"--");
717 if (!s || (*(s += 2) !=
'>' && *s) || (!*s && e !=
'>'))
718 return ezxml_err(root, d,
"unclosed <!--");
719 while (temp != s && *temp !=
'\0') {
725 }
else if (!strncmp(s,
"![CDATA[", 8)) {
727 s = strstr(s,
"]]>");
731 return ezxml_err(root, d,
"unclosed <![CDATA[");
732 }
else if (!strncmp(s,
"!DOCTYPE", 8)) {
735 && ((!l && *s !=
'>')
742 l = (*s ==
'[') ? 1 : l)
743 s += strcspn(s + 1,
"[]>") + 1;
745 return ezxml_err(root, d,
"unclosed <!DOCTYPE");
746 d = (l) ? strchr(d,
'[') + 1 : d;
749 }
else if (*s ==
'?') {
752 }
while (s && *(++s) && *s !=
'>');
753 if (!s || (!*s && e !=
'>'))
754 return ezxml_err(root, d,
"unclosed <?");
758 return ezxml_err(root, d,
"unexpected <");
764 if (*s && *s !=
'<') {
765 while (*s && *s !=
'<') {
782 return ezxml_err(root, d,
"root tag missing");
809 root->
len = (size_t) (-1);
827 l = (st.st_size + sysconf(_SC_PAGESIZE) - 1) & ~(sysconf(_SC_PAGESIZE) - 1);
828 if ((m = mmap(NULL, l, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0))
830 madvise(m, l, MADV_SEQUENTIAL);
832 madvise(m, root->
len = l, MADV_NORMAL);
835 l = read(fd, m = malloc(st.st_size), st.st_size);
838 root->
len = (size_t) (-1);
847 int fd = open(file, O_RDONLY, 0);
859 size_t *
max,
short a) {
862 for (e = s + len; s != e; s++) {
863 while (*dlen + 10 > *max)
870 *dlen += sprintf(*dst + *dlen,
"&");
873 *dlen += sprintf(*dst + *dlen,
"<");
876 *dlen += sprintf(*dst + *dlen,
">");
879 *dlen += sprintf(*dst + *dlen, (a) ?
""" :
"\"");
882 *dlen += sprintf(*dst + *dlen, (a) ?
"
" :
"\n");
885 *dlen += sprintf(*dst + *dlen, (a) ?
"	" :
"\t");
888 *dlen += sprintf(*dst + *dlen,
"
");
891 (*dst)[(*dlen)++] = *s;
910 while (*len + strlen(xml->
name) + 4 > *
max)
913 *len += sprintf(*s + *len,
"<%s", xml->
name);
914 for (i = 0; xml->
attr[i]; i += 2) {
917 while (*len + strlen(xml->
attr[i]) + 7 > *max)
920 *len += sprintf(*s + *len,
" %s=\"", xml->
attr[i]);
923 *len += sprintf(*s + *len,
"\"");
926 for (i = 0; attr[i] && strcmp(attr[i][0], xml->
name); i++)
928 for (j = 1; attr[i] && attr[i][j]; j += 3) {
929 if (!attr[i][j + 1] ||
ezxml_attr(xml, attr[i][j]) != attr[i][j + 1])
931 while (*len + strlen(attr[i][j]) + 7 > *
max)
934 *len += sprintf(*s + *len,
" %s=\"", attr[i][j]);
937 *len += sprintf(*s + *len,
"\"");
939 *len += sprintf(*s + *len,
">");
947 while (*len + strlen(xml->
name) + 4 > *max)
950 *len += sprintf(*s + *len,
"</%s>", xml->
name);
952 while (txt[off] && off < xml->off)
967 char *s = strcpy((
char*)malloc(
max),
""), *t, *n;
970 if (!xml || !xml->
name)
971 return (
char*)realloc(s, len + 1);
975 for (i = 0; !p && root->
pi[i]; i++) {
976 for (k = 2; root->
pi[i][k - 1]; k++)
978 for (j = 1; root->
pi[i][j]; j++) {
981 if (root->
pi[i][k][j - 1] ==
'>')
983 while (len + strlen(t = root->
pi[i][0]) + strlen(n) + 7 >
max)
985 len += sprintf(s + len,
"<?%s%s%s?>\n", t, *n ?
" " :
"", n);
994 for (i = 0; !p && root->
pi[i]; i++) {
995 for (k = 2; root->
pi[i][k - 1]; k++)
997 for (j = 1; root->
pi[i][j]; j++) {
1000 if (root->
pi[i][k][j - 1] ==
'<')
1002 while (len + strlen(t = root->
pi[i][0]) + strlen(n) + 7 >
max)
1004 len += sprintf(s + len,
"\n<?%s%s%s?>", t, *n ?
" " :
"", n);
1007 return (
char*)realloc(s, len + 1);
1022 for (i = 10; root->
ent[i]; i += 2)
1023 if ((s = root->
ent[i + 1]) < root->
s || s > root->
e)
1027 for (i = 0; root->
attr[i]; i++) {
1030 for (j = 1; a[j++]; j += 2)
1031 if (a[j] && (a[j] < root->
s || a[j] > root->
e))
1038 for (i = 0; root->
pi[i]; i++) {
1039 for (j = 1; root->
pi[i][j]; j++)
1041 free(root->
pi[i][j + 1]);
1047 if (root->
len == (
size_t)-1)
1049 #ifndef EZXML_NOMMAP
1051 munmap(root->
m, root->
len);
1068 while (xml && xml->
parent)
1075 static char *ent[] = {
"lt;",
"<",
"gt;",
">",
"quot;",
""",
1076 "apos;",
"'",
"amp;",
"&", NULL };
1083 root->
ent = (
char**)memcpy(malloc(
sizeof(ent)),
ent,
sizeof(
ent));
1099 if (head->
off <= off) {
1110 for (cur = head, prev = NULL; cur && strcmp(cur->
name, xml->
name);
1113 if (cur && cur->off <= off) {
1114 while (cur->next && cur->next->off <= off)
1122 for (cur = head, prev = NULL; cur && cur->
off <= off;
1142 child = (
ezxml_t) memset(malloc(
sizeof(
struct ezxml)),
'\0',
1143 sizeof(
struct ezxml));
1158 strcpy(xml->
txt, txt);
1170 while (xml->
attr[l] && strcmp(xml->
attr[l], name))
1172 if (!xml->
attr[l]) {
1176 xml->
attr = (
char**)malloc(4 *
sizeof(
char *));
1180 xml->
attr = (
char**)realloc(xml->
attr, (l + 4) *
sizeof(
char *));
1183 xml->
attr[l + 2] = NULL;
1184 xml->
attr[l + 3] = (
char*)realloc(xml->
attr[l + 1],
1185 (c = strlen(xml->
attr[l + 1])) + 2);
1186 strcpy(xml->
attr[l + 3] + c,
" ");
1191 for (c = l; xml->
attr[c]; c += 2)
1194 free(xml->
attr[l + 1]);
1201 xml->
attr[l + 1] = value;
1207 memmove(xml->
attr + l, xml->
attr + l + 2, (c - l) *
sizeof(
char *));
1211 xml->
attr = (
char**)realloc(xml->
attr, (c + 2) *
sizeof(
char *));
1212 memmove(xml->
attr[c + 1] + (l / 2), xml->
attr[c + 1] + (l / 2) + 1,
1245 if (strcmp(cur->
name, xml->
name)) {
1255 while (cur->
next && cur->
next != xml)
1275 return vpr_printf(TIO_MESSAGE_ERROR,
"usage: %s xmlfile\n", argv[0]);
const char * ezxml_error(ezxml_t xml)
static ezxml_t ezxml_vget(ezxml_t xml, va_list ap)
ezxml_t ezxml_cut(ezxml_t xml)
ezxml_t ezxml_idx(ezxml_t xml, int idx)
ezxml_t ezxml_set_flag(ezxml_t xml, short flag)
int main(int argc, char **argv)
struct ezxml_root * ezxml_root_t
static void ezxml_char_content(ezxml_root_t root, char *s, size_t len, char t)
static void ezxml_open_tag(ezxml_root_t root, int line, char *name, char **attr)
static ezxml_t ezxml_close_tag(ezxml_root_t root, char *name, char *s)
static char * ezxml_ampencode(const char *s, size_t len, char **dst, size_t *dlen, size_t *max, short a)
ezxml_t ezxml_new(char *name)
static void ezxml_free_attr(char **attr)
ezxml_t ezxml_insert(ezxml_t xml, ezxml_t dest, size_t off)
void ezxml_free(ezxml_t xml)
ezxml_t ezxml_parse_fp(FILE *fp)
char ** ezxml_pi(ezxml_t xml, const char *target)
static char * ezxml_decode(char *s, char **ent, char t)
ezxml_t ezxml_set_attr(ezxml_t xml, char *name, char *value)
ezxml_t ezxml_child(ezxml_t xml, const char *name)
const char * ezxml_attr(ezxml_t xml, const char *attr)
static char * ezxml_str2utf8(char **s, size_t *len)
ezxml_t ezxml_set_txt(ezxml_t xml, char *txt)
static short ezxml_internal_dtd(ezxml_root_t root, char *s, size_t len)
static void ezxml_proc_inst(ezxml_root_t root, char *s, size_t len)
ezxml_t ezxml_add_child(ezxml_t xml, char *name, size_t off)
static ezxml_t ezxml_err(ezxml_root_t root, char *s, const char *err,...)
ezxml_t ezxml_parse_file(const char *file)
ezxml_t ezxml_parse_fd(int fd)
static char * ezxml_toxml_r(ezxml_t xml, char **s, size_t *len, size_t *max, size_t start, char ***attr)
char * ezxml_toxml(ezxml_t xml)
ezxml_t ezxml_get(ezxml_t xml,...)
static int ezxml_ent_ok(char *name, char *s, char **ent)
ezxml_t ezxml_parse_str(char *s, size_t len)
char * my_strdup(const char *str)