2 Copyright Red Hat, Inc. 2002-2003
4 The Red Hat Cluster Manager API Library is free software; you can
5 redistribute it and/or modify it under the terms of the GNU Lesser
6 General Public License as published by the Free Software Foundation;
7 either version 2.1 of the License, or (at your option) any later
10 The Red Hat Cluster Manager API Library is distributed in the hope
11 that it will be useful, but WITHOUT ANY WARRANTY; without even the
12 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
13 PURPOSE. See the GNU Lesser General Public License for more details.
15 You should have received a copy of the GNU Lesser General Public
16 License along with this library; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
21 * Configuration Library using libxml2 Doc Tree.
23 * XXX Needs Doxygenification.
29 #include <libxml/xmlmemory.h>
30 #include <libxml/parser.h>
31 #include <sys/queue.h>
33 #include <sys/param.h>
34 #include <sys/types.h>
35 #include <regex.h> /* Regular Expression Matching */
36 #include <fnmatch.h> /* Glob pattern matching */
37 #include <xmlconfig.h>
43 struct _uint_stack
*uis_next
;
49 _uis_push(struct _uint_stack
**stack
, int val
)
51 struct _uint_stack
*new;
56 if (!(new = malloc(sizeof(*new))))
59 new->uis_next
= *stack
;
68 _uis_pop(struct _uint_stack
**stack
)
70 struct _uint_stack
*del
;
77 *stack
= (*stack
)->uis_next
;
86 _uis_kill(struct _uint_stack
**stack
)
88 while (_uis_pop(stack
) != -1);
92 static inline xmlAttrPtr
93 _xmlGetAttrPtr(xmlNodePtr cur
, const char *prop
)
95 xmlAttrPtr attr
= cur
->properties
;
97 for (; attr
; attr
= attr
->next
)
98 if (!strcasecmp((char *)attr
->name
, prop
))
106 _is_regex(const char *token
)
108 return (strcspn(token
,"([.*|+])") != strlen(token
));
113 * construct a list of all tokens in our XML tree in the form:
114 * "tag%subtag%subtag1%abc123%property"
115 * TODO optimize, optimize, optimize...
118 xtree_tl_build(xmlDocPtr xtree
, struct _token_list_head
*head
,
119 const char *m_pat
, int m_type
)
121 xmlNodePtr cur
= xmlDocGetRootElement(xtree
);
122 xmlAttrPtr attr
= NULL
;
123 char token
[MAX_TOKEN_LEN
], *prop
;
124 unsigned int pos
= 0, tmp
;
125 struct _uint_stack
*stack
= NULL
;
126 struct _token_list_node
*tnode
;
129 MATCH_INIT(m_pat
, m_type
);
132 MATCH_FREE(m_pat
, m_type
);
138 cur
= cur
->xmlChildrenNode
;
140 if (cur
->type
== XML_TEXT_NODE
)
143 strncpy(token
+ pos
, (char *)cur
->name
, sizeof(token
) - pos
);
144 prop
= (char *)xmlGetProp(cur
, (xmlChar
*)"id");
146 strncat(token
+ strlen(token
), prop
,
147 MIN(strlen(prop
) + 1,
148 sizeof(token
) - strlen(token
)));
152 if (cur
->xmlChildrenNode
) {
153 _uis_push(&stack
, pos
);
154 cur
= cur
->xmlChildrenNode
;
155 strncat(token
+ strlen(token
), "%",
156 MIN(2, sizeof(token
) - strlen(token
)));
161 /* Here we tack on the properties */
163 strncat(token
+ tmp
, "%", MIN(2, sizeof(token
) - tmp
));
166 attr
= cur
->properties
;
168 if (!strcasecmp((char *)attr
->name
,"id")) {
173 strncpy(token
+ tmp
, (char *)attr
->name
,
174 MIN(strlen((char *)attr
->name
) + 1,
175 sizeof(token
) - tmp
));
177 if (!MATCH(token
, m_pat
, m_type
)) {
182 if (!(tnode
= malloc(sizeof(*tnode
)))) {
184 MATCH_FREE(m_pat
, m_type
);
189 memset(tnode
,0,sizeof(*tnode
));
191 if (!(tnode
->tl_token
= strdup(token
))) {
193 MATCH_FREE(m_pat
, m_type
);
199 if (!(tnode
->tl_value
=
200 strdup((char *)attr
->children
->content
))) {
202 MATCH_FREE(m_pat
, m_type
);
204 free(tnode
->tl_token
);
209 tnode
->tl_terminal
= attr
;
211 TAILQ_INSERT_TAIL(head
, tnode
, tl_chain
);
225 pos
= _uis_pop(&stack
);
234 MATCH_FREE(m_pat
,m_type
);
240 xtree_tl_free(struct _token_list_head
*head
)
242 struct _token_list_node
*cur
, *back
;
244 cur
= head
->tqh_first
;
247 cur
= cur
->tl_chain
.tqe_next
;
249 TAILQ_REMOVE(head
, back
, tl_chain
);
250 free(back
->tl_token
);
251 free(back
->tl_value
);
255 head
->tqh_first
= NULL
;
260 _extract_int(char *chunk
, char *rv
, int rv_size
)
265 if ((id_loc
= strcspn(chunk
,"0123456789")) < strlen(chunk
)) {
267 strncpy(rv
, id
, rv_size
);
277 _has_attributes(xmlNodePtr node
)
279 xmlAttrPtr attr
= node
->properties
;
282 if ((attr
->type
== XML_ATTRIBUTE_NODE
) &&
283 strcasecmp((char *)attr
->name
,"id"))
293 _has_children(xmlNodePtr node
)
295 xmlNodePtr cur
= node
->xmlChildrenNode
;
298 if (node
->type
== XML_ELEMENT_NODE
)
308 _xtree_del(xmlAttrPtr attr
)
318 /* Ok, check if that was our last property/child */
319 while (!_has_children(cur
) && !_has_attributes(cur
)) {
331 _xtree_find(xmlDocPtr xtree
, const char *token
)
339 xmlNodePtr cur
= xmlDocGetRootElement(xtree
),
341 xmlAttrPtr rv
= NULL
;
343 /* duplicate our inbound token, so we can tokenize it */
344 if (!cur
|| (!(tok
= malloc(strlen(token
)+1))))
350 cur
= cur
->xmlChildrenNode
;
353 while ((nextpart
= strchr(part
,'%')) && cur
) {
354 *nextpart
= 0; /* remove '%' */
356 id
= _extract_int(part
, buf
, sizeof(buf
));
358 while (cur
) { /* check for drop-to-child */
359 if (xmlStrcmp(cur
->name
, (xmlChar
*)part
) != 0) {
366 id_check
= (char *)xmlGetProp(cur
,
369 if (id_check
&& strcasecmp(id
, id_check
)) {
381 cur
= cur
->xmlChildrenNode
;
386 * if id is till set here, we have an id from above, but it
397 if (id
) /* ID not found! */
399 else /* xml node property */
400 rv
= _xmlGetAttrPtr(last_parent
, part
);
410 * bottom-up deletion... ;)
413 xtree_del(xmlDocPtr xtree
, const char *token
)
415 return _xtree_del(_xtree_find(xtree
,token
));
420 xtree_set(xmlDocPtr xtree
, const char *token
, char *value
)
430 xmlNodePtr cur
= xmlDocGetRootElement(xtree
),
434 /* Reject regexps in this case */
435 if (_is_regex(token
))
438 /* duplicate our inbound token, so we can hack it up */
439 if (!cur
|| !strlen(token
) || (!(tok
= malloc(strlen(token
)+1))))
443 strncpy(tok
, token
, strlen(token
)+1);
445 cur
= cur
->xmlChildrenNode
;
448 nextpart
= strchr(part
, '%');
450 *nextpart
= 0; /* remove '%' */
453 id
= _extract_int(part
, buf
, sizeof(buf
));
455 while (cur
) { /* check for drop-to-child */
457 if (strcasecmp((char *)cur
->name
, part
)) {
464 id_check
= (char *)xmlGetProp(cur
,
467 if (strcasecmp(id
, id_check
)) {
479 cur
= cur
->xmlChildrenNode
;
486 * Ok, we dropped to child successfully. No IDs needed,
491 nextpart
= strchr(part
, '%');
496 * ok, so we've run off the end of our token or the
497 * end of the XML tree.
503 /* New regular node. Add it. */
506 newnode
= xmlNewNode(NULL
, (xmlChar
*)part
);
509 cur
= xmlAddChild(last_parent
, newnode
);
511 xmlFreeNode(newnode
);
517 cur
= newnode
->xmlChildrenNode
; /* same as NULL */
519 /* Don't forget to continue eating the token */
521 nextpart
= strchr(part
, '%');
523 /* set id property if it exists */
525 xmlSetProp(newnode
, (xmlChar
*)"id", (xmlChar
*)id
);
528 /* Write out the property */
530 xmlSetProp(last_parent
, (xmlChar
*)part
, (xmlChar
*)value
);
538 xtree_get(xmlDocPtr xtree
, const char *token
, char *dflt
, char **value
)
542 /* Reject regexps in this case */
543 if (_is_regex(token
)) {
544 printf("token is regex\n");
548 attr
= _xtree_find(xtree
, token
);
550 if (attr
&& attr
->children
->content
&&
551 strlen((char*)attr
->children
->content
)) {
553 *value
= (char *)attr
->children
->content
;
568 xtree_readfile(const char *filename
, xmlDocPtr
*xtreep
)
572 xmlKeepBlanksDefault(0);
573 xmlIndentTreeOutput
= 1;
575 *xtreep
= xmlParseFile(filename
);
580 if (!((cur
= xmlDocGetRootElement(*xtreep
)))) {
591 xtree_readbuffer(const char *buffer
, size_t size
, xmlDocPtr
*xtreep
)
595 xmlKeepBlanksDefault(0);
596 xmlIndentTreeOutput
= 1;
598 *xtreep
= xmlParseMemory(buffer
, size
);
601 printf("parse failure %p %d\n", buffer
, (int)size
);
605 if (!((cur
= xmlDocGetRootElement(*xtreep
)))) {
606 printf("root element failure\n");
617 xtree_writefile(const char *filename
, xmlDocPtr xtree
)
623 int n
, remain
, written
, size
= 0;
625 snprintf(tmpfn
, sizeof(tmpfn
), "%s.XXXXXX", filename
);
626 tmpfd
= mkstemp(tmpfn
);
630 memset(&flock
, 0, sizeof(flock
));
631 flock
.l_type
= F_WRLCK
;
633 fd
= open(filename
, O_WRONLY
| O_CREAT
| O_SYNC
);
642 while (fcntl(fd
, F_SETLKW
, &flock
) == -1) {
653 xmlDocDumpFormatMemory(xtree
, (xmlChar
**)&buffer
, (int *)&size
, 1);
658 n
= write(tmpfd
, buffer
+ written
, remain
);
678 if (rename(tmpfn
, filename
) == -1) {
695 xtree_writebuffer(xmlDocPtr xtree
, char **buffer
, size_t *size
)
698 xmlDocDumpFormatMemory(xtree
, (xmlChar
**)buffer
, (int *)size
, 1);
704 tlist_dump(struct _token_list_head
*lh
)
706 struct _token_list_node
*cur
;
710 printf("%s => %s\n", cur
->tl_token
,
711 cur
->tl_terminal
->children
->content
);
712 cur
= cur
->tl_chain
.tqe_next
;