📄 ezxml.c
字号:
for(e = s + len; s != e; s++) { while(*dlen + 10 > *max) *dst = realloc(*dst, *max += EZXML_BUFSIZE); switch (*s) { case '\0': return *dst; case '&': *dlen += sprintf(*dst + *dlen, "&"); break; case '<': *dlen += sprintf(*dst + *dlen, "<"); break; case '>': *dlen += sprintf(*dst + *dlen, ">"); break; case '"': *dlen += sprintf(*dst + *dlen, (a) ? """ : "\""); break; case '\n': *dlen += sprintf(*dst + *dlen, (a) ? "
" : "\n"); break; case '\t': *dlen += sprintf(*dst + *dlen, (a) ? "	" : "\t"); break; case '\r': *dlen += sprintf(*dst + *dlen, "
"); break; default: (*dst)[(*dlen)++] = *s; } } return *dst;}/* Recursively converts each tag to xml appending it to *s. Reallocates *s if *//* its length excedes max. start is the location of the previous tag in the *//* parent tag's character content. Returns *s. */char *ezxml_toxml_r(ezxml_t xml, char **s, size_t * len, size_t * max, size_t start, char ***attr){ int i, j; char *txt = (xml->parent) ? xml->parent->txt : ""; size_t off = 0; /* parent character content up to this tag */ *s = ezxml_ampencode(txt + start, xml->off - start, s, len, max, 0); while(*len + strlen(xml->name) + 4 > *max) /* reallocate s */ *s = realloc(*s, *max += EZXML_BUFSIZE); *len += sprintf(*s + *len, "<%s", xml->name); /* open tag */ for(i = 0; xml->attr[i]; i += 2) { /* tag attributes */ if(ezxml_attr(xml, xml->attr[i]) != xml->attr[i + 1]) continue; while(*len + strlen(xml->attr[i]) + 7 > *max) /* reallocate s */ *s = realloc(*s, *max += EZXML_BUFSIZE); *len += sprintf(*s + *len, " %s=\"", xml->attr[i]); /* Ted Campbell, Aug 14, 2007. Added explicit cast to size_t. */ ezxml_ampencode(xml->attr[i + 1], (size_t) (-1), s, len, max, 1); *len += sprintf(*s + *len, "\""); } for(i = 0; attr[i] && strcmp(attr[i][0], xml->name); i++); for(j = 1; attr[i] && attr[i][j]; j += 3) { /* default attributes */ if(!attr[i][j + 1] || ezxml_attr(xml, attr[i][j]) != attr[i][j + 1]) continue; /* skip duplicates and non-values */ while(*len + strlen(attr[i][j]) + 7 > *max) /* reallocate s */ *s = realloc(*s, *max += EZXML_BUFSIZE); *len += sprintf(*s + *len, " %s=\"", attr[i][j]); /* Ted Campbell, Aug 14, 2007. Added explicit cast to size_t. */ ezxml_ampencode(attr[i][j + 1], (size_t) (-1), s, len, max, 1); *len += sprintf(*s + *len, "\""); } *len += sprintf(*s + *len, ">"); /* Ted Campbell, Aug 14, 2007. Added explicit cast to size_t. */ *s = (xml->child) ? ezxml_toxml_r(xml->child, s, len, max, 0, attr) /*child */ : ezxml_ampencode(xml->txt, (size_t) (-1), s, len, max, 0); /*data */ while(*len + strlen(xml->name) + 4 > *max) /* reallocate s */ *s = realloc(*s, *max += EZXML_BUFSIZE); *len += sprintf(*s + *len, "</%s>", xml->name); /* close tag */ while(txt[off] && off < xml->off) off++; /* make sure off is within bounds */ /* Ted Campbell, Aug 14, 2007. Added explicit cast to size_t. */ return (xml->ordered) ? ezxml_toxml_r(xml->ordered, s, len, max, off, attr) : ezxml_ampencode(txt + off, (size_t) (-1), s, len, max, 0);}/* Converts an ezxml structure back to xml. Returns a string of xml data that *//* must be freed. */char *ezxml_toxml(ezxml_t xml){ ezxml_t p = (xml) ? xml->parent : NULL, o = (xml) ? xml->ordered : NULL; ezxml_root_t root = (ezxml_root_t) xml; size_t len = 0, max = EZXML_BUFSIZE; char *s = strcpy(malloc(max), ""), *t, *n; int i, j, k; if(!xml || !xml->name) return realloc(s, len + 1); while(root->xml.parent) root = (ezxml_root_t) root->xml.parent; /* root tag */ for(i = 0; !p && root->pi[i]; i++) { /* pre-root processing instructions */ for(k = 2; root->pi[i][k - 1]; k++); for(j = 1; root->pi[i][j]; j++) { /* Jason Luu, Aug 29, 2007. Removed assignment in conditional statement */ n = root->pi[i][j]; if(root->pi[i][k][j - 1] == '>') continue; /* not pre-root */ while(len + strlen(t = root->pi[i][0]) + strlen(n) + 7 > max) s = realloc(s, max += EZXML_BUFSIZE); len += sprintf(s + len, "<?%s%s%s?>\n", t, *n ? " " : "", n); } } xml->parent = xml->ordered = NULL; s = ezxml_toxml_r(xml, &s, &len, &max, 0, root->attr); xml->parent = p; xml->ordered = o; for(i = 0; !p && root->pi[i]; i++) { /* post-root processing instructions */ for(k = 2; root->pi[i][k - 1]; k++); for(j = 1; root->pi[i][j]; j++) { /* Jason Luu, Aug 29, 2007. Removed assignment in conditional statement */ n = root->pi[i][j]; if(root->pi[i][k][j - 1] == '<') continue; /* not post-root */ while(len + strlen(t = root->pi[i][0]) + strlen(n) + 7 > max) s = realloc(s, max += EZXML_BUFSIZE); len += sprintf(s + len, "\n<?%s%s%s?>", t, *n ? " " : "", n); } } return realloc(s, len + 1);}/* free the memory allocated for the ezxml structure */voidezxml_free(ezxml_t xml){ ezxml_root_t root = (ezxml_root_t) xml; int i, j; char **a, *s; if(!xml) return; ezxml_free(xml->child); ezxml_free(xml->ordered); if(!xml->parent) { /* free root tag allocations */ for(i = 10; root->ent[i]; i += 2) /* 0 - 9 are default entites (<>&"') */ if((s = root->ent[i + 1]) < root->s || s > root->e) free(s); free(root->ent); /* free list of general entities */ for(i = 0; root->attr[i]; i++) { /* Jason Luu, Aug 29, 2007. Removed assignment in conditional statement */ a = root->attr[i]; for(j = 1; a[j++]; j += 2) /* free malloced attribute values */ if(a[j] && (a[j] < root->s || a[j] > root->e)) free(a[j]); free(a); } if(root->attr[0]) free(root->attr); /* free default attribute list */ for(i = 0; root->pi[i]; i++) { for(j = 1; root->pi[i][j]; j++); free(root->pi[i][j + 1]); free(root->pi[i]); } if(root->pi[0]) free(root->pi); /* free processing instructions */ if(root->len == -1) free(root->m); /* malloced xml data */#ifndef EZXML_NOMMAP else if(root->len) munmap(root->m, root->len); /* mem mapped xml data */#endif /* EZXML_NOMMAP */ if(root->u) free(root->u); /* utf8 conversion */ } ezxml_free_attr(xml->attr); /* tag attributes */ if((xml->flags & EZXML_TXTM)) free(xml->txt); /* character content */ if((xml->flags & EZXML_NAMEM)) free(xml->name); /* tag name */ free(xml);}/* return parser error message or empty string if none */const char *ezxml_error(ezxml_t xml){ while(xml && xml->parent) xml = xml->parent; /* find root tag */ return (xml) ? ((ezxml_root_t) xml)->err : "";}/* returns a new empty ezxml structure with the given root tag name */ezxml_tezxml_new(const char *name){ static char *ent[] = { "lt;", "<", "gt;", ">", "quot;", """, "apos;", "'", "amp;", "&", NULL }; ezxml_root_t root = (ezxml_root_t) memset(malloc(sizeof(struct ezxml_root)), '\0', sizeof(struct ezxml_root)); root->xml.name = (char *)name; root->cur = &root->xml; strcpy(root->err, root->xml.txt = ""); root->ent = memcpy(malloc(sizeof(ent)), ent, sizeof(ent)); root->attr = root->pi = (char ***)(root->xml.attr = EZXML_NIL); return &root->xml;}/* inserts an existing tag into an ezxml structure */ezxml_tezxml_insert(ezxml_t xml, ezxml_t dest, size_t off){ ezxml_t cur, prev, head; xml->next = xml->sibling = xml->ordered = NULL; xml->off = off; xml->parent = dest; /* Jason Luu, Aug 29, 2007. Removed assignment in conditional statement */ head = dest->child; if(head) { /* already have sub tags */ if(head->off <= off) { /* not first subtag */ for(cur = head; cur->ordered && cur->ordered->off <= off; cur = cur->ordered); xml->ordered = cur->ordered; cur->ordered = xml; } else { /* first subtag */ xml->ordered = head; dest->child = xml; } for(cur = head, prev = NULL; cur && strcmp(cur->name, xml->name); prev = cur, cur = cur->sibling); /* find tag type */ if(cur && cur->off <= off) { /* not first of type */ while(cur->next && cur->next->off <= off) cur = cur->next; xml->next = cur->next; cur->next = xml; } else { /* first tag of this type */ if(prev && cur) prev->sibling = cur->sibling; /* remove old first */ xml->next = cur; /* old first tag is now next */ for(cur = head, prev = NULL; cur && cur->off <= off; prev = cur, cur = cur->sibling); /* new sibling insert point */ xml->sibling = cur; if(prev) prev->sibling = xml; } } else dest->child = xml; /* only sub tag */ return xml;}/* Adds a child tag. off is the offset of the child tag relative to the start *//* of the parent tag's character content. Returns the child tag. */ezxml_tezxml_add_child(ezxml_t xml, const char *name, size_t off){ ezxml_t child; if(!xml) return NULL; child = (ezxml_t) memset(malloc(sizeof(struct ezxml)), '\0', sizeof(struct ezxml)); child->name = (char *)name; child->attr = EZXML_NIL; child->txt = ""; return ezxml_insert(child, xml, off);}/* sets the character content for the given tag and returns the tag */ezxml_tezxml_set_txt(ezxml_t xml, const char *txt){ if(!xml) return NULL; if(xml->flags & EZXML_TXTM) free(xml->txt); /* existing txt was malloced */ xml->flags &= ~EZXML_TXTM; xml->txt = (char *)txt; return xml;}/* Sets the given tag attribute or adds a new attribute if not found. A value *//* of NULL will remove the specified attribute. Returns the tag given. */ezxml_tezxml_set_attr(ezxml_t xml, const char *name, const char *value){ int l = 0, c; if(!xml) return NULL; while(xml->attr[l] && strcmp(xml->attr[l], name)) l += 2; if(!xml->attr[l]) { /* not found, add as new attribute */ if(!value) return xml; /* nothing to do */ if(xml->attr == EZXML_NIL) { /* first attribute */ xml->attr = malloc(4 * sizeof(char *)); /* Ted Campbell, Aug 14, 2007. Changed to use 'my_strdup' */ xml->attr[1] = my_strdup(""); /* empty list of malloced names/vals */ } else xml->attr = realloc(xml->attr, (l + 4) * sizeof(char *)); xml->attr[l] = (char *)name; /* set attribute name */ xml->attr[l + 2] = NULL; /* null terminate attribute list */ xml->attr[l + 3] = realloc(xml->attr[l + 1], (c = strlen(xml->attr[l + 1])) + 2); strcpy(xml->attr[l + 3] + c, " "); /* set name/value as not malloced */ if(xml->flags & EZXML_DUP) xml->attr[l + 3][c] = (char)(unsigned char)EZXML_NAMEM; } else if(xml->flags & EZXML_DUP) free((char *)name); /* name was strduped */ for(c = l; xml->attr[c]; c += 2); /* find end of attribute list */ if(xml->attr[c + 1][l / 2] & EZXML_TXTM) free(xml->attr[l + 1]); /*old val */ if(xml->flags & EZXML_DUP) xml->attr[c + 1][l / 2] |= EZXML_TXTM; else xml->attr[c + 1][l / 2] &= ~EZXML_TXTM; if(value) xml->attr[l + 1] = (char *)value; /* set attribute value */ else { /* remove attribute */ if(xml->attr[c + 1][l / 2] & EZXML_NAMEM) free(xml->attr[l]); /* Ted Campbell, Aug 14, 2007. It seems that the size should be * (c + 2) - (l + 2) = (c - l) */ memmove(xml->attr + l, xml->attr + l + 2, (c - l) * sizeof(char *)); /* Ted Campbell, Aug 14, 2007. We need to adjust c to point to new * location it was moved to since its old location is undefined */ c -= 2; /* We have one less elements */ xml->attr = realloc(xml->attr, (c + 2) * sizeof(char *)); memmove(xml->attr[c + 1] + (l / 2), xml->attr[c + 1] + (l / 2) + 1, (c / 2) - (l / 2)); /* fix list of which name/vals are malloced */ } xml->flags &= ~EZXML_DUP; /* clear strdup() flag */ return xml;}/* sets a flag for the given tag and returns the tag */ezxml_tezxml_set_flag(ezxml_t xml, short flag){ if(xml) xml->flags |= flag; return xml;}/* removes a tag along with its subtags without freeing its memory */ezxml_tezxml_cut(ezxml_t xml){ ezxml_t cur; if(!xml) return NULL; /* nothing to do */ if(xml->next) xml->next->sibling = xml->sibling; /* patch sibling list */ if(xml->parent) { /* not root tag */ cur = xml->parent->child; /* find head of subtag list */ if(cur == xml) xml->parent->child = xml->ordered; /* first subtag */ else { /* not first subtag */ while(cur->ordered != xml) cur = cur->ordered; cur->ordered = cur->ordered->ordered; /* patch ordered list */ cur = xml->parent->child; /* go back to head of subtag list */ if(strcmp(cur->name, xml->name)) { /* not in first sibling list */ while(strcmp(cur->sibling->name, xml->name)) cur = cur->sibling; if(cur->sibling == xml) { /* first of a sibling list */ cur->sibling = (xml->next) ? xml->next : cur->sibling->sibling; } else cur = cur->sibling; /* not first of a sibling list */ } while(cur->next && cur->next != xml) cur = cur->next; if(cur->next) cur->next = cur->next->next; /* patch next list */ } } xml->ordered = xml->sibling = xml->next = NULL; return xml;}#ifdef EZXML_TEST /* test harness */intmain(int argc, char **argv){ ezxml_t xml; char *s; int i; if(argc != 2) return fprintf(stderr, "usage: %s xmlfile\n", argv[0]); xml = ezxml_parse_file(argv[1]); printf("%s\n", (s = ezxml_toxml(xml))); free(s); i = fprintf(stderr, "%s", ezxml_error(xml)); ezxml_free(xml); return (i) ? 1 : 0;}#endif /* EZXML_TEST */
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -