00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020 #ifndef lint
00021 static const char rcsid[] = "$Id: xml.c,v 1.27 2007-08-19 19:49:17 sven Exp $";
00022 #endif
00023
00024 #include <eggdrop/eggdrop.h>
00025
00026 static char *last_error = NULL;
00027
00028 const char *xml_last_error(void)
00029 {
00030 return last_error;
00031 }
00032
00033 void xml_set_error(const char *err)
00034 {
00035 str_redup(&last_error, err);
00036 }
00037
00044 xml_node_t *xml_node_new()
00045 {
00046 xml_node_t *node;
00047
00048 node = calloc(sizeof(*node), 1);
00049
00050 return node;
00051 }
00052
00061 xml_node_t *xml_node_new_named(const char *name)
00062 {
00063 xml_node_t *node = xml_node_new();
00064 node->name = strdup(name);
00065 return(node);
00066 }
00067
00074 void xml_node_free(xml_node_t *node)
00075 {
00076 xml_attr_t *attr;
00077 int i;
00078
00079 if (node->name) free(node->name);
00080 if (node->text) free(node->text);
00081 for (i = 0; i < node->nattributes; i++) {
00082 attr = node->attributes[i];
00083 xml_attr_free(attr);
00084 }
00085 if (node->attributes) free(node->attributes);
00086 free(node);
00087 }
00088
00098 void xml_node_unlink(xml_node_t *node)
00099 {
00100 xml_node_t *parent = node->parent;
00101
00102
00103 if (parent) {
00104 parent->nchildren--;
00105 if (parent->children == node) parent->children = node->next;
00106 if (parent->last_child == node) parent->last_child = node->prev;
00107
00108 node->parent = NULL;
00109 }
00110
00111
00112 if (node->prev) node->prev->next = node->next;
00113 if (node->next) node->next->prev = node->prev;
00114
00115
00116 if (node->prev_sibling) node->prev_sibling->next_sibling = node->next_sibling;
00117 if (node->next_sibling) node->next_sibling->prev_sibling = node->prev_sibling;
00118 }
00119
00131 void xml_node_delete(xml_node_t *node)
00132 {
00133 xml_node_delete_callbacked(node, NULL);
00134 }
00135
00146 void xml_node_delete_callbacked(xml_node_t *node, void (*callback)(void *))
00147 {
00148 xml_node_t *child, *child_next;
00149
00150 if (node->client_data && callback) callback(node->client_data);
00151
00152 xml_node_unlink(node);
00153
00154
00155 for (child = node->children; child; child = child_next) {
00156 child_next = child->next;
00157 child->parent = NULL;
00158 xml_node_delete_callbacked(child, callback);
00159 }
00160
00161
00162 xml_node_free(node);
00163 }
00164
00174 void xml_doc_delete(xml_node_t *root)
00175 {
00176 while (root->parent) root = root->parent;
00177 xml_node_delete(root);
00178 }
00179
00180 xml_node_t *xml_node_vlookup(xml_node_t *root, va_list args, int create)
00181 {
00182 char *path;
00183 int index;
00184
00185 for (; root;) {
00186 path = va_arg(args, char *);
00187 if (!path) break;
00188 index = va_arg(args, int);
00189 root = xml_node_path_lookup(root, path, index, create);
00190 }
00191 return(root);
00192 }
00193
00194 xml_node_t *xml_node_lookup(xml_node_t *root, int create, ...)
00195 {
00196 va_list args;
00197 xml_node_t *node;
00198
00199 va_start(args, create);
00200 node = xml_node_vlookup(root, args, create);
00201 va_end(args);
00202 return(node);
00203 }
00204
00222 xml_node_t *xml_node_path_lookup(xml_node_t *root, const char *path, int index, int create)
00223 {
00224 int thisindex, len;
00225 xml_node_t *child;
00226 const char *next;
00227 char *name, *sep, buf[512];
00228
00229 for (; root && path; path = next) {
00230
00231 sep = strchr(path, '.');
00232 if (sep) {
00233 next = sep+1;
00234 len = sep - path;
00235 }
00236 else {
00237 next = NULL;
00238 len = strlen(path);
00239 }
00240
00241
00242 if (!len) continue;
00243 else if (len > sizeof(buf) - 10) {
00244 name = malloc(len+1);
00245 }
00246 else {
00247 name = buf;
00248 }
00249 memcpy(name, path, len);
00250 name[len] = 0;
00251
00252
00253
00254 thisindex = 0;
00255 if (len > 3 && name[len-1] == ']') {
00256 sep = strrchr(name, '[');
00257 if (sep) {
00258 *sep = 0;
00259 name[len-1] = 0;
00260 thisindex = atoi(sep+1);
00261 }
00262 }
00263
00264
00265 if (!next) thisindex += index;
00266
00267 for (child = root->children; child; child = child->next) {
00268 if (child->name && !strcasecmp(child->name, name)) break;
00269 }
00270
00271 while (child && thisindex > 0) {
00272 thisindex--;
00273 child = child->next_sibling;
00274 }
00275
00276 if (!child && create) {
00277 do {
00278 child = xml_node_new();
00279 child->type = XML_ELEMENT;
00280 child->name = strdup(name);
00281 xml_node_append(root, child);
00282 } while (thisindex-- > 0);
00283 }
00284 if (name != buf) free(name);
00285
00286 root = child;
00287 }
00288 return(root);
00289 }
00290
00291 char *xml_node_fullname(xml_node_t *thenode)
00292 {
00293 xml_node_t *node;
00294 char *name, *name2;
00295 int len, total_len;
00296
00297 len = total_len = 0;
00298 name = calloc(1, 1);
00299 for (node = thenode; node; node = node->parent) {
00300 if (!node->name) continue;
00301
00302
00303 len = strlen(node->name) + 1;
00304
00305
00306 name2 = malloc(len + total_len + 1);
00307
00308
00309 sprintf(name2, "%s.%s", node->name, name);
00310 free(name);
00311 name = name2;
00312 total_len += len;
00313 }
00314 if (total_len > 0) name[total_len-1] = 0;
00315 return(name);
00316 }
00317
00318 int xml_node_get_int(int *value, xml_node_t *node, ...)
00319 {
00320 va_list args;
00321
00322 va_start(args, node);
00323 node = xml_node_vlookup(node, args, 0);
00324 va_end(args);
00325 if (node && node->text) {
00326 *value = strtol(node->text, NULL, 0);
00327 return(0);
00328 }
00329 *value = 0;
00330 return(-1);
00331 }
00332
00346 int xml_node_int(xml_node_t *node, int def)
00347 {
00348 int value;
00349 char *ptr;
00350
00351 if (!node || !node->text) return(def);
00352 value = strtol(node->text, &ptr, 0);
00353 if (!ptr || *ptr) return(def);
00354 else return(value);
00355 }
00356
00357 int xml_node_get_str(char **str, xml_node_t *node, ...)
00358 {
00359 va_list args;
00360
00361 va_start(args, node);
00362 node = xml_node_vlookup(node, args, 0);
00363 va_end(args);
00364 if (node) {
00365 *str = node->text;
00366 return(0);
00367 }
00368 *str = NULL;
00369 return(-1);
00370 }
00371
00384 char *xml_node_str(xml_node_t *node, char *def)
00385 {
00386 if (!node || !node->text) return(def);
00387 else return(node->text);
00388 }
00389
00390 int xml_node_set_int(int value, xml_node_t *node, ...)
00391 {
00392 char buf[32];
00393 va_list args;
00394
00395 va_start(args, node);
00396 node = xml_node_vlookup(node, args, 1);
00397 va_end(args);
00398 if (!node) return(-1);
00399
00400 snprintf(buf, sizeof(buf), "%d", value);
00401 str_redup(&node->text, buf);
00402
00403 return(0);
00404 }
00405
00406 int xml_node_set_str(const char *str, xml_node_t *node, ...)
00407 {
00408 va_list args;
00409
00410 va_start(args, node);
00411 node = xml_node_vlookup(node, args, 1);
00412 va_end(args);
00413 if (!node) return(-1);
00414
00415 str_redup(&node->text, str);
00416
00417 return(0);
00418 }
00419
00420 int xml_node_get_vars(xml_node_t *node, const char *fmt, ...)
00421 {
00422 va_list args;
00423 char *name, **strptr;
00424 int *intptr;
00425 xml_node_t **nodeptr;
00426
00427 va_start(args, fmt);
00428 while (*fmt) {
00429 name = va_arg(args, char *);
00430 switch (*fmt) {
00431 case 's':
00432 strptr = va_arg(args, char **);
00433 xml_node_get_str(strptr, node, name, 0, 0);
00434 break;
00435 case 'i':
00436 intptr = va_arg(args, int *);
00437 xml_node_get_int(intptr, node, name, 0, 0);
00438 break;
00439 case 'n':
00440 nodeptr = va_arg(args, xml_node_t **);
00441 *nodeptr = xml_node_path_lookup(node, name, 0, 0);
00442 break;
00443 }
00444 fmt++;
00445 }
00446 va_end(args);
00447 return(0);
00448 }
00449
00450 int xml_node_set_vars(xml_node_t *node, const char *fmt, ...)
00451 {
00452 va_list args;
00453 char *name, *strval;
00454 int intval;
00455
00456 va_start(args, fmt);
00457 while (*fmt) {
00458 name = va_arg(args, char *);
00459 switch (*fmt) {
00460 case 's':
00461 strval = va_arg(args, char *);
00462 xml_node_set_str(strval, node, name, 0, 0);
00463 break;
00464 case 'i':
00465 intval = va_arg(args, int);
00466 xml_node_set_int(intval, node, name, 0, 0);
00467 break;
00468 }
00469 fmt++;
00470 }
00471 va_end(args);
00472 return(0);
00473 }
00474
00475 xml_node_t *xml_root_element(xml_node_t *node)
00476 {
00477 if (node == NULL) return NULL;
00478
00479
00480 while (node && node->parent) node = node->parent;
00481
00482
00483 node = node->children;
00484 while (node && node->type != XML_ELEMENT) node = node->next;
00485 return node;
00486 }
00487
00498 void xml_node_append(xml_node_t *parent, xml_node_t *child)
00499 {
00500 xml_node_t *node;
00501
00502 child->parent = parent;
00503 parent->nchildren++;
00504
00505 if (!parent->children) {
00506 parent->children = child;
00507 }
00508 else {
00509 parent->last_child->next = child;
00510 child->prev = parent->last_child;
00511 }
00512
00513 parent->last_child = child;
00514
00515 if (!child->name) return;
00516 for (node = child->prev; node; node = node->prev) {
00517 if (node->name && !strcasecmp(node->name, child->name)) {
00518 node->next_sibling = child;
00519 child->prev_sibling = node;
00520 break;
00521 }
00522 }
00523 }
00524
00538 xml_attr_t *xml_attr_new(char *name, char *value)
00539 {
00540 xml_attr_t *attr;
00541
00542 attr = malloc(sizeof(*attr));
00543 attr->name = name;
00544 attr->value = value;
00545 attr->len = strlen(value);
00546 return(attr);
00547 }
00548
00557 void xml_attr_free(xml_attr_t *attr)
00558 {
00559 if (attr->name) free(attr->name);
00560 if (attr->value) free(attr->value);
00561 free(attr);
00562 }
00563
00573 int xml_node_append_attr(xml_node_t *node, xml_attr_t *attr)
00574 {
00575 node->attributes = realloc(node->attributes, sizeof(*node->attributes) * (node->nattributes+1));
00576 node->attributes[node->nattributes++] = attr;
00577 return(0);
00578 }
00579
00592 xml_attr_t *xml_attr_lookup(xml_node_t *node, const char *name)
00593 {
00594 int i;
00595
00596 for (i = 0; i < node->nattributes; i++) {
00597 if (!strcasecmp(node->attributes[i]->name, name)) return(node->attributes[i]);
00598 }
00599 return(NULL);
00600 }
00601
00616 int xml_attr_int(xml_node_t *node, const char *name, int def)
00617 {
00618 xml_attr_t *attr = xml_attr_lookup(node, name);
00619 if (attr && attr->value) return atoi(attr->value);
00620 else return(def);
00621 }
00622
00637 char *xml_attr_str(xml_node_t *node, const char *name, char *def)
00638 {
00639 xml_attr_t *attr = xml_attr_lookup(node, name);
00640 if (attr && attr->value) return(attr->value);
00641 else return(def);
00642 }