1 /*****************************************************************************
2 *
3 * FILE: sxml.c
4 * DESCRIPTION: Skimpy XML Parser/Grafter Library
5 * DATE: Wed, Sep 8 2004
6 * UPDATED: Fri, Mar 26 2010
7 * AUTHOR: Kouichi ABE (WALL) / ��������
8 * E-MAIL: kouichi@MysticWALL.COM
9 * URL: http://www.MysticWALL.COM/
10 * COPYRIGHT: (c) 2004-2010 �������졿Kouichi ABE (WALL), All rights reserved.
11 * LICENSE:
12 *
13 * Copyright (c) 2004-2010 Kouichi ABE (WALL) <kouichi@MysticWALL.COM>,
14 * All rights reserved.
15 *
16 * Redistribution and use in source and binary forms, with or without
17 * modification, are permitted provided that the following conditions
18 * are met:
19 *
20 * 1. Redistributions of source code must retain the above copyright
21 * notice, this list of conditions and the following disclaimer.
22 * 2. Redistributions in binary form must reproduce the above copyright
23 * notice, this list of conditions and the following disclaimer in the
24 * documentation and/or other materials provided with the distribution.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
28 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
29 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
30 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
31 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
32 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 * SUCH DAMAGE.
37 *
38 * $Id: sxml.c,v 1.9 2010/03/26 07:56:17 kouichi Exp $
39 *
40 *****************************************************************************/
41
42 #if HAVE_CONFIG_H
43 #include "config.h"
44 #endif /* HAVE_CONFIG_H */
45
46 #include <stdio.h>
47 #if HAVE_STDLIB_H
48 #include <stdlib.h>
49 #endif /* HAVE_STDLIB_H */
50 #if HAVE_STRING_H
51 #include <string.h>
52 #endif /* HAVE_STRING_H */
53 #if HAVE_SYS_TYPES_H
54 #include <sys/types.h>
55 #endif /* HAVE_SYS_TYPES_H */
56 #include <sys/stat.h>
57 #include <sys/mman.h>
58 #include "sxml.h"
59
60 /******************************************************************************
61 *
62 * Macros and structures definition
63 *
64 *****************************************************************************/
65 #ifndef _BOOL_T
66 #define _BOOL_T
67 typedef enum {
68 false = 0,
69 true = 1
70 } bool;
71 #endif /* _BOOL_T */
72
73 #define EOL '\0'
74 #define HTAB '\011'
75 #define LF '\012'
76 #define VTAB '\013'
77 #define NP '\014'
78 #define CR '\015'
79 #define SPC '\040'
80
81 /******************************************************************************
82 *
83 * Local functions declaration
84 *
85 *****************************************************************************/
86 static char * strxsep(char **, const char *);
87 static int whitespace(const char *);
88 static char * mkstr(const char *, const char *);
89 static sxml_node_t * create_new_node(sxml_node_t *);
90 static void delete_node(sxml_node_t *);
91 static sxml_attr_t * set_attribute(sxml_attr_t *, const char *,
92 const char *);
93 static int set_element(sxml_element_t *, char *);
94 static void delete_element(sxml_element_t *);
95 static int parse(sxml_node_t *, const char *, size_t);
96 static int mkval(sxml_node_t * node, const char * vp,
97 const char * p);
98
99 static void print_node(sxml_node_t *, int, FILE *);
100
101 /******************************************************************************
102 *
103 * Functions definition
104 *
105 *****************************************************************************/
106 static char *
strxsep(stringp,delim)107 strxsep(stringp, delim)
108 register char ** stringp;
109 register const char * delim;
110 {
111 register char * s;
112 register const char * spanp;
113 register int c;
114 register int sc;
115 char * tok;
116
117 if ((s = *stringp) == NULL) {
118 return NULL;
119 }
120 for (tok = s; ; ) {
121 c = *s++;
122 spanp = delim;
123 if (c == '"') {
124 register char * p;
125
126 for (p = s; *s != '"'; s++) {
127 if (*s == '\0') {
128 s = p; /* reset */
129 break;
130 }
131 }
132 if (*s == '"') {
133 c = *s++;
134 }
135 }
136 do {
137 if ((sc = *spanp++) == c) {
138 if (c == '\0') {
139 s = NULL;
140 }
141 else {
142 s[-1] = '\0';
143 }
144 *stringp = s;
145 return tok;
146 }
147 } while (sc != '\0');
148 }
149 /* NOTREACHED */
150 }
151
152 static int
whitespace(s)153 whitespace(s)
154 const char * s;
155 {
156 int c = 0;
157
158 while (*s == SPC || *s == HTAB || *s == VTAB || *s == CR || *s == LF ||
159 *s == NP) {
160 c++;
161 s++;
162 }
163
164 return c;
165 }
166
167 static char *
mkstr(sp,ep)168 mkstr(sp, ep)
169 const char * sp;
170 const char * ep;
171 {
172 if (sp != NULL && ep != NULL) {
173 size_t len;
174
175 len = ep - sp;
176 if (len > 0) {
177 char * new;
178
179 /* strip white space of string end */
180 while (*(sp + len - 1) == CR || *(sp + len - 1) == LF ||
181 *(sp + len - 1) == SPC ||
182 *(sp + len - 1) == HTAB || *(sp + len - 1) == VTAB) {
183 len--;
184 }
185 new = (char *)calloc(len + 1, sizeof(char));
186 if (new != NULL) {
187 memcpy(new, sp, len);
188 }
189 return new;
190 }
191 }
192
193 return NULL;
194 }
195
196 static sxml_node_t *
create_new_node(parent)197 create_new_node(parent)
198 sxml_node_t * parent;
199 {
200 sxml_node_t * new;
201
202 new = (sxml_node_t *)calloc(1, sizeof(sxml_node_t));
203 if (new != NULL) {
204 new->parent = parent;
205 new->child = NULL; /* first child */
206 new->last_child = NULL; /* last child */
207 new->next = NULL; /* sibling */
208 new->prev = NULL; /* sibling */
209 new->type = SXML_ELEMENT;
210 }
211
212 return new;
213 }
214
215 static void
delete_node(node)216 delete_node(node)
217 sxml_node_t * node;
218 {
219 register sxml_node_t * np;
220 register sxml_node_t * np_next;
221
222 for (np = node; np != NULL; np = np_next) {
223 np_next = np->next;
224 switch (np->type) {
225 case SXML_PROLOG:
226 delete_element(&np->value.element);
227 break;
228 case SXML_ELEMENT:
229 delete_element(&np->value.element);
230 break;
231 case SXML_CONTENT:
232 free((char *)np->value.content); np->value.content = NULL;
233 default:
234 break;
235 }
236 if (np->child != NULL) { delete_node(np->child); }
237 free(np); np = NULL;
238 }
239 }
240
241 static sxml_attr_t *
set_attribute(ap,name,value)242 set_attribute(ap, name, value)
243 sxml_attr_t * ap;
244 const char * name;
245 const char * value;
246 {
247 sxml_attr_t * new;
248
249 new = (sxml_attr_t *)malloc(sizeof(sxml_attr_t));
250 if (new != NULL) {
251 new->name = strdup(name);
252 new->value = strdup(value);
253 new->next = ap;
254 }
255
256 return new;
257 }
258
259 static int
set_element(e,s)260 set_element(e, s)
261 sxml_element_t * e; /* element */
262 char * s; /* element string */
263 {
264 static const char sep[] = " \t\r\n";
265 char * name;
266 register char * attr;
267
268 name = strxsep(&s, sep);
269 e->name = strdup(name);
270 e->attrs = NULL;
271
272 for (attr = strxsep(&s, sep); attr != NULL; attr = strxsep(&s, sep)) {
273 register char * p;
274 register char * q;
275
276 if (*attr == EOL) { continue; }
277 p = strchr(attr, '=');
278 if (p) {
279 *p = EOL;
280 p += 2;
281 q = strchr(p, '"');
282 if (q != NULL) {
283 *q = EOL;
284 e->attrs = set_attribute(e->attrs, attr, p);
285 }
286 }
287 }
288
289 return 0;
290 }
291
292 static void
delete_element(e)293 delete_element(e)
294 sxml_element_t * e;
295 {
296 free((char *)e->name); e->name = NULL;
297 if (e->attrs != NULL) {
298 register sxml_attr_t * ap;
299 register sxml_attr_t * ap_next;
300
301 for (ap = e->attrs; ap != NULL; ap = ap_next) {
302 ap_next = ap->next;
303 free((char *)ap->name); ap->name = NULL;
304 free((char *)ap->value); ap->value = NULL;
305 free((sxml_attr_t *)ap); ap = NULL;
306 }
307 }
308 }
309
310 static int
parse(vertex,text,size)311 parse(vertex, text, size)
312 sxml_node_t * vertex;
313 const char * text;
314 size_t size;
315 {
316 typedef enum {
317 ST_INIT,
318 ST_TAG_BEGIN,
319 ST_TAG_END,
320 ST_PROLOG_BEGIN,
321 ST_PROLOG_END,
322 ST_COMMENT_BEGIN,
323 ST_COMMENT_S1,
324 ST_COMMENT,
325 ST_COMMENT_S2,
326 ST_COMMENT_END,
327 ST_CTEXT,
328 ST_CDATA,
329 ST_ELEMENT,
330 ST_ATTRIBUTE,
331 ST_VALUE
332 } state_t;
333 const char * p = text;
334 const char * vp = NULL; /* start position of value */
335 state_t state = ST_INIT;
336 sxml_node_t * node = vertex; /* current node */
337 const char * endp = text + size;
338 static bool prolog = false;
339
340 while (p < endp) {
341 p += whitespace(p);
342 switch (state) {
343 case ST_INIT:
344 if (*p == '<') { state = ST_TAG_BEGIN; }
345 else if (p == endp) { return 0; }
346 else { return -1; }
347 break;
348 case ST_TAG_BEGIN:
349 if (*p == '?') { state = ST_PROLOG_BEGIN; }
350 else if (*p == '!') { state = ST_COMMENT_BEGIN; }
351 else if (*p == '/') { state = ST_TAG_END; }
352 else { state = ST_ELEMENT; p--; }
353 break;
354 case ST_TAG_END:
355 if (*p == '>') { state = ST_INIT;
356 if (node->parent != NULL) { node = node->parent; }
357 }
358 break;
359 case ST_PROLOG_BEGIN:
360 if (*p < 'a' || *p > 'z') { return -2; }
361 else { state = ST_ELEMENT; p--; continue; }
362 break;
363 case ST_PROLOG_END:
364 if (*p == '>') { state = ST_INIT; prolog = false; }
365 else { return -3; }
366 break;
367 case ST_COMMENT_BEGIN:
368 if (*p == '-') { state = ST_COMMENT_S1; }
369 else if (*p >= 'A' || *p <= 'Z') { state = ST_CTEXT; }
370 else { return -4; }
371 break;
372 case ST_COMMENT_S1:
373 if (*p == '-') { state = ST_COMMENT; }
374 else { return -5; }
375 break;
376 case ST_COMMENT:
377 if (*p == '-') { state = ST_COMMENT_S2; }
378 break;
379 case ST_COMMENT_S2:
380 if (*p == '-') { state = ST_COMMENT_END; }
381 else { state = ST_COMMENT; }
382 break;
383 case ST_COMMENT_END:
384 if (*p == '>') { state = ST_INIT; }
385 else { state = ST_COMMENT; }
386 break;
387 case ST_CTEXT:
388 if (*p == '>') { state = ST_INIT; }
389 break;
390 case ST_ELEMENT: {
391 state_t nest1 = ST_ELEMENT;
392 const char * sp = p; /* start position of element */
393 char * s; /* element with attributes */
394
395 while (p < endp) {
396 switch (nest1) {
397 case ST_ELEMENT:
398 if (*p == '"') { nest1 = ST_ATTRIBUTE; }
399 else if (*p == '>') { state = ST_VALUE; vp = NULL; goto end; }
400 else if (*p == '/') { state = ST_TAG_END; goto end; }
401 else if (*p == '?') {
402 if (prolog) { state = ST_PROLOG_END; goto end; }
403 else { prolog = true; sp = ++p; /* remove '?' */ }
404 }
405 break;
406 case ST_ATTRIBUTE:
407 if (*p == '"') { nest1 = ST_ELEMENT; }
408 break;
409 default:
410 break;
411 }
412 p++;
413 }
414 end:
415 s = mkstr(sp, p);
416 if (s != NULL) {
417 sxml_node_t * n; /* new node */
418
419 n = create_new_node(node); if (n == NULL) { return -6; }
420 set_element(&n->value.element, s);
421 if (node->child != NULL) {
422 node->last_child->next = n;
423 n->prev = node->last_child;
424 node->last_child = n;
425 }
426 else {
427 node->last_child = node->child = n;
428 }
429 if (prolog) { /* prolog has no children */
430 n->type = SXML_PROLOG;
431 }
432 else {
433 node = n; /* set new node to current node */
434 }
435 free(s); s = NULL;
436 }
437 }
438 break;
439 case ST_VALUE:
440 if (vp == NULL) { vp = p; }
441 if (strncmp(p, "<![CDATA[", 9) == 0) {
442 const char * src = p + 9;
443 char * dst = (char *)p;
444 size_t len = endp - src;
445
446 dst = memmove(dst, src, len);
447 p = dst - 1; /* XXX: */
448 endp -= 9;
449 state = ST_CDATA;
450 }
451 else if (*p == '<') {
452 if (mkval(node, vp, p) == 0) { state = ST_TAG_BEGIN; }
453 else { return -7; }
454 }
455 break;
456 case ST_CDATA:
457 if (strncmp(p, "]]>", 3) == 0) {
458 const char * src = p + 3;
459 char * dst = (char *)p;
460 size_t len = endp - src;
461
462 dst = memmove(dst, src, len);
463 p = dst - 1; /* XXX: */
464 endp -= 3;
465 state = ST_VALUE;
466 }
467 break;
468 default:
469 return -9;
470 }
471 p++;
472 }
473
474 return 0;
475 }
476
477 static int
mkval(node,vp,p)478 mkval(node, vp, p)
479 sxml_node_t * node;
480 const char * vp;
481 const char * p;
482 {
483 char * s;
484
485 s = mkstr(vp, p);
486 if (s != NULL) {
487 sxml_node_t * n; /* new node */
488
489 n = create_new_node(node); if (n == NULL) { return -1; }
490 n->type = SXML_CONTENT;
491 n->value.content = s;
492 node->child = node->last_child = n;
493 }
494
495 return 0;
496 }
497
498 /*****************************************************************************/
499
500 sxml_node_t *
sxml_parse_file(fd)501 sxml_parse_file(fd)
502 int fd; /* XML file descriptor */
503 {
504 sxml_node_t * root = NULL; /* root node */
505
506 if (fd != -1) {
507 struct stat sbuf;
508
509 if (fstat(fd, &sbuf) == 0) {
510 void * md;
511
512 md = mmap(0, (size_t)sbuf.st_size, PROT_READ|PROT_WRITE, MAP_PRIVATE, fd,
513 (off_t)0);
514 if (md != MAP_FAILED) {
515 root = create_new_node(NULL); root->type = SXML_VERTEX;
516 if (root != NULL) {
517 int status;
518
519 status = parse(root, (const char *)md, (size_t)sbuf.st_size);
520 if (status != 0) {
521 #if DEBUG
522 fprintf(stderr, "DEBUG[sxml_parse_file] status=%d\n", status);
523 #endif /* DEBUG */
524 delete_node(root);
525 root = NULL;
526 }
527 }
528 munmap(md, (size_t)sbuf.st_size);
529 }
530 }
531 }
532
533 return root;
534 }
535
536 void
sxml_delete_node(node)537 sxml_delete_node(node)
538 sxml_node_t * node;
539 {
540 delete_node(node);
541 }
542
543 sxml_node_t *
sxml_find_prolog(node,name)544 sxml_find_prolog(node, name)
545 sxml_node_t * node; /* start node to find element */
546 const char * name; /* element name */
547 {
548 register sxml_node_t * np;
549
550 for (np = node; np != NULL; np = np->next) {
551 if (np->type == SXML_PROLOG) {
552 if (name == NULL) { return np; } /* first matched */
553 if (strcmp(name, np->value.element.name) == 0) {
554 return np;
555 }
556 }
557 /* descend child */
558 if (np->child != NULL) {
559 sxml_node_t * child;
560
561 child = sxml_find_prolog(np->child, name);
562 if (child != NULL) {
563 return child;
564 }
565 }
566 }
567
568 return NULL;
569 }
570
571 sxml_node_t *
sxml_find_element(node,name,attr,value)572 sxml_find_element(node, name, attr, value)
573 sxml_node_t * node; /* start node to find element */
574 const char * name; /* element name */
575 const char * attr; /* attribute name */
576 const char * value; /* attribute value */
577 {
578 struct found_s {
579 sxml_node_t * name;
580 sxml_node_t * attr;
581 sxml_node_t * value;
582 };
583 register sxml_node_t * np;
584
585 for (np = node; np != NULL; np = np->next) {
586 struct found_s found = { NULL, NULL, NULL };
587
588 if (np->type == SXML_ELEMENT) {
589 register sxml_attr_t * ap;
590
591 if (name != NULL && strcmp(name, np->value.element.name) == 0) {
592 found.name = np;
593 }
594 for (ap = np->value.element.attrs; ap != NULL; ap = ap->next) {
595 if (attr != NULL && ap->name && strcmp(attr, ap->name) == 0) {
596 found.attr = np;
597 }
598 if (value != NULL && ap->value && strcmp(value, ap->value) == 0) {
599 found.value = np;
600 }
601
602 if (attr != NULL && value != NULL) {
603 if (found.attr != NULL && found.value != NULL) { break; }
604 }
605 else if (attr != NULL) { if (found.attr != NULL) { break; } }
606 else if (value != NULL) { if (found.value != NULL) { break; } }
607 }
608
609 if (name != NULL && attr != NULL && value != NULL) {
610 if (found.name != NULL && found.attr != NULL && found.value != NULL) {
611 return np;
612 }
613 }
614 else if (name != NULL && attr != NULL) {
615 if (found.name != NULL && found.attr != NULL) { return np; }
616 }
617 else if (name != NULL && value != NULL) {
618 if (found.name != NULL && found.value != NULL) { return np; }
619 }
620 else if (attr != NULL && value != NULL) {
621 if (found.attr != NULL && found.value != NULL) { return np; }
622 }
623 else if (name != NULL) {
624 if (found.name != NULL) { return np; }
625 }
626 else if (attr != NULL) {
627 if (found.attr != NULL) { return np; }
628 }
629 else if (value != NULL) {
630 if (found.value != NULL) { return np; }
631 }
632 }
633
634 /* descend child */
635 if (np->child != NULL) {
636 sxml_node_t * child;
637
638 child = sxml_find_element(np->child, name, attr, value);
639 if (child != NULL) {
640 return child;
641 }
642 }
643 }
644
645 return NULL;
646 }
647
648 const char *
sxml_get_attribute(node,name)649 sxml_get_attribute(node, name)
650 sxml_node_t * node; /* prolog/element node */
651 const char * name; /* name of attribute */
652 {
653 if (node->type == SXML_ELEMENT || node->type == SXML_PROLOG) {
654 if (node->value.element.attrs != NULL) {
655 register sxml_attr_t * ap;
656
657 for (ap = node->value.element.attrs; ap != NULL; ap = ap->next) {
658 if (ap->name != NULL && strcmp(name, ap->name) == 0) {
659 return ap->value;
660 }
661 }
662 }
663 }
664
665 return NULL;
666 }
667
668 const char *
sxml_get_content(node)669 sxml_get_content(node)
670 sxml_node_t * node;
671 {
672 return (node != NULL && node->type == SXML_CONTENT) ?
673 node->value.content : NULL;
674 }
675
676 /*****************************************************************************
677 *
678 *****************************************************************************/
679 void
sxml_print_tree(node,fout)680 sxml_print_tree(node, fout)
681 sxml_node_t * node;
682 register FILE * fout;
683 {
684 if (fout != NULL) {
685 print_node(node, node->type == SXML_VERTEX ? -1 : 0, fout);
686 fflush(fout);
687 }
688 }
689
690 static void
print_node(node,depth,fout)691 print_node(node, depth, fout)
692 sxml_node_t * node;
693 int depth;
694 register FILE * fout;
695 {
696 register sxml_node_t * np;
697
698 for (np = node; np; np = np->next) {
699 switch (np->type) {
700 case SXML_PROLOG: {
701 register sxml_attr_t * ap;
702
703 fprintf(fout, "<?%s", np->value.element.name);
704 for (ap = np->value.element.attrs; ap != NULL; ap = ap->next) {
705 fprintf(fout, " %s=\"%s\"", ap->name, ap->value);
706 }
707 fputs("?>\n", fout);
708 }
709 break;
710 case SXML_ELEMENT: {
711 register int i;
712 register sxml_attr_t * ap;
713
714 for (i = 0; i < depth; i++) {
715 fputs(" ", fout);
716 }
717 fprintf(fout, "<%s", np->value.element.name);
718 for (ap = np->value.element.attrs; ap != NULL; ap = ap->next) {
719 fprintf(fout, " %s=\"%s\"", ap->name, ap->value);
720 }
721 fputs(">", fout);
722 if (np->child && np->child->type == SXML_ELEMENT) {
723 fputs("\n", fout);
724 }
725 }
726 break;
727 case SXML_CONTENT:
728 fprintf(fout, "%s", np->value.content);
729 default:
730 break;
731 }
732 if (np->child) { print_node(np->child, depth + 1, fout); }
733 if (np->type == SXML_ELEMENT) {
734 if (np->child && np->child->type == SXML_ELEMENT) {
735 register int i;
736
737 for (i = 0; i < depth; i++) {
738 fputs(" ", fout);
739 }
740 }
741 fprintf(fout, "</%s>\n", np->value.element.name);
742 }
743 }
744 }
745
746 void
sxml_print_node(node,fout)747 sxml_print_node(node, fout)
748 sxml_node_t * node;
749 register FILE * fout;
750 {
751 if (node != NULL) {
752 switch (node->type) {
753 case SXML_ELEMENT: {
754 register sxml_attr_t * ap;
755
756 fprintf(fout, "<%s", node->value.element.name);
757 for (ap = node->value.element.attrs; ap != NULL; ap = ap->next) {
758 fprintf(fout, " %s=\"%s\"", ap->name, ap->value);
759 }
760 fprintf(fout, ">\n");
761 }
762 break;
763 case SXML_CONTENT:
764 fprintf(fout, "%s\n", node->value.content);
765 default:
766 break;
767 }
768 fflush(fout);
769 }
770 }
771
772 /*****************************************************************************
773 *
774 *****************************************************************************/
775
776 sxml_node_t *
sxml_new_vertex(void)777 sxml_new_vertex(void)
778 {
779 sxml_node_t * new;
780
781 new = create_new_node(NULL);
782 if (new != NULL) {
783 new->type = SXML_VERTEX;
784 }
785
786 return new;
787 }
788
789 sxml_node_t *
sxml_new_prolog(parent,name)790 sxml_new_prolog(parent, name)
791 sxml_node_t * parent;
792 const char * name; /* name of prolog */
793 {
794 sxml_node_t * new; /* node of new element */
795
796 new = create_new_node(parent);
797 if (new != NULL) {
798 new->value.element.name = strdup(name);
799 new->value.element.attrs = NULL;
800 new->type = SXML_PROLOG;
801
802 if (parent->child != NULL) { /* parent has children */
803 new->next = parent->child;
804 parent->child->prev = new;
805 parent->child = new;
806 }
807 else { /* I'm fist child of the parent */
808 parent->last_child = parent->child = new;
809 }
810 }
811
812 return new;
813 }
814
815 sxml_node_t *
sxml_new_element(parent,name)816 sxml_new_element(parent, name)
817 sxml_node_t * parent;
818 const char * name; /* name of element */
819 {
820 sxml_node_t * new; /* node of new element */
821
822 new = create_new_node(parent);
823 if (new != NULL) {
824 new->value.element.name = strdup(name);
825 new->value.element.attrs = NULL;
826
827 if (parent->child != NULL) { /* parent has children */
828 parent->last_child->next = new;
829 new->prev = parent->last_child;
830 parent->last_child = new;
831 }
832 else { /* I'm fist child of the parent */
833 parent->last_child = parent->child = new;
834 }
835 }
836
837 return new;
838 }
839
840 sxml_node_t *
sxml_set_content(element,content)841 sxml_set_content(element, content)
842 sxml_node_t * element;
843 const char * content; /* content of element */
844 {
845 sxml_node_t * new; /* content */
846
847 new = create_new_node(element);
848 if (new != NULL) {
849 new->type = SXML_CONTENT;
850 new->value.content = strdup(content);
851 element->child = element->last_child = new;
852 }
853
854 return new;
855 }
856
857 int
sxml_set_attribute(node,name,value)858 sxml_set_attribute(node, name, value)
859 sxml_node_t * node;
860 const char * name;
861 const char * value;
862 {
863 if (node->type == SXML_ELEMENT || node->type == SXML_PROLOG) {
864 sxml_attr_t * ap;
865
866 ap = set_attribute(node->value.element.attrs, name, value);
867 if (ap != NULL) {
868 node->value.element.attrs = ap;
869 return 0;
870 }
871 }
872
873 return -1;
874 }
875
876 int
sxml_set_fattribute(sxml_node_t * node,const char * name,const char * fmt,...)877 sxml_set_fattribute(
878 sxml_node_t * node,
879 const char * name,
880 const char * fmt,
881 ...)
882 {
883 sxml_attr_t * ap = NULL;
884
885 if (node->type == SXML_ELEMENT || node->type == SXML_PROLOG) {
886 char * val;
887
888 #define MAGIC_SIZE (4*1024) /* XXX: groundless value */
889 val = calloc(MAGIC_SIZE, sizeof(char));
890 if (val != NULL) {
891 va_list vp;
892
893 va_start(vp, fmt);
894 vsnprintf(val, MAGIC_SIZE, fmt, vp);
895 va_end(vp);
896
897 ap = set_attribute(node->value.element.attrs, name, val);
898 if (ap != NULL) {
899 node->value.element.attrs = ap;
900 }
901 free(val);
902 }
903 }
904
905 return (ap != NULL ? 0 : -1);
906 }
907
908 sxml_node_t *
sxml_set_node(parent,name,content)909 sxml_set_node(parent, name, content)
910 sxml_node_t * parent;
911 const char * name; /* name of element */
912 const char * content; /* content of element */
913 {
914 sxml_node_t * new;
915
916 new = sxml_new_element(parent, name);
917 if (new != NULL) {
918 sxml_set_content(new, content);
919 }
920
921 return new;
922 }
923
924 sxml_node_t *
sxml_set_fnode(sxml_node_t * parent,const char * name,const char * fmt,...)925 sxml_set_fnode(
926 sxml_node_t * parent,
927 const char * name, /* name of element */
928 const char * fmt, /* format for content of element */
929 ...)
930 {
931 sxml_node_t * new = NULL;
932 char * val;
933
934 val = calloc(MAGIC_SIZE, sizeof(char));
935 if (val != NULL) {
936 va_list vp;
937
938 va_start(vp, fmt);
939 vsnprintf(val, MAGIC_SIZE, fmt, vp);
940 va_end(vp);
941
942 new = sxml_new_element(parent, name);
943 if (new != NULL) {
944 sxml_set_content(new, val);
945 }
946 free(val);
947 }
948
949 return new;
950 }
951