Annotation of gpl/axl/src/axl_node.c, revision 1.1
1.1 ! misho 1: /*
! 2: * LibAxl: Another XML library
! 3: * Copyright (C) 2006 Advanced Software Production Line, S.L.
! 4: *
! 5: * This program is free software; you can redistribute it and/or
! 6: * modify it under the terms of the GNU Lesser General Public License
! 7: * as published by the Free Software Foundation; either version 2.1 of
! 8: * the License, or (at your option) any later version.
! 9: *
! 10: * This program is distributed in the hope that it will be useful,
! 11: * but WITHOUT ANY WARRANTY; without even the implied warranty of
! 12: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
! 13: * GNU Lesser General Public License for more details.
! 14: *
! 15: * You should have received a copy of the GNU Lesser General Public
! 16: * License along with this program; if not, write to the Free
! 17: * Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
! 18: * 02111-1307 USA
! 19: *
! 20: * You may find a copy of the license under this software is released
! 21: * at COPYING file. This is LGPL software: you are welcome to
! 22: * develop proprietary applications using this library without any
! 23: * royalty or fee but returning back any change, improvement or
! 24: * addition in the form of source code, project image, documentation
! 25: * patches, etc.
! 26: *
! 27: * For commercial support on build XML enabled solutions contact us:
! 28: *
! 29: * Postal address:
! 30: * Advanced Software Production Line, S.L.
! 31: * Edificio Alius A, Oficina 102,
! 32: * C/ Antonio Suarez Nº 10,
! 33: * Alcalá de Henares 28802 Madrid
! 34: * Spain
! 35: *
! 36: * Email address:
! 37: * info@aspl.es - http://www.aspl.es/xml
! 38: */
! 39:
! 40: #include <axl.h>
! 41: #define LOG_DOMAIN "axl-node"
! 42:
! 43: /**
! 44: * \defgroup axl_node_module Axl Node: Xml node interface functions to use and manipulate xml nodes inside documents.
! 45: */
! 46:
! 47: /**
! 48: * \addtogroup axl_node_module
! 49: * @{
! 50: */
! 51:
! 52: struct _axlAttrCursor {
! 53: axlPointer data;
! 54: int count;
! 55: axlNode * node;
! 56: };
! 57:
! 58: /**
! 59: * @internal Axl content representation used to store comments, xml
! 60: * content, CDATA content and entity references.
! 61: */
! 62: typedef struct _axlNodeContent axlNodeContent;
! 63:
! 64: struct _axlNodeContent {
! 65: /**
! 66: * @internal
! 67: *
! 68: * @brief Pointer which holds current content inside the xml
! 69: * node.
! 70: */
! 71: char * content;
! 72: /**
! 73: * @internal
! 74: *
! 75: * @brief Current content size stored on the given axlNode.
! 76: */
! 77: int content_size;
! 78:
! 79: };
! 80:
! 81: /**
! 82: * @internal Type representation to hold node attributes while they
! 83: * are fewer.
! 84: */
! 85: typedef struct _axlNodeAttr axlNodeAttr;
! 86:
! 87: struct _axlNodeAttr {
! 88: /**
! 89: * @internal Node attribute name.
! 90: */
! 91: char * attribute;
! 92:
! 93: /**
! 94: * @internal Node attribute value.
! 95: */
! 96: char * value;
! 97:
! 98: /**
! 99: * @internal Flags the attribute pair to be considered from a
! 100: * factory.
! 101: */
! 102: axl_bool from_factory;
! 103:
! 104: /**
! 105: * @internal Next attribute.
! 106: */
! 107: axlNodeAttr * next;
! 108: };
! 109:
! 110: /**
! 111: * @internal Function that allows to copy all attributes found on the
! 112: * list received.
! 113: *
! 114: * @param list The attribute list to copy.
! 115: *
! 116: * @return A newly allocated attribute list.
! 117: */
! 118: axlNodeAttr * __axl_node_copy_attr_list (axlNodeAttr * list)
! 119: {
! 120: axlNodeAttr * result = NULL;
! 121:
! 122: /* if the list isn't defined, return NULL */
! 123: if (list == NULL)
! 124: return NULL;
! 125:
! 126: /* alloc memory to hold attribute name and value, and
! 127: * copy it from the list */
! 128: result = axl_new (axlNodeAttr, 1);
! 129: result->attribute = axl_strdup (list->attribute);
! 130: result->value = axl_strdup (list->value);
! 131:
! 132: /* call to copy the rest of the list */
! 133: result->next = __axl_node_copy_attr_list (list->next);
! 134:
! 135: /* return result created */
! 136: return result;
! 137: }
! 138:
! 139: /**
! 140: * @internal Deallocs the attribute list received.
! 141: *
! 142: * @param list The attribute list to copy.
! 143: *
! 144: * @return A newly allocated attribute list.
! 145: */
! 146: void __axl_node_free_attr_list (axlNodeAttr * attr)
! 147: {
! 148: axlNodeAttr * next;
! 149:
! 150: /* if the list isn't defined, return NULL */
! 151: if (attr == NULL)
! 152: return;
! 153:
! 154: /* copy all nodes */
! 155: while (attr != NULL) {
! 156: /* get the next attribute */
! 157: next = attr->next;
! 158:
! 159: /* free attribute description */
! 160: if (! attr->from_factory) {
! 161: axl_free (attr->attribute);
! 162: axl_free (attr->value);
! 163: axl_free (attr);
! 164: } /* end if */
! 165:
! 166: /* get the next */
! 167: attr = next;
! 168:
! 169: } /* end while */
! 170:
! 171: /* return result created */
! 172: return;
! 173: }
! 174:
! 175: /**
! 176: * @internal Function that allows to now if both lists represents the
! 177: * same set of attributes, even if they aren't ordered using the same.
! 178: *
! 179: * @param attr The first attribute pointing to the rest of the
! 180: * attribute list.
! 181: *
! 182: * @param attr2 The second attribute pointing to the rest of the
! 183: * attribute list.
! 184: *
! 185: * @return \ref axl_true if both lists are equal, otherwise \ref axl_false is
! 186: * returned.
! 187: */
! 188: axl_bool __axl_node_attr_list_is_equal (axlNodeAttr * attr, axlNodeAttr * attr2)
! 189: {
! 190: axlNodeAttr * attrAux;
! 191: axl_bool found;
! 192:
! 193: /* for each attribute found in the attribute list, check it on
! 194: * the second list */
! 195: while (attr != NULL) {
! 196:
! 197: attrAux = attr2;
! 198: found = axl_false;
! 199: while (attrAux != NULL) {
! 200:
! 201: /* check attribute */
! 202: if (axl_cmp (attrAux->attribute, attr->attribute) &&
! 203: axl_cmp (attrAux->value, attr->value)) {
! 204: /* attribute found, break the loop */
! 205: found = axl_true;
! 206: break;
! 207: }
! 208:
! 209: /* next attribute */
! 210: attrAux = attrAux->next;
! 211:
! 212: } /* end while */
! 213:
! 214: /* check if the attribute was found */
! 215: if (! found )
! 216: return axl_false;
! 217:
! 218: /* get the next */
! 219: attr = attr->next;
! 220:
! 221: } /* end while */
! 222:
! 223: /* all attributes was found, including its values, so, the
! 224: * list is equal */
! 225: return axl_true;
! 226: }
! 227:
! 228: typedef enum {
! 229: /**
! 230: * @internal Signal axl library that the node was allocated by
! 231: * a factory not by the system alloc.
! 232: */
! 233: NODE_FROM_FACTORY = 1,
! 234:
! 235: /**
! 236: * @internal Signal axl library that the node node was
! 237: * allocated by a factory not by the system alloc.
! 238: */
! 239: NODE_NAME_FROM_FACTORY = 1 << 2
! 240: } axlNodeConf;
! 241:
! 242: struct _axlNode {
! 243: /**
! 244: * @internal
! 245: *
! 246: * Node name that is the value found at the very begining of
! 247: * the node definition <name.../>
! 248: */
! 249: char * name;
! 250:
! 251: /**
! 252: * @internal Number of attributes stored. This value is used
! 253: * to now if the attributes are stored using a hash or a
! 254: * linked list. In the case it is equal or greater than 11, a
! 255: * hash is used to store attribute. Otherwise, a linked list
! 256: * (using axlAttrNode) is used.
! 257: */
! 258: int attr_num;
! 259:
! 260: /**
! 261: * @internal
! 262: * @brief The attributes this node has.
! 263: */
! 264: axlPointer * attributes;
! 265:
! 266: /**
! 267: * @internal A reference to the first child.
! 268: */
! 269: axlItem * first;
! 270:
! 271: /**
! 272: * @internal A reference to the last child.
! 273: */
! 274: axlItem * last;
! 275:
! 276: /**
! 277: * @internal A hash used to store arbitrary data associated to
! 278: * the node.
! 279: */
! 280: axlHash * annotate_data;
! 281:
! 282: /**
! 283: * @internal Internal reference to the holder axlItem
! 284: * containing the axl node reference.
! 285: */
! 286: axlItem * holder;
! 287:
! 288: /**
! 289: * @internal Value that contains flags for configuration.
! 290: */
! 291: int conf;
! 292: };
! 293:
! 294: struct _axlItem {
! 295: /**
! 296: * @internal A reference to the type that is being hold by the
! 297: * encapsulation reference.
! 298: */
! 299: AxlItemType type;
! 300:
! 301: /**
! 302: * @internal The reference to the pointer that is actually
! 303: * stored.
! 304: */
! 305: axlPointer data;
! 306:
! 307: /**
! 308: * @internal
! 309: * A pointer to the parent node.
! 310: */
! 311: axlNode * parent;
! 312:
! 313: /**
! 314: * @internal
! 315: *
! 316: * A pointer to the brother node, the node that is found on
! 317: * the next position.
! 318: */
! 319: axlItem * next;
! 320:
! 321: /**
! 322: * @internal Stores a reference to the previous node inside
! 323: * the same level.
! 324: */
! 325: axlItem * previous;
! 326:
! 327: /**
! 328: * @internal
! 329: *
! 330: * Internal reference to the whole xml document where the node
! 331: * is contained.
! 332: */
! 333: axlDoc * doc;
! 334: };
! 335:
! 336: /**
! 337: * @internal
! 338: *
! 339: * @brief Internal position function which ensures that nodes added
! 340: * will be added at the end of the list.
! 341: */
! 342: int __axl_node_equal (axlPointer a, axlPointer b)
! 343: {
! 344: return 1;
! 345: }
! 346:
! 347: /**
! 348: * @internal
! 349: *
! 350: * Internal function which allocates the enough memory to copy
! 351: * received content changing all escape sequences.
! 352: */
! 353: char * __axl_node_content_copy_and_escape (const char * content,
! 354: int content_size,
! 355: int additional_size,
! 356: axl_bool cdata)
! 357: {
! 358: int iterator = 0;
! 359: int iterator2 = 0;
! 360: char * result;
! 361: axl_return_val_if_fail (content, NULL);
! 362:
! 363: /* allocate the memory to be returned */
! 364: result = axl_new (char, content_size + additional_size + 1);
! 365:
! 366: /* iterate over all content defined */
! 367: while (iterator2 < content_size) {
! 368: /* check for ' */
! 369: if (content [iterator2] == '\'') {
! 370: memcpy (result + iterator, "'", 6);
! 371: iterator += 6;
! 372: iterator2++;
! 373: continue;
! 374: }
! 375:
! 376: /* check for " */
! 377: if (content [iterator2] == '"') {
! 378: memcpy (result + iterator, """, 6);
! 379: iterator += 6;
! 380: iterator2++;
! 381: continue;
! 382: }
! 383:
! 384: /* check for & */
! 385: if (content [iterator2] == '&') {
! 386: memcpy (result + iterator, "&", 5);
! 387: iterator += 5;
! 388: iterator2++;
! 389: continue;
! 390: }
! 391:
! 392: /* check for > */
! 393: if (content [iterator2] == '>') {
! 394: memcpy (result + iterator, ">", 4);
! 395: iterator += 4;
! 396: iterator2++;
! 397: continue;
! 398: }
! 399:
! 400: /* check for < */
! 401: if (content [iterator2] == '<') {
! 402: memcpy (result + iterator, "<", 4);
! 403: iterator += 4;
! 404: iterator2++;
! 405: continue;
! 406: }
! 407:
! 408: /* check for ]]> declaration */
! 409: if (content [iterator2] == ']' && content [iterator2 + 1] == ']' && content [iterator2 + 2] == '>') {
! 410: if (cdata) {
! 411: memcpy (result + iterator, "]]>]]><![CDATA[", 18);
! 412: iterator += 18;
! 413: iterator2 +=3;
! 414: } else {
! 415: memcpy (result + iterator, "]]>", 6);
! 416: iterator += 6;
! 417: iterator2 += 3;
! 418: }
! 419: continue;
! 420: }
! 421:
! 422: /* copy value received because it is not an escape
! 423: * sequence */
! 424: memcpy (result + iterator, content + iterator2, 1);
! 425:
! 426: /* update the iterator */
! 427: iterator++;
! 428: iterator2++;
! 429: }
! 430:
! 431: /* return results */
! 432: return result;
! 433: }
! 434:
! 435: /**
! 436: * @brief Replaces all entity references to its corresponding
! 437: * values. This function only implements translation for default
! 438: * recognized entities (&, <, >, ' and ").
! 439: *
! 440: * @param content The string content having escaped XML declarations
! 441: * such \> or \< which should be
! 442: * translated into its corresponding utf-8 symbol (for example > and
! 443: * <).
! 444: *
! 445: * @param content_size A non-optional reference to an integer variable
! 446: * which will hold the new size of the string returned. You can pass a
! 447: * variable initialized to 0 or -1 to let the function to calculate
! 448: * the initial string length (by using strlen).
! 449: *
! 450: * Because the substitution pattern applied on this operation makes
! 451: * not necessary to allocate memory, the function return the same
! 452: * string received, but with all values replaced. If you want to avoid
! 453: * this behaviour, use \ref axl_strdup before calling to this
! 454: * function.
! 455: *
! 456: * @return Returns the string modified or NULL if it fails.
! 457: */
! 458: char * axl_node_content_translate_defaults (char * content,
! 459: int * content_size)
! 460: {
! 461: int iterator = 0;
! 462: int iterator2 = 0;
! 463:
! 464: axl_return_val_if_fail (content, NULL);
! 465: axl_return_val_if_fail (content_size, NULL);
! 466:
! 467: /* update string length if no data was provided */
! 468: if (*content_size == 0 || *content_size == -1)
! 469: *content_size = strlen (content);
! 470:
! 471: /* iterate over all content defined */
! 472: while (iterator < (*content_size)) {
! 473:
! 474: /* check for ' */
! 475: if (axl_stream_cmp (content + iterator, "'", 6)) {
! 476: content [iterator2] = '\'';
! 477: iterator2++;
! 478:
! 479: iterator += 6;
! 480: continue;
! 481: }
! 482:
! 483: /* check for " */
! 484: if (axl_stream_cmp (content + iterator, """, 6)) {
! 485: content [iterator2] = '"';
! 486: iterator2++;
! 487:
! 488: iterator += 6;
! 489: continue;
! 490: }
! 491:
! 492: /* check for & */
! 493: if (axl_stream_cmp (content + iterator, "&", 5)) {
! 494: content [iterator2] = '&';
! 495: iterator2++;
! 496:
! 497: iterator += 5;
! 498: continue;
! 499: }
! 500:
! 501: /* check for > */
! 502: if (axl_stream_cmp (content + iterator, ">", 4)) {
! 503: content [iterator2] = '>';
! 504: iterator2++;
! 505:
! 506: iterator += 4;
! 507: continue;
! 508: }
! 509:
! 510: /* check for < */
! 511: if (axl_stream_cmp (content + iterator, "<", 4)) {
! 512: content [iterator2] = '<';
! 513: iterator2++;
! 514:
! 515: iterator += 4;
! 516: continue;
! 517: }
! 518:
! 519: /* copy move the content */
! 520: if (iterator2 != iterator)
! 521: content [iterator2] = content [iterator];
! 522:
! 523: /* update the iterator */
! 524: iterator++;
! 525: iterator2++;
! 526: }
! 527:
! 528: /* return results, setting the new content size */
! 529: *content_size = iterator2;
! 530: content [iterator2] = 0;
! 531: return content;
! 532: }
! 533:
! 534:
! 535:
! 536: /**
! 537: * @brief Creates a new \ref axlNode with the provided name.
! 538: *
! 539: * The function will perform a new local copy from the name reference
! 540: * received. See also \ref axl_node_create_ref for an explanation
! 541: * about how to save memory.
! 542: *
! 543: * @param name The name to be used for the node be created. The
! 544: * function doesn't check if the paramater received is null.
! 545: *
! 546: * @return A newly allocated \ref axlNode reference, that must be
! 547: * deallocated by \ref axl_node_free.
! 548: */
! 549: axlNode * axl_node_create (const char * name)
! 550: {
! 551:
! 552: axlNode * node;
! 553:
! 554: /* init the node */
! 555: node = axl_new (axlNode, 1);
! 556: node->name = axl_strdup (name);
! 557:
! 558: return node;
! 559: }
! 560:
! 561: /**
! 562: * @brief This function allows to create a xml node from the provided
! 563: * xml content (bootstraping XML content).
! 564: *
! 565: * This function is useful if it is required to create a node with a
! 566: * particular complex content, without going into the detail of
! 567: * creating all childs, attributes and content.
! 568: *
! 569: * Here is an example:
! 570: * \code
! 571: * axlError * error = NULL;
! 572: * axlNode * node = NULL;
! 573: *
! 574: * // parse document
! 575: * root = axl_node_parse_strings (error,
! 576: * "<child>",
! 577: * " <widget class=\"GtkLabel\" id=\"label4\">",
! 578: * " <property name=\"visible\">True</property>",
! 579: * " <property name=\"label\" translatable=\"yes\"><b>1. Seleccione el sistema:</b></property>",
! 580: * " <property name=\"use_underline\">False</property>",
! 581: * " <property name=\"use_markup\">True</property>",
! 582: * " <property name=\"justify\">GTK_JUSTIFY_LEFT</property>",
! 583: * " <property name=\"wrap\">False</property>",
! 584: * " <property name=\"selectable\">False</property>",
! 585: * " <property name=\"xalign\">0</property>",
! 586: * " <property name=\"yalign\">0.5</property>",
! 587: * " <property name=\"xpad\">0</property>",
! 588: * " <property name=\"ypad\">0</property>",
! 589: * " <property name=\"ellipsize\">PANGO_ELLIPSIZE_NONE</property>",
! 590: * " <property name=\"width_chars\">-1</property>",
! 591: * " <property name=\"single_line_mode\">False</property>",
! 592: * " <property name=\"angle\">0</property>",
! 593: * " </widget>",
! 594: * " <packing>",
! 595: * " <property name=\"padding\">0</property>",
! 596: * " <property name=\"expand\">False</property>",
! 597: * " <property name=\"fill\">False</property>",
! 598: * " </packing>",
! 599: * "</child>",
! 600: * NULL);
! 601: * if (root == NULL) {
! 602: * printf ("Error: unable to parse content, error: %s\n", axl_error_get (error));
! 603: * axl_error_free (error);
! 604: * return;
! 605: * }
! 606: *
! 607: * // once finished, free the node
! 608: * axl_node_free (root);
! 609: * \endcode
! 610: *
! 611: * @param error Optional error reference to report parsing error
! 612: * problems that can be found.
! 613: *
! 614: * The function receives a set of strings, separate by comma, ended by
! 615: * NULL.
! 616: *
! 617: * @return A newly allocated reference to the \ref axlNode or NULL if
! 618: * it fails. In such case, the error variable is filled with the error
! 619: * found.
! 620: */
! 621: axlNode * axl_node_parse_strings (axlError ** error, ...)
! 622: {
! 623: axlDoc * doc;
! 624: axlNode * root;
! 625: va_list args;
! 626: char * string = NULL;
! 627: char * stream = NULL;
! 628: char * stream_aux = NULL;
! 629:
! 630: /* check incoming data */
! 631: axl_return_val_if_fail (error, NULL);
! 632:
! 633: /* open the stdargs */
! 634: va_start (args, error);
! 635:
! 636: while ((string = va_arg (args, char *)) != NULL) {
! 637: stream_aux = stream;
! 638: stream = axl_stream_concat (stream, string);
! 639: if (stream_aux != NULL) {
! 640: axl_free (stream_aux);
! 641: stream_aux = NULL;
! 642: }
! 643: }
! 644:
! 645: /* close the stdargs */
! 646: va_end (args);
! 647:
! 648: /* check that we have received, at least, an string
! 649: * parseable */
! 650: if (stream == NULL)
! 651: return NULL;
! 652:
! 653: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "string to parse: %s", stream);
! 654:
! 655: /* parse the string */
! 656: doc = axl_doc_parse (stream, -1, error);
! 657: if (doc == NULL) {
! 658: /* free document */
! 659: axl_free (stream);
! 660: return NULL;
! 661: }
! 662:
! 663: /* free the stream */
! 664: axl_free (stream);
! 665:
! 666: /* deattach the root node */
! 667: root = axl_doc_get_root (doc);
! 668: axl_node_deattach (root);
! 669:
! 670: /* do not free the document, rather, store it to be
! 671: * deallocated by the node just after it is deallocated. */
! 672: axl_node_annotate_data_full (root, "__root_document", NULL, doc, (axlDestroyFunc) axl_doc_free);
! 673:
! 674: /* return the node created */
! 675: return root;
! 676: }
! 677:
! 678: /**
! 679: * @brief Allows to create a complete node configuring not only the
! 680: * node but its content, using a printf-like format.
! 681: *
! 682: * This handy function, like \ref axl_node_parse_strings, allows to
! 683: * create complex xml structures providing inline content.
! 684: *
! 685: * Here is an example:
! 686: * \code
! 687: * axlNode * node = axl_node_parse (NULL, "<content attr='value' attr2='value'>This is content</content>");
! 688: * \endcode
! 689: *
! 690: * The previous call will create a node called <b>content</b> with the
! 691: * provided attributes and content, in one step.
! 692: *
! 693: * The node returned can be integrated into a xml document using usual
! 694: * API, for example: \ref axl_node_set_child or \ref axl_doc_set_root.
! 695: *
! 696: * @param error The optional error reference holding the returned
! 697: * result.
! 698: *
! 699: * @param content The content to be used to create the node.
! 700: *
! 701: * @return A reference to a newly allocated \ref axlNode or NULL if it
! 702: * fails. The \ref axlError is filled with the error found if provided
! 703: * by the caller.
! 704: */
! 705: axlNode * axl_node_parse (axlError ** error, const char * content, ...)
! 706: {
! 707: char * _content;
! 708: va_list args;
! 709: axlDoc * doc;
! 710: axlNode * root;
! 711:
! 712: /* open the stdargs */
! 713: va_start (args, content);
! 714:
! 715: /* create the content */
! 716: _content = axl_strdup_printfv (content, args);
! 717:
! 718: /* close the stdargs */
! 719: va_end (args);
! 720:
! 721: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "parsing document:\n %s", _content);
! 722:
! 723: /* parse the string */
! 724: doc = axl_doc_parse (_content, -1, error);
! 725: if (doc == NULL) {
! 726: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "failed to parse document:\n %s", _content);
! 727:
! 728: /* free document */
! 729: axl_free (_content);
! 730:
! 731: return NULL;
! 732: }
! 733:
! 734: /* free the content */
! 735: axl_free (_content);
! 736:
! 737: /* deattach the root node */
! 738: root = axl_doc_get_root (doc);
! 739: axl_node_deattach (root);
! 740:
! 741: /* do not free the document, rather, store it to be
! 742: * deallocated by the node just after it is deallocated. */
! 743: axl_node_annotate_data_full (root, "__root_document", NULL, doc, (axlDestroyFunc) axl_doc_free);
! 744:
! 745: /* return the node created */
! 746: return root;
! 747: }
! 748:
! 749:
! 750: /**
! 751: * @brief Creates a new \ref axlNode but reusing the memory passed in
! 752: * by the name reference.
! 753: *
! 754: * This function works the same way like \ref axl_node_create, but
! 755: * previous one makes a local copy from the name provided. This means
! 756: * that, if you have allocated the reference being passed, the
! 757: * previous function will allocate again memory for the name
! 758: * reference.
! 759: *
! 760: * Obviously, for a few xml nodes this have none or little effect but,
! 761: * if your xml document have 100.000 nodes you save 100.000 extra
! 762: * memory allocations and deallocations. This may improve your
! 763: * application performace because memory
! 764: * fragmentation/allocations/deallocations are reduced.
! 765: *
! 766: * Keep in mind that this function should not be used with static strings. Example:
! 767: * \code
! 768: * // propery node creation
! 769: * axlNode * node = axl_node_create ("test");
! 770: *
! 771: * // NOT PROPER node creation
! 772: * axlNode * node = axl_node_create_ref ("test");
! 773: * \endcode
! 774: *
! 775: * @param name A user-space allocated memory representing the node
! 776: * name. The function doesn't check if the parameter received is null.
! 777: *
! 778: * @return A newly created \ref axlNode reference that must be
! 779: * deallocated by \ref axl_node_free.
! 780: */
! 781: axlNode * axl_node_create_ref (char * name)
! 782: {
! 783: axlNode * node;
! 784:
! 785: /* init the node */
! 786: node = axl_new (axlNode, 1);
! 787: node->name = name;
! 788:
! 789: /* return a reference to a new axlNode */
! 790: return node;
! 791: }
! 792:
! 793: /**
! 794: * @brief Allows to configure the node name, using the value provided.
! 795: *
! 796: * The function will dealloc the previous name stored, if found.
! 797: *
! 798: * @param node The node to be configured with a new name.
! 799: *
! 800: * @param name The new name to configure on the node. Function will
! 801: * create a local copy from the new name provided. The function won't
! 802: * check the name parameter received to be a non-null pointer.
! 803: */
! 804: void axl_node_set_name (axlNode * node, const char * name)
! 805: {
! 806: /* check the name to be already configured and dealloc it */
! 807: if (node->name != NULL && ! (node->conf & NODE_NAME_FROM_FACTORY))
! 808: axl_free (node->name);
! 809:
! 810: /* alloc the new name */
! 811: node->name = axl_strdup (name);
! 812: node->conf &= ~NODE_NAME_FROM_FACTORY;
! 813:
! 814: return;
! 815: }
! 816:
! 817: /**
! 818: * @brief Allows to configure the node name, using the value provided
! 819: * as a reference allocated and to be owned by the node.
! 820: *
! 821: * The function will dealloc the previous name stored, if found.
! 822: *
! 823: * @param node The node to be configured with a new name.
! 824: *
! 825: * @param name The new name to configure on the node. The value
! 826: * provided will be owned by the node. The function won't check the
! 827: * name parameter received to be a non-null pointer.
! 828: */
! 829: void axl_node_set_name_ref (axlNode * node, char * name)
! 830: {
! 831: /* check the name to be already configured and dealloc it */
! 832: if (node->name != NULL && ! (node->conf & NODE_NAME_FROM_FACTORY))
! 833: axl_free (node->name);
! 834:
! 835: /* alloc the new name */
! 836: node->name = name;
! 837:
! 838: return;
! 839: }
! 840:
! 841: /**
! 842: * @internal Allows to configure the xml node, flaging the string
! 843: * received to be owned by a factory. Do not use this API from your
! 844: * application. This is only useful for Axl Library internals.
! 845: *
! 846: * @param node The xml node that is going to be configured.
! 847: *
! 848: * @param name The xml node name to be configured. Previous
! 849: * configuration won't be deallocated as it is supposed that this
! 850: * function is only used from inside axl library.
! 851: */
! 852: void axl_node_set_name_from_factory (axlNode * node, char * name)
! 853: {
! 854: /* set node name */
! 855: node->name = name;
! 856:
! 857: /* update configuration */
! 858: node->conf |= NODE_NAME_FROM_FACTORY;
! 859:
! 860: return;
! 861: }
! 862:
! 863: axlPointer __axl_node_copy_key (axlPointer key, axlDestroyFunc key_destroy,
! 864: axlPointer data, axlDestroyFunc data_destroy)
! 865: {
! 866: /* copy the key */
! 867: return axl_strdup (key);
! 868: }
! 869:
! 870: axlPointer __axl_node_copy_value (axlPointer key, axlDestroyFunc key_destroy,
! 871: axlPointer data, axlDestroyFunc data_destroy)
! 872: {
! 873: /* copy data */
! 874: return axl_strdup (data);
! 875: }
! 876:
! 877: /**
! 878: * @brief Allows to perform a copy operation for the provided node.
! 879: *
! 880: * @param node The source node to copy.
! 881: *
! 882: * @param copy_attributes Signals the function to also copy node
! 883: * attributes into the newly created node.
! 884: *
! 885: * @param copy_childs Signals the function to also copy childs for the
! 886: * source node.
! 887: *
! 888: * @return A newly created node copy or null if it fails. The function
! 889: * will fail if the node reference provided is null.
! 890: */
! 891: axlNode * axl_node_copy (axlNode * node,
! 892: axl_bool copy_attributes,
! 893: axl_bool copy_childs)
! 894: {
! 895: axlNode * result;
! 896: axlItem * child;
! 897: axlItem * copy;
! 898:
! 899:
! 900: axl_return_val_if_fail (node, NULL);
! 901:
! 902: /* create the copy */
! 903: result = axl_node_create (axl_node_get_name (node));
! 904:
! 905: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "node=<%s> (copy operation)",
! 906: result->name);
! 907:
! 908: /* check for attributes */
! 909: if (node->attributes != NULL && copy_attributes) {
! 910:
! 911: /* copy attribute configuration and attributes */
! 912: result->attr_num = node->attr_num;
! 913: if (node->attr_num >= 11) {
! 914: /* copy attribute list supposing it is a
! 915: * hash */
! 916: result->attributes = (axlPointer) axl_hash_copy ((axlHash *) node->attributes,
! 917: /* key copy function */
! 918: __axl_node_copy_key,
! 919: /* value copy function */
! 920: __axl_node_copy_value);
! 921: } else {
! 922: /* copy attribute list */
! 923: result->attributes = (axlPointer) __axl_node_copy_attr_list ((axlNodeAttr *) node->attributes);
! 924: }
! 925: }
! 926:
! 927: /* check if child nodes must be also copied */
! 928: if (copy_childs && (node->first != NULL)) {
! 929:
! 930: /* copy all content inside */
! 931: child = node->first;
! 932: while (child != NULL) {
! 933:
! 934: /* copy the child found */
! 935: copy = axl_item_copy (child, result);
! 936:
! 937: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, " new item created (copy operation) with parent=<%s> and type=%d",
! 938: copy->parent->name,
! 939: axl_item_get_type (copy));
! 940:
! 941: /* set the content */
! 942: axl_item_set_child_ref (result, copy);
! 943:
! 944: /* get the next element */
! 945: child = child->next;
! 946:
! 947: } /* end while */
! 948: } /* end if */
! 949:
! 950:
! 951: /* return the node created */
! 952: return result;
! 953: }
! 954:
! 955: /**
! 956: * @brief Allows to get the xml document (\ref axlDoc) where the
! 957: * provided xml node is stored.
! 958: *
! 959: * @param node The node that is being requested to return is xml
! 960: * document reference.
! 961: *
! 962: * @return The xml document reference or NULL if it is not already
! 963: * set.
! 964: */
! 965: axlDoc * axl_node_get_doc (axlNode * node)
! 966: {
! 967: axl_return_val_if_fail (node, NULL);
! 968:
! 969: /* return the internal reference */
! 970: return axl_item_get_doc (node->holder);
! 971: }
! 972:
! 973: /**
! 974: * @internal
! 975: *
! 976: * This function is not provided to the public API because it is used
! 977: * by the Axl internals to set the root node for a provided xml node,
! 978: * that is usually the root document xml node.
! 979: *
! 980: * @param node The node that is being configured to have, or being contained in, the provided xml document.
! 981: *
! 982: * @param doc The xml document that holds the node.
! 983: */
! 984: void axl_node_set_doc (axlNode * node, axlDoc * doc)
! 985: {
! 986: axlItem * item;
! 987:
! 988: axl_return_if_fail (node);
! 989: axl_return_if_fail (doc);
! 990:
! 991: /* get the item reference */
! 992: item = node->holder;
! 993:
! 994: if (item == NULL) {
! 995:
! 996: /* create an empty reference */
! 997: item = axl_item_factory_get (axl_doc_get_item_factory (doc));
! 998: item->type = ITEM_NODE | ITEM_FROM_FACTORY;
! 999: item->data = node;
! 1000: node->holder = item;
! 1001:
! 1002: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "node received doesn't have a holder reference, creating ref=0x%x, node=0x%x, type=%d",
! 1003: item, node, item->type);
! 1004: } /* end if */
! 1005:
! 1006: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "setting doc to the item node");
! 1007:
! 1008: /* call to set item at the document */
! 1009: item->doc = doc;
! 1010:
! 1011: return;
! 1012: }
! 1013:
! 1014:
! 1015: /**
! 1016: * @internal
! 1017: *
! 1018: * Support function to install attribute information provided into the
! 1019: * \ref axlNode provided.
! 1020: *
! 1021: * @return axl_true if the attribute was added, otherwise axl_false is
! 1022: * returned.
! 1023: */
! 1024: axl_bool __axl_node_set_attribute (axlFactory * factory,
! 1025: axlNode * node,
! 1026: char * attribute,
! 1027: char * value,
! 1028: axl_bool from_factory)
! 1029: {
! 1030: axlNodeAttr * attr;
! 1031: axlNodeAttr * next;
! 1032:
! 1033: /* init attribute list */
! 1034: /* do not init attribute list twice */
! 1035: if (node->attributes == NULL) {
! 1036: /* configure default axl attribute list */
! 1037: node->attr_num = 1;
! 1038:
! 1039: /* create the node */
! 1040: if (from_factory)
! 1041: attr = axl_factory_get (factory);
! 1042: else
! 1043: attr = axl_new (axlNodeAttr, 1);
! 1044: attr->from_factory = from_factory;
! 1045: attr->attribute = attribute;
! 1046: attr->value = value;
! 1047:
! 1048: /* store the node */
! 1049: node->attributes = (axlPointer) attr;
! 1050:
! 1051: return axl_true;
! 1052: }
! 1053:
! 1054: /* store the attribute using the general case */
! 1055: if (node->attr_num < 10) {
! 1056:
! 1057: /* check if the attribute exists */
! 1058: if (axl_node_has_attribute (node, attribute))
! 1059: return axl_false;
! 1060:
! 1061: /* create the node */
! 1062: if (from_factory)
! 1063: attr = axl_factory_get (factory);
! 1064: else
! 1065: attr = axl_new (axlNodeAttr, 1);
! 1066: attr->from_factory = from_factory;
! 1067: attr->attribute = attribute;
! 1068: attr->value = value;
! 1069:
! 1070: /* set the next to the new item to be the current first */
! 1071: attr->next = (axlNodeAttr *) node->attributes;
! 1072:
! 1073: /* set the new first */
! 1074: node->attributes = (axlPointer) attr;
! 1075:
! 1076: } else if (node->attr_num >= 10) {
! 1077:
! 1078: /* check if the attribute exists */
! 1079: if (axl_node_has_attribute (node, attribute))
! 1080: return axl_false;
! 1081:
! 1082: /* check if we have to translate current attributes */
! 1083: if (node->attr_num == 10) {
! 1084: /* get a reference to current attribute list */
! 1085: attr = (axlNodeAttr *) node->attributes;
! 1086:
! 1087: /* create the hash */
! 1088: node->attributes = (axlPointer) axl_hash_new_full (axl_hash_string, axl_hash_equal_string, 1);
! 1089:
! 1090: while (attr != NULL) {
! 1091: /* add the attribute */
! 1092: axl_hash_insert_full ((axlHash *) node->attributes,
! 1093: /* attribute name */
! 1094: attr->attribute, attr->from_factory ? NULL : axl_free,
! 1095: /* attribute value */
! 1096: attr->value, attr->from_factory ? NULL : axl_free);
! 1097: /* free current node */
! 1098: next = attr->next;
! 1099: if (! attr->from_factory)
! 1100: axl_free (attr);
! 1101:
! 1102: /* get the next item to store */
! 1103: attr = next;
! 1104: } /* end while */
! 1105:
! 1106: } /* end if */
! 1107:
! 1108: /* add the attribute */
! 1109: axl_hash_insert_full ((axlHash *) node->attributes,
! 1110: attribute, from_factory ? NULL : axl_free,
! 1111: value, from_factory ? NULL : axl_free);
! 1112:
! 1113: } /* end if */
! 1114:
! 1115: /* update attribute count */
! 1116: node->attr_num++;
! 1117:
! 1118: return axl_true;
! 1119: }
! 1120:
! 1121: /**
! 1122: * @brief Allows to configure an xml attribute on the given node.
! 1123: *
! 1124: * \code
! 1125: * <complex attr1='value'>
! 1126: * ..
! 1127: * </complex>
! 1128: * \endcode
! 1129: *
! 1130: * It is not allowed to store the same attribute twice inside the same
! 1131: * node. If the function detects that a node is being set to have the
! 1132: * same attribute name several times, the attribute will be silently
! 1133: * not added.
! 1134: *
! 1135: * Values for the attribute name (<b>attribute</b>) and its associated
! 1136: * value can be deallocated once the function finish. This function
! 1137: * will perform a local copy.
! 1138: *
! 1139: * @param node The \ref axlNode where the attribute will be installed.
! 1140: *
! 1141: * @param attribute The attribute name to configure. This value can't
! 1142: * be NULL.
! 1143: *
! 1144: * @param value The value associated to the attribute to be
! 1145: * configured. This value can't be NULL.
! 1146: */
! 1147: void axl_node_set_attribute (axlNode * node,
! 1148: const char * attribute,
! 1149: const char * value)
! 1150: {
! 1151: int additional_size = 0;
! 1152: char * _attr;
! 1153: char * _value;
! 1154:
! 1155: axl_return_if_fail (node);
! 1156: axl_return_if_fail (attribute);
! 1157: axl_return_if_fail (value);
! 1158:
! 1159: /* check for empty attribute names */
! 1160: if (attribute[0] == 0) {
! 1161: __axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "skipping setting attribute with no name!");
! 1162: return;
! 1163: }
! 1164:
! 1165: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "setting attribute: %s='%s'", attribute, value);
! 1166:
! 1167: /* check attribute name */
! 1168: if (axl_node_has_invalid_chars (attribute, strlen (attribute),
! 1169: &additional_size)) {
! 1170:
! 1171: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found attribute content with escapable, non-valid content");
! 1172: _attr = __axl_node_content_copy_and_escape (attribute,
! 1173: strlen (attribute),
! 1174: additional_size,
! 1175: axl_false);
! 1176: }else {
! 1177:
! 1178: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "'%s' is a valid string..", attribute);
! 1179: _attr = axl_strdup (attribute);
! 1180: }
! 1181:
! 1182: /* check attribute value */
! 1183: additional_size = 0;
! 1184: if (axl_node_has_invalid_chars (value, strlen (value),
! 1185: &additional_size)) {
! 1186:
! 1187: _value = __axl_node_content_copy_and_escape (value,
! 1188: strlen (value),
! 1189: additional_size,
! 1190: axl_false);
! 1191: }else {
! 1192:
! 1193: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "'%s' is a valid string..", value);
! 1194: _value = axl_strdup (value);
! 1195: }
! 1196:
! 1197: /* insert the attribute */
! 1198: if (! __axl_node_set_attribute (NULL, node, _attr, _value, axl_false)) {
! 1199: axl_free (_attr);
! 1200: axl_free (_value);
! 1201: } /* end if */
! 1202:
! 1203: return;
! 1204: }
! 1205:
! 1206: /**
! 1207: * @brief Allows to install a new attribute pair, based on the
! 1208: * attribute name and the attribute value, without allocating memory
! 1209: * for them.
! 1210: *
! 1211: * This function works the same way like \ref axl_node_set_attribute
! 1212: * but reusing memory allocated by the user space.
! 1213: *
! 1214: * @param node The \ref axlNode where the attributes will be
! 1215: * installed.
! 1216: *
! 1217: * @param attribute The attribute name to be installed.
! 1218: *
! 1219: * @param value The attribute value to be installed.
! 1220: */
! 1221: void axl_node_set_attribute_ref (axlNode * node, char * attribute, char * value)
! 1222: {
! 1223:
! 1224: axl_return_if_fail (node);
! 1225: axl_return_if_fail (attribute);
! 1226: axl_return_if_fail (value);
! 1227:
! 1228: /* insert the attribute */
! 1229: if (! __axl_node_set_attribute (NULL, node, attribute, value, axl_false)) {
! 1230: axl_free (attribute);
! 1231: axl_free (value);
! 1232: return;
! 1233: } /* end if */
! 1234:
! 1235: return;
! 1236: }
! 1237:
! 1238: /**
! 1239: * @internal Function that allows configuring attributes to the
! 1240: * selected node, notifying that they come from a factory and
! 1241: * shouldn't be deallocated in the usual way. This function shouldn't
! 1242: * be used by API consumers. This is only useful for Axl Library
! 1243: * internals.
! 1244: *
! 1245: * @param node The node to be configured with the attribute values.
! 1246: *
! 1247: * @param attribute The attribute to configure.
! 1248: * @param value The attribute value to configure.
! 1249: */
! 1250: void axl_node_set_attribute_from_factory (axlFactory * factory,
! 1251: axlNode * node,
! 1252: char * attribute,
! 1253: char * value)
! 1254: {
! 1255: /* insert the attribute */
! 1256: __axl_node_set_attribute (factory, node, attribute, value, axl_true);
! 1257:
! 1258: return;
! 1259: }
! 1260:
! 1261: /**
! 1262: * @brief Allows to check if a particular attribute is installed on
! 1263: * the given node.
! 1264: *
! 1265: * @param node The node where the attribute will be checked to be
! 1266: * configured.
! 1267: *
! 1268: * @param attribute The attribute to check.
! 1269: *
! 1270: * @return A \ref axl_true if the attribute value is set, otherwise
! 1271: * \ref axl_false is returned.
! 1272: *
! 1273: * See also \ref HAS_ATTR.
! 1274: */
! 1275: axl_bool axl_node_has_attribute (axlNode * node, const char * attribute)
! 1276: {
! 1277: axlNodeAttr * attr;
! 1278:
! 1279: axl_return_val_if_fail (node, axl_false);
! 1280: axl_return_val_if_fail (attribute, axl_false);
! 1281:
! 1282: /* check for empty hash */
! 1283: if (node->attributes == NULL)
! 1284: return axl_false;
! 1285:
! 1286: if (node->attr_num <= 10) {
! 1287: /* linked configuration */
! 1288: attr = (axlNodeAttr *) node->attributes;
! 1289: while (attr != NULL) {
! 1290: /* check that the attribute is equal */
! 1291: if (axl_cmp (attr->attribute, attribute))
! 1292: return axl_true;
! 1293:
! 1294: /* get the next attribute */
! 1295: attr = attr->next;
! 1296: } /* end while */
! 1297:
! 1298: /* attribute not found */
! 1299: return axl_false;
! 1300: } /* end if */
! 1301:
! 1302: /* hashed configuration */
! 1303: return axl_hash_exists ((axlHash *) node->attributes, (axlPointer) attribute);
! 1304: }
! 1305:
! 1306: /**
! 1307: * @brief Allows to remove the provided attribute, from the node
! 1308: * provided.
! 1309: *
! 1310: * @param node The node to be updated by removing the attribute
! 1311: * provided.
! 1312: *
! 1313: * @param attribute The attribute to locate and remove.
! 1314: */
! 1315: void axl_node_remove_attribute (axlNode * node,
! 1316: const char * attribute)
! 1317: {
! 1318: axlNodeAttr * attr;
! 1319: axlNodeAttr * previous;
! 1320:
! 1321: axl_return_if_fail (node);
! 1322: axl_return_if_fail (attribute);
! 1323:
! 1324: /* check for empty hash */
! 1325: if (node->attributes == NULL)
! 1326: return;
! 1327:
! 1328: if (node->attr_num <= 10) {
! 1329: /* linked configuration */
! 1330: attr = (axlNodeAttr *) node->attributes;
! 1331: previous = NULL;
! 1332: while (attr != NULL) {
! 1333: /* check that the attribute is equal */
! 1334: if (axl_cmp (attr->attribute, attribute)) {
! 1335: /* attribute found */
! 1336: if (previous == NULL)
! 1337: node->attributes = (axlPointer) attr->next;
! 1338: else
! 1339: previous->next = attr->next;
! 1340:
! 1341: /* do not decrease attribute number
! 1342: * since it is used to know the kind
! 1343: * of store used. */
! 1344:
! 1345: /* now dealloc the attribute */
! 1346: if (! attr->from_factory) {
! 1347: axl_free (attr->attribute);
! 1348: axl_free (attr->value);
! 1349: axl_free (attr);
! 1350: } /* end if */
! 1351:
! 1352: return;
! 1353: }
! 1354:
! 1355: /* get the next attribute */
! 1356: previous = attr;
! 1357: attr = attr->next;
! 1358: } /* end while */
! 1359:
! 1360: /* attribute not found */
! 1361: return;
! 1362: } /* end if */
! 1363:
! 1364: /* hashed configuration */
! 1365: axl_hash_remove ((axlHash *) node->attributes, (axlPointer) attribute);
! 1366:
! 1367: /* do not decrease attribute number
! 1368: * since it is used to know the kind
! 1369: * of store used. */
! 1370:
! 1371: return;
! 1372: }
! 1373:
! 1374: /**
! 1375: * @brief Allows to get the number of attributes installed on the
! 1376: * provided node.
! 1377: *
! 1378: * @param node The node that is requested to return the number of
! 1379: * attributes installed.
! 1380: *
! 1381: * @return Number of attributes installed, or -1 if it fails.
! 1382: */
! 1383: int axl_node_num_attributes (axlNode * node)
! 1384: {
! 1385: int result = 0;
! 1386: axlNodeAttr * attr;
! 1387:
! 1388: axl_return_val_if_fail (node, -1);
! 1389:
! 1390: if (node->attr_num <= 10) {
! 1391: /* linked configuration */
! 1392: attr = (axlNodeAttr *) node->attributes;
! 1393: while (attr != NULL) {
! 1394: /* update sum */
! 1395: result++;
! 1396:
! 1397: /* get the next attribute */
! 1398: attr = attr->next;
! 1399: } /* end while */
! 1400:
! 1401: /* attribute not found */
! 1402: return result;
! 1403: } /* end if */
! 1404:
! 1405: /* hashed configuration */
! 1406: return axl_hash_items ((axlHash *) node->attributes);
! 1407: }
! 1408:
! 1409: /**
! 1410: * @brief Allows to check if the provided node has attributes
! 1411: * installed.
! 1412: *
! 1413: * @param node The node to be checked for attributes.
! 1414: *
! 1415: * @return \ref axl_true if the node has attributes, otherwise \ref axl_false
! 1416: * is returned. The function also returns \ref axl_false if a null
! 1417: * reference for the node is provided.
! 1418: */
! 1419: axl_bool axl_node_has_attributes (axlNode * node)
! 1420: {
! 1421: axl_return_val_if_fail (node, axl_false);
! 1422:
! 1423: /* return if the attributes reference is configured */
! 1424: return (node->attributes != NULL);
! 1425: }
! 1426:
! 1427: /**
! 1428: * @brief Allows to get current content of the provided attribute
! 1429: * inside the given node.
! 1430: *
! 1431: * It is recomended to call first to \ref axl_node_has_attribute to
! 1432: * ensure that the attribute to be reported its value already
! 1433: * exists. See also \ref ATTR_VALUE.
! 1434: *
! 1435: * @param node The \ref axlNode where the attribute value associated
! 1436: * will be returned.
! 1437: *
! 1438: * @param attribute The attribute that is being required for its
! 1439: * value.
! 1440: *
! 1441: * @return A string containing the attribute value or NULL if
! 1442: * fails. Returned value must not be deallocated, it is a reference to
! 1443: * a local copy. Use \ref axl_strdup function to get a persistent
! 1444: * copy.
! 1445: */
! 1446: const char * axl_node_get_attribute_value (axlNode * node, const char * attribute)
! 1447: {
! 1448: axlNodeAttr * attr;
! 1449:
! 1450: /* check values received */
! 1451: axl_return_val_if_fail (node, NULL);
! 1452: axl_return_val_if_fail (attribute, NULL);
! 1453:
! 1454: /* check for empty hash */
! 1455: if (node->attributes == NULL)
! 1456: return NULL;
! 1457:
! 1458: if (node->attr_num <= 10) {
! 1459: /* linked configuration */
! 1460: attr = (axlNodeAttr *) node->attributes;
! 1461: while (attr != NULL) {
! 1462: /* check that the attribute is equal */
! 1463: if (axl_cmp (attr->attribute, attribute))
! 1464: return attr->value;
! 1465:
! 1466: /* get the next attribute */
! 1467: attr = attr->next;
! 1468: } /* end while */
! 1469:
! 1470: /* attribute not found */
! 1471: return NULL;
! 1472: } /* end if */
! 1473:
! 1474: /* return value stored for the provided key */
! 1475: return axl_hash_get ((axlHash *) node->attributes, (axlPointer) attribute);
! 1476: }
! 1477:
! 1478: /**
! 1479: * @brief Gets an allocated copy for the value associated to the given
! 1480: * attribute.
! 1481: *
! 1482: * See \ref axl_node_get_attribute_value for more information. This
! 1483: * function works the same way but returning an already allocated
! 1484: * attribute value.
! 1485: *
! 1486: * @param node The node where the attribute value is requested.
! 1487: *
! 1488: * @param attribute The attribute that is being requested.
! 1489: *
! 1490: * @return A newly allocated reference that must be deallocated when
! 1491: * no longer needed calling to \ref axl_free.
! 1492: */
! 1493: char * axl_node_get_attribute_value_copy (axlNode * node,
! 1494: const char * attribute)
! 1495: {
! 1496: const char * _value;
! 1497:
! 1498: /* get the attribute */
! 1499: _value = axl_node_get_attribute_value (node, attribute);
! 1500: axl_return_val_if_fail (_value, NULL);
! 1501:
! 1502: /* return a copy */
! 1503: return axl_strdup (_value);
! 1504: }
! 1505:
! 1506: /**
! 1507: * @brief Gets the attribute content for the provided attribute name,
! 1508: * at the provided node, but translating entity references found.
! 1509: *
! 1510: * This function works the same way like \ref
! 1511: * axl_node_get_attribute_value_copy, in the sense it returns a
! 1512: * dinamically allocated copy for the attribute value requested but,
! 1513: * at the same time, it returns the content with all entity references
! 1514: * already translated.
! 1515: *
! 1516: * @param node The \ref axlNode instance where the attribute content
! 1517: * will be returned.
! 1518: *
! 1519: * @param attribute The attribute name that is being requested.
! 1520: *
! 1521: * @return The attribute content, already translated, for those
! 1522: * entities found. The function returns a dinamilly allocated string
! 1523: * so \ref axl_free must be used.
! 1524: */
! 1525: char * axl_node_get_attribute_value_trans (axlNode * node,
! 1526: const char * attribute)
! 1527: {
! 1528: char * _value;
! 1529: int size;
! 1530:
! 1531: /* get the attribute */
! 1532: _value = (char *) axl_node_get_attribute_value (node, attribute);
! 1533: axl_return_val_if_fail (_value, NULL);
! 1534:
! 1535: /* perform a local copy */
! 1536: _value = axl_strdup (_value);
! 1537:
! 1538: /* return a copy */
! 1539: size = strlen (_value);
! 1540: return axl_node_content_translate_defaults (_value, &size);
! 1541: }
! 1542:
! 1543: /**
! 1544: * @brief Allows to get the value associated to the attribute
! 1545: * provided, inside the node selected, removing trailing and ending
! 1546: * white spaces (in the W3C sence: \\n, \\t, \\r, ' ').
! 1547: *
! 1548: * See \ref ATTR_VALUE_TRIMMED for a convenience macro.
! 1549: *
! 1550: * @param node The node that is requested to return the associated
! 1551: * value to the attribute.
! 1552: *
! 1553: * @param attribute The attribute that is being requested.
! 1554: *
! 1555: * @return A reference to the attribute value or NULL if it fails. The
! 1556: * function doesn't return a copy, it returns a reference to the
! 1557: * internal value.
! 1558: */
! 1559: const char * axl_node_get_attribute_value_trimmed (axlNode * node,
! 1560: const char * attribute)
! 1561: {
! 1562: char * _value;
! 1563:
! 1564: /* get the attribute */
! 1565: _value = (char *) axl_node_get_attribute_value (node, attribute);
! 1566: axl_return_val_if_fail (_value, NULL);
! 1567:
! 1568: /* trim the value */
! 1569: axl_stream_trim (_value);
! 1570:
! 1571: /* return value */
! 1572: return _value;
! 1573: }
! 1574:
! 1575: /**
! 1576: * @brief Convenience function that allows to check if a particular
! 1577: * attribute with a particular value is found at the provided node.
! 1578: *
! 1579: * This function will check if the attribute provided in the node is
! 1580: * found and in such case, if the value that is contained inside the
! 1581: * node is actually the same as the one provide to this function.
! 1582: *
! 1583: * You can also use hits macro associated: \ref HAS_ATTR_VALUE.
! 1584: *
! 1585: * @param node The node that will be checked.
! 1586: * @param attribute The attribute to be checked.
! 1587: * @param value The value to checked if the attribute is found.
! 1588: *
! 1589: * @return \ref axl_true if the node has the attribute with the
! 1590: * provided value.
! 1591: */
! 1592: axl_bool axl_node_has_attribute_value (axlNode * node,
! 1593: const char * attribute,
! 1594: const char * value)
! 1595: {
! 1596: axl_return_val_if_fail (node, axl_false);
! 1597: axl_return_val_if_fail (attribute, axl_false);
! 1598: axl_return_val_if_fail (value, axl_false);
! 1599:
! 1600: /* return if the attribute value found is the same */
! 1601: return axl_cmp (axl_node_get_attribute_value (node, attribute), value);
! 1602: }
! 1603:
! 1604: /**
! 1605: * @}
! 1606: */
! 1607:
! 1608: /**
! 1609: * \defgroup axl_node_annotate Axl Node Annotate: An interface that allows associate arbitrary data to a particular node, indexed as a hash.
! 1610: */
! 1611:
! 1612: /**
! 1613: * \addtogroup axl_node_annotate
! 1614: * @{
! 1615: */
! 1616:
! 1617: /**
! 1618: * @internal function which checks and initializes the hash used for
! 1619: * annotated data.
! 1620: */
! 1621: void __init_node_annotation (axlNode * node)
! 1622: {
! 1623: if (node->annotate_data == NULL)
! 1624: node->annotate_data = axl_hash_new (axl_hash_string, axl_hash_equal_string);
! 1625: return;
! 1626: }
! 1627:
! 1628: /**
! 1629: * @brief Allows to store user defined data associated to the node
! 1630: * that is not visible from an XML perspective.
! 1631: *
! 1632: * This function allows to store data associated to the node and to
! 1633: * retrieve it later in an inherited fashion. This allows to store
! 1634: * semantic/metadata information while parsing xml documents.
! 1635: *
! 1636: * This function stores the given key using a hash,
! 1637: * associating the data provided on the given node. You can also check
! 1638: * the \ref axl_node_annotate_data_full which performs the same task
! 1639: * but allowing to provide key and data destroy functions.
! 1640: *
! 1641: * Once data is stored, it could be inherited by child nodes because
! 1642: * the access to it is done using \ref axl_node_annotate_get which can
! 1643: * configure the data lookup to into the particular node or its
! 1644: * parents.
! 1645: *
! 1646: * Additionally, you can also perform annotation using native types:
! 1647: * int, string and double. Check the following functions to do so.
! 1648: *
! 1649: * - \ref axl_node_annotate_int
! 1650: * - \ref axl_node_annotate_double
! 1651: * - \ref axl_node_annotate_string
! 1652: *
! 1653: * @param node The node where the annotated data will be stored.
! 1654: *
! 1655: * @param key The key under which the annotated data will be stored
! 1656: * (and indexed).
! 1657: *
! 1658: * @param data The data to be stored associated to the key provided.
! 1659: */
! 1660: void axl_node_annotate_data (axlNode * node,
! 1661: const char * key,
! 1662: axlPointer data)
! 1663: {
! 1664: axl_return_if_fail (node);
! 1665:
! 1666: /* check and init node annotation */
! 1667: __init_node_annotation (node);
! 1668:
! 1669: /* insert data */
! 1670: axl_hash_insert (node->annotate_data, (axlPointer) key, data);
! 1671:
! 1672: /* nothing more to do */
! 1673: return;
! 1674: }
! 1675:
! 1676: /**
! 1677: * @brief Allows to store user defined data associated to the node
! 1678: * that is not visible from an XML perspective.
! 1679: *
! 1680: * See \ref axl_node_annotate_data for a long explanation. This
! 1681: * function performs the same task as \ref axl_node_annotate_data but
! 1682: * allowing to set a key destroy and data destroy functions. They are
! 1683: * later used to deallocate key and data references.
! 1684: *
! 1685: * @param node The node where the annotated data will be stored.
! 1686: *
! 1687: * @param key The key under which the annotated data will be stored.
! 1688: *
! 1689: * @param key_destroy The destroy function to be called to deallocate
! 1690: * the key stored.
! 1691: *
! 1692: * @param data The data to be stored associated to the key provided.
! 1693: *
! 1694: * @param data_destroy The destroy function to be called to deallocate
! 1695: * the data provided.
! 1696: */
! 1697: void axl_node_annotate_data_full (axlNode * node,
! 1698: const char * key,
! 1699: axlDestroyFunc key_destroy,
! 1700: axlPointer data,
! 1701: axlDestroyFunc data_destroy)
! 1702: {
! 1703: axl_return_if_fail (node);
! 1704:
! 1705: /* check and init node annotation */
! 1706: __init_node_annotation (node);
! 1707:
! 1708: /* insert data */
! 1709: axl_hash_insert_full (node->annotate_data, (axlPointer) key, key_destroy, data, data_destroy);
! 1710:
! 1711: /* nothing more to do */
! 1712: return;
! 1713: }
! 1714:
! 1715: /**
! 1716: * @brief Allows to perform a lookup for annotated data stored on the
! 1717: * provided node.
! 1718: *
! 1719: * @param node The node where the lookup will be performed.
! 1720: *
! 1721: * @param key The key to lookup in the \ref axlNode reference.
! 1722: *
! 1723: * @param lookup_in_parent Once the lookup fails in the current node,
! 1724: * this variable allows to signal the function to also lookup the
! 1725: * value in the parent nodes recursively. This mechanism allows to
! 1726: * store data on parent nodes that are shared among all child nodes.
! 1727: *
! 1728: * @return The data associated to the key according to the lookup
! 1729: * configuration (lookup_in_parent and lookup_in_doc).
! 1730: */
! 1731: axlPointer axl_node_annotate_get (axlNode * node,
! 1732: const char * key,
! 1733: axl_bool lookup_in_parent)
! 1734: {
! 1735: axlPointer result = NULL;
! 1736: axlNode * parent;
! 1737:
! 1738: /* check node received before nothing */
! 1739: axl_return_val_if_fail (node, NULL);
! 1740: axl_return_val_if_fail (key, NULL);
! 1741:
! 1742: /* lookup the data in the current node */
! 1743: if (node->annotate_data != NULL) {
! 1744: /* lookup the data */
! 1745: result = axl_hash_get (node->annotate_data, (axlPointer) key);
! 1746:
! 1747: /* check result returned */
! 1748: if (result != NULL)
! 1749: return result;
! 1750: } /* end if */
! 1751:
! 1752: /* check if we have to lookup the data in parent nodes */
! 1753: if (lookup_in_parent) {
! 1754: /* get the first parent reference */
! 1755: parent = axl_item_get_parent (node->holder);
! 1756:
! 1757: /* for each parent, try to lookup the data */
! 1758: while (parent != NULL) {
! 1759: /* lookup the data */
! 1760: if (parent->annotate_data)
! 1761: result = axl_hash_get (parent->annotate_data, (axlPointer) key);
! 1762:
! 1763: /* check result returned */
! 1764: if (result != NULL)
! 1765: return result;
! 1766:
! 1767: /* get the next parent */
! 1768: parent = axl_item_get_parent (parent->holder);
! 1769: }
! 1770: }
! 1771:
! 1772: /* no node was found */
! 1773: return result;
! 1774: }
! 1775:
! 1776: /**
! 1777: * @internal definition to clasify node annotation.
! 1778: */
! 1779: typedef enum {
! 1780: /**
! 1781: * @internal definition to clasify int elements.
! 1782: */
! 1783: ANNOTATE_INT = 0,
! 1784: /**
! 1785: * @internal definition to clasify string elements.
! 1786: */
! 1787: ANNOTATE_STRING = 1,
! 1788: /**
! 1789: * @internal definition to clasify int elements.
! 1790: */
! 1791: ANNOTATE_DOUBLE = 2
! 1792: } AnnotateType;
! 1793:
! 1794: typedef struct _AnnotateNodeData {
! 1795: /**
! 1796: * @internal type annotated.
! 1797: */
! 1798: AnnotateType type;
! 1799:
! 1800: /**
! 1801: * @internal Value annotated: int, string or double.
! 1802: */
! 1803: union {
! 1804: int int_value;
! 1805: char * string_value;
! 1806: double double_value;
! 1807: } value;
! 1808: } AnnotateNodeData;
! 1809:
! 1810: void __axl_annotate_data_free (AnnotateNodeData * data)
! 1811: {
! 1812: if (data == NULL)
! 1813: return;
! 1814:
! 1815: /* free the string */
! 1816: if (data->type == ANNOTATE_STRING)
! 1817: axl_free (data->value.string_value);
! 1818:
! 1819: /* free the data */
! 1820: axl_free (data);
! 1821:
! 1822: return;
! 1823: }
! 1824:
! 1825: /**
! 1826: * @brief Allows to perform an annotation to the node at runtime,
! 1827: * storing a integer value.
! 1828: *
! 1829: * While using xml documents loaded into memory, each node could be
! 1830: * processed and annotated with particular information, indexed with a
! 1831: * key, that could be retrieved later for faster process.
! 1832: *
! 1833: * This data annotation doesn't perform any modification to the xml
! 1834: * document in any form. It is just a programming support that allows
! 1835: * developers to avoid creating complex and independent structures to
! 1836: * the xml document while developing XML based solutions.
! 1837: *
! 1838: * While using annotation support, you can use low level functions
! 1839: * that provide a simple way to store pointers associated to
! 1840: * particular nodes and retrieve them using:
! 1841: *
! 1842: * - \ref axl_node_annotate_data_full
! 1843: * - \ref axl_node_annotate_data
! 1844: * - \ref axl_node_annotate_get
! 1845: *
! 1846: * However, additional functions are provided to store and retreive
! 1847: * easily integers, strings and double data annotated. See the
! 1848: * following:
! 1849: *
! 1850: * - \ref axl_node_annotate_int
! 1851: * - \ref axl_node_annotate_string
! 1852: * - \ref axl_node_annotate_double
! 1853: *
! 1854: * If you use this function to store an integer data you must use \ref
! 1855: * axl_node_annotate_get_int to retreive data stored. You can't use
! 1856: * \ref axl_node_annotate_get.
! 1857: *
! 1858: * @param node The node where the annotation will be aplied.
! 1859: *
! 1860: * @param key The key to index the data annotated to the node.
! 1861: *
! 1862: * @param int_value An integer value that will be annotated to the
! 1863: * node received under the key provided.
! 1864: */
! 1865: void axl_node_annotate_int (axlNode * node,
! 1866: const char * key,
! 1867: int int_value)
! 1868: {
! 1869: AnnotateNodeData * data;
! 1870:
! 1871: /* check received values */
! 1872: axl_return_if_fail (node);
! 1873: axl_return_if_fail (key);
! 1874:
! 1875: /* allocate the node */
! 1876: data = axl_new (AnnotateNodeData, 1);
! 1877: data->type = ANNOTATE_INT;
! 1878: data->value.int_value = int_value;
! 1879:
! 1880: /* annotate the value */
! 1881: axl_node_annotate_data_full (node, key, NULL, data, (axlDestroyFunc) __axl_annotate_data_free);
! 1882:
! 1883: return;
! 1884: }
! 1885:
! 1886: /**
! 1887: * @brief Allows to perform an annotation to the node at runtime,
! 1888: * storing a string value.
! 1889: *
! 1890: * While using xml documents loaded into memory, each node could be
! 1891: * processed and annotated with particular information, indexed with a
! 1892: * key, that could be retrieved later for faster process.
! 1893: *
! 1894: * This data annotation doesn't perform any modification to the xml
! 1895: * document in any form. It is just a programming support that allows
! 1896: * developers to avoid creating complex and independent structures to
! 1897: * the xml document while developing XML based solutions.
! 1898: *
! 1899: * While using annotation support, you can use low level functions
! 1900: * that provide a simple way to store pointers associated to
! 1901: * particular nodes and retrieve them using:
! 1902: *
! 1903: * - \ref axl_node_annotate_data_full
! 1904: * - \ref axl_node_annotate_data
! 1905: * - \ref axl_node_annotate_get
! 1906: *
! 1907: * However, additional functions are provided to store and retreive
! 1908: * easily integers, strings and double data annotated. See the
! 1909: * following:
! 1910: *
! 1911: * - \ref axl_node_annotate_int
! 1912: * - \ref axl_node_annotate_string
! 1913: * - \ref axl_node_annotate_double
! 1914: *
! 1915: * If you use this function to store a string data you must use \ref
! 1916: * axl_node_annotate_get_string to retreive data stored. You can't use \ref axl_node_annotate_get.
! 1917: *
! 1918: * @param node The node where the annotation will be aplied.
! 1919: *
! 1920: * @param key The key to index the data annotated to the node.
! 1921: *
! 1922: * @param string_value A string value that will be annotated to the
! 1923: * node received under the key provided. This value will be copied and
! 1924: * released once the node is deallocated.
! 1925: */
! 1926: void axl_node_annotate_string (axlNode * node,
! 1927: const char * key,
! 1928: const char * string_value)
! 1929: {
! 1930: AnnotateNodeData * data;
! 1931:
! 1932: /* check received values */
! 1933: axl_return_if_fail (node);
! 1934: axl_return_if_fail (key);
! 1935: axl_return_if_fail (string_value);
! 1936:
! 1937: /* allocate the node */
! 1938: data = axl_new (AnnotateNodeData, 1);
! 1939: data->type = ANNOTATE_STRING;
! 1940: data->value.string_value = axl_strdup (string_value);
! 1941:
! 1942: /* annotate the value */
! 1943: axl_node_annotate_data_full (node, key, NULL, data, (axlDestroyFunc) __axl_annotate_data_free);
! 1944:
! 1945: return;
! 1946: }
! 1947:
! 1948: /**
! 1949: * @brief Allows to perform an annotation to the node at runtime,
! 1950: * storing a double value.
! 1951: *
! 1952: * While using xml documents loaded into memory, each node could be
! 1953: * processed and annotated with particular information, indexed with a
! 1954: * key, that could be retrieved later for faster process.
! 1955: *
! 1956: * This data annotation doesn't perform any modification to the xml
! 1957: * document in any form. It is just a programming support that allows
! 1958: * developers to avoid creating complex and independent structures to
! 1959: * the xml document while developing XML based solutions.
! 1960: *
! 1961: * While using annotation support, you can use low level functions
! 1962: * that provide a simple way to store pointers associated to
! 1963: * particular nodes and retrieve them using:
! 1964: *
! 1965: * - \ref axl_node_annotate_data_full
! 1966: * - \ref axl_node_annotate_data
! 1967: * - \ref axl_node_annotate_get
! 1968: *
! 1969: * However, additional functions are provided to store and retreive
! 1970: * easily integers, strings and double data annotated. See the
! 1971: * following:
! 1972: *
! 1973: * - \ref axl_node_annotate_int
! 1974: * - \ref axl_node_annotate_string
! 1975: * - \ref axl_node_annotate_double
! 1976: *
! 1977: * If you use this function to store a double data you must use \ref
! 1978: * axl_node_annotate_get_double to retreive data stored. You can't use \ref axl_node_annotate_get.
! 1979: *
! 1980: * @param node The node where the annotation will be aplied.
! 1981: *
! 1982: * @param key The key to index the data annotated to the node.
! 1983: *
! 1984: * @param double_value A string value that will be annotated to the node
! 1985: * received under the key provided.
! 1986: */
! 1987: void axl_node_annotate_double (axlNode * node,
! 1988: const char * key,
! 1989: double double_value)
! 1990: {
! 1991: AnnotateNodeData * data;
! 1992:
! 1993: /* check received values */
! 1994: axl_return_if_fail (node);
! 1995: axl_return_if_fail (key);
! 1996:
! 1997: /* allocate the node */
! 1998: data = axl_new (AnnotateNodeData, 1);
! 1999: data->type = ANNOTATE_DOUBLE;
! 2000: data->value.double_value = double_value;
! 2001:
! 2002: /* annotate the value */
! 2003: axl_node_annotate_data_full (node, key, NULL, data, (axlDestroyFunc) __axl_annotate_data_free);
! 2004:
! 2005: return;
! 2006: }
! 2007:
! 2008: /**
! 2009: * @brief Allows to retrieve the annotated int value stored on the
! 2010: * particular node, under the provided key.
! 2011: *
! 2012: * @param node The node that is required to return the annotated data.
! 2013: *
! 2014: * @param key The key to be used to lookup for the data annotated.
! 2015: *
! 2016: * @param lookup_in_parent Once the lookup fails, this variable allows
! 2017: * to signal the function to also lookup the value in the parent
! 2018: * nodes. This mechanism allows to store data on parent nodes that are
! 2019: * shared by child nodes.
! 2020: *
! 2021: * NOTE: To make this function work properly you must store double
! 2022: * values using \ref axl_node_annotate_int. Storing values using
! 2023: * other functions will lead to unpredictable results.
! 2024: *
! 2025: * @return The integer value stored using \ref
! 2026: * axl_node_annotate_int. If the key provided doesn't exists, the
! 2027: * function returns 0.
! 2028: */
! 2029: int axl_node_annotate_get_int (axlNode * node,
! 2030: const char * key,
! 2031: axl_bool lookup_in_parent)
! 2032: {
! 2033: AnnotateNodeData * data;
! 2034:
! 2035: /* check received values */
! 2036: axl_return_val_if_fail (node, 0);
! 2037: axl_return_val_if_fail (key, 0);
! 2038:
! 2039: /* get the annotated data */
! 2040: data = axl_node_annotate_get (node, key, lookup_in_parent);
! 2041:
! 2042: /* check for null value. */
! 2043: if (data == NULL)
! 2044: return 0;
! 2045:
! 2046: if (data->type != ANNOTATE_INT) {
! 2047: /* drop a log */
! 2048: __axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "accesing to a annotation data that isn't flaged as integer");
! 2049: return 0;
! 2050: }
! 2051:
! 2052: /* return the integer value inside */
! 2053: return data->value.int_value;
! 2054: }
! 2055:
! 2056: /**
! 2057: * @brief Allows to retrieve the annotated string value stored on the
! 2058: * particular node, under the provided key.
! 2059: *
! 2060: * @param node The node that is required to return the annotated data.
! 2061: *
! 2062: * @param key The key to be used to lookup for the data annotated.
! 2063: *
! 2064: * @param lookup_in_parent Once the lookup fails, this variable allows
! 2065: * to signal the function to also lookup the value in the parent
! 2066: * nodes. This mechanism allows to store data on parent nodes that are
! 2067: * shared by child nodes.
! 2068: *
! 2069: * NOTE: To make this function work properly you must store double
! 2070: * values using \ref axl_node_annotate_string. Storing values using
! 2071: * other functions will lead to unpredictable results.
! 2072: *
! 2073: * @return The string value stored using \ref
! 2074: * axl_node_annotate_string. If the key provided doesn't exists, the
! 2075: * function returns NULL.
! 2076: */
! 2077: char * axl_node_annotate_get_string (axlNode * node,
! 2078: const char * key,
! 2079: axl_bool lookup_in_parent)
! 2080: {
! 2081: AnnotateNodeData * data;
! 2082:
! 2083: /* check received values */
! 2084: axl_return_val_if_fail (node, NULL);
! 2085: axl_return_val_if_fail (key, NULL);
! 2086:
! 2087: /* get the annotated data */
! 2088: data = axl_node_annotate_get (node, key, lookup_in_parent);
! 2089:
! 2090: /* check for null value. */
! 2091: if (data == NULL)
! 2092: return NULL;
! 2093:
! 2094: if (data->type != ANNOTATE_STRING) {
! 2095: /* drop a log */
! 2096: __axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "accesing to a annotation data that isn't flaged as string");
! 2097: return NULL;
! 2098: }
! 2099:
! 2100: /* return the string value inside */
! 2101: return data->value.string_value;
! 2102: }
! 2103:
! 2104: /**
! 2105: * @brief Allows to retrieve the annotated double value stored on the
! 2106: * particular node, under the provided key.
! 2107: *
! 2108: * @param node The node that is required to return the annotated data.
! 2109: *
! 2110: * @param key The key to be used to lookup for the data annotated.
! 2111: *
! 2112: * @param lookup_in_parent Once the lookup fails, this variable allows
! 2113: * to signal the function to also lookup the value in the parent
! 2114: * nodes. This mechanism allows to store data on parent nodes that are
! 2115: * shared by child nodes.
! 2116: *
! 2117: * NOTE: To make this function work properly you must store double
! 2118: * values using \ref axl_node_annotate_double. Storing values using
! 2119: * other functions will lead to unpredictable results.
! 2120: *
! 2121: * @return The double value stored using \ref
! 2122: * axl_node_annotate_double. If the key provided doesn't exists, the
! 2123: * function returns 0.0.
! 2124: */
! 2125: double axl_node_annotate_get_double (axlNode * node,
! 2126: const char * key,
! 2127: axl_bool lookup_in_parent)
! 2128: {
! 2129: AnnotateNodeData * data;
! 2130:
! 2131: /* check received values */
! 2132: axl_return_val_if_fail (node, 0.0);
! 2133: axl_return_val_if_fail (key, 0.0);
! 2134:
! 2135: /* get the annotated data */
! 2136: data = axl_node_annotate_get (node, key, lookup_in_parent);
! 2137:
! 2138: /* check for null value. */
! 2139: if (data == NULL)
! 2140: return 0.0;
! 2141:
! 2142: if (data->type != ANNOTATE_DOUBLE) {
! 2143: /* drop a log */
! 2144: __axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "accesing to a annotation data that isn't flaged as double");
! 2145: return 0.0;
! 2146: }
! 2147:
! 2148: /* return the double value inside */
! 2149: return data->value.double_value;
! 2150: }
! 2151:
! 2152: /**
! 2153: * @}
! 2154: */
! 2155:
! 2156: /**
! 2157: * \addtogroup axl_node_module
! 2158: * @{
! 2159: */
! 2160:
! 2161: /**
! 2162: * @brief Allows to configure the given node to be empty.
! 2163: *
! 2164: * A \ref axlNode is empty when it is known that the node doesn't have
! 2165: * any content inside it as a child element. If the node has content,
! 2166: * and the value provided to this function is \ref axl_true, the function
! 2167: * will deallocate the content inside.
! 2168: *
! 2169: * You can use this function to clear all the node content (\ref
! 2170: * ITEM_CONTENT and \ref ITEM_CDATA) found inside the node, as follows:
! 2171: * \code
! 2172: * // clear all content inside
! 2173: * axl_node_set_is_empty (node, axl_true);
! 2174: * \endcode
! 2175: *
! 2176: * @param node The node to configure as empty.
! 2177: *
! 2178: * @param empty The value for emptyness to be used. axl_false will
! 2179: * mean that the node is not empty.
! 2180: */
! 2181: void axl_node_set_is_empty (axlNode * node, axl_bool empty)
! 2182: {
! 2183: axlItem * child;
! 2184: axlItem * aux;
! 2185: int removed = 0;
! 2186: int count = 0;
! 2187:
! 2188: axl_return_if_fail (node);
! 2189:
! 2190: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "received set to empty node=<%s> is_empty=\"%s\"",
! 2191: node->name, empty ? "true" : "false");
! 2192:
! 2193: /* do no perform any operation if axl_false is received */
! 2194: if (! empty)
! 2195: return;
! 2196:
! 2197: /* get the first child and eliminate all content */
! 2198: child = node->first;
! 2199: while (child != NULL) {
! 2200:
! 2201: /* count each item found */
! 2202: count++;
! 2203:
! 2204: /* get a reference to the next */
! 2205: aux = child->next;
! 2206:
! 2207: /* check item node that represents content, and
! 2208: * therefore, an emptyless state */
! 2209: if (axl_item_get_type (child) == ITEM_CONTENT ||
! 2210: axl_item_get_type (child) == ITEM_CDATA) {
! 2211:
! 2212: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found item content and item CDATA..");
! 2213:
! 2214: /* remove the node */
! 2215: axl_item_remove (child, axl_true);
! 2216:
! 2217: /* count each item removed */
! 2218: removed++;
! 2219:
! 2220: } /* end if */
! 2221:
! 2222: /* update to the next */
! 2223: child = aux;
! 2224:
! 2225: } /* end while */
! 2226:
! 2227: /* now check if items removed are equal to items counted */
! 2228: if (removed == count) {
! 2229: /* then clear node references */
! 2230: node->first = NULL;
! 2231: node->last = NULL;
! 2232: }
! 2233:
! 2234: return;
! 2235: }
! 2236:
! 2237: /**
! 2238: * @brief Allows to get current xml node name.
! 2239: *
! 2240: * If it is required to check if the given \ref axlNode have a
! 2241: * particular name you can use the macro \ref NODE_CMP_NAME.
! 2242: *
! 2243: * Here is an example:
! 2244: * \code
! 2245: * void check_name (axlNode * node) {
! 2246: * if (NODE_CMP_NAME (node, "data")) {
! 2247: * // we got a xml node called "data"
! 2248: * }
! 2249: * // the node doesn't have that name
! 2250: * }
! 2251: * \endcode
! 2252: *
! 2253: * @param node The \ref axlNode where the name will be returned.
! 2254: *
! 2255: * @return A string reference containing the name. Returned value must
! 2256: * not deallocated. If a copy is required use \ref axl_strdup
! 2257: * function.
! 2258: */
! 2259: const char * axl_node_get_name (axlNode * node)
! 2260: {
! 2261: axl_return_val_if_fail (node, NULL);
! 2262:
! 2263: return node->name;
! 2264: }
! 2265:
! 2266: /**
! 2267: * @brief Allows to get the parent xml node (\ref axlNode) of the
! 2268: * provided xml node reference.
! 2269: *
! 2270: * @param node The xml node that is requested to return its parent
! 2271: * node.
! 2272: *
! 2273: * @return An internal reference to the parent node, that must not be
! 2274: * deallocated, or NULL if fails. The function will also return NULL
! 2275: * if the node provided is the document root. The function could only
! 2276: * fail if the provided reference is NULL.
! 2277: */
! 2278: axlNode * axl_node_get_parent (axlNode * node)
! 2279: {
! 2280: axl_return_val_if_fail (node, NULL);
! 2281:
! 2282: /* if holder is NULL, no parent is posible */
! 2283: if (node->holder == NULL) {
! 2284: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "received a node without holder (an axlItem reference), unable to get the parent reference: %s",
! 2285: node->name);
! 2286: return NULL;
! 2287: }
! 2288:
! 2289: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "the node has a holder reference, returning current parent");
! 2290:
! 2291: /* return the parent */
! 2292: return node->holder->parent;
! 2293: }
! 2294:
! 2295: /**
! 2296: * @brief Allows to get the node that is located, at the same level,
! 2297: * on the next position on the child list.
! 2298: *
! 2299: * When a parent node holds more node childs, all of them have the
! 2300: * same parent child, and at the same time, all of them have a brother
! 2301: * relation. This relation makes that two nodes that are childs for a
! 2302: * parent node, are positioned sequentially as childs for the parent.
! 2303: *
! 2304: * This function allows to get the next child that is stored at the
! 2305: * next position, inside the same level, for the given child node.
! 2306: *
! 2307: * There are an alternative API that allows to get the next node,
! 2308: * following to the node selected, but providing the name to match. See
! 2309: * \ref axl_node_get_next_called.
! 2310: *
! 2311: * @param node The node to get the next xml node reference.
! 2312: *
! 2313: * @return Returns an internal reference to the next xml node or NULL
! 2314: * if fails. The function will also return NULL if no next xml node is
! 2315: * found starting from the provided reference. The root node will
! 2316: * always returns a NULL reference.
! 2317: */
! 2318: axlNode * axl_node_get_next (axlNode * node)
! 2319: {
! 2320: axlItem * item;
! 2321:
! 2322: axl_return_val_if_fail (node, NULL);
! 2323:
! 2324: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "getting next node for=<%s>", axl_node_get_name (node));
! 2325:
! 2326: if (node->holder == NULL) {
! 2327: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "received a node without item holder (maybe it wasn't inserted into a xml document)");
! 2328: return NULL;
! 2329: }
! 2330:
! 2331: /* get the next axlNode situated at the same level of the
! 2332: * provided axlNode reference */
! 2333: item = axl_item_get_next (node->holder);
! 2334:
! 2335: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "%s", (item != NULL) ? "next item is defined, check if it is a node" : "next item isn't defined");
! 2336:
! 2337: /* while the item is not null and different from item node,
! 2338: * get the next */
! 2339: while (item != NULL) {
! 2340:
! 2341: /* get the item found */
! 2342: if (axl_item_get_type (item) == ITEM_NODE)
! 2343: return item->data;
! 2344:
! 2345: /* get next item */
! 2346: item = item->next;
! 2347:
! 2348: } /* end while */
! 2349:
! 2350: /* or null if no reference is defined */
! 2351: return NULL;
! 2352: }
! 2353:
! 2354: /**
! 2355: * @brief Allows to get the next node, following to the node provided,
! 2356: * matching the given name.
! 2357: *
! 2358: * <i><b>NOTE:</b> This function isn't XML Namespace aware. You must
! 2359: * use \ref axl_ns_node_get_next_called instead. See \ref
! 2360: * axl_ns_doc_validate. </i>
! 2361: *
! 2362: * @param node The node that is requested to return its next sibling
! 2363: * node.
! 2364: *
! 2365: * @param name The name to match for the next node.
! 2366: *
! 2367: * @return A reference to the next node or NULL if it fails. The
! 2368: * returned reference mustn't be deallocated.
! 2369: */
! 2370: axlNode * axl_node_get_next_called (axlNode * node,
! 2371: const char * name)
! 2372: {
! 2373: axlNode * next;
! 2374: axl_return_val_if_fail (node, NULL);
! 2375: axl_return_val_if_fail (name, NULL);
! 2376:
! 2377: /* while there is a next node */
! 2378: next = axl_node_get_next (node);
! 2379: while (next != NULL) {
! 2380: /* check the node */
! 2381: if (NODE_CMP_NAME (next, name))
! 2382: return next;
! 2383:
! 2384: /* update to the next */
! 2385: next = axl_node_get_next (next);
! 2386: } /* end while */
! 2387:
! 2388: /* no node was found */
! 2389: return NULL;
! 2390: }
! 2391:
! 2392: /**
! 2393: * @brief Allows to get the previous reference relative to the node
! 2394: * reference provided.
! 2395: *
! 2396: * See \ref axl_node_get_next. Previous reference is the considered
! 2397: * the previous node to the referenced provided that shares the same
! 2398: * parent and it is situated in the same level.
! 2399: *
! 2400: * @param node The node where the previous reference to the previous
! 2401: * node will be returned.
! 2402: *
! 2403: * @return The previous node reference or NULL if the node doesn't
! 2404: * have previous reference or NULL if the function fails (the function
! 2405: * only fails if the node reference provided is null).
! 2406: */
! 2407: axlNode * axl_node_get_previous (axlNode * node)
! 2408: {
! 2409: axlItem * item;
! 2410:
! 2411: axl_return_val_if_fail (node, NULL);
! 2412:
! 2413: /* get the previous axlNode situated at the same level of the
! 2414: * provided axlNode reference */
! 2415: item = axl_item_get_previous (node->holder);
! 2416:
! 2417: /* while the item is not null and different from item node,
! 2418: * get the previous */
! 2419: while ((item != NULL) && axl_item_get_type (item) !=ITEM_NODE)
! 2420: item = axl_item_get_previous (item);
! 2421:
! 2422: /* return the previous reference */
! 2423: if (item != NULL)
! 2424: return item->data;
! 2425:
! 2426: /* or null if no reference is defined */
! 2427: return NULL;
! 2428: }
! 2429:
! 2430: /**
! 2431: * @brief Allows to get the previous node, preceding to the node
! 2432: * provided, matching the given name.
! 2433: *
! 2434: * <i><b>NOTE:</b> This function isn't XML Namespace aware. You must
! 2435: * use \ref axl_ns_node_get_previous_called instead. See \ref
! 2436: * axl_ns_doc_validate. </i>
! 2437: *
! 2438: * @param node The node that is requested to return its previous sibling node.
! 2439: * @param name The name to match for the previous node.
! 2440: *
! 2441: * @return A reference to the previous node or NULL if it fails. The
! 2442: * returned reference mustn't be deallocated.
! 2443: */
! 2444: axlNode * axl_node_get_previous_called (axlNode * node,
! 2445: const char * name)
! 2446: {
! 2447: axlNode * previous;
! 2448:
! 2449: axl_return_val_if_fail (node, NULL);
! 2450: axl_return_val_if_fail (name, NULL);
! 2451:
! 2452: /* while there is a previous node */
! 2453: previous = axl_node_get_previous (node);
! 2454: while (previous != NULL) {
! 2455: /* check the node */
! 2456: if (NODE_CMP_NAME (previous, name))
! 2457: return previous;
! 2458:
! 2459: /* update to the next */
! 2460: previous = axl_node_get_previous (previous);
! 2461: } /* end while */
! 2462:
! 2463: /* no node was found */
! 2464: return NULL;
! 2465:
! 2466: }
! 2467:
! 2468:
! 2469: /**
! 2470: * @brief Allows to get the first child that holds the node.
! 2471: *
! 2472: * This function is considered inside the CHILDREN API, which is the
! 2473: * set of functions that are used to handle XML documents that have
! 2474: * node that contains more nodes or content, but not mixed.
! 2475: *
! 2476: * This function allows to get the first child found that is an \ref
! 2477: * axlNode. In the case your application is handling a document that
! 2478: * don't mix nodes and content at the same level inside another xml
! 2479: * nodes, you'll get the expected results.
! 2480: *
! 2481: * But, calling to this function on a node that contains content mixed
! 2482: * with another nodes, you will skip all items stored before the first
! 2483: * xml node found as child.
! 2484: *
! 2485: * Let's see some examples to clarify this. Provided the following xml
! 2486: * document:
! 2487: *
! 2488: * \code
! 2489: * <document>
! 2490: * <child>
! 2491: * Content
! 2492: * </child>
! 2493: * </document>
! 2494: * \endcode
! 2495: *
! 2496: * If you want to get a reference to the <b>child</b> node you can do
! 2497: * the following:
! 2498: *
! 2499: * \code
! 2500: * // supposing the document is already loaded in "doc"
! 2501: * axlNode * node = axl_doc_get_root (doc);
! 2502: *
! 2503: * // get the first child
! 2504: * node = axl_node_get_first_child (node);
! 2505: *
! 2506: * // now you have in "node" a reference to the child node.
! 2507: * \endcode
! 2508: *
! 2509: * However, in the case the previous content mix node with content as
! 2510: * follows:
! 2511: *
! 2512: * \code
! 2513: * <document>
! 2514: * Some content previous to the first child.
! 2515: * <child>
! 2516: * Content
! 2517: * </child>
! 2518: * </document>
! 2519: * \endcode
! 2520: *
! 2521: * Using this function will make you to skip the first content, that
! 2522: * is, <i>"Some content previous to the first child"</i>, which is found
! 2523: * before the <child> node. In the case you want to have full
! 2524: * access to all items stored as child for a particular node, check
! 2525: * \ref axl_item_get_first_child.
! 2526: *
! 2527: * @param node The node that is requested to return its first child.
! 2528: *
! 2529: * @return The first child node or NULL if it has no child node.
! 2530: */
! 2531: axlNode * axl_node_get_first_child (axlNode * node)
! 2532: {
! 2533: axlItem * item;
! 2534:
! 2535: /* check values */
! 2536: axl_return_val_if_fail (node, NULL);
! 2537:
! 2538: /* get first item child and lookup for the first child that is
! 2539: * a node */
! 2540: item = node->first;
! 2541: while (item != NULL) {
! 2542: /* check the item type */
! 2543: if (axl_item_get_type (item) == ITEM_NODE)
! 2544: return item->data;
! 2545:
! 2546: /* get the next */
! 2547: item = item->next;
! 2548: }
! 2549:
! 2550: /* return NULL: no child axlNode was found */
! 2551: return NULL;
! 2552: }
! 2553:
! 2554: /**
! 2555: * @brief Allows to get the last child that holds the node.
! 2556: *
! 2557: * See also \ref axl_node_get_first_child and \ref axl_item_get_last_child.
! 2558: *
! 2559: * @param node The node that is requested to return its last child.
! 2560: *
! 2561: * @return The last child node or NULL if it has no child node.
! 2562: */
! 2563: axlNode * axl_node_get_last_child (axlNode * node)
! 2564: {
! 2565: axlItem * item;
! 2566:
! 2567: /* check values */
! 2568: axl_return_val_if_fail (node, NULL);
! 2569:
! 2570: /* get first item child and lookup for the first child that is
! 2571: * a node */
! 2572: item = node->last;
! 2573: while (item != NULL) {
! 2574: /* check the item type */
! 2575: if (axl_item_get_type (item) == ITEM_NODE)
! 2576: return item->data;
! 2577:
! 2578: /* get the next */
! 2579: item = item->previous;
! 2580: }
! 2581:
! 2582: /* return NULL: no child axlNode was found */
! 2583: return NULL;
! 2584: }
! 2585:
! 2586: /**
! 2587: * @brief Allows to check if the provided \ref axlNode is empty.
! 2588: *
! 2589: * If a node have content, this function will return \ref
! 2590: * axl_false. The content must not be confused with the node childs. A
! 2591: * xml node (\ref axlNode) could be empty but have childs at the same
! 2592: * time (\ref axl_node_have_childs).
! 2593: *
! 2594: * The following xml code snipet shows a xml <data> node with
! 2595: * childs that have content, but the parent node, <data> do not
! 2596: * have content, therefore is empty.
! 2597: *
! 2598: * \code
! 2599: * <data>
! 2600: * <row>Some data</row>
! 2601: * <row>More content</row>
! 2602: * </data>
! 2603: * \endcode
! 2604: *
! 2605: * A node that is empty will return NULL data once called to \ref
! 2606: * axl_node_get_content.
! 2607: *
! 2608: * @param node The node to check for its empty status.
! 2609: *
! 2610: * @return \ref axl_true if the node is empty or \ref axl_false if
! 2611: * not.
! 2612: */
! 2613: axl_bool axl_node_is_empty (axlNode * node)
! 2614: {
! 2615: axlItem * child;
! 2616: axl_return_val_if_fail (node, axl_false);
! 2617:
! 2618: /* get the first child */
! 2619: child = node->first;
! 2620: while (child != NULL) {
! 2621:
! 2622: /* check item node that represents content, and
! 2623: * therefore, an emptyless state */
! 2624: if (axl_item_get_type (child) == ITEM_CONTENT ||
! 2625: axl_item_get_type (child) == ITEM_CDATA) {
! 2626:
! 2627: /* the node has content */
! 2628: return axl_false;
! 2629:
! 2630: } /* end if */
! 2631:
! 2632: /* go to the next */
! 2633: child = child->next;
! 2634:
! 2635: } /* end while */
! 2636:
! 2637: return axl_true;
! 2638: }
! 2639:
! 2640: /**
! 2641: * @brief Allows to get current xml node content (\ref axlNode).
! 2642: *
! 2643: * See \ref axl_node_is_empty for more details. This function allows
! 2644: * to get current xml node content, which is the free text enclosed
! 2645: * inside the node.
! 2646: *
! 2647: * Returned value is an internal reference to the content stored. So,
! 2648: * in the case a local copy is desired, you should check \ref
! 2649: * axl_node_get_content_copy.
! 2650: *
! 2651: * Keep in mind that the content returned could have references like
! 2652: * "&" or """ which are entities references not translated
! 2653: * into the application level values.
! 2654: *
! 2655: * This is done because while using the content, you may be interested
! 2656: * in getting the raw content to be passed to another xml parser which
! 2657: * is also able to process that entities.
! 2658: *
! 2659: * If you don't like this behaviour you can check \ref
! 2660: * axl_node_get_content_trans which returns a copy for the xml node
! 2661: * content with all entities references translated.
! 2662: *
! 2663: * Here is a summary of functions available to get the content of a
! 2664: * node:
! 2665: *
! 2666: * - \ref axl_node_get_content_copy (the same like this function but
! 2667: * producing an independent copy)
! 2668: *
! 2669: * - \ref axl_node_get_content_trans (the same like this function but
! 2670: * translating all entity references and producing an indenpendent
! 2671: * copy).
! 2672: *
! 2673: * - \ref axl_node_get_content_trim (the same like this function but
! 2674: * removing initial and trailing white spaces in the W3C sense: spaces,
! 2675: * tabulars, carry returns and line feed values).
! 2676: *
! 2677: * @param node The \ref axlNode node where the content will be retrieved.
! 2678: *
! 2679: * @param content_size Optional pointer to an integer variable where
! 2680: * the content size will be reported. If the variable is not set, the
! 2681: * function will not report the content size. If this value is
! 2682: * configured, it will contain the content size starting from 0 up to
! 2683: * the content size.
! 2684: *
! 2685: * @return Current xml node content. You must not deallocate reference
! 2686: * returned. If you want a permanet copy you should use \ref
! 2687: * axl_node_get_content_copy. Keep in mind that the function will always
! 2688: * return an string reference. In the case the node has no content, an
! 2689: * empty string will be returned, not NULL.
! 2690: */
! 2691: const char * axl_node_get_content (axlNode * node, int * content_size)
! 2692: {
! 2693: axlNodeContent * content;
! 2694: axlItem * child;
! 2695:
! 2696: axl_return_val_if_fail (node, NULL);
! 2697:
! 2698: /* get the first child */
! 2699: child = node->first;
! 2700: while (child != NULL) {
! 2701:
! 2702: /* check item node that represents content, and
! 2703: * therefore, an emptyless state */
! 2704: if (axl_item_get_type (child) == ITEM_CONTENT ||
! 2705: axl_item_get_type (child) == ITEM_CDATA) {
! 2706: /* cast a reference */
! 2707: content = child->data;
! 2708:
! 2709: /* return the content */
! 2710: if (content_size != NULL)
! 2711: *content_size = content->content_size;
! 2712:
! 2713: /* return a local reference */
! 2714: return content->content;
! 2715: } /* end if */
! 2716:
! 2717: /* get the next item */
! 2718: child = child->next;
! 2719:
! 2720: } /* end while */
! 2721:
! 2722: /* set content size to zero */
! 2723: if (content_size != NULL)
! 2724: *content_size = 0;
! 2725: return "";
! 2726: }
! 2727:
! 2728: /**
! 2729: * @brief Allows to set content to the given \ref axlNode instance.
! 2730: *
! 2731: * The xml node content is that part defined inside two balanced xml tags,
! 2732: * using the same label. Here is an example:
! 2733: * \code
! 2734: * <data>
! 2735: * Content inside the xml node.
! 2736: * </data>
! 2737: * \endcode
! 2738: *
! 2739: * The function perform a local copy from the content received, doing
! 2740: * all entity replacement required.
! 2741: *
! 2742: * The following table shows the set of characters that this function
! 2743: * will translate into its corresponding entity:
! 2744: *
! 2745: * <table>
! 2746: * <tr><td><b>Character</b></td><td>Entity name</td></tr>
! 2747: * <tr><td>'</td><td>&apos;</td></tr>
! 2748: * <tr><td><</td><td>&lt;</td></tr>
! 2749: * <tr><td>></td><td>&gt;</td></tr>
! 2750: * <tr><td>&</td><td>&amp;</td></tr>
! 2751: * <tr><td>"</td><td>&quot;</td></tr>
! 2752: * </table>
! 2753: *
! 2754: * @param node The xml node, represented by an already initialized
! 2755: * \ref axlNode, where the node content will be set.
! 2756: *
! 2757: * @param content The content to set to the \ref axlNode. The function
! 2758: * will perform a local copy from it.
! 2759: *
! 2760: * @param content_size The content size that is being provided. If -1
! 2761: * is used, the function will use strlen function to get current
! 2762: * content size.
! 2763: */
! 2764: void axl_node_set_content (axlNode * node,
! 2765: const char * content,
! 2766: int content_size)
! 2767: {
! 2768: axlNodeContent * itemContent;
! 2769: int additional_size = 0;
! 2770:
! 2771: axl_return_if_fail (node);
! 2772: axl_return_if_fail (content);
! 2773:
! 2774: /* get current content in the case a -1 is provided */
! 2775: if (content_size == -1)
! 2776: content_size = strlen (content);
! 2777:
! 2778: /* allocate the content */
! 2779: itemContent = axl_new (axlNodeContent, 1);
! 2780:
! 2781: /* check if the string received have escapable characters */
! 2782: if (axl_node_has_invalid_chars (content, content_size,
! 2783: &additional_size)) {
! 2784: /* copy content */
! 2785: itemContent->content = __axl_node_content_copy_and_escape (content,
! 2786: content_size,
! 2787: additional_size,
! 2788: axl_false);
! 2789: /* set node content size */
! 2790: itemContent->content_size = content_size + additional_size;
! 2791: }else {
! 2792: /* set current content */
! 2793: itemContent->content_size = content_size;
! 2794: itemContent->content = axl_new (char, content_size + 1);
! 2795:
! 2796: /* copy content */
! 2797: memcpy (itemContent->content, content, itemContent->content_size);
! 2798: }
! 2799:
! 2800: /* add it to the current node */
! 2801: axl_item_set_child (node, ITEM_CONTENT, itemContent);
! 2802:
! 2803:
! 2804: /* job done */
! 2805: return;
! 2806: }
! 2807:
! 2808: /**
! 2809: * @internal Common implementation for axl_node_set_content_ref and
! 2810: * axl_node_set_content_from_factory.
! 2811: */
! 2812: void __axl_node_set_content_common_ref (axlFactory * factory,
! 2813: axlNode * node,
! 2814: char * content,
! 2815: int content_size,
! 2816: axl_bool from_factory,
! 2817: axl_bool cdata)
! 2818: {
! 2819:
! 2820: axlNodeContent * itemContent;
! 2821:
! 2822: axl_return_if_fail (node);
! 2823: axl_return_if_fail (content);
! 2824:
! 2825: /* get current content in the case a -1 is provided */
! 2826: if (content_size == -1)
! 2827: content_size = strlen (content);
! 2828:
! 2829: /* create a content checking it it comes from the
! 2830: * factory. Because the string received could come from the
! 2831: * factory, already allocated, do not call to allocate */
! 2832: if (from_factory && factory)
! 2833: itemContent = axl_factory_get (factory);
! 2834: else
! 2835: itemContent = axl_new (axlNodeContent, 1);
! 2836:
! 2837: /* configure content size */
! 2838: itemContent->content_size = content_size;
! 2839:
! 2840: /* set current content */
! 2841: itemContent->content = content;
! 2842:
! 2843: if (from_factory) {
! 2844: if (cdata) {
! 2845: /* store it */
! 2846: axl_item_set_child (node, ITEM_CDATA | ITEM_CONTENT_FROM_FACTORY, itemContent);
! 2847: } else {
! 2848: /* store it */
! 2849: axl_item_set_child (node, ITEM_CONTENT | ITEM_CONTENT_FROM_FACTORY, itemContent);
! 2850: }
! 2851: } else {
! 2852: /* store it */
! 2853: if (cdata) {
! 2854: /* store as cdata */
! 2855: axl_item_set_child (node, ITEM_CDATA, itemContent);
! 2856: } else {
! 2857: /* store as parsed xml content */
! 2858: axl_item_set_child (node, ITEM_CONTENT, itemContent);
! 2859: }
! 2860: } /* end if */
! 2861:
! 2862: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "setting xml node (name: %s) content (size: %d) %s",
! 2863: node->name, itemContent->content_size, itemContent->content);
! 2864:
! 2865: return;
! 2866: }
! 2867:
! 2868: /**
! 2869: * @brief Set the content for the provided node, reusing the reference
! 2870: * provided, without making a local copy.
! 2871: *
! 2872: * This function works like \ref axl_node_set_content_ref but without
! 2873: * copy memory provided. This allows reduce memory allocations if the
! 2874: * memory was already allocated by the user space.
! 2875: *
! 2876: * Because this function doesn't perform a copy, if the content
! 2877: * received has to be escaped, the function will fail. To use this
! 2878: * function the caller must ensure that entity references are used to
! 2879: * especify the &, ', ", < or >.
! 2880: *
! 2881: * If the node have content already configured, it is deallocated,
! 2882: * configuring new content received.
! 2883: *
! 2884: * @param node The \ref axlNode where the content will be set.
! 2885: *
! 2886: * @param content The user space allocated content to be set to the
! 2887: * node.
! 2888: *
! 2889: * @param content_size The content size.
! 2890: */
! 2891: void axl_node_set_content_ref (axlNode * node,
! 2892: char * content,
! 2893: int content_size)
! 2894: {
! 2895:
! 2896: /* call to set content without signaling that the content
! 2897: * wasn't allocated by a factory. */
! 2898: __axl_node_set_content_common_ref (NULL, node, content, content_size, axl_false, axl_false);
! 2899:
! 2900: /* job done */
! 2901: return;
! 2902: }
! 2903:
! 2904: /**
! 2905: * @internal Internal API used by the axl doc module to signal that
! 2906: * the content was allocated though the string factory and shouldn't
! 2907: * be deallocated.
! 2908: */
! 2909: void axl_node_set_content_from_factory (axlFactory * factory,
! 2910: axlNode * node,
! 2911: char * content,
! 2912: int content_size)
! 2913: {
! 2914: /* call to set content without signaling that the content was
! 2915: * allocated by a factory. */
! 2916: __axl_node_set_content_common_ref (factory, node, content, content_size, axl_true, axl_false);
! 2917:
! 2918: /* job done */
! 2919: return;
! 2920: }
! 2921:
! 2922: /**
! 2923: * @brief Allows to store CDATA enclosed content on the provided node.
! 2924: *
! 2925: * Some characters are not allowed to be stored "as is" inside a
! 2926: * parseable XML document. The basic set of them are: &, ', ", < or >.
! 2927: *
! 2928: * In order to store content containing previous characters inside an
! 2929: * xml node, and to remain valid, functions like \ref
! 2930: * axl_node_set_content will translate those value, into the accepted
! 2931: * escape sequences.
! 2932: *
! 2933: * As an alternative, the XML node content could be stored enclosed as
! 2934: * a CDATA section: <![CDATA[..]]>, which allows to store unparsed
! 2935: * characters, including those not allowed.
! 2936: *
! 2937: * NOTE: In the case content received includes a ]]> declaration, it
! 2938: * is escaped to allow it. This is provided not to allow nested CDATA
! 2939: * declarations which is not allowed by XML 1.0 standard but to allow
! 2940: * binary content to be stored that may include a ]]> declaration.
! 2941: *
! 2942: * @param node The node where the CDATA will be stored.
! 2943: *
! 2944: * @param content The content to store.
! 2945: *
! 2946: * @param content_size The content size or -1 if required Axl to
! 2947: * figure out current sizes.
! 2948: */
! 2949: void axl_node_set_cdata_content (axlNode * node,
! 2950: const char * content,
! 2951: int content_size)
! 2952: {
! 2953: char * copy;
! 2954: int additional_size = 0;
! 2955:
! 2956: axl_return_if_fail (node);
! 2957: axl_return_if_fail (content);
! 2958:
! 2959: /* reconfigure content_size if found -1 value */
! 2960: if (content_size == -1)
! 2961: content_size = strlen (content);
! 2962:
! 2963: if (axl_node_has_invalid_chars_cdata (content, content_size, &additional_size)) {
! 2964: /* call to get escaped version */
! 2965: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "CDATA found content to scape (content size: %d): '%s'",
! 2966: content_size, content);
! 2967: copy = __axl_node_content_copy_and_escape (content, content_size, additional_size, axl_true);
! 2968: content_size += additional_size;
! 2969: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "CDATA content escaped (content size: %d): '%s'",
! 2970: content_size, copy);
! 2971: } else {
! 2972: /* call to set node content */
! 2973: copy = axl_strdup (content);
! 2974: } /* end if */
! 2975:
! 2976: /* set content */
! 2977: __axl_node_set_content_common_ref (NULL, node, copy, content_size, axl_false, axl_true);
! 2978:
! 2979: return;
! 2980: }
! 2981:
! 2982: /**
! 2983: * @internal Internal API used by the axl doc module to signal that
! 2984: * the content was allocated though the string factory and shouldn't
! 2985: * be deallocated, and the content was found inside cdata
! 2986: * declarations.
! 2987: */
! 2988: void axl_node_set_cdata_content_from_factory (axlFactory * factory,
! 2989: axlNode * node,
! 2990: char * content,
! 2991: int content_size)
! 2992: {
! 2993: /* call to set content without signaling that the content was
! 2994: * allocated by a factory. */
! 2995: __axl_node_set_content_common_ref (factory, node, content, content_size, axl_true, axl_true);
! 2996:
! 2997: /* job done */
! 2998: return;
! 2999: }
! 3000:
! 3001: /**
! 3002: * @brief Allows to configure a new comment (<!-- xml comment -->) that will be
! 3003: * stored as a child for the node provided.
! 3004: *
! 3005: * The comment will be placed at the end of the current child
! 3006: * list. So, if you want to place a xml comment before a xml node,
! 3007: * call first to this function and then to \ref axl_node_set_child.
! 3008: *
! 3009: * @param node The node that will contain the comment.
! 3010: *
! 3011: * @param comment The comment to be stored. The function will perform
! 3012: * a copy from it.
! 3013: *
! 3014: * @param comment_size The comment size or -1 to make the function to
! 3015: * calculate it.
! 3016: */
! 3017: void axl_node_set_comment (axlNode * node,
! 3018: char * comment,
! 3019: int comment_size)
! 3020: {
! 3021: axlNodeContent * content;
! 3022:
! 3023: axl_return_if_fail (node);
! 3024: axl_return_if_fail (comment);
! 3025:
! 3026: /* check current coment size */
! 3027: if (comment_size == -1)
! 3028: comment_size = strlen (comment);
! 3029:
! 3030: /* create the comment */
! 3031: content = axl_new (axlNodeContent, 1);
! 3032: content->content = axl_new (char, comment_size + 1);
! 3033: content->content_size = comment_size;
! 3034:
! 3035: /* copy the content */
! 3036: memcpy (content->content, comment, comment_size);
! 3037:
! 3038: /* now store it on the node */
! 3039: axl_item_set_child (node, ITEM_COMMENT, content);
! 3040:
! 3041: return;
! 3042: }
! 3043:
! 3044:
! 3045: /**
! 3046: * @brief Allows to get a copy for the content stored inside the given
! 3047: * \ref axlNode reference.
! 3048: *
! 3049: * This function works the same way than \ref axl_node_get_content but
! 3050: * returning a copy from the internal content, that the caller is
! 3051: * responsible of deallocating it.
! 3052: *
! 3053: * @param node The \ref axlNode where the content is being required.
! 3054: *
! 3055: * @param content_size An optional reference to an integer variable
! 3056: * where the content size will be returned. The function will return
! 3057: * the content size (if the variable is defined) ranging from 0 up to
! 3058: * the content size.
! 3059: *
! 3060: * @return A newly allocated string representing the node content.
! 3061: */
! 3062: char * axl_node_get_content_copy (axlNode * node, int * content_size)
! 3063: {
! 3064: int _content_size;
! 3065: char * result;
! 3066: const char * content;
! 3067:
! 3068: /* get the content and check if it is defined */
! 3069: if (content_size)
! 3070: content = axl_node_get_content (node, content_size);
! 3071: else
! 3072: content = axl_node_get_content (node, &_content_size);
! 3073:
! 3074: /* check result */
! 3075: if (content == NULL || strlen (content) == 0) {
! 3076: return axl_strdup ("");
! 3077: }
! 3078:
! 3079: /* allocate enough memory for the result */
! 3080: if (content_size) {
! 3081: result = axl_new (char, (*content_size) + 1);
! 3082: memcpy (result, content, *content_size);
! 3083: }else {
! 3084: result = axl_new (char, _content_size + 1);
! 3085: memcpy (result, content, _content_size);
! 3086: }
! 3087:
! 3088: /* return a newly allocated reference to the content */
! 3089: return result;
! 3090: }
! 3091:
! 3092: /**
! 3093: * @brief Allows to get the content inside the provided node, trimming
! 3094: * the head and trailing white spaces found.
! 3095: *
! 3096: * Note that calling to this function will modify the node content,
! 3097: * removing beginig and ending "white spaces" found. Once the function
! 3098: * is called, the node content will be returned by \ref
! 3099: * axl_node_get_content already trimmed.
! 3100: *
! 3101: * @param node The node where the content will be trimmed and
! 3102: * returned.
! 3103: *
! 3104: * @param content_size The node content size reference where the
! 3105: * content size will be reported.
! 3106: *
! 3107: * @return The reference returned is an internal copy that must not be
! 3108: * deallocated. The function always return content. If the node has no
! 3109: * content, the function will return an empty string (but never a NULL
! 3110: * value).
! 3111: */
! 3112: char * axl_node_get_content_trim (axlNode * node,
! 3113: int * content_size)
! 3114: {
! 3115: int trimmed;
! 3116:
! 3117: axlNodeContent * content;
! 3118: axlItem * child;
! 3119:
! 3120: axl_return_val_if_fail (node, NULL);
! 3121:
! 3122: /* get the first child */
! 3123: child = node->first;
! 3124: while (child != NULL) {
! 3125:
! 3126: /* check item node that represents content, and
! 3127: * therefore, an emptyless state */
! 3128: if (axl_item_get_type (child) == ITEM_CONTENT ||
! 3129: axl_item_get_type (child) == ITEM_CDATA) {
! 3130: /* cast a reference */
! 3131: content = child->data;
! 3132:
! 3133: /* trim the content */
! 3134: axl_stream_trim_with_size (content->content, &trimmed);
! 3135:
! 3136: /* updates current internal content size */
! 3137: content->content_size -= trimmed;
! 3138:
! 3139: /* return the content */
! 3140: if (content_size != NULL)
! 3141: *content_size = content->content_size;
! 3142:
! 3143: /* return a local reference */
! 3144: return content->content;
! 3145: } /* end if */
! 3146:
! 3147: /* get the next item */
! 3148: child = child->next;
! 3149:
! 3150: } /* end while */
! 3151:
! 3152: /* set content size to zero */
! 3153: if (content_size != NULL)
! 3154: *content_size = 0;
! 3155: return "";
! 3156: }
! 3157:
! 3158: void axl_node_get_content_trans_count (axlItem * item, int * count, int *total_size)
! 3159: {
! 3160: axlNodeContent * content;
! 3161:
! 3162: /* reset counters received */
! 3163: (*count) = 0;
! 3164: (*total_size) = 0;
! 3165: while (item != NULL) {
! 3166:
! 3167: /* check item time stored and increase counting */
! 3168: if (axl_item_get_type (item) == ITEM_CONTENT ||
! 3169: axl_item_get_type (item) == ITEM_CDATA) {
! 3170: /* found item */
! 3171: (*count)++;
! 3172:
! 3173: /* update totals */
! 3174: content = item->data;
! 3175: (*total_size) += content->content_size;
! 3176: }
! 3177:
! 3178: /* next item */
! 3179: item = item->next;
! 3180: } /* end while */
! 3181:
! 3182: return;
! 3183: }
! 3184:
! 3185:
! 3186: void axl_node_get_content_trans_copy (axlItem * item, char * result)
! 3187: {
! 3188: axlNodeContent * content;
! 3189: int desp;
! 3190:
! 3191: /* reset counters received */
! 3192: desp = 0;
! 3193: while (item != NULL) {
! 3194:
! 3195: /* check item time stored and increase counting */
! 3196: if (axl_item_get_type (item) == ITEM_CONTENT ||
! 3197: axl_item_get_type (item) == ITEM_CDATA) {
! 3198: /* update totals */
! 3199: content = item->data;
! 3200:
! 3201: /* copy content */
! 3202: memcpy (result + desp, content->content, content->content_size);
! 3203:
! 3204: /* update iterator */
! 3205: desp += content->content_size;
! 3206: }
! 3207:
! 3208: /* next item */
! 3209: item = item->next;
! 3210: } /* end while */
! 3211:
! 3212: return;
! 3213: }
! 3214:
! 3215: /**
! 3216: * @brief Allows to the get node content, performing a memory
! 3217: * allocation for the returned result, translating default entities
! 3218: * values with its replacement text.
! 3219: *
! 3220: * @param node The XML node where the content is being requested to be
! 3221: * translated.
! 3222: *
! 3223: * @param content_size An optional reference to an integer variable to
! 3224: * return the node content size.
! 3225: *
! 3226: * @return A newly allocated string, representing the node content,
! 3227: * with all entities references already translated into the
! 3228: * replacement text.
! 3229: */
! 3230: char * axl_node_get_content_trans (axlNode * node, int * content_size)
! 3231: {
! 3232: char * result;
! 3233: int _content_size = 0;
! 3234: int count;
! 3235: int total_size;
! 3236:
! 3237: /* check received reference */
! 3238: axl_return_val_if_fail (node, NULL);
! 3239:
! 3240: /* check if the node has one item content inside the node or
! 3241: * several CDATA or content items */
! 3242: axl_node_get_content_trans_count (node->first, &count, &total_size);
! 3243:
! 3244: /* accoring to the number of items found */
! 3245: switch (count) {
! 3246: case 0:
! 3247: /* report content size */
! 3248: if (content_size)
! 3249: *content_size = 0;
! 3250: /* nothing found return */
! 3251: return NULL;
! 3252: case 1:
! 3253: /* get a copy for the node content, getting the node
! 3254: * content size. If the user don't provide a
! 3255: * reference, use a local one. */
! 3256: if (content_size)
! 3257: result = axl_node_get_content_copy (node, content_size);
! 3258: else
! 3259: result = axl_node_get_content_copy (node, &_content_size);
! 3260: break;
! 3261: default:
! 3262: /* if reached this place, only positive values from 2
! 3263: * up to N are found */
! 3264: result = axl_new (char, total_size + 1);
! 3265: if (content_size)
! 3266: *content_size = total_size;
! 3267: else
! 3268: _content_size = total_size;
! 3269:
! 3270: /* now copy all content found */
! 3271: axl_node_get_content_trans_copy (node->first, result);
! 3272: }
! 3273:
! 3274:
! 3275: /* check result returned */
! 3276: if (result == NULL || strlen (result) == 0) {
! 3277: /* do not perform a copy here, it is already done by
! 3278: * get_content_copy, even in error */
! 3279: return result;
! 3280: }
! 3281:
! 3282: /* translate all references that performs the entities to the
! 3283: * replacement text. */
! 3284: if (content_size)
! 3285: return axl_node_content_translate_defaults (result, content_size);
! 3286: return axl_node_content_translate_defaults (result, &_content_size);
! 3287: }
! 3288:
! 3289:
! 3290: /**
! 3291: * @brief Allows to configure a child node to the given parent.
! 3292: *
! 3293: * This is a fundamental function while building xml document inside
! 3294: * memory. The way the xml nodes are linked to conform the xml
! 3295: * document structure relay on this function.
! 3296: *
! 3297: * The idea is that every call to this function makes the <b>child
! 3298: * </b> xml node to be placed at the end of the current item child
! 3299: * set, that represents current child list for the provided
! 3300: * <b>parent</b>.
! 3301: *
! 3302: * One important question while using this function is that you must
! 3303: * not reuse the same xml node reference, adding it several time to
! 3304: * the same parent (or different parents). You must create a new xml
! 3305: * node reference (axl_node_create) for every call you do to this
! 3306: * function.
! 3307: *
! 3308: * So, to build the following structure:
! 3309: * \code
! 3310: * <document>
! 3311: * <child1 />
! 3312: * <child2 />
! 3313: * </document>
! 3314: * \endcode
! 3315: *
! 3316: * You must perform the following operations:
! 3317: * \code
! 3318: * axlNode * parent;
! 3319: * axlNode * child;
! 3320: *
! 3321: * // create the parent node
! 3322: * parent = axl_node_create ("document");
! 3323: *
! 3324: * // create the first child
! 3325: * child = axl_node_create ("child1");
! 3326: *
! 3327: * // set it to the parent
! 3328: * axl_node_set_child (parent, child);
! 3329: *
! 3330: * // create the second child
! 3331: * child = axl_node_create ("child2");
! 3332: *
! 3333: * // set it to the parent
! 3334: * axl_node_set_child (parent, child);
! 3335: *
! 3336: * \endcode
! 3337: *
! 3338: * See also \ref axl_node_set_child_after which could help you adding
! 3339: * new nodes not using a parent node as a reference but a brother
! 3340: * node.
! 3341: *
! 3342: * @param parent The parent node.
! 3343: *
! 3344: * @param child The child node. The child node must be a deep
! 3345: * copy. Passing several references, pointing to the same value, will
! 3346: * cause to seg fault the program at the time the parent child is
! 3347: * deallocated.
! 3348: */
! 3349: void axl_node_set_child (axlNode * parent, axlNode * child)
! 3350: {
! 3351: axl_return_if_fail (parent);
! 3352: axl_return_if_fail (child);
! 3353:
! 3354: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "received parent=0x%x and child=0x%x", parent, child);
! 3355:
! 3356: /* set a xml node child */
! 3357: axl_item_set_child (parent, ITEM_NODE, child);
! 3358:
! 3359: return;
! 3360: }
! 3361:
! 3362: /**
! 3363: * @brief Sets a new child after the node provided, using it as a
! 3364: * reference.
! 3365: *
! 3366: * This function is useful to allow configuring new childs placed
! 3367: * after some particular node. The child configured will be placed
! 3368: * after the reference and child of the reference's parent node.
! 3369: *
! 3370: * @param reference The xml node acting as a reference.
! 3371: * @param child The new xml node child to configure.
! 3372: */
! 3373: void axl_node_set_child_after (axlNode * reference,
! 3374: axlNode * child)
! 3375: {
! 3376: /* call to the item implementation */
! 3377: axl_item_set_after (reference->holder, ITEM_NODE, child);
! 3378:
! 3379: return;
! 3380: }
! 3381:
! 3382: /**
! 3383: * @brief Allows to replace a selected node with a new reference
! 3384: * inside its context (updating all references: next, previous and
! 3385: * parent).
! 3386: *
! 3387: * The \ref axlNode replaced will be unreference according to dealloc
! 3388: * value.
! 3389: *
! 3390: * @param node The node to be replaced by <b>new_node</b> reference.
! 3391: *
! 3392: * @param new_node The node that will replace <b>node</b> reference.
! 3393: *
! 3394: * @param dealloc Signal if <b>node</b> must be deallocated after the
! 3395: * replace operation.
! 3396: */
! 3397: void axl_node_replace (axlNode * node,
! 3398: axlNode * new_node,
! 3399: axl_bool dealloc)
! 3400: {
! 3401: axlItem * p_item;
! 3402:
! 3403: axl_return_if_fail (node);
! 3404: axl_return_if_fail (new_node);
! 3405:
! 3406: if (axl_item_get_parent (node->holder) == NULL) {
! 3407: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "replacing the root node=<%s> with <%s>..",
! 3408: axl_node_get_name (node), axl_node_get_name (new_node));
! 3409: /* seems to be a root document */
! 3410: if (axl_item_get_doc (node->holder) != NULL) {
! 3411: axl_doc_set_root (axl_item_get_doc (node->holder), new_node);
! 3412: }
! 3413: } else {
! 3414:
! 3415: /* check for holder reference */
! 3416: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "replacing a non-root node=<%s> with <%s>..",
! 3417: axl_node_get_name (node), axl_node_get_name (new_node));
! 3418: if (node->holder != NULL) {
! 3419:
! 3420: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "axl item holder is defined for node=<%s>",
! 3421: axl_node_get_name (node));
! 3422: /* get a reference to the holder item */
! 3423: p_item = node->holder;
! 3424:
! 3425: /* configure the new node */
! 3426: p_item->data = new_node;
! 3427:
! 3428: /* nullify the holder reference, and configure
! 3429: * the holder reference in the node */
! 3430: node->holder = NULL;
! 3431: new_node->holder = p_item;
! 3432:
! 3433: } /* end if */
! 3434: }
! 3435:
! 3436: /* dealloc node if configured so */
! 3437: if (dealloc) {
! 3438: /* free the node */
! 3439: axl_node_free (node);
! 3440: }
! 3441:
! 3442: return;
! 3443: }
! 3444:
! 3445: /**
! 3446: * @brief Allows to remove the selected reference from the document
! 3447: * containing it.
! 3448: *
! 3449: * The function remove the selected reference from the document. If
! 3450: * the node asked to be removed is the root one, the node won't be
! 3451: * removed because the \ref axl_doc_set_root doesn't accept to remove
! 3452: * the root node.
! 3453: *
! 3454: * All childs hold by the node removed from the document will also be
! 3455: * removed if dealloc is selected.
! 3456: *
! 3457: * @param node The node to remove.
! 3458: *
! 3459: * @param dealloc \ref axl_true to also dealloc the memory used by the
! 3460: * node. Setting this parameter to \ref axl_false only unlinks the
! 3461: * node from the document making possible to reuse the node in another
! 3462: * part of the document or to move the node to a different document.
! 3463: */
! 3464: void axl_node_remove (axlNode * node,
! 3465: axl_bool dealloc)
! 3466: {
! 3467: axlItem * item;
! 3468: axl_return_if_fail (node);
! 3469:
! 3470: /* get a reference to the item element */
! 3471: item = node->holder;
! 3472:
! 3473: /* check if the node is the root node of its document */
! 3474: if (item != NULL && item->doc != NULL) {
! 3475: if (axl_doc_get_root (item->doc) == node) {
! 3476: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "attempting to dettach the root node from the document, nullify");
! 3477: axl_doc_set_root (item->doc, NULL);
! 3478: } /* end if */
! 3479: } /* end if */
! 3480:
! 3481: if (axl_item_get_parent (item) != NULL) {
! 3482:
! 3483: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "doing reference relocation (remove operation) for=<%s>",
! 3484: node->name);
! 3485:
! 3486: /* make previous node to point to the new node */
! 3487: if (item->previous != NULL) {
! 3488: item->previous->next = item->next;
! 3489: }
! 3490:
! 3491: /* make next node to point to the new node */
! 3492: if (item->next != NULL) {
! 3493: item->next->previous = item->previous;
! 3494: }
! 3495:
! 3496: /* now, update the parent reference */
! 3497: if (item->previous == NULL) {
! 3498: /* seems the node is the first child of the parent,
! 3499: * update the reference */
! 3500: item->parent->first = item->next;
! 3501: }
! 3502:
! 3503: if (item->next == NULL) {
! 3504: /* seems the node is the last child of the parent,
! 3505: * update the reference */
! 3506: item->parent->last = item->previous;
! 3507: }
! 3508:
! 3509: if (item != NULL) {
! 3510: /* disconnect the item */
! 3511: item->previous = NULL;
! 3512: item->next = NULL;
! 3513: } /* end if */
! 3514:
! 3515: } /* end if */
! 3516:
! 3517: /* dealloc node if configured so */
! 3518: if (dealloc) {
! 3519: /* free the node */
! 3520: axl_node_free (node);
! 3521: }
! 3522:
! 3523: return;
! 3524: }
! 3525:
! 3526: /**
! 3527: * @brief Supposing the node is attached to a xml document (\ref
! 3528: * axlDoc), this function allows to deattach the node from the
! 3529: * document that is holding it.
! 3530: *
! 3531: * This function is useful while requiring to reallocate nodes from
! 3532: * parent to parent, making the parent node that is holding it to
! 3533: * cancel its references to the node, decreasing all internal counts
! 3534: * to the node, etc.
! 3535: *
! 3536: * If the node isn't attached to any document, the function does
! 3537: * nothing.
! 3538: *
! 3539: * @param node The node to deattach.
! 3540: */
! 3541: void axl_node_deattach (axlNode * node)
! 3542: {
! 3543: axl_return_if_fail (node);
! 3544:
! 3545: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "deattaching node..");
! 3546:
! 3547: /* call to remove */
! 3548: axl_node_remove (node, axl_false);
! 3549:
! 3550: return;
! 3551: }
! 3552:
! 3553: /**
! 3554: * @brief Allows to configure that the given node have child nodes.
! 3555: *
! 3556: * <b>DEPRECATED:</b> The function doesn't perform any operation. See
! 3557: * \ref axl_node_have_childs.
! 3558: *
! 3559: * @param node The node to configure.
! 3560: *
! 3561: * @param childs The child configuration, \ref axl_true to notify that
! 3562: * the node have childs, otherwise, \ref axl_false is returned.
! 3563: */
! 3564: void axl_node_set_have_childs (axlNode * node, axl_bool childs)
! 3565: {
! 3566: /* do nothing */
! 3567: return;
! 3568: }
! 3569:
! 3570: /**
! 3571: * @brief Allows to get current childs configuration from the given
! 3572: * xml node (\ref axlNode).
! 3573: *
! 3574: * An xml node (represented by an \ref axlNode) is considered to have
! 3575: * childs only if it has more xml child nodes. The content is not
! 3576: * considered be a child. See \ref axl_node_is_empty for more
! 3577: * information.
! 3578: *
! 3579: * @param node The \ref axlNode reference.
! 3580: *
! 3581: * @return An \ref axl_true if the \ref axlNode have childs or \ref
! 3582: * axl_false if not.
! 3583: */
! 3584: axl_bool axl_node_have_childs (axlNode * node)
! 3585: {
! 3586: axlItem * item;
! 3587:
! 3588: axl_return_val_if_fail (node, axl_false);
! 3589:
! 3590: item = node->first;
! 3591: while (item != NULL) {
! 3592: /* check item type */
! 3593: if (axl_item_get_type (item) == ITEM_NODE)
! 3594: return axl_true;
! 3595:
! 3596: /* go to the next */
! 3597: item = item->next;
! 3598:
! 3599: } /* end while */
! 3600:
! 3601: /* return axl_false because no item was found with ITEM_NODE
! 3602: * type */
! 3603: return axl_false;
! 3604: }
! 3605:
! 3606: /**
! 3607: * @internal Function that allows to check if the provided node have
! 3608: * childs, including in the list, nodes, comments,
! 3609: *
! 3610: * @param node
! 3611: *
! 3612: * @return
! 3613: */
! 3614: axl_bool axl_node_have_childs_aux (axlNode * node)
! 3615: {
! 3616: axlItem * item;
! 3617:
! 3618: axl_return_val_if_fail (node, axl_false);
! 3619:
! 3620: item = node->first;
! 3621: while (item != NULL) {
! 3622: /* check item type */
! 3623: if (axl_item_get_type (item) == ITEM_NODE ||
! 3624: axl_item_get_type (item) == ITEM_PI ||
! 3625: axl_item_get_type (item) == ITEM_COMMENT)
! 3626: return axl_true;
! 3627:
! 3628: /* go to the next */
! 3629: item = item->next;
! 3630:
! 3631: } /* end while */
! 3632:
! 3633: /* return axl_false because no item was found with ITEM_NODE
! 3634: * type */
! 3635: return axl_false;
! 3636: }
! 3637:
! 3638: /**
! 3639: * @brief Allows to get a particular child node from the given node
! 3640: * (\ref axlNode).
! 3641: *
! 3642: * <i><b>NOTE:</b> This function isn't XML Namespace aware. You must
! 3643: * use \ref axl_ns_node_get_child_called instead. See \ref
! 3644: * axl_ns_doc_validate. </i>
! 3645: *
! 3646: * @param parent The parent node where the child will be looked up.
! 3647: *
! 3648: * @param name The name for the child to search.
! 3649: *
! 3650: * @return A refernce to a \ref axlNode or NULL if no child exists
! 3651: * called by the name provided, inside the node provided.
! 3652: */
! 3653: axlNode * axl_node_get_child_called (axlNode * parent, const char * name)
! 3654: {
! 3655: axlNode * node;
! 3656: axlItem * item;
! 3657:
! 3658: axl_return_val_if_fail (parent, NULL);
! 3659: axl_return_val_if_fail (name, NULL);
! 3660:
! 3661: /* if the child list is not defined, assume there is no node
! 3662: * called the name requested */
! 3663: if (parent->first == NULL)
! 3664: return NULL;
! 3665:
! 3666: /* if no childs, no result */
! 3667: item = parent->first;
! 3668: while (item != NULL) {
! 3669: /* check item type */
! 3670: if (axl_item_get_type (item) == ITEM_NODE) {
! 3671: /* get a reference to the node */
! 3672: node = item->data;
! 3673:
! 3674: /* compare for find the child */
! 3675: if (NODE_CMP_NAME (node, name))
! 3676: return node;
! 3677:
! 3678: } /* end if */
! 3679:
! 3680: /* next child */
! 3681: item = axl_item_get_next (item);
! 3682: }
! 3683:
! 3684: /* no child was found */
! 3685: return NULL;
! 3686: }
! 3687:
! 3688: /**
! 3689: * @brief Allows to find the first child called <b>name</b>, inside
! 3690: * all childs (including its descendants) held by the parent provided.
! 3691: *
! 3692: * This function is similar to \ref axl_node_get_child_called but
! 3693: * though it will also look for a child node called as provided not
! 3694: * only in direct childs but also on its all descendants.
! 3695: *
! 3696: * If you are looking for a function to search for a particular child
! 3697: * node inside direct childs stored for the provided parent, then you
! 3698: * must use \ref axl_node_get_child_called.
! 3699: *
! 3700: * There is also a convenience function that allows to perform a
! 3701: * lookup using as a reference a document (using the root node from
! 3702: * it): \ref axl_doc_find_called.
! 3703: *
! 3704: * <i><b>NOTE:</b> This function isn't XML Namespace aware. You must
! 3705: * use \ref axl_ns_node_find_called instead. See \ref
! 3706: * axl_ns_doc_validate. </i>
! 3707: *
! 3708: * @param parent The parent where the lookup will be produced.
! 3709: *
! 3710: * @param name The name of the child to be looked up.
! 3711: *
! 3712: * @return A reference to the node found (first instaned matching the
! 3713: * name) or NULL if it fails to find a child.
! 3714: */
! 3715: axlNode * axl_node_find_called (axlNode * parent, const char * name)
! 3716: {
! 3717: axlNode * node;
! 3718: axlNode * child;
! 3719:
! 3720: /* for the first child found */
! 3721: node = axl_node_get_first_child (parent);
! 3722: while (node != NULL) {
! 3723: /* check and return the node found */
! 3724: if (NODE_CMP_NAME (node, name))
! 3725: return node;
! 3726:
! 3727: /* get next */
! 3728: node = axl_node_get_next (node);
! 3729: } /* end while */
! 3730:
! 3731: /* now, for all childs, try to look for the node */
! 3732: node = axl_node_get_first_child (parent);
! 3733: while (node != NULL) {
! 3734: /* make the search */
! 3735: child = axl_node_find_called (node, name);
! 3736:
! 3737: /* child found, return the reference */
! 3738: if (child != NULL)
! 3739: return child;
! 3740:
! 3741: /* get next */
! 3742: node = axl_node_get_next (node);
! 3743: } /* end while */
! 3744:
! 3745: /* child note found */
! 3746: return NULL;
! 3747: }
! 3748:
! 3749: /**
! 3750: * @brief Allows to get the child that is located at the given
! 3751: * position, inside the given parent node.
! 3752: *
! 3753: * @param parent The parent node where the child will be looked up.
! 3754: *
! 3755: * @param position The position where the child will be looked up. The
! 3756: * values for the position ranges from 0 up to (N - 1).
! 3757: *
! 3758: * @return A reference to the child node \ref axlNode or NULL if fails.
! 3759: */
! 3760: axlNode * axl_node_get_child_nth (axlNode * parent, int position)
! 3761: {
! 3762: int iterator;
! 3763: axlItem * item;
! 3764:
! 3765: /* perform some environment checks */
! 3766: axl_return_val_if_fail (parent, NULL);
! 3767:
! 3768: /* check for first reference */
! 3769: if (parent->first == NULL) {
! 3770: return NULL;
! 3771: }
! 3772:
! 3773: /* get the first item */
! 3774: item = parent->first;
! 3775:
! 3776: /* get the first node found */
! 3777: iterator = 0;
! 3778: while (item != NULL) {
! 3779: /* check the item type */
! 3780: if (axl_item_get_type (item) == ITEM_NODE) {
! 3781: if (iterator == position) {
! 3782: return item->data;
! 3783: } else
! 3784: iterator++;
! 3785: } /* end if */
! 3786:
! 3787: /* get the next */
! 3788: item = item->next;
! 3789:
! 3790: } /* end while */
! 3791:
! 3792: /* no first child found */
! 3793: return NULL;
! 3794: }
! 3795:
! 3796: /**
! 3797: * @brief Allows to get the number of childs that the provided node
! 3798: * has.
! 3799: *
! 3800: * @param parent The node where the number of childs is being queried.
! 3801: *
! 3802: * @return The number of childs or -1 if fails.
! 3803: */
! 3804: int axl_node_get_child_num (axlNode * parent)
! 3805: {
! 3806: int count;
! 3807: axlItem * item;
! 3808:
! 3809: /* perform some environment checks */
! 3810: axl_return_val_if_fail (parent, -1);
! 3811:
! 3812: /* init values */
! 3813: count = 0;
! 3814: item = parent->first;
! 3815:
! 3816: /* for each child inside the parent node */
! 3817: while (item != NULL) {
! 3818:
! 3819: /* check item type */
! 3820: if (axl_item_get_type (item) == ITEM_NODE)
! 3821: count++;
! 3822:
! 3823: /* get the next */
! 3824: item = item->next;
! 3825:
! 3826: } /* end while */
! 3827:
! 3828: /* return the number of chils */
! 3829: return count;
! 3830: }
! 3831:
! 3832:
! 3833: /**
! 3834: * @brief Allows to get childs nodes from the given xml node (\ref
! 3835: * axlNode).
! 3836: *
! 3837: * This function creates a newly allocated list. In the case you want
! 3838: * to iterate over all nodes, it is better to use something similar to
! 3839: * this:
! 3840: *
! 3841: * \code
! 3842: * axlNode * child;
! 3843: *
! 3844: * // get the first child
! 3845: * child = axl_node_get_first_child (parent);
! 3846: *
! 3847: * // iterate over all nodes
! 3848: * while (child != NULL) {
! 3849: *
! 3850: * // do something with the child
! 3851: * do_some_work (child);
! 3852: *
! 3853: * // update the reference to the next child
! 3854: * child = axl_node_get_next (child);
! 3855: * }
! 3856: * \endcode
! 3857: *
! 3858: * @param node The node where the childs will be returned.
! 3859: *
! 3860: * @return An \ref axlList containing \ref axlNode items or NULL if it
! 3861: * fails. The list returned MUST be deallocated.
! 3862: */
! 3863: axlList * axl_node_get_childs (axlNode * node)
! 3864: {
! 3865: axlItem * child;
! 3866: axlList * result;
! 3867:
! 3868: axl_return_val_if_fail (node, NULL);
! 3869:
! 3870: /* create the result list without destroy function */
! 3871: result = axl_list_new (__axl_node_equal, NULL);
! 3872:
! 3873: /* get the first child */
! 3874: child = node->first;
! 3875:
! 3876: while (child != NULL) {
! 3877: /* check the node type */
! 3878: if (axl_item_get_type (child) == ITEM_NODE) {
! 3879: /* add the child to the list */
! 3880: axl_list_add (result, child->data);
! 3881:
! 3882: } /* end if */
! 3883:
! 3884: /* update the reference to the next child */
! 3885: child = child->next;
! 3886: } /* end while */
! 3887:
! 3888: /* return current childs */
! 3889: return result;
! 3890: }
! 3891:
! 3892: axl_bool __axl_node_are_equal_attr (axlPointer key,
! 3893: axlPointer value,
! 3894: axlPointer user_data,
! 3895: axlPointer user_data2)
! 3896: {
! 3897: char * value2;
! 3898: axl_bool * result = user_data2;
! 3899:
! 3900: /* get the attr value and compare it with data */
! 3901: value2 = axl_hash_get ((axlHash *) user_data, (char *) key);
! 3902:
! 3903: if (! axl_cmp ((char *) value, value2)) {
! 3904: /* flag that node attributes aren't equal */
! 3905: (* result) = axl_false;
! 3906:
! 3907: /* stop foreach */
! 3908: return axl_true;
! 3909: }
! 3910:
! 3911: /* make the process to continue */
! 3912: return axl_false;
! 3913: }
! 3914:
! 3915: /**
! 3916: * @brief Allows to check if the provided references represents two
! 3917: * equivalent nodes.
! 3918: *
! 3919: * The function will check node name, node content and node attributes
! 3920: * and its values.
! 3921: *
! 3922: * @param node The node to check.
! 3923: * @param node2 The second node to check.
! 3924: * @param error Optional reference to an \ref axlError where the particular differ is reported.
! 3925: *
! 3926: * @return axl_true if both nodes are equivalent or axl_false if not.
! 3927: */
! 3928: axl_bool axl_node_are_equal_full (axlNode * node, axlNode * node2, axlError ** error)
! 3929: {
! 3930: axl_bool result;
! 3931:
! 3932: if (node == NULL) {
! 3933: axl_error_report (error, -1, "Nodes differs because first node reference is NULL");
! 3934: return axl_false;
! 3935: } /* end if */
! 3936: if (node2 == NULL) {
! 3937: axl_error_report (error, -1, "Nodes differs because second node reference is NULL");
! 3938: return axl_false;
! 3939: } /* end if */
! 3940:
! 3941: /* check document root name */
! 3942: if (! axl_cmp (axl_node_get_name (node), axl_node_get_name (node2))) {
! 3943: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "node names aren't equal <%s> != <%s>",
! 3944: node->name, node2->name);
! 3945: axl_error_report (error, -1, "node names aren't equal <%s> != <%s>",
! 3946: node->name, node2->name);
! 3947: return axl_false;
! 3948: }
! 3949:
! 3950: /* check empty ness configuration */
! 3951: if (axl_node_is_empty (node) != axl_node_is_empty (node2)) {
! 3952: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "emptyness configuration differs <%s> != <%s>",
! 3953: node->name, node2->name);
! 3954:
! 3955: axl_error_report (error, -1, "emptyness configuration differs <%s> != <%s>",
! 3956: node->name, node2->name);
! 3957: return axl_false;
! 3958: }
! 3959:
! 3960: /* check childs configuration */
! 3961: if (axl_node_have_childs (node) != axl_node_have_childs (node2)) {
! 3962: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "childs configuration differs <%s> != <%s>",
! 3963: node->name, node2->name);
! 3964: axl_error_report (error, -1, "childs configuration differs <%s> != <%s>",
! 3965: node->name, node2->name);
! 3966: return axl_false;
! 3967: }
! 3968:
! 3969: /* check childs number */
! 3970: if (axl_node_get_child_num (node) != axl_node_get_child_num (node2)) {
! 3971: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "child number differs <%s>(%d) != <%s>(%d)",
! 3972: node->name, axl_node_get_child_num (node), node2->name, axl_node_get_child_num (node2));
! 3973: axl_error_report (error, -1, "childs configuration differs <%s> != <%s>",
! 3974: node->name, node2->name);
! 3975: return axl_false;
! 3976: }
! 3977:
! 3978: /* check attribute values */
! 3979: if ((node->attributes != NULL && node2->attributes != NULL)) {
! 3980:
! 3981: /* check the number of attributes that has the hash */
! 3982: if (node->attr_num != node2->attr_num) {
! 3983: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "both nodes have different number of attributes (<%s>:%d != <%s>:%d)",
! 3984: node->name, node->attr_num,
! 3985: node2->name, node2->attr_num);
! 3986: axl_error_report (error, -1, "both nodes have different number of attributes (<%s>:%d != <%s>:%d)",
! 3987: node->name, node->attr_num,
! 3988: node2->name, node2->attr_num);
! 3989: return axl_false;
! 3990: }
! 3991:
! 3992: /* now both hashes */
! 3993: result = axl_true;
! 3994: if (node->attr_num <= 10) {
! 3995: /* check both list are equal */
! 3996: result = __axl_node_attr_list_is_equal ((axlNodeAttr *) node->attributes, (axlNodeAttr *) node2->attributes);
! 3997: } else {
! 3998: /* check both hashes are equal */
! 3999: axl_hash_foreach2 ((axlHash *) node->attributes, __axl_node_are_equal_attr, (axlHash *) node2->attributes, &result);
! 4000: }
! 4001:
! 4002: if (! result) {
! 4003: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "node attributes differs <%s> != <%s>",
! 4004: node->name, node2->name);
! 4005: axl_error_report (error, -1, "node attributes differs <%s> != <%s>",
! 4006: node->name, node2->name);
! 4007: /* attribute missmatch */
! 4008: return axl_false;
! 4009: }
! 4010: } else {
! 4011: if (node->attributes == NULL && node2->attributes != NULL) {
! 4012: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "node <%s> has no attributes but <%s> has",
! 4013: axl_node_get_name (node), axl_node_get_name (node2));
! 4014: axl_error_report (error, -1, "node <%s> has no attributes but <%s> has",
! 4015: axl_node_get_name (node), axl_node_get_name (node2));
! 4016: return axl_false;
! 4017: }
! 4018:
! 4019: if (node2->attributes == NULL && node->attributes != NULL) {
! 4020: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "node <%s> has no attributes but <%s> has",
! 4021: axl_node_get_name (node2), axl_node_get_name (node));
! 4022: axl_error_report (error, -1, "node <%s> has no attributes but <%s> has",
! 4023: axl_node_get_name (node2), axl_node_get_name (node));
! 4024: return axl_false;
! 4025: }
! 4026:
! 4027: } /* end if */
! 4028:
! 4029: /* both nodes seems to be equal */
! 4030: return axl_true;
! 4031: }
! 4032:
! 4033: /**
! 4034: * @brief Allows to check if the provided references represents two
! 4035: * equivalent nodes.
! 4036: *
! 4037: * The function will check node name, node content and node attributes
! 4038: * and its values.
! 4039: *
! 4040: * @param node The node to check.
! 4041: * @param node2 The second node to check.
! 4042: *
! 4043: * @return axl_true if both nodes are equivalent or axl_false if not.
! 4044: */
! 4045: axl_bool axl_node_are_equal (axlNode * node, axlNode * node2)
! 4046: {
! 4047: /* use common implementation */
! 4048: return axl_node_are_equal_full (node, node2, NULL);
! 4049: }
! 4050:
! 4051: /**
! 4052: * @brief Allows to associate a PI element, including its content to
! 4053: * the provided node.
! 4054: *
! 4055: * See the following function for more information: \ref
! 4056: * axl_doc_add_pi_target.
! 4057: *
! 4058: * @param node The \ref axlNode where the PI element (\ref axlPI) will
! 4059: * be added.
! 4060: *
! 4061: * @param target The PI target name to add.
! 4062: *
! 4063: * @param content Optional PI content.
! 4064: */
! 4065: void axl_node_add_pi_target (axlNode * node,
! 4066: char * target,
! 4067: char * content)
! 4068: {
! 4069: axlPI * pi;
! 4070:
! 4071: /* perform some environmental checks */
! 4072: axl_return_if_fail (node);
! 4073: axl_return_if_fail (target);
! 4074:
! 4075: /* create the PI element */
! 4076: pi = axl_pi_create (target, content);
! 4077:
! 4078: /* set the new process instruction found */
! 4079: axl_item_set_child (node, ITEM_PI, pi);
! 4080:
! 4081: return;
! 4082: }
! 4083:
! 4084:
! 4085: /**
! 4086: * @brief Allows to check if the provided Processing instruction
! 4087: * target is defined on the given xml node document (\ref axlNode).
! 4088: *
! 4089: * Processing instruction are a way to configure the xml node document
! 4090: * with processing information to instruct the application level that
! 4091: * is going to consume the XML information.
! 4092: *
! 4093: * @param node The \ref axlNode where the processing instruction will
! 4094: * be read.
! 4095: *
! 4096: * @param pi_target The process instruction name.
! 4097: *
! 4098: * @return axl_true is the processing instruction is defined,
! 4099: * otherwise axl_false is returned.
! 4100: */
! 4101: axl_bool axl_node_has_pi_target (axlNode * node,
! 4102: char * pi_target)
! 4103: {
! 4104: axlPI * pi;
! 4105: axlItem * item;
! 4106:
! 4107: axl_return_val_if_fail (node, axl_false);
! 4108: axl_return_val_if_fail (pi_target, axl_false);
! 4109:
! 4110: /* assume the pi target doesn't exist if it is not
! 4111: * initialized */
! 4112: item = node->first;
! 4113: while (item != NULL) {
! 4114:
! 4115: /* check the type */
! 4116: if (axl_item_get_type (item) == ITEM_PI) {
! 4117: /* get a reference */
! 4118: pi = item->data;
! 4119:
! 4120: /* only check the first ocurrency */
! 4121: if (axl_cmp (axl_pi_get_name (pi), pi_target))
! 4122: return axl_true;
! 4123: } /* end if */
! 4124:
! 4125: /* get the next item */
! 4126: item = item->next;
! 4127:
! 4128: } /* end while */
! 4129:
! 4130: return axl_false;
! 4131: }
! 4132:
! 4133: /**
! 4134: * @brief Allows to get current processing instruction content.
! 4135: *
! 4136: * @param node The document where the processing instruction is placed.
! 4137: *
! 4138: * @param pi_target The processing instruction target to get current
! 4139: * content.
! 4140: *
! 4141: * @return An internal reference to the process instruction target
! 4142: * content. Value returned mustn't be deallocated
! 4143: */
! 4144: char * axl_node_get_pi_target_content (axlNode * node,
! 4145: char * pi_target)
! 4146: {
! 4147: axlPI * pi;
! 4148: axlItem * item;
! 4149:
! 4150: axl_return_val_if_fail (node, NULL);
! 4151: axl_return_val_if_fail (pi_target, NULL);
! 4152:
! 4153: /* assume the pi target doesn't exist if it is not
! 4154: * initialized */
! 4155: item = node->first;
! 4156: while (item != NULL) {
! 4157:
! 4158: /* check the type */
! 4159: if (axl_item_get_type (item) == ITEM_PI) {
! 4160: /* get a reference */
! 4161: pi = item->data;
! 4162:
! 4163: /* only check the first ocurrency */
! 4164: if (axl_cmp (axl_pi_get_name (pi), pi_target))
! 4165: return axl_pi_get_content (pi);
! 4166: } /* end if */
! 4167:
! 4168: /* get the next item */
! 4169: item = item->next;
! 4170:
! 4171: } /* end while */
! 4172:
! 4173: return NULL;
! 4174: }
! 4175:
! 4176: /**
! 4177: * @brief Allows to transfer (move from) all childs (including
! 4178: * comments, content, PI, nodes, etc) from the old parent to the new
! 4179: * parent.
! 4180: *
! 4181: * This function is particular useful while moving content from nodes.
! 4182: *
! 4183: * @param old_parent The old parent node where all childs will be
! 4184: * removed and placed in the new parent.
! 4185: *
! 4186: * @param new_parent The parent node where the content will be
! 4187: * placed. If the parent node already have childs, the content will be
! 4188: * appended.
! 4189: */
! 4190: void axl_node_transfer_childs (axlNode * old_parent,
! 4191: axlNode * new_parent)
! 4192: {
! 4193: axlItem * item;
! 4194: axlItem * item_aux;
! 4195:
! 4196: /* get the first child for the old parent */
! 4197: item = old_parent->first;
! 4198: while (item != NULL) {
! 4199:
! 4200: /* get a reference to the next before adding */
! 4201: item_aux = item->next;
! 4202:
! 4203: /* set the item to parent for the new node */
! 4204: axl_item_set_child_ref (new_parent, item);
! 4205:
! 4206:
! 4207: /* get the next */
! 4208: item = item_aux;
! 4209:
! 4210: } /* end while */
! 4211:
! 4212: /* clear reference from previous parent */
! 4213: old_parent->first = NULL;
! 4214: old_parent->last = NULL;
! 4215:
! 4216: return;
! 4217: }
! 4218:
! 4219: /**
! 4220: * @internal Implementation for the public API provided to dump node content.
! 4221: */
! 4222: axl_bool __axl_node_dump_common (axlNode * node, char ** content, int * size, axl_bool pretty_print, int level, int tabular)
! 4223: {
! 4224: int _size;
! 4225: int index;
! 4226: char * result;
! 4227:
! 4228: /* check refererences received */
! 4229: axl_return_val_if_fail (node, axl_false);
! 4230: axl_return_val_if_fail (content, axl_false);
! 4231:
! 4232: /* get dump size */
! 4233: _size = axl_node_get_flat_size (node, pretty_print, level, tabular);
! 4234:
! 4235: /* dump the content */
! 4236: result = axl_new (char, _size + 1);
! 4237: index = axl_node_dump_at (node, result, 0, pretty_print, level, tabular);
! 4238:
! 4239: /* check result */
! 4240: if (index != _size) {
! 4241: __axl_log (LOG_DOMAIN, AXL_LEVEL_CRITICAL, "failed to dump xml node, size dump operation mismatch: %d != %d",
! 4242: index, _size);
! 4243: /* free allocated result */
! 4244: axl_free (result);
! 4245:
! 4246: /* nullify content */
! 4247: if (size)
! 4248: *size = -1;
! 4249: *content = NULL;
! 4250:
! 4251: return axl_false;
! 4252: } /* end if */
! 4253:
! 4254: /* fill the size */
! 4255: if (size)
! 4256: *size = _size;
! 4257: *content = result;
! 4258:
! 4259: /* return content */
! 4260: return axl_true;
! 4261: }
! 4262:
! 4263: /**
! 4264: * @brief Allows to dump the xml content taking as starting point the
! 4265: * xml node provided.
! 4266: *
! 4267: * @param node The \ref axlNode used as reference and starting point
! 4268: * to dump.
! 4269: *
! 4270: * @param content The reference where the result will be returned.
! 4271: *
! 4272: * @param size The reference where the document content size will be
! 4273: * returned.
! 4274: *
! 4275: * @return The function returns \ref axl_true if the dump operation
! 4276: * was performed. Otherwise \ref axl_false is returned.
! 4277: */
! 4278: axl_bool axl_node_dump (axlNode * node,
! 4279: char ** content,
! 4280: int * size)
! 4281: {
! 4282: /* use common implementation for all functions */
! 4283: return __axl_node_dump_common (node, content, size, axl_false, 0, 0);
! 4284: }
! 4285:
! 4286: /**
! 4287: * @brief Allows to perform a pretty print operation using as
! 4288: * reference (starting point) the node provided.
! 4289: *
! 4290: * @param node The node to be used as reference for the dump operation.
! 4291: *
! 4292: * @param content A reference to a user defined pointer where the
! 4293: * content will be placed. Non optional parameter.
! 4294: *
! 4295: * @param size A reference to a user defined pointer where the content
! 4296: * size will be placed. Optional parameter.
! 4297: *
! 4298: * @param tabular How many spaces to be placed on each level.
! 4299: *
! 4300: * @return \ref axl_true if the dump operation was properly done, otherwise
! 4301: * \ref axl_false is returned.
! 4302: */
! 4303: axl_bool axl_node_dump_pretty (axlNode * node,
! 4304: char ** content,
! 4305: int * size,
! 4306: int tabular)
! 4307: {
! 4308: /* use common implementation for all functions */
! 4309: return __axl_node_dump_common (node, content, size, axl_true, 0, tabular);
! 4310: }
! 4311:
! 4312: /**
! 4313: * @brief Allows to dump the xml document using as reference the node
! 4314: * provided, at the file path provided.
! 4315: *
! 4316: * @param node The document node reference to use to build the
! 4317: * content.
! 4318: *
! 4319: * @param file_path File path where place the result.
! 4320: *
! 4321: * @return \ref axl_true if the dump operation was done, otherwise \ref axl_false is
! 4322: * returned.
! 4323: */
! 4324: axl_bool axl_node_dump_to_file (axlNode * node,
! 4325: char * file_path)
! 4326: {
! 4327: char * content;
! 4328: int size;
! 4329: FILE * fd;
! 4330: int written;
! 4331:
! 4332: /* use common implementation for all functions */
! 4333: if (! __axl_node_dump_common (node, &content, &size, axl_true, 0, 0))
! 4334: return axl_false;
! 4335:
! 4336: /* open the file and check */
! 4337: #if defined(AXL_OS_WIN32) && ! defined(__GNUC__)
! 4338: if (fopen_s (&fd, file_path, "w") != 0) {
! 4339: #else
! 4340: if ((fd = fopen (file_path, "w")) == NULL) {
! 4341: #endif
! 4342: /* failed to open the file to dump the content */
! 4343: axl_free (content);
! 4344:
! 4345: return axl_false;
! 4346: }
! 4347:
! 4348: /* dump the content */
! 4349: written = fwrite (content, 1, size, fd);
! 4350:
! 4351: /* free the content */
! 4352: axl_free (content);
! 4353:
! 4354: /* close file */
! 4355: fclose (fd);
! 4356:
! 4357: /* return if we have failed to dump all the content to the
! 4358: * file or not. */
! 4359: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "returning that the dump was: %s (written:%d == size:%d)",
! 4360: (written == size) ? "OK" : "FAILED",
! 4361: written, size);
! 4362:
! 4363: return (written == size);
! 4364:
! 4365: }
! 4366:
! 4367: /**
! 4368: * @brief Allows to pretty print dump the xml document using as
! 4369: * reference the node provided, at the file path provided.
! 4370: *
! 4371: * @param node The document node reference to use to build the
! 4372: * content.
! 4373: *
! 4374: * @param file_path File path where place the result.
! 4375: *
! 4376: * @param tabular How many spaces to be placed at each level.
! 4377: *
! 4378: * @return \ref axl_true if the dump operation was done, otherwise \ref axl_false is
! 4379: * returned.
! 4380: */
! 4381: axl_bool axl_node_dump_pretty_to_file (axlNode * node,
! 4382: char * file_path,
! 4383: int tabular)
! 4384: {
! 4385: char * content;
! 4386: int size;
! 4387: FILE * fd;
! 4388: int written;
! 4389:
! 4390: /* use common implementation for all functions */
! 4391: if (! __axl_node_dump_common (node, &content, &size, axl_true, 0, tabular))
! 4392: return axl_false;
! 4393:
! 4394: /* open the file and check */
! 4395: #if defined(AXL_OS_WIN32) && ! defined(__GNUC__)
! 4396: if (fopen_s (&fd, file_path, "w") != 0) {
! 4397: #else
! 4398: if ((fd = fopen (file_path, "w")) == NULL) {
! 4399: #endif
! 4400: /* failed to open the file to dump the content */
! 4401: axl_free (content);
! 4402:
! 4403: return axl_false;
! 4404: }
! 4405:
! 4406: /* dump the content */
! 4407: written = fwrite (content, 1, size, fd);
! 4408:
! 4409: /* free the content */
! 4410: axl_free (content);
! 4411:
! 4412: /* close file */
! 4413: fclose (fd);
! 4414:
! 4415: /* return if we have failed to dump all the content to the
! 4416: * file or not. */
! 4417: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "returning that the dump was: %s (written:%d == size:%d)",
! 4418: (written == size) ? "OK" : "FAILED",
! 4419: written, size);
! 4420:
! 4421: return (written == size);
! 4422: }
! 4423:
! 4424: /**
! 4425: * @brief Allows to get a list which contains \ref axlPI nodes,
! 4426: * representing all process instruction that the \ref axlNode (xml
! 4427: * document node) has.
! 4428: *
! 4429: * While using PI, you can use the following functions to get PI
! 4430: * information:
! 4431: *
! 4432: * - \ref axl_node_has_pi_target
! 4433: * - \ref axl_node_get_pi_target_content
! 4434: *
! 4435: * However, this function will return first ocurrence for PI found
! 4436: * inside the xml document. If you don't use repeated PI elements, you
! 4437: * won't find problems, but, if you need to iterate ever all PI found
! 4438: * or you are using repeated PI, you can use this function as follows
! 4439: * to get current pi elements:
! 4440: *
! 4441: * \code
! 4442: * void show_all_pi (axlNode * node)
! 4443: * {
! 4444: * int iterator;
! 4445: * axlPI * pi;
! 4446: * axlList * PIs;
! 4447: *
! 4448: * // get all PI target that the node has
! 4449: * PIs = axl_node_get_pi_target_list (node);
! 4450: * iterator = 0;
! 4451: *
! 4452: * while (iterator < axl_list_length (PIs)) {
! 4453: * // get next pi stored
! 4454: * pi = axl_list_get_nth (PIs, iterator);
! 4455: *
! 4456: * // do some stuff
! 4457: * printf ("PI found target name=%s, content=%s\n",
! 4458: * axl_pi_get_name (pi),
! 4459: * axl_pi_get_content (pi));
! 4460: *
! 4461: * // update the iterator
! 4462: * iterator++;
! 4463: * }
! 4464: *
! 4465: * // once finished, free the list
! 4466: * axl_list_free (PIs);
! 4467: * return;
! 4468: * }
! 4469: * \endcode
! 4470: *
! 4471: * @param node The xml node (\ref axlNode) where the process
! 4472: * instruction will be returned.
! 4473: *
! 4474: * @return A reference to the list of processing instruction that the
! 4475: * xml node (\ref axlNode) has. The returned list, if defined, must be
! 4476: * deallocated.
! 4477: */
! 4478: axlList * axl_node_get_pi_target_list (axlNode * node)
! 4479: {
! 4480: axlList * result = NULL;
! 4481: axlItem * item;
! 4482:
! 4483: axl_return_val_if_fail (node, NULL);
! 4484:
! 4485: /* assume the pi target doesn't exist if it is not
! 4486: * initialized */
! 4487: item = node->first;
! 4488: while (item != NULL) {
! 4489:
! 4490: /* check the type */
! 4491: if (axl_item_get_type (item) == ITEM_PI) {
! 4492: /* create the result list */
! 4493: if (result == NULL)
! 4494: result = axl_list_new (axl_list_always_return_1, (axlDestroyFunc) axl_pi_free);
! 4495:
! 4496: /* add the list */
! 4497: axl_list_add (result, item->data);
! 4498:
! 4499: } /* end if */
! 4500:
! 4501: /* get the next item */
! 4502: item = item->next;
! 4503:
! 4504: } /* end while */
! 4505:
! 4506: return result;
! 4507: }
! 4508:
! 4509: axl_bool __axl_node_get_flat_size_attributes_foreach (axlPointer attr,
! 4510: axlPointer value,
! 4511: axlPointer user_data)
! 4512: {
! 4513: int * length = user_data;
! 4514:
! 4515: /* " attribute='value' */
! 4516: (*length) += 4 + strlen ((char*) attr) + strlen ((char*) value);
! 4517:
! 4518: /* make the process to continue */
! 4519: return axl_false;
! 4520: }
! 4521:
! 4522: /**
! 4523: * @internal
! 4524: * @brief Returns the space required to write the attribute part.
! 4525: */
! 4526: int __axl_node_get_flat_size_attributes (axlNode * node)
! 4527: {
! 4528:
! 4529: int length = 0;
! 4530: axlNodeAttr * attr = NULL;
! 4531:
! 4532: /* if attribute list is not defined just return 0 */
! 4533: if (node->attributes == NULL)
! 4534: return 0;
! 4535:
! 4536: /* perform a foreach and accumulate */
! 4537: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "get flat size for node <%s>",
! 4538: axl_node_get_name (node));
! 4539: if (node->attr_num <= 10) {
! 4540: /* get the first reference */
! 4541: attr = (axlNodeAttr *) node->attributes;
! 4542: while (attr != NULL) {
! 4543: /* call to get length */
! 4544: __axl_node_get_flat_size_attributes_foreach (attr->attribute, attr->value, &length);
! 4545:
! 4546: /* get the next */
! 4547: attr = attr->next;
! 4548: }
! 4549:
! 4550: } else {
! 4551: /* perform a foreach */
! 4552: axl_hash_foreach ((axlHash *) node->attributes, __axl_node_get_flat_size_attributes_foreach, &length);
! 4553: }
! 4554:
! 4555: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "after foreach flat size for node <%s> is %d",
! 4556: axl_node_get_name (node), length);
! 4557:
! 4558: /* return the length */
! 4559: return length;
! 4560: }
! 4561:
! 4562: /**
! 4563: * @internal
! 4564: *
! 4565: * Returns which the size that the node and its childs will hold if
! 4566: * the are represented into a flat xml stream.
! 4567: *
! 4568: * @param node The node that is requested its stream xml size.
! 4569: *
! 4570: * @param pretty_print If pretty print is activated.
! 4571: *
! 4572: * @param level Which is the relative level of the node respected to
! 4573: * the root node.
! 4574: *
! 4575: * @return The stream size or -1 if fails.
! 4576: */
! 4577: int axl_node_get_flat_size (axlNode * node, axl_bool pretty_print, int level, int tabular)
! 4578: {
! 4579: int result = 0;
! 4580: axlItem * item;
! 4581: axlNodeContent * content;
! 4582: axl_bool is_empty;
! 4583: axl_bool have_childs;
! 4584:
! 4585: axl_return_val_if_fail (node, -1);
! 4586:
! 4587: /* get values */
! 4588: is_empty = axl_node_is_empty (node);
! 4589: have_childs = axl_node_have_childs_aux (node);
! 4590:
! 4591: if (have_childs || (!have_childs && !is_empty)) {
! 4592: /* the node is emtpy because it has no content but it has
! 4593: * childs:
! 4594: *
! 4595: * "<" + strlen (node-name) + ">" + ... + "</" + strlen (node-name) + ">" */
! 4596: result = 5 + (2 * strlen (node->name)) + __axl_node_get_flat_size_attributes (node);
! 4597:
! 4598: /* check pretty_print */
! 4599: if (pretty_print) {
! 4600: /* two tabulations plus two carry return \r\n
! 4601: * on windows and \n on unix */
! 4602: if (have_childs)
! 4603: result += (level * tabular * 2) + 2;
! 4604: else
! 4605: result += (level * tabular) + 1;
! 4606: #ifdef __AXL_OS_WIN32__
! 4607: if (have_childs)
! 4608: result += 2;
! 4609: else
! 4610: result ++;
! 4611: #endif
! 4612: }
! 4613: } else {
! 4614: if (is_empty) {
! 4615: /* "<" + strlen (node-name) + " />" */
! 4616: result = strlen (node->name) + 4 + __axl_node_get_flat_size_attributes (node);
! 4617:
! 4618: /* check pretty print */
! 4619: if (pretty_print) {
! 4620: /* one tabular plus one carry return
! 4621: * \r\n on windows and \n on unix */
! 4622: result += (level * tabular) + 1;
! 4623: #ifdef __AXL_OS_WIN32__
! 4624: result += 1;
! 4625: #endif
! 4626: }
! 4627:
! 4628: /* return sum */
! 4629: return result;
! 4630: }
! 4631: }
! 4632:
! 4633: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "node=<%s> count=%d", node->name, result);
! 4634:
! 4635: /* get first child */
! 4636: item = node->first;
! 4637: while (item != NULL) {
! 4638: /* according to the type, check a size */
! 4639: switch (axl_item_get_type (item)) {
! 4640: case ITEM_NODE:
! 4641: /* count how many bytes the node holds */
! 4642: result += axl_node_get_flat_size (item->data, pretty_print, level + 1, tabular);
! 4643: break;
! 4644: case ITEM_CONTENT:
! 4645: /* content */
! 4646: content = (axlNodeContent *) item->data;
! 4647: result += content->content_size;
! 4648: break;
! 4649: case ITEM_CDATA:
! 4650: /* content + '<![CDATA[' + ']]>' */
! 4651: content = (axlNodeContent *) item->data;
! 4652: result += content->content_size + 12;
! 4653: break;
! 4654: case ITEM_PI:
! 4655: /* get current size */
! 4656: result += axl_pi_get_size (item->data);
! 4657: break;
! 4658: case ITEM_COMMENT:
! 4659: /* content + '<!-- ' + ' -->' */
! 4660: content = (axlNodeContent *) item->data;
! 4661:
! 4662: /* check if the content has already defined white spaces */
! 4663: if (content->content[0] == ' ' && content->content[content->content_size - 1] == ' ')
! 4664: result += content->content_size + 7;
! 4665: else if (content->content[0] != ' ' && content->content[content->content_size - 1] == ' ')
! 4666: result += content->content_size + 8;
! 4667: else if (content->content[0] == ' ' && content->content[content->content_size - 1] != ' ')
! 4668: result += content->content_size + 8;
! 4669: else
! 4670: result += content->content_size + 9;
! 4671: if (pretty_print) {
! 4672: /* tabular indent + \n */
! 4673: result += ((level + 1) * tabular) + 1;
! 4674: #ifdef __AXL_OS_WIN32__
! 4675: /* \r\n */
! 4676: result += 1;
! 4677: #endif
! 4678: }
! 4679:
! 4680: break;
! 4681: case ITEM_REF:
! 4682: /* item ref + '&' + ';' */
! 4683: content = (axlNodeContent *) item->data;
! 4684: result += content->content_size + 2;
! 4685: break;
! 4686: case ITEM_FROM_FACTORY:
! 4687: case ITEM_CONTENT_FROM_FACTORY:
! 4688: /* never reached */
! 4689: break;
! 4690: }
! 4691: /* get next item */
! 4692: item = item->next;
! 4693:
! 4694: } /* end while */
! 4695:
! 4696: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "child processing finished for: parent=<%s>, count=%d", node->name, result);
! 4697:
! 4698: /* return the result */
! 4699: return result;
! 4700: }
! 4701:
! 4702: axl_bool __axl_node_dump_attributes_at_foreach (axlPointer key,
! 4703: axlPointer value,
! 4704: axlPointer user_data,
! 4705: axlPointer user_data2)
! 4706: {
! 4707: char * content = user_data;
! 4708: int * _desp = user_data2;
! 4709: axl_bool terminator = axl_false;
! 4710: int desp = (*_desp);
! 4711: int length;
! 4712:
! 4713: memcpy (content + desp, " ", 1);
! 4714: desp += 1;
! 4715:
! 4716: length = strlen ((char*) key);
! 4717: memcpy (content + desp, (char *) key, length);
! 4718: desp += length;
! 4719:
! 4720: /* check if the content contains a ' so, enclose the attribute
! 4721: * with " */
! 4722: if (strstr (value, "'") == NULL) {
! 4723: memcpy (content + desp, "='", 2);
! 4724: desp += 2;
! 4725: }else {
! 4726: terminator = axl_true;
! 4727: memcpy (content + desp, "=\"", 2);
! 4728: desp += 2;
! 4729: }
! 4730:
! 4731: length = strlen ((char*) value);
! 4732: memcpy (content + desp, (char*) value, length);
! 4733: desp += length;
! 4734:
! 4735: /* dump attribute termination */
! 4736: if (terminator) {
! 4737: memcpy (content + desp, "\"", 1);
! 4738: }else {
! 4739: memcpy (content + desp, "'", 1);
! 4740: }
! 4741: desp += 1;
! 4742:
! 4743: /* update desp */
! 4744: (*_desp) = desp;
! 4745:
! 4746: /* make the process to continue */
! 4747: return axl_false;
! 4748: }
! 4749:
! 4750: void __axl_node_dump_at_the_end (axlNodeAttr * attr, char * content, int * desp)
! 4751: {
! 4752: /* return if no attribute must be dumped */
! 4753: if (attr == NULL)
! 4754: return;
! 4755:
! 4756: /* call to dump next attributes first */
! 4757: __axl_node_dump_at_the_end (attr->next, content, desp);
! 4758:
! 4759: /* now dump our attribute */
! 4760: __axl_node_dump_attributes_at_foreach (attr->attribute, attr->value, content, desp);
! 4761:
! 4762: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "dumping attribute: %s=%s", attr->attribute, attr->value);
! 4763:
! 4764: return;
! 4765: }
! 4766:
! 4767: /**
! 4768: * @internal
! 4769: *
! 4770: * Internal support function which dumps current attribute
! 4771: * configuration into the given memory using the provided desp.
! 4772: */
! 4773: int axl_node_dump_attributes_at (axlNode * node, char * content, int desp)
! 4774: {
! 4775: axlNodeAttr * attr = NULL;
! 4776:
! 4777: /* if attribute list is not defined just return 0 */
! 4778: if (node->attributes == NULL)
! 4779: return desp;
! 4780:
! 4781: /* according to the attribute num */
! 4782: if (node->attr_num <= 10) {
! 4783: /* get the first reference */
! 4784: attr = (axlNodeAttr *) node->attributes;
! 4785: __axl_node_dump_at_the_end (attr, content, &desp);
! 4786:
! 4787: } else {
! 4788: /* foreach attribute dump */
! 4789: axl_hash_foreach2 ((axlHash *) node->attributes, __axl_node_dump_attributes_at_foreach, content, &desp);
! 4790: }
! 4791:
! 4792: /* return the length */
! 4793: return desp;
! 4794: }
! 4795:
! 4796: /**
! 4797: * @internal Writes the indentation according to the tabular size and
! 4798: * the indent level.
! 4799: *
! 4800: * @param content The reference to the content where the dump
! 4801: * operation will be performed.
! 4802: *
! 4803: * @param tabular The tabular size to be applied for each level.
! 4804: *
! 4805: * @param level The indent level to be applied.
! 4806: *
! 4807: * @return The number of bytes written.
! 4808: */
! 4809: int __axl_node_dump_at_write_indent (char * content, int tabular, int level)
! 4810: {
! 4811: int iterator = 0;
! 4812:
! 4813: while (iterator < (tabular * level)) {
! 4814: /* write tabular info */
! 4815: memcpy (content + iterator, " ", 1);
! 4816:
! 4817: /* update iterator */
! 4818: iterator++;
! 4819: } /* end while */
! 4820:
! 4821: return iterator;
! 4822: }
! 4823:
! 4824: /* dump content */
! 4825: int __axl_node_dump_items (axlItem * item, char * content, int level, axl_bool pretty_print, int desp, int tabular)
! 4826: {
! 4827:
! 4828: axlNodeContent * nodeContent;
! 4829: char * string_aux;
! 4830:
! 4831: /* get first child */
! 4832: while (item != NULL) {
! 4833: /* according to the type, check a size */
! 4834: switch (axl_item_get_type (item)) {
! 4835: case ITEM_NODE:
! 4836: /* write axl node content */
! 4837: desp = axl_node_dump_at (item->data, content, desp, pretty_print, level + 1, tabular);
! 4838: break;
! 4839: case ITEM_CONTENT:
! 4840: /* write content information */
! 4841: nodeContent = (axlNodeContent *)item->data;
! 4842: memcpy (content + desp, nodeContent->content, nodeContent->content_size);
! 4843: desp += nodeContent->content_size;
! 4844: break;
! 4845: case ITEM_CDATA:
! 4846: /* write content information */
! 4847: nodeContent = (axlNodeContent *)item->data;
! 4848:
! 4849: /* write cdata content */
! 4850: memcpy (content + desp, "<![CDATA[", 9);
! 4851: desp += 9;
! 4852:
! 4853: /* write content */
! 4854: memcpy (content + desp, nodeContent->content, nodeContent->content_size);
! 4855: desp += nodeContent->content_size;
! 4856:
! 4857: /* write cdata end */
! 4858: memcpy (content + desp, "]]>", 3);
! 4859: desp += 3;
! 4860: break;
! 4861: case ITEM_PI:
! 4862: /* write pi start */
! 4863: memcpy (content + desp, "<?", 2);
! 4864: desp += 2;
! 4865:
! 4866: /* write pi name */
! 4867: string_aux = axl_pi_get_name (item->data);
! 4868: memcpy (content + desp, string_aux, strlen (string_aux));
! 4869: desp += strlen (string_aux);
! 4870:
! 4871: /* write pi start */
! 4872: memcpy (content + desp, " ", 1);
! 4873: desp += 1;
! 4874:
! 4875: /* write pi content */
! 4876: string_aux = axl_pi_get_content (item->data);
! 4877: memcpy (content + desp, string_aux, strlen (string_aux));
! 4878: desp += strlen (string_aux);
! 4879:
! 4880: /* write pi start */
! 4881: memcpy (content + desp, "?>", 2);
! 4882: desp += 2;
! 4883: break;
! 4884: case ITEM_COMMENT:
! 4885:
! 4886: /* check for pretty print to write indent */
! 4887: if (pretty_print) {
! 4888: desp += __axl_node_dump_at_write_indent (content + desp, tabular, level + 1);
! 4889: }
! 4890:
! 4891: /* get a reference to the content */
! 4892: nodeContent = (axlNodeContent *)item->data;
! 4893:
! 4894: /* add an space if the content is found to not
! 4895: * have one */
! 4896: if (nodeContent->content [0] == ' ') {
! 4897: memcpy (content + desp, "<!--", 4);
! 4898: desp += 4;
! 4899: } else {
! 4900: memcpy (content + desp, "<!-- ", 5);
! 4901: desp += 5;
! 4902: }
! 4903:
! 4904:
! 4905:
! 4906: /* write content */
! 4907: memcpy (content + desp, nodeContent->content, nodeContent->content_size);
! 4908: desp += nodeContent->content_size;
! 4909:
! 4910: /* add an space if the content is found to not
! 4911: * have one */
! 4912: if (nodeContent->content [nodeContent->content_size - 1] == ' ') {
! 4913: memcpy (content + desp, "-->", 3);
! 4914: desp += 3;
! 4915: } else {
! 4916: memcpy (content + desp, " -->", 4);
! 4917: desp += 4;
! 4918: } /* end if */
! 4919:
! 4920: if (pretty_print) {
! 4921: #ifdef __AXL_OS_WIN32__
! 4922: memcpy (content + desp, "\r\n", 2);
! 4923: desp += 2;
! 4924: #else
! 4925: memcpy (content + desp, "\n", 1);
! 4926: desp += 1;
! 4927: #endif
! 4928: }
! 4929:
! 4930: break;
! 4931: case ITEM_REF:
! 4932: /* content + '&' + ';' */
! 4933: memcpy (content + desp, "&", 1);
! 4934: desp += 1;
! 4935:
! 4936: /* get a reference to the content */
! 4937: nodeContent = (axlNodeContent *)item->data;
! 4938:
! 4939: /* write content */
! 4940: memcpy (content + desp, nodeContent->content, nodeContent->content_size);
! 4941: desp += nodeContent->content_size;
! 4942:
! 4943: memcpy (content + desp, ";", 1);
! 4944: desp += 1;
! 4945: break;
! 4946: case ITEM_FROM_FACTORY:
! 4947: case ITEM_CONTENT_FROM_FACTORY:
! 4948: /* never reached */
! 4949: break;
! 4950: }
! 4951:
! 4952: /* get next item */
! 4953: item = item->next;
! 4954:
! 4955: } /* end while */
! 4956:
! 4957: /* return desp calculated */
! 4958: return desp;
! 4959:
! 4960: } /* end __axl_node_dump_items */
! 4961:
! 4962: /**
! 4963: * @internal
! 4964: *
! 4965: * Writes the node information represented by the node provided at the
! 4966: * given position into the buffer provided.
! 4967: *
! 4968: * @param node The node to dump and its childs.
! 4969: *
! 4970: * @param content The memory buffer where the content will be dumped.
! 4971: *
! 4972: * @param desp A memory desp where to dump the node content inside the
! 4973: * memory provided.
! 4974: *
! 4975: * @return The new desp value to be used on the next dump.
! 4976: */
! 4977: int axl_node_dump_at (axlNode * node,
! 4978: char * content,
! 4979: int desp,
! 4980: axl_bool pretty_print,
! 4981: int level,
! 4982: int tabular)
! 4983: {
! 4984: axlItem * item;
! 4985: axl_bool have_childs;
! 4986:
! 4987: axl_return_val_if_fail (node, -1);
! 4988:
! 4989: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "dumping node=<%s> at %d",
! 4990: axl_node_get_name (node), desp);
! 4991:
! 4992: /* get current have childs status */
! 4993: have_childs = axl_node_have_childs_aux (node);
! 4994:
! 4995: /* check for pretty print and tabular */
! 4996: if (pretty_print) {
! 4997: desp += __axl_node_dump_at_write_indent (content + desp, tabular, level);
! 4998: } /* end if */
! 4999:
! 5000: /* check if the node is empty */
! 5001: if (axl_node_is_empty (node)) {
! 5002: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "the node <%s> is empty",
! 5003: axl_node_get_name (node));
! 5004:
! 5005: if (! have_childs) {
! 5006: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "dumping an empty node without childs=<%s>",
! 5007: axl_node_get_name (node));
! 5008:
! 5009: /* "<" + strlen (node-name) + " />" */
! 5010: memcpy (content + desp, "<", 1);
! 5011: desp += 1;
! 5012:
! 5013: memcpy (content + desp, node->name, strlen (node->name));
! 5014: desp += strlen (node->name);
! 5015:
! 5016: /* dump attribute values */
! 5017: desp = axl_node_dump_attributes_at (node, content, desp);
! 5018:
! 5019: memcpy (content + desp, " />", 3);
! 5020: desp += 3;
! 5021:
! 5022: /* write traling node information */
! 5023: if (pretty_print) {
! 5024: #ifdef __AXL_OS_WIN32__
! 5025: memcpy (content + desp, "\r\n", 2);
! 5026: desp += 2;
! 5027: #else
! 5028: memcpy (content + desp, "\n", 1);
! 5029: desp += 1;
! 5030: #endif
! 5031: }
! 5032:
! 5033: return desp;
! 5034: }
! 5035: }
! 5036:
! 5037: /* the node is empty because it doesn't have content but it
! 5038: * has childs
! 5039: * "<" + strlen (node-name) + ">" + strlen (node-content) +
! 5040: * "</" + strlen (node-name) + ">" */
! 5041: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "getting content for: <%s>", axl_node_get_name (node));
! 5042:
! 5043: /* dump node start tag */
! 5044: memcpy (content + desp, "<", 1);
! 5045: desp += 1;
! 5046:
! 5047: memcpy (content + desp, node->name, strlen (node->name));
! 5048: desp += strlen (node->name);
! 5049:
! 5050: /* dump attribute values */
! 5051: desp = axl_node_dump_attributes_at (node, content, desp);
! 5052:
! 5053: memcpy (content + desp, ">", 1);
! 5054: desp += 1;
! 5055:
! 5056: /* if the node have childs */
! 5057: if (have_childs) {
! 5058:
! 5059: /* write traling node information */
! 5060: if (pretty_print) {
! 5061: #ifdef __AXL_OS_WIN32__
! 5062: memcpy (content + desp, "\r\n", 2);
! 5063: desp += 2;
! 5064: #else
! 5065: memcpy (content + desp, "\n", 1);
! 5066: desp += 1;
! 5067: #endif
! 5068: } /* end if */
! 5069:
! 5070: /* dump content */
! 5071: item = node->first;
! 5072: desp = __axl_node_dump_items (item, content, level, pretty_print, desp, tabular);
! 5073:
! 5074: /* check for pretty print and tabular */
! 5075: if (pretty_print) {
! 5076: desp += __axl_node_dump_at_write_indent (content + desp, tabular, level);
! 5077: } /* end if */
! 5078:
! 5079: }else {
! 5080: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "the node is not empty and have no childs");
! 5081:
! 5082: /* dump content */
! 5083: item = node->first;
! 5084: desp = __axl_node_dump_items (item, content, level, pretty_print, desp, tabular);
! 5085: } /* end if */
! 5086:
! 5087: /* dump close tag */
! 5088: memcpy (content + desp, "</", 2);
! 5089: desp += 2;
! 5090:
! 5091: memcpy (content + desp, node->name, strlen (node->name));
! 5092: desp += strlen (node->name);
! 5093:
! 5094: memcpy (content + desp, ">", 1);
! 5095: desp += 1;
! 5096:
! 5097: /* write traling node information */
! 5098: if (pretty_print) {
! 5099: #ifdef __AXL_OS_WIN32__
! 5100: memcpy (content + desp, "\r\n", 2);
! 5101: desp += 2;
! 5102: #else
! 5103: memcpy (content + desp, "\n", 1);
! 5104: desp += 1;
! 5105: #endif
! 5106: }
! 5107:
! 5108: /* return the result */
! 5109: return desp;
! 5110: }
! 5111:
! 5112: /**
! 5113: * @internal Function used by axl_node_has_invalid_chars which also
! 5114: * provides features for CDATA sections.
! 5115: */
! 5116: axl_bool axl_node_has_invalid_chars_internal (const char * content,
! 5117: int content_size,
! 5118: int * added_size,
! 5119: axl_bool cdata)
! 5120: {
! 5121: int iterator = 0;
! 5122: axl_bool result = axl_false;
! 5123: axl_return_val_if_fail (content, axl_false);
! 5124:
! 5125: /* reset additional size value */
! 5126: if (added_size != NULL)
! 5127: *added_size = 0;
! 5128:
! 5129: /* calculate the content size */
! 5130: if (content_size == -1)
! 5131: content_size = strlen (content);
! 5132:
! 5133: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "checking valid sequence: content size=%d", content_size);
! 5134:
! 5135: /* iterate over all content defined */
! 5136: while (iterator < content_size) {
! 5137: /* check for ' */
! 5138: if (content [iterator] == '\'') {
! 5139: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found invalid sequence='\\'");
! 5140: result = axl_true;
! 5141: if (added_size != NULL)
! 5142: (*added_size) += 5;
! 5143: }
! 5144:
! 5145: /* check for " */
! 5146: if (content [iterator] == '"') {
! 5147: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found invalid sequence='\"'");
! 5148: result = axl_true;
! 5149: if (added_size != NULL)
! 5150: (*added_size) += 5;
! 5151: }
! 5152:
! 5153: /* check for & */
! 5154: if (content [iterator] == '&') {
! 5155: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found invalid sequence='&'");
! 5156: result = axl_true;
! 5157: if (added_size != NULL)
! 5158: (*added_size) += 4;
! 5159: }
! 5160:
! 5161: /* check for > */
! 5162: if (content [iterator] == '>') {
! 5163: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found invalid sequence='>'");
! 5164: result = axl_true;
! 5165: if (added_size != NULL)
! 5166: (*added_size) += 3;
! 5167: }
! 5168:
! 5169: /* check for < */
! 5170: if (content [iterator] == '<') {
! 5171: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found invalid sequence='<'");
! 5172: result = axl_true;
! 5173: if (added_size != NULL)
! 5174: (*added_size) += 3;
! 5175: }
! 5176:
! 5177: /* check for ]]> */
! 5178: if (content [iterator] == ']' && content [iterator + 1] == ']' && content [iterator + 2] == '>') {
! 5179: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "found invalid sequence=']]>'");
! 5180: result = axl_true;
! 5181: if (cdata) {
! 5182: /* inside CDATA section that is, we
! 5183: * have to escape this value and
! 5184: * reopen a new CDATA section to match
! 5185: * with the last terminator */
! 5186: if (added_size != NULL)
! 5187: (*added_size) += 15;
! 5188: } else {
! 5189: if (added_size != NULL)
! 5190: (*added_size) += 3;
! 5191: }
! 5192: iterator += 3;
! 5193: continue;
! 5194: } /* end if */
! 5195:
! 5196: /* update the iterator */
! 5197: iterator++;
! 5198: }
! 5199:
! 5200: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "valid sequence checking result=%d: content size=%d, additional size=%d resul=%s",
! 5201: result, content_size, (added_size != NULL) ? *added_size : 0, result ? "HAS INVALID SEQUENCES" : "HAS NO INVALID SEQUENCES");
! 5202:
! 5203: /* return results */
! 5204: return result;
! 5205: }
! 5206:
! 5207: /**
! 5208: * @brief Allows to check if the provided string have invalid chars
! 5209: * that must be escaped by using the entity reference rather the value
! 5210: * itself.
! 5211: *
! 5212: * This function is useful in the sense it allows to know if a
! 5213: * particular content will contain elements not allowed by the XML 1.0
! 5214: * definition to be placed directly (like &, <, ;, ' and ").
! 5215: *
! 5216: *
! 5217: * This function use usually complemented with \ref axl_node_content_copy_and_escape.
! 5218: *
! 5219: * @param content The content to check.
! 5220: *
! 5221: * @param content_size The size of the content to be checked. If -1 is
! 5222: * provided, the function will calculate the content length.
! 5223: *
! 5224: * @param added_size An integer reference where the additional size
! 5225: * variable will be added. This additional size will be the space
! 5226: * required to replace non-valid characters with entity
! 5227: * references. This parameter is optional, so passing a NULL value is
! 5228: * allowed.
! 5229: *
! 5230: * @return \ref axl_true if the string contains non valid chars
! 5231: * that must be escaped using entity references.
! 5232: */
! 5233: axl_bool axl_node_has_invalid_chars (const char * content,
! 5234: int content_size,
! 5235: int * added_size)
! 5236: {
! 5237: /* call to internal implementation supposing this is for a
! 5238: * node without CDATA section */
! 5239: return axl_node_has_invalid_chars_internal (content, content_size, added_size, axl_false);
! 5240: }
! 5241:
! 5242: /**
! 5243: * @brief Allows to check if the provided string have escape sequences
! 5244: * that must be defined by using the entity reference rather the value
! 5245: * itself, taking into consideration the content will be used for a
! 5246: * <![CDATA[..]]> section.
! 5247: *
! 5248: * This function is useful in the sense it allows to know if a
! 5249: * particular content will contain elements not allowed by the XML 1.0
! 5250: * definition to be placed directly (like &, <, ;, ' and ").
! 5251: *
! 5252: * This function use usually complemented with \ref axl_node_content_copy_and_escape_cdata.
! 5253: *
! 5254: * @param content The content to check.
! 5255: *
! 5256: * @param content_size The size of the content to be checked. If -1 is
! 5257: * provided, the function will calculate the content length.
! 5258: *
! 5259: * @param added_size An integer reference where the additional size
! 5260: * variable will be added. This additional size will be the space
! 5261: * required to replace non-valid characters with entity
! 5262: * references. This parameter is optional, so passing a NULL value is
! 5263: * allowed.
! 5264: *
! 5265: * @return axl_true if the string contains non valid sequences that
! 5266: * must be escaped using entity references.
! 5267: */
! 5268: axl_bool axl_node_has_invalid_chars_cdata (const char * content,
! 5269: int content_size,
! 5270: int * added_size)
! 5271: {
! 5272: /* call to internal implementation supposing this is for a
! 5273: * node with CDATA section */
! 5274: return axl_node_has_invalid_chars_internal (content, content_size, added_size, axl_true);
! 5275: }
! 5276:
! 5277: /**
! 5278: * @brief Allows to perform a copy from the content provided, doing an
! 5279: * xml character escaping for non allowed values (&, <, >, ' and ").
! 5280: *
! 5281: * This function must be used with \ref axl_node_has_invalid_chars to
! 5282: * check if the content has escapable chars an to get the additional
! 5283: * content that must be allocated by this function.
! 5284: *
! 5285: * Here is an example:
! 5286: * \code
! 5287: * char * content = "Some content with invalid chars & < >";
! 5288: * int additional_size;
! 5289: * char * new_content
! 5290: *
! 5291: * if (axl_node_has_invalid_chars (content, strlen (content), &additional_size)) {
! 5292: * // found that the string has invalid chars, escape them
! 5293: * new_content = axl_node_content_copy_and_escape (content, strlen (content), additional_size);
! 5294: * }
! 5295: *
! 5296: * \endcode
! 5297: *
! 5298: * @param content The content to be escaped. If this parameter is
! 5299: * NULL, the function returns NULL.
! 5300: *
! 5301: * @param content_size The content size for the first parameter.
! 5302: *
! 5303: * @param additional_size The additional size calculated from \ref axl_node_has_invalid_chars.
! 5304: *
! 5305: * @return A newly allocated string with all characters escaped. Use
! 5306: * \ref axl_free to dealloc the result.
! 5307: */
! 5308: char * axl_node_content_copy_and_escape (const char * content,
! 5309: int content_size,
! 5310: int additional_size)
! 5311: {
! 5312: axl_return_val_if_fail (content, NULL);
! 5313:
! 5314: /* call to the internal implementation */
! 5315: return __axl_node_content_copy_and_escape (content, content_size, additional_size, axl_false);
! 5316: }
! 5317:
! 5318: /**
! 5319: * @brief Allows to perform a copy for the content provided, doing an
! 5320: * xml character escaping for non allowed values (&, <, >, ' and ")
! 5321: * taking into consideration the content will be placed inside a
! 5322: * <![CDATA[..]]> declaration.
! 5323: *
! 5324: * This function must be used with \ref axl_node_has_invalid_chars_cdata to
! 5325: * check if the content has escapable chars an to get the additional
! 5326: * content that must be allocated by this function.
! 5327: *
! 5328: * Here is an example:
! 5329: * \code
! 5330: * char * content = "Some content with invalid chars & < >";
! 5331: * int additional_size;
! 5332: * char * new_content
! 5333: *
! 5334: * if (axl_node_has_invalid_chars_cdata (content, strlen (content), &additional_size)) {
! 5335: * // found that the string has invalid chars, escape them
! 5336: * new_content = axl_node_content_copy_and_escape_cdata (content, strlen (content), additional_size);
! 5337: * }
! 5338: * \endcode
! 5339: *
! 5340: * @param content The content to be escaped. If this parameter is
! 5341: * null, the function returns NULL.
! 5342: *
! 5343: * @param content_size The content size for the first parameter.
! 5344: *
! 5345: * @param additional_size The additional size calculated from \ref axl_node_has_invalid_chars_cdata.
! 5346: *
! 5347: * @return A newly allocated string with all characters escaped. Use
! 5348: * \ref axl_free to dealloc the result.
! 5349: */
! 5350: char * axl_node_content_copy_and_escape_cdata (const char * content,
! 5351: int content_size,
! 5352: int additional_size)
! 5353: {
! 5354: axl_return_val_if_fail (content, NULL);
! 5355:
! 5356: /* call to the internal implementation */
! 5357: return __axl_node_content_copy_and_escape (content, content_size, additional_size, axl_true);
! 5358: }
! 5359:
! 5360: void __axl_node_free_internal (axlNode * node, axl_bool also_childs)
! 5361: {
! 5362: axlItem * item;
! 5363: axlItem * itemAux;
! 5364:
! 5365: axl_return_if_fail (node);
! 5366:
! 5367: /* free current node */
! 5368: if (node->name != NULL && ! (node->conf & NODE_NAME_FROM_FACTORY))
! 5369: axl_free (node->name);
! 5370:
! 5371: /* release memory hold by attributes */
! 5372: if (node->attributes != NULL) {
! 5373: if (node->attr_num <= 10)
! 5374: __axl_node_free_attr_list ((axlNodeAttr *) node->attributes);
! 5375: else
! 5376: axl_hash_free ((axlHash *) node->attributes);
! 5377: }
! 5378:
! 5379: /* release memory hold by childs */
! 5380: if (node->first != NULL && also_childs) {
! 5381: /* get the first item */
! 5382: item = node->first;
! 5383:
! 5384: /* foreach item stored */
! 5385: while (item != NULL) {
! 5386:
! 5387: /* get the next item */
! 5388: itemAux = item->next;
! 5389:
! 5390: /* free the item */
! 5391: axl_item_free (item, axl_true);
! 5392:
! 5393: /* update reference */
! 5394: item = itemAux;
! 5395:
! 5396: } /* end while */
! 5397:
! 5398: } /* end if */
! 5399:
! 5400: /* free the item itself */
! 5401: if (node->holder != NULL) {
! 5402: if ((node->holder->type & ITEM_FROM_FACTORY) == 0) {
! 5403: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG,
! 5404: "item holder found to be not from a factory, dealloc reference=0x%x, node=0x%x, type=%d",
! 5405: node->holder, node, node->holder->type);
! 5406: axl_free (node->holder);
! 5407: node->holder = NULL;
! 5408: }
! 5409: }
! 5410:
! 5411: /* do not free the node itself */
! 5412: return;
! 5413: }
! 5414:
! 5415: /**
! 5416: * @brief Destroy the given node provided by the reference.
! 5417: *
! 5418: * The function will check for nodes that are NULL references,
! 5419: * returning immediately.
! 5420: *
! 5421: * @param node The node to destroy.
! 5422: */
! 5423: void axl_node_free (axlNode * node)
! 5424: {
! 5425: axlHash * hash;
! 5426: axl_return_if_fail (node);
! 5427:
! 5428: /* get a reference to the hash */
! 5429: hash = node->annotate_data;
! 5430:
! 5431: /* free internal content */
! 5432: __axl_node_free_internal (node, axl_true);
! 5433:
! 5434: /* free attributes */
! 5435: if (! (node->conf & NODE_FROM_FACTORY))
! 5436: axl_free (node);
! 5437:
! 5438: /* annotate data deallocation must be done here because it is
! 5439: * used by the application user and the library to store
! 5440: * reference that could be pointing to internal structures
! 5441: * deallocated by the __axl_node_free_internal */
! 5442: axl_hash_free (hash);
! 5443:
! 5444: /* the node to release */
! 5445: return;
! 5446: }
! 5447:
! 5448: /**
! 5449: * @brief Allows to remove the provided node, optionally without
! 5450: * removing childs inside it.
! 5451: *
! 5452: * @param node The node to deallocate.
! 5453: *
! 5454: * @param also_childs Signal the function to also dealloc childs or
! 5455: * not.
! 5456: */
! 5457: void axl_node_free_full (axlNode * node, axl_bool also_childs)
! 5458: {
! 5459: axlHash * hash;
! 5460: axl_return_if_fail (node);
! 5461:
! 5462: /* get a reference to the hash */
! 5463: hash = node->annotate_data;
! 5464:
! 5465: /* free node */
! 5466: __axl_node_free_internal (node, axl_false);
! 5467:
! 5468: /* free the node itself */
! 5469: if (!(node->conf & NODE_FROM_FACTORY))
! 5470: axl_free (node);
! 5471:
! 5472: /* annotate data deallocation must be done here because it is
! 5473: * used by the application user and the library to store
! 5474: * reference that could be pointing to internal structures
! 5475: * deallocated by the __axl_node_free_internal */
! 5476: axl_hash_free (hash);
! 5477:
! 5478: return;
! 5479: }
! 5480:
! 5481: /**
! 5482: * @}
! 5483: */
! 5484:
! 5485: /**
! 5486: * \defgroup axl_node_attribute_cursor Axl Node Attribute iteration: An interface provided to iterate attribute nodes without knowing them.
! 5487: */
! 5488:
! 5489: /**
! 5490: * \addtogroup axl_node_attribute_cursor
! 5491: * @{
! 5492: */
! 5493:
! 5494:
! 5495: /**
! 5496: * @brief Allows to get a cursor to iterate attributes found in the
! 5497: * provided node in a linear and efficient way.
! 5498: *
! 5499: * The \ref axlAttrCursor could be used to iterate attributes
! 5500: * inside a particular node in an efficient way because it stores
! 5501: * current state (position), hiding all module details, providing
! 5502: * access to attributes without knowing them. Then using the following
! 5503: * functions you can modify the state (current position to get):
! 5504: *
! 5505: * - \ref axl_node_attr_cursor_first
! 5506: * - \ref axl_node_attr_cursor_next
! 5507: *
! 5508: * Finally, the following functions are provided to get the key and
! 5509: * the value data associated to the current selected attribute,
! 5510: * pointed by the current status of the cursor:
! 5511: *
! 5512: * - \ref axl_node_attr_cursor_get_key (returns the key of the current attribute selected)
! 5513: * - \ref axl_node_attr_cursor_get_value (returns the value of the current attribute selected)
! 5514: *
! 5515: * Here is an example:
! 5516: * \code
! 5517: * axlPointer key;
! 5518: * axlPointer value;
! 5519: * axlAttrCursor * cursor;
! 5520: *
! 5521: * // create the cursor
! 5522: * cursor = axl_node_attr_cursor_new (node);
! 5523: *
! 5524: * // while there are more elements
! 5525: * while (axl_node_attr_cursor_has_item (cursor)) {
! 5526: *
! 5527: * // get the value and key
! 5528: * key = axl_node_attr_cursor_get_key (cursor);
! 5529: * value = axl_node_attr_cursor_get_value (cursor);
! 5530: *
! 5531: * // get the next
! 5532: * axl_node_attr_cursor_next (cursor);
! 5533: *
! 5534: * }
! 5535: *
! 5536: * // free the cursor
! 5537: * axl_node_attr_cursor_free (cursor);
! 5538: * \endcode
! 5539: *
! 5540: * Once created the \ref axlAttrCursor you must release it and create
! 5541: * a new one if you modify your \ref axlNode attribute configuration
! 5542: * adding more items.
! 5543: *
! 5544: * @param node The node that is requested to create the \ref
! 5545: * axlAttrCursor reference to iterate all attributes inside.
! 5546: *
! 5547: * @return A newly created \ref axlAttrCursor used to iterate
! 5548: * attributes inside the node provided. Once finished you must call to
! 5549: * \ref axl_node_attr_cursor_free.
! 5550: */
! 5551: axlAttrCursor * axl_node_attr_cursor_new (axlNode * node)
! 5552: {
! 5553: axlAttrCursor * cursor;
! 5554:
! 5555: axl_return_val_if_fail (node, NULL);
! 5556:
! 5557: /* create and configure basics */
! 5558: cursor = axl_new (axlAttrCursor, 1);
! 5559: cursor->node = node;
! 5560: cursor->count = node->attr_num;
! 5561:
! 5562: /* according to the number of attributes configure the hash or
! 5563: * the linked attribte list */
! 5564: if (cursor->count <= 10) {
! 5565: /* just point to the first attribute (managed as AxlNodeAttr) */
! 5566: cursor->data = node->attributes;
! 5567: } else {
! 5568: /* create an axl hash cursor */
! 5569: cursor->data = axl_hash_cursor_new ((axlHash *) node->attributes);
! 5570: } /* end if */
! 5571:
! 5572: /* return created cursor */
! 5573: return cursor;
! 5574: }
! 5575:
! 5576: /**
! 5577: * @brief Allows to configure the provided cursor to point to the
! 5578: * first attribute found inside the node.
! 5579: *
! 5580: * @param cursor The cursor that is going to be configured.
! 5581: */
! 5582: void axl_node_attr_cursor_first (axlAttrCursor * cursor)
! 5583: {
! 5584: axl_return_if_fail (cursor);
! 5585:
! 5586: /* check attribute configuration */
! 5587: if (cursor->count != cursor->node->attr_num) {
! 5588: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "Your cursor was created with another attribute configuration, renew it.");
! 5589: return;
! 5590: } /* end if */
! 5591:
! 5592: if (cursor->count <= 10) {
! 5593: /* just point to the first attribute (managed as AxlAttribute) */
! 5594: cursor->data = cursor->node->attributes;
! 5595: } else {
! 5596: /* make hash cursor to point to the first */
! 5597: axl_hash_cursor_first (cursor->data);
! 5598: } /* end if */
! 5599:
! 5600: return;
! 5601: }
! 5602:
! 5603: /**
! 5604: * @brief Configures the provided attribute cursor to point to the
! 5605: * next attribute.
! 5606: *
! 5607: * @param cursor The attribute cursor to be configured.
! 5608: */
! 5609: void axl_node_attr_cursor_next (axlAttrCursor * cursor)
! 5610: {
! 5611: axl_return_if_fail (cursor);
! 5612:
! 5613: /* check attribute configuration */
! 5614: if (cursor->count != cursor->node->attr_num) {
! 5615: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "Your cursor was created with another attribute configuration, renew it.");
! 5616: return;
! 5617: } /* end if */
! 5618:
! 5619: if (cursor->count <= 10) {
! 5620: /* check null values */
! 5621: if (cursor->data == NULL)
! 5622: return;
! 5623:
! 5624: /* just point to the first attribute (managed as AxlAttribute) */
! 5625: cursor->data = ((axlNodeAttr *) cursor->data)->next;
! 5626:
! 5627: return;
! 5628: } /* end if */
! 5629:
! 5630: /* make hash cursor to point to the first */
! 5631: axl_hash_cursor_next (cursor->data);
! 5632:
! 5633:
! 5634: return;
! 5635: }
! 5636:
! 5637: /**
! 5638: * @brief Allows to check if the is a next attribute, following
! 5639: * current attribute selected.
! 5640: *
! 5641: * @param cursor The cursor to be configured.
! 5642: *
! 5643: * @return \ref axl_true if it has next element, otherwise \ref axl_false.
! 5644: */
! 5645: axl_bool axl_node_attr_cursor_has_next (axlAttrCursor * cursor)
! 5646: {
! 5647: axl_return_val_if_fail (cursor, axl_false);
! 5648:
! 5649: if (cursor->count != cursor->node->attr_num) {
! 5650: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "Your cursor was created with another attribute configuration, renew it.");
! 5651: return axl_false;
! 5652: } /* end if */
! 5653:
! 5654: if (cursor->count <= 10) {
! 5655: /* just point to the first attribute (managed as AxlAttribute) */
! 5656: return (((axlNodeAttr *) cursor->data)->next) != NULL;
! 5657: } /* end if */
! 5658:
! 5659: /* make hash cursor to point to the first */
! 5660: return axl_hash_cursor_has_next (cursor->data);
! 5661: }
! 5662:
! 5663: /**
! 5664: * @brief Allows to check if the current position selected has an
! 5665: * attribute reference.
! 5666: *
! 5667: * @param cursor The cursor that is being queried.
! 5668: *
! 5669: * @return \ref axl_true if it has item element, otherwise \ref axl_false.
! 5670: */
! 5671: axl_bool axl_node_attr_cursor_has_item (axlAttrCursor * cursor)
! 5672: {
! 5673: axl_return_val_if_fail (cursor, axl_false);
! 5674:
! 5675: /* check attribute configuration */
! 5676: if (cursor->count != cursor->node->attr_num) {
! 5677: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "Your cursor was created with another attribute configuration, renew it.");
! 5678: return axl_false;
! 5679: } /* end if */
! 5680:
! 5681: if (cursor->count <= 10) {
! 5682: /* just point to the first attribute (managed as AxlAttribute) */
! 5683: return cursor->data != NULL;
! 5684: } /* end if */
! 5685:
! 5686: /* make hash cursor to point to the first */
! 5687: return axl_hash_cursor_has_item (cursor->data);
! 5688: }
! 5689:
! 5690: /**
! 5691: * @brief Allows to get the attribute key associated to the current
! 5692: * attribute selected by the cursor.
! 5693: *
! 5694: * @param cursor The cursor that is being queried.
! 5695: *
! 5696: * @return A reference to the attribute key or NULL if it fails.
! 5697: */
! 5698: const char * axl_node_attr_cursor_get_key (axlAttrCursor * cursor)
! 5699: {
! 5700: axl_return_val_if_fail (cursor, NULL);
! 5701:
! 5702: /* check attribute configuration */
! 5703: if (cursor->count != cursor->node->attr_num) {
! 5704: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "Your cursor was created with another attribute configuration, renew it.");
! 5705: return NULL;
! 5706: } /* end if */
! 5707:
! 5708: if (cursor->count <= 10) {
! 5709: /* just point to the first attribute (managed as AxlAttribute) */
! 5710: return ((axlNodeAttr *) cursor->data)->attribute;
! 5711: } /* end if */
! 5712:
! 5713: /* make hash cursor to point to the first */
! 5714: return axl_hash_cursor_get_key (cursor->data);
! 5715: }
! 5716:
! 5717: /**
! 5718: * @brief Allows to get the attribute value associated to the
! 5719: * attribute selected by the cursor.
! 5720: *
! 5721: * @param cursor The cursor that is being queried.
! 5722: *
! 5723: * @return A reference to the attribute value or NULL if it fails.
! 5724: */
! 5725: const char * axl_node_attr_cursor_get_value (axlAttrCursor * cursor)
! 5726: {
! 5727: axl_return_val_if_fail (cursor, NULL);
! 5728:
! 5729: /* check attribute configuration */
! 5730: if (cursor->count != cursor->node->attr_num) {
! 5731: __axl_log (LOG_DOMAIN, AXL_LEVEL_DEBUG, "Your cursor was created with another attribute configuration, renew it.");
! 5732: return NULL;
! 5733: } /* end if */
! 5734:
! 5735: if (cursor->count <= 10) {
! 5736: /* just point to the first attribute (managed as AxlAttribute) */
! 5737: return ((axlNodeAttr *) cursor->data)->value;
! 5738: } /* end if */
! 5739:
! 5740: /* make hash cursor to point to the first */
! 5741: return axl_hash_cursor_get_value (cursor->data);
! 5742: }
! 5743:
! 5744: /**
! 5745: * @brief Allows to release \ref axlAttrCursor.
! 5746: *
! 5747: * @param cursor The cursor to release.
! 5748: */
! 5749: void axl_node_attr_cursor_free (axlAttrCursor * cursor)
! 5750: {
! 5751: axl_return_if_fail (cursor);
! 5752:
! 5753: /* free hash cursor */
! 5754: if (cursor->count > 10)
! 5755: axl_hash_cursor_free (cursor->data);
! 5756:
! 5757: /* free the cursor */
! 5758: axl_free (cursor);
! 5759:
! 5760: return;
! 5761: }
! 5762:
! 5763:
! 5764: /**
! 5765: * @internal Function that helps axl_node_attr_foreach to iterate all
! 5766: * attributes.
! 5767: */
! 5768: axl_bool __axl_node_attr_foreach_aux (axlPointer key, axlPointer data, axlPointer user_data, axlPointer user_data2, axlPointer user_data3)
! 5769: {
! 5770: return ((axlNodeAttrForeachFunc) user_data) (key, data, user_data2, user_data3);
! 5771: }
! 5772:
! 5773: /**
! 5774: * @brief Allows to provide a function which is called for each
! 5775: * attribute installed on the provided node.
! 5776: *
! 5777: * This function will allow you to operate on every attribute
! 5778: * installed, doing an foreach operation. This is an alternative API
! 5779: * to the \ref axlAttrCursor, which could be used to save allocations.
! 5780: *
! 5781: * @param node The node for which the provided function will be called
! 5782: * for each attribute found.
! 5783: *
! 5784: * @param func The foreach function to be called.
! 5785: *
! 5786: * @param data User defined data to be passed to the foreach function.
! 5787: *
! 5788: * @param data2 Second user defined data to be passed to the foreach
! 5789: * function.
! 5790: */
! 5791: void axl_node_attr_foreach (axlNode * node,
! 5792: axlNodeAttrForeachFunc func,
! 5793: axlPointer data,
! 5794: axlPointer data2)
! 5795: {
! 5796: axlNodeAttr * attr;
! 5797: axl_return_if_fail (node);
! 5798: axl_return_if_fail (func);
! 5799:
! 5800: /* if no attributes no foreach operation */
! 5801: if (node->attributes == NULL)
! 5802: return;
! 5803:
! 5804: /* store the attribute using the general case */
! 5805: if (node->attr_num < 11) {
! 5806: /* handled as a simple list */
! 5807: attr = (axlNodeAttr *) node->attributes;
! 5808: while (attr != NULL) {
! 5809: /* call to notify each attribute */
! 5810: if (func (attr->attribute, attr->value, data, data2))
! 5811: return;
! 5812:
! 5813: /* get the next */
! 5814: attr = attr->next;
! 5815: } /* end while */
! 5816: } else {
! 5817: /* handled as a hash */
! 5818: axl_hash_foreach3 ((axlHash *) node->attributes, __axl_node_attr_foreach_aux, func, data, data2);
! 5819: } /* end if */
! 5820:
! 5821: return;
! 5822: }
! 5823:
! 5824: /**
! 5825: * @}
! 5826: */
! 5827:
! 5828: /**
! 5829: * \defgroup axl_item_module Axl Item: A basic item abstraction that represents a child node that could be another node, content, xml comment, etc.
! 5830: */
! 5831:
! 5832: /**
! 5833: * \addtogroup axl_item_module
! 5834: * @{
! 5835: */
! 5836:
! 5837: /**
! 5838: * @brief Allows to create an \ref axlItem, with the provided type and
! 5839: * holding the provided data.
! 5840: *
! 5841: * The function won't configure the parent node holding the
! 5842: * item. There is an alternative API that allows to create an \ref
! 5843: * axlItem without performing a copy: \ref axl_item_new_ref.
! 5844: *
! 5845: * @param type The type that will represent the \ref axlItem created.
! 5846: *
! 5847: * @param data Data associated to the axlItem. In the case the \ref
! 5848: * axlItem being created will represent content (\ref ITEM_CONTENT),
! 5849: * an entity ref (\ref ITEM_REF), a comment (\ref ITEM_COMMENT) or
! 5850: * cdata (\ref ITEM_CDATA), the function will create a local copy. In
! 5851: * the case of a \ref ITEM_NODE, the function will copy the entire
! 5852: * node, and all its childs.
! 5853: *
! 5854: * @return A newly allocated \ref axlItem with no parent and holding
! 5855: * the data provided.
! 5856: */
! 5857: axlItem * axl_item_new (AxlItemType type,
! 5858: axlPointer data)
! 5859: {
! 5860: axlItem * item = NULL;
! 5861: axlNode * node;
! 5862: axlNodeContent * content;
! 5863:
! 5864: /* allocate an item type */
! 5865: item = axl_new (axlItem, 1);
! 5866: item->type = type;
! 5867:
! 5868: switch (axl_item_get_type (item)) {
! 5869: case ITEM_NODE:
! 5870: /* item the node */
! 5871: node = axl_node_copy (item->data, axl_true, axl_true);
! 5872: node->holder = item;
! 5873: item->data = node;
! 5874: break;
! 5875: case ITEM_CONTENT:
! 5876: case ITEM_CDATA:
! 5877: case ITEM_COMMENT:
! 5878: /* item content */
! 5879: content = axl_new (axlNodeContent, 1);
! 5880: content->content = axl_strdup ((const char *) data);
! 5881: content->content_size = strlen ((const char *) data);
! 5882:
! 5883: /* item content */
! 5884: item->data = content;
! 5885: break;
! 5886: case ITEM_PI:
! 5887: /* item pi */
! 5888: item->data = axl_pi_copy (data);
! 5889: break;
! 5890: case ITEM_REF:
! 5891: /* not implemented yet */
! 5892: break;
! 5893: case ITEM_FROM_FACTORY:
! 5894: case ITEM_CONTENT_FROM_FACTORY:
! 5895: /* never reached */
! 5896: break;
! 5897: } /* end switch */
! 5898:
! 5899: /* return item created */
! 5900: return item;
! 5901: }
! 5902:
! 5903: /**
! 5904: * @brief Allows to create an \ref axlItem, with the provided type and
! 5905: * holding the provided data.
! 5906: *
! 5907: * The function won't configure the parent node holding the item.
! 5908: *
! 5909: * @param type The type that will represent the \ref axlItem created.
! 5910: *
! 5911: * @param data Data associated to the axlItem. This function won't
! 5912: * perform any copy for the data received. The user calling to this
! 5913: * API must check that the data is only owned by the \ref axlItem
! 5914: * created (that is, used by this function).
! 5915: *
! 5916: * @return A newly allocated \ref axlItem with no parent and holding
! 5917: * the data provided.
! 5918: */
! 5919: axlItem * axl_item_new_ref (AxlItemType type,
! 5920: axlPointer data)
! 5921: {
! 5922: axlItem * item = NULL;
! 5923: axlNode * node;
! 5924: axlNodeContent * content;
! 5925:
! 5926: /* allocate an item type */
! 5927: item = axl_new (axlItem, 1);
! 5928: item->type = type;
! 5929:
! 5930: switch (axl_item_get_type (item)) {
! 5931: case ITEM_NODE:
! 5932: /* item the node */
! 5933: node = data;
! 5934: node->holder = item;
! 5935: item->data = node;
! 5936: break;
! 5937: case ITEM_CONTENT:
! 5938: case ITEM_CDATA:
! 5939: case ITEM_COMMENT:
! 5940: /* item content */
! 5941: content = axl_new (axlNodeContent, 1);
! 5942: content->content = data;
! 5943: content->content_size = strlen ((const char *) data);
! 5944:
! 5945: /* item content */
! 5946: item->data = content;
! 5947: break;
! 5948: case ITEM_PI:
! 5949: /* item pi */
! 5950: item->data = data;
! 5951: break;
! 5952: case ITEM_REF:
! 5953: /* not implemented yet */
! 5954: break;
! 5955: case ITEM_FROM_FACTORY:
! 5956: case ITEM_CONTENT_FROM_FACTORY:
! 5957: /* never reached */
! 5958: break;
! 5959: } /* end switch */
! 5960:
! 5961: /* return item created */
! 5962: return item;
! 5963: }
! 5964:
! 5965:
! 5966: /**
! 5967: * @brief Allows to get the reference to the document that is holding
! 5968: * the provided item without taking into consideration the item type.
! 5969: *
! 5970: * @param item The item that is required to return its document.
! 5971: *
! 5972: * @return A reference to the \ref axlDoc that is holding the item.
! 5973: */
! 5974: axlDoc * axl_item_get_doc (axlItem * item)
! 5975: {
! 5976: /* do not report an error since it is usual to have a node
! 5977: * without an item hold configured: for example after
! 5978: * axl_node_create */
! 5979: if (item == NULL)
! 5980: return NULL;
! 5981:
! 5982: /* return the document reference */
! 5983: return item->doc;
! 5984: }
! 5985:
! 5986: /**
! 5987: * @internal Internal function that allows to configure the document
! 5988: * that is holding the item provided.
! 5989: *
! 5990: * @param item The axlItem to be configured.
! 5991: * @param doc The axlDoc reference to configure.
! 5992: */
! 5993: void axl_item_set_doc (axlItem * item, axlDoc * doc)
! 5994: {
! 5995: axl_return_if_fail (item);
! 5996:
! 5997: /* configure document */
! 5998: item->doc = doc;
! 5999:
! 6000: return;
! 6001: }
! 6002:
! 6003: /**
! 6004: * @brief Allows to get the parent that is containing the \ref axlItem
! 6005: * provider. The parent of a \ref axlItem is always a node.
! 6006: *
! 6007: * @param item The \ref axlItem reference that is required to return
! 6008: * its parent.
! 6009: *
! 6010: * @return A reference to the \ref axlNode.
! 6011: */
! 6012: axlNode * axl_item_get_parent (axlItem * item)
! 6013: {
! 6014: /* return that we don't have parent */
! 6015: if (item == NULL)
! 6016: return NULL;
! 6017:
! 6018: /* return the parent */
! 6019: return item->parent;
! 6020: }
! 6021:
! 6022: /**
! 6023: * @brief Allows to get the following element that is next to the item
! 6024: * reference provided (\ref axlItem), and at the same level.
! 6025: *
! 6026: * @param item The item that is required to return its next reference.
! 6027: *
! 6028: * @return A reference to the next element or NULL if it fails or no
! 6029: * element is found next to the element provided.
! 6030: */
! 6031: axlItem * axl_item_get_next (axlItem * item)
! 6032: {
! 6033: axl_return_val_if_fail (item, NULL);
! 6034:
! 6035: /* return the next element */
! 6036: return item->next;
! 6037: }
! 6038:
! 6039: /**
! 6040: * @brief Returns the following \ref axlItem to the \ref axlNode
! 6041: * reference, in the same level.
! 6042: *
! 6043: * @param node The node that is required to return the following item
! 6044: * to it.
! 6045: *
! 6046: * @return An reference to the following or NULL.
! 6047: */
! 6048: axlItem * axl_item_node_next (axlNode * node)
! 6049: {
! 6050: axl_return_val_if_fail (node, NULL);
! 6051:
! 6052: if (node->holder != NULL) {
! 6053: /* return the next */
! 6054: return node->holder->next;
! 6055: }
! 6056:
! 6057: /* no holder, no next */
! 6058: return NULL;
! 6059:
! 6060: }
! 6061:
! 6062: /**
! 6063: * @brief Allows to get the following element that is previous to the
! 6064: * item reference provided (\ref axlItem), and at the same level.
! 6065: *
! 6066: * @param item The item that is required to return its previous
! 6067: * reference.
! 6068: *
! 6069: * @return A reference to the previous element or NULL if it fails or
! 6070: * no element is found previous to the element provided.
! 6071: */
! 6072: axlItem * axl_item_get_previous (axlItem * item)
! 6073: {
! 6074: axl_return_val_if_fail (item, NULL);
! 6075:
! 6076: /* return the previous element */
! 6077: return item->previous;
! 6078: }
! 6079:
! 6080: /**
! 6081: * @brief Returns the previous \ref axlItem to the \ref axlNode
! 6082: * reference, in the same level.
! 6083: *
! 6084: * @param node The node that is required to return the previous item
! 6085: * to it.
! 6086: *
! 6087: * @return An reference to the previous or NULL.
! 6088: */
! 6089: axlItem * axl_item_node_previous (axlNode * node)
! 6090: {
! 6091: axl_return_val_if_fail (node, NULL);
! 6092:
! 6093: if (node->holder != NULL) {
! 6094: /* return the previousx */
! 6095: return node->holder->previous;
! 6096: }
! 6097:
! 6098: /* no holder, no previous */
! 6099: return NULL;
! 6100: }
! 6101:
! 6102: /**
! 6103: * @brief Allows to get the \ref axlItem reference that is holding the
! 6104: * node provided.
! 6105: *
! 6106: * @param node The node that is required to return its holding item.
! 6107: *
! 6108: * @return The item reference or NULL if it fails or it isn't set.
! 6109: */
! 6110: axlItem * axl_item_node_holder (axlNode * node)
! 6111: {
! 6112: axl_return_val_if_fail (node, NULL);
! 6113:
! 6114: /* return the holder */
! 6115: return node->holder;
! 6116: }
! 6117:
! 6118: /**
! 6119: * @brief Allows to get the very first child item stored on the
! 6120: * provided \ref axlNode.
! 6121: *
! 6122: * This function is similar to \ref axl_node_get_first_child, but
! 6123: * returning the first \ref axlItem no matter its type.
! 6124: *
! 6125: * This function is mainly used inside the MIXED API where nodes are
! 6126: * expected to enclose content mixed with another xml nodes. See \ref
! 6127: * axl_node_get_first_child for more details.
! 6128: *
! 6129: * @param node The \ref axlNode reference that is required to return
! 6130: * is first child reference (\ref axlItem).
! 6131: *
! 6132: * @return The \ref axlItem reference or NULL if the axlNode is empty
! 6133: * (\ref axl_node_is_empty) and have no childs (\ref
! 6134: * axl_node_have_childs). The function also returns NULL if it fails
! 6135: * (when it receives a NULL reference).
! 6136: */
! 6137: axlItem * axl_item_get_first_child (axlNode * node)
! 6138: {
! 6139: /* check reference received */
! 6140: axl_return_val_if_fail (node, NULL);
! 6141:
! 6142: /* return the first item reference */
! 6143: return node->first;
! 6144: }
! 6145:
! 6146: /**
! 6147: * @brief Allows to get the very last child item stored on the
! 6148: * provided \ref axlNode.
! 6149: *
! 6150: * This function is similar to \ref axl_node_get_last_child, but
! 6151: * returning the last \ref axlItem no matter its type.
! 6152: *
! 6153: * This function is mainly used inside the MIXED API where nodes are
! 6154: * expected to enclose content mixed with another xml nodes. See \ref
! 6155: * axl_node_get_last_child for more details.
! 6156: *
! 6157: * @param node The \ref axlNode reference that is required to return
! 6158: * is last child reference (\ref axlItem).
! 6159: *
! 6160: * @return The \ref axlItem reference or NULL if the axlNode is empty
! 6161: * (\ref axl_node_is_empty) and have no childs (\ref
! 6162: * axl_node_have_childs). The function also returns NULL if it fails
! 6163: * (when it receives a NULL reference).
! 6164: */
! 6165: axlItem * axl_item_get_last_child (axlNode * node)
! 6166: {
! 6167: /* check reference received */
! 6168: axl_return_val_if_fail (node, NULL);
! 6169:
! 6170: /* return the last item reference */
! 6171: return node->last;
! 6172: }
! 6173:
! 6174: /**
! 6175: * @brief Allows to get the item type that represents the reference
! 6176: * received (\ref axlItem).
! 6177: *
! 6178: * Every \ref axlItem represents a particular content that could be
! 6179: * found inside an xml document parsed by the library (\ref
! 6180: * axlDoc). This function allows to return the type associated to the
! 6181: * element encapsulated by the \ref axlItem. See \ref AxlItemType for
! 6182: * more details.
! 6183: *
! 6184: * @param item The reference that is required to return its type.
! 6185: *
! 6186: * @return The type that is inside the reference or -1 if it fails.
! 6187: */
! 6188: AxlItemType axl_item_get_type (axlItem * item)
! 6189: {
! 6190: /* return stored type */
! 6191: return item->type & (~ (ITEM_FROM_FACTORY | ITEM_CONTENT_FROM_FACTORY));
! 6192: }
! 6193:
! 6194: /**
! 6195: * @brief Returns the item data that is stored inside the \ref axlItem
! 6196: * received.
! 6197: *
! 6198: * According to the type that is representing the \ref axlItem
! 6199: * received, it will return a particular type. Check \ref AxlItemType
! 6200: * for more information.
! 6201: *
! 6202: * @param item The item that is required to return the data
! 6203: * encapsulated on it.
! 6204: *
! 6205: * @return A pointer to the data stored, or NULL if it fails. The
! 6206: * pointer returned, in the case it is defined, mustn't be
! 6207: * released. It is a internal reference to the content.
! 6208: */
! 6209: axlPointer axl_item_get_data (axlItem * item)
! 6210: {
! 6211: axl_return_val_if_fail (item, NULL);
! 6212:
! 6213: /* return stored type */
! 6214: return item->data;
! 6215: }
! 6216:
! 6217: /**
! 6218: * @brief Convenience API that allows to get the content stored (and
! 6219: * its size) from the received \ref axlItem, supposing it is storing
! 6220: * an \ref ITEM_CONTENT, \ref ITEM_CDATA, \ref ITEM_COMMENT or \ref ITEM_REF.
! 6221: *
! 6222: * @param item The \ref axlItem that is supposed to store an item with
! 6223: * type: \ref ITEM_CONTENT, \ref ITEM_CDATA, \ref ITEM_COMMENT or \ref
! 6224: * ITEM_REF.
! 6225: *
! 6226: * @param size Optional variable reference. If defined, if returns the
! 6227: * content size.
! 6228: *
! 6229: * @return An internal reference to the content stored and optionally
! 6230: * the content size notified on the variable received. In the case the
! 6231: * function receives an incompatible \ref axlItem (which is not \ref
! 6232: * ITEM_CONTENT, \ref ITEM_CDATA, \ref ITEM_COMMENT or \ref ITEM_REF),
! 6233: * the function will return NULL, and the optional variable will be
! 6234: * filled with -1.
! 6235: */
! 6236: char * axl_item_get_content (axlItem * item,
! 6237: int * size)
! 6238: {
! 6239: axlNodeContent * content;
! 6240:
! 6241: /* check content received */
! 6242: if (size != NULL)
! 6243: *size = -1;
! 6244:
! 6245: /* check if the item reference is NULL */
! 6246: axl_return_val_if_fail (item,
! 6247: NULL);
! 6248: axl_return_val_if_fail (axl_item_get_type (item) != ITEM_NODE && axl_item_get_type (item) != ITEM_PI,
! 6249: NULL);
! 6250:
! 6251: /* get the content */
! 6252: content = item->data;
! 6253:
! 6254: /* fill the size */
! 6255: if (size != NULL)
! 6256: *size = content->content_size;
! 6257:
! 6258: /* return a pointer to the content */
! 6259: return content->content;
! 6260: }
! 6261:
! 6262: /* prepare the item to be added to the xml document */
! 6263: axlItem * __axl_item_common_configure (axlNode * parent, AxlItemType type, axlPointer data)
! 6264: {
! 6265: axlNode * node = NULL;
! 6266: axlItem * item = NULL;
! 6267:
! 6268: /* return if the parent is defined */
! 6269: axl_return_val_if_fail (parent, NULL);
! 6270:
! 6271: /* check if the node received already have a pointer to a
! 6272: * holder created */
! 6273: if (type & ITEM_NODE) {
! 6274: /* get a reference to the node */
! 6275: node = (axlNode *) data;
! 6276:
! 6277: /* get a reference to the holder */
! 6278: item = node->holder;
! 6279:
! 6280: /* check if the current item was allocated from a
! 6281: * factory to ensure we don't loose that
! 6282: * information */
! 6283: if ((item != NULL) && (item->type & ITEM_FROM_FACTORY))
! 6284: type = type | ITEM_FROM_FACTORY;
! 6285: }
! 6286:
! 6287: /* create an item to hold the child, configuring the node, the
! 6288: * parent and the document */
! 6289: if (item == NULL) {
! 6290: if ((parent->holder != NULL) && (parent->holder->doc != NULL)) {
! 6291: item = axl_item_factory_get (axl_doc_get_item_factory (parent->holder->doc));
! 6292: type = type | ITEM_FROM_FACTORY;
! 6293: } else
! 6294: item = axl_new (axlItem, 1);
! 6295: }
! 6296: item->type = type;
! 6297: item->data = data;
! 6298: item->doc = (parent->holder != NULL) ? parent->holder->doc : NULL;
! 6299:
! 6300: if (item->type & ITEM_NODE) {
! 6301: /* now configure the item that will hold the new child */
! 6302: node->holder = item;
! 6303: } /* end if */
! 6304:
! 6305: /* return item created */
! 6306: return item;
! 6307: }
! 6308:
! 6309: /**
! 6310: * @internal Function that helps adding a new item to the provided
! 6311: * parent node.
! 6312: *
! 6313: * The new item will be added as flaged by the type provided. The
! 6314: * function isn't exposed to the public API because there are better
! 6315: * alternatives to add items to a \ref axlNode. Don't use this API
! 6316: * directly.
! 6317: *
! 6318: * @param parent The axl node that will receive the new content.
! 6319: *
! 6320: * @param type The type to configure to the new item.
! 6321: *
! 6322: * @param data The data associated to the data being stored.
! 6323: *
! 6324: * NOTE: the function doesn't check data received as it is supposed to
! 6325: * receive calls from the library.
! 6326: */
! 6327: void axl_item_set_child (axlNode * parent, AxlItemType type, axlPointer data)
! 6328: {
! 6329: axlItem * item;
! 6330:
! 6331: /* prepare the item to be added to the xml document */
! 6332: item = __axl_item_common_configure (parent, type, data);
! 6333:
! 6334: /* call to set child with a created item */
! 6335: axl_item_set_child_ref (parent, item);
! 6336:
! 6337: return;
! 6338: }
! 6339:
! 6340: /**
! 6341: * @brief Allows to configure xml content just after the item used as
! 6342: * reference.
! 6343: *
! 6344: * @param item The item used as reference to place the content after
! 6345: * it.
! 6346: *
! 6347: * @param type AxlItemType to configure the content to be placed.
! 6348: *
! 6349: * @param data Pointer that is associated to the type.
! 6350: */
! 6351: void axl_item_set_after (axlItem * item,
! 6352: AxlItemType type,
! 6353: axlPointer data)
! 6354: {
! 6355: axlItem * new_item = NULL;
! 6356:
! 6357: /* prepare the item to be added to the xml document */
! 6358: new_item = __axl_item_common_configure (item->parent, type, data);
! 6359:
! 6360: /* configure the parent node */
! 6361: new_item->parent = item->parent;
! 6362:
! 6363: /* configure new item references */
! 6364: new_item->previous = item;
! 6365: new_item->next = item->next;
! 6366:
! 6367: /* configure item references */
! 6368: if (item->next != NULL)
! 6369: item->next->previous = new_item;
! 6370: else
! 6371: item->parent->last = new_item;
! 6372: item->next = new_item;
! 6373:
! 6374: return;
! 6375: }
! 6376:
! 6377: /* call to set child with a created item */
! 6378: void axl_item_set_child_ref (axlNode * parent, axlItem * item)
! 6379: {
! 6380: axl_return_if_fail (parent);
! 6381: axl_return_if_fail (item);
! 6382:
! 6383: /* configure the parent node */
! 6384: item->parent = parent;
! 6385:
! 6386: /* get the current last child */
! 6387: if (parent->first == NULL) {
! 6388: /* init first and last reference to the only one
! 6389: * child */
! 6390: parent->first = item;
! 6391: parent->last = item;
! 6392: }else {
! 6393: /* configure the next item to the current last
! 6394: * child */
! 6395: parent->last->next = item;
! 6396:
! 6397: /* update the last child reference */
! 6398: item->previous = parent->last;
! 6399: item->next = NULL;
! 6400: parent->last = item;
! 6401: }
! 6402:
! 6403: return;
! 6404: }
! 6405:
! 6406: /**
! 6407: * @brief Copy the reference provided creating a newly allocated
! 6408: * reference, including the content inside.
! 6409: *
! 6410: * @param item The item to copy.
! 6411: *
! 6412: * @param set_parent Optionally, allows to provide the parent to be
! 6413: * configured to the item created. This is really required while
! 6414: * copying items that contains nodes.
! 6415: *
! 6416: * @return A newly allocated \ref axlItem reference, containing the
! 6417: * same data (a deep copy) and optionally configured with the provided
! 6418: * parent.
! 6419: */
! 6420: axlItem * axl_item_copy (axlItem * item, axlNode * set_parent)
! 6421: {
! 6422: axlItem * copy;
! 6423: axlNode * node;
! 6424: axlNodeContent * content;
! 6425:
! 6426: /* check values received */
! 6427: axl_return_val_if_fail (item, NULL);
! 6428:
! 6429: /* allocate an copy type */
! 6430: copy = axl_new (axlItem, 1);
! 6431: copy->type = axl_item_get_type (item);
! 6432: copy->parent = set_parent;
! 6433:
! 6434: switch (axl_item_get_type (item)) {
! 6435: case ITEM_NODE:
! 6436: /* copy the node */
! 6437: node = axl_node_copy (item->data, axl_true, axl_true);
! 6438: node->holder = copy;
! 6439: copy->data = node;
! 6440: break;
! 6441: case ITEM_CONTENT:
! 6442: case ITEM_CDATA:
! 6443: case ITEM_COMMENT:
! 6444: /* copy content */
! 6445: content = axl_new (axlNodeContent, 1);
! 6446: content->content = axl_strdup (((axlNodeContent * ) item->data)->content);
! 6447: content->content_size = ((axlNodeContent * ) item->data)->content_size;
! 6448:
! 6449: /* copy content */
! 6450: copy->data = content;
! 6451: break;
! 6452: case ITEM_PI:
! 6453: /* copy pi */
! 6454: copy->data = axl_pi_copy (item->data);
! 6455: break;
! 6456: case ITEM_REF:
! 6457: /* not implemented yet */
! 6458: break;
! 6459: case ITEM_FROM_FACTORY:
! 6460: case ITEM_CONTENT_FROM_FACTORY:
! 6461: /* never reached */
! 6462: break;
! 6463: } /* end switch */
! 6464:
! 6465: /* return copy created */
! 6466: return copy;
! 6467: }
! 6468:
! 6469: /**
! 6470: * @brief Allows to remove the \ref axlItem instance from the document
! 6471: * that is currently holding it, optionally deallocating the memory
! 6472: * used by the structure.
! 6473: *
! 6474: * @param item The item to remove from its container (without taking
! 6475: * into consideration the item type).
! 6476: *
! 6477: * @param dealloc Deallocs the memory used by the \ref axlItem
! 6478: * reference.
! 6479: */
! 6480: void axl_item_remove (axlItem * item,
! 6481: axl_bool dealloc)
! 6482: {
! 6483:
! 6484: /* free the item */
! 6485: axl_return_if_fail (item);
! 6486:
! 6487: /* realloc references */
! 6488: if (item->previous != NULL)
! 6489: item->previous->next = item->next;
! 6490:
! 6491: if (item->next != NULL)
! 6492: item->next->previous = item->previous;
! 6493:
! 6494: /* realloc parent references in the case of a node */
! 6495: if (axl_item_get_type (item) == ITEM_NODE) {
! 6496: if (item->previous == NULL)
! 6497: item->parent->first = item->next;
! 6498:
! 6499: if (item->next == NULL)
! 6500: item->parent->last = item->previous;
! 6501: } /* end if */
! 6502:
! 6503: /* free the item */
! 6504: item->next = NULL;
! 6505: item->previous = NULL;
! 6506:
! 6507: if (dealloc) {
! 6508: axl_item_free (item, axl_true);
! 6509: } /* end if */
! 6510:
! 6511: return;
! 6512:
! 6513: } /* end axl_item_remove */
! 6514:
! 6515: /**
! 6516: * @brief Allows to replace the content held by the \ref axlItem
! 6517: * reference with a new \ref axlItem, updating all references, and
! 6518: * optionally, deallocating the memory used by the previous item
! 6519: * reference.
! 6520: *
! 6521: * @param item The item to be replaced.
! 6522: *
! 6523: * @param new_item The new item to be placed where the previous one is
! 6524: * located.
! 6525: *
! 6526: * @param dealloc Signal to function to dealloc the memory hold the
! 6527: * the item replaced.
! 6528: */
! 6529: void axl_item_replace (axlItem * item,
! 6530: axlItem * new_item,
! 6531: axl_bool dealloc)
! 6532: {
! 6533: /* free the item */
! 6534: axl_return_if_fail (item);
! 6535: axl_return_if_fail (new_item);
! 6536:
! 6537: /* realloc references */
! 6538: if (item->previous != NULL) {
! 6539: item->previous->next = new_item;
! 6540: new_item->previous = item->previous;
! 6541: }
! 6542:
! 6543: if (item->next != NULL) {
! 6544: item->next->previous = new_item;
! 6545: new_item->next = item->next;
! 6546: }
! 6547:
! 6548: /* realloc parent references in the case of a node */
! 6549: if (axl_item_get_type (item) == ITEM_NODE) {
! 6550: if (item->previous == NULL)
! 6551: item->parent->first = new_item;
! 6552:
! 6553: if (item->next == NULL)
! 6554: item->parent->last = new_item;
! 6555: } /* end if */
! 6556:
! 6557: /* free the item */
! 6558: item->next = NULL;
! 6559: item->previous = NULL;
! 6560:
! 6561: /* configure values */
! 6562: new_item->parent = item->parent;
! 6563: new_item->doc = item->doc;
! 6564:
! 6565: if (dealloc) {
! 6566: axl_item_free (item, axl_true);
! 6567:
! 6568: } /* end if */
! 6569:
! 6570: return;
! 6571:
! 6572: } /* end axl_item_replace */
! 6573:
! 6574: /**
! 6575: * @brief Allows to transfer all childs contained inside the provided
! 6576: * \ref axlNode (old_parent) placed after the provided axlItem
! 6577: * (item_ref) on the same level.
! 6578: *
! 6579: * This function allows to manipulate a xml document loaded inside
! 6580: * memory, by transfering all childs (including xml nodes, xml
! 6581: * comments, content, process instructions and entity references) from
! 6582: * the selected parent (the old parent) provided by the
! 6583: * <i>old_parent</i> attribute, to be placed at the same level, where
! 6584: * the <i>item_ref</i> is situated following it.
! 6585: *
! 6586: *
! 6587: * @param old_parent Previous parent, where the childs to be
! 6588: * transfered will be found.
! 6589: *
! 6590: * @param item_ref The \ref axlItem that will act as a reference
! 6591: * placing all childs following the item.
! 6592: */
! 6593: void axl_item_transfer_childs_after (axlNode * old_parent,
! 6594: axlItem * item_ref)
! 6595: {
! 6596: axlItem * item;
! 6597: axlItem * item_aux;
! 6598:
! 6599: /* get the first child for the old parent */
! 6600: item = old_parent->first;
! 6601:
! 6602: /* check if the parent node contains childs to be
! 6603: * transferred. If no child is found, just return */
! 6604: if (item == NULL)
! 6605: return;
! 6606:
! 6607: /* remember previous next */
! 6608: item_aux = item_ref->next;
! 6609:
! 6610: /* make the first child to follow the item ref */
! 6611: item_ref->next = item;
! 6612: item->previous = item_ref;
! 6613:
! 6614: /* set the next at the end of all items transferred, and the
! 6615: * new parent node */
! 6616: while (item != NULL) {
! 6617: /* configure the new parent */
! 6618: item->parent = item_ref->parent;
! 6619:
! 6620: /* check the item to be the last */
! 6621: if (item->next == NULL) {
! 6622: /* the last item was found, configure it */
! 6623: item->next = item_aux;
! 6624:
! 6625: /* configure it to point to the last item
! 6626: * transferred */
! 6627: if (item_aux != NULL)
! 6628: item_aux->previous = item;
! 6629:
! 6630: /* break the loop! */
! 6631: break;
! 6632: } /* end if */
! 6633:
! 6634: /* get the next */
! 6635: item = item->next;
! 6636:
! 6637: } /* end while */
! 6638:
! 6639: /* check that the item selected to be reference isn't the last
! 6640: * child inside new parent node. If it is, update the new
! 6641: * last */
! 6642: if (item_aux == NULL) {
! 6643: /* because item is pointing to the last item in the
! 6644: * level, use it as the new last */
! 6645: item->parent->last = item;
! 6646: } /* end if */
! 6647:
! 6648: /* clear reference from previous parent */
! 6649: old_parent->first = NULL;
! 6650: old_parent->last = NULL;
! 6651:
! 6652: return;
! 6653: }
! 6654:
! 6655: /**
! 6656: * @brief Allows to check if both items are equal, considering the
! 6657: * item type and the content associated to the item type.
! 6658: *
! 6659: * @param item The first item to check.
! 6660: *
! 6661: * @param item2 The second item to check.
! 6662: *
! 6663: * @param trimmed This paramenter allows to configure how the equal
! 6664: * check is performed for content element (\ref ITEM_CONTENT, \ref
! 6665: * ITEM_CDATA, \ref ITEM_COMMENT and \ref ITEM_REF).
! 6666: *
! 6667: * @param error Optional \ref axlError reference where textual
! 6668: * diagnostic is reported.
! 6669: *
! 6670: *
! 6671: * @return \ref axl_true if the both items represents the same
! 6672: * information, otherwise \ref axl_false is returned. If the function
! 6673: * receives a null value it will return axl_false.
! 6674: */
! 6675: axl_bool axl_item_are_equal_full (axlItem * item,
! 6676: axlItem * item2,
! 6677: axl_bool trimmed,
! 6678: axlError ** error)
! 6679: {
! 6680: axlNodeContent * content;
! 6681: axlNodeContent * content2;
! 6682:
! 6683: /* trim content */
! 6684: char * trim;
! 6685: char * trim2;
! 6686: axl_bool result;
! 6687:
! 6688: axl_return_val_if_fail (item, axl_false);
! 6689: axl_return_val_if_fail (item2, axl_false);
! 6690:
! 6691: /* basic type check */
! 6692: if (axl_item_get_type (item) != axl_item_get_type (item2)) {
! 6693: axl_error_report (error, -1, "Items types differs (%d != %d)",
! 6694: axl_item_get_type (item), axl_item_get_type (item2));
! 6695: return axl_false;
! 6696: }
! 6697:
! 6698: /* according the type */
! 6699: switch (axl_item_get_type (item)) {
! 6700: case ITEM_NODE:
! 6701: /* check that both nodes are equal */
! 6702: return axl_node_are_equal_full (item->data, item2->data, error);
! 6703: case ITEM_CONTENT:
! 6704: case ITEM_CDATA:
! 6705: case ITEM_COMMENT:
! 6706: case ITEM_REF:
! 6707: /* get the contenet */
! 6708: content = item->data;
! 6709: content2 = item2->data;
! 6710:
! 6711: if (! trimmed) {
! 6712: /* check first content length */
! 6713: if (content->content_size != content2->content_size) {
! 6714: axl_error_report (error, -1, "Items content size differs (%s:%d != %s:%d)",
! 6715: content->content,
! 6716: content->content_size,
! 6717: content2->content,
! 6718: content2->content_size);
! 6719: return axl_false;
! 6720: }
! 6721:
! 6722: /* now check content value */
! 6723: return axl_cmp (content->content, content2->content);
! 6724: }else {
! 6725: /* duplicate the content */
! 6726: trim = axl_strdup (content->content);
! 6727: trim2 = axl_strdup (content2->content);
! 6728:
! 6729: /* trim content */
! 6730: axl_stream_trim (trim);
! 6731: axl_stream_trim (trim2);
! 6732:
! 6733: /* do the comparision */
! 6734: result = axl_cmp (trim, trim2);
! 6735:
! 6736: if (! result) {
! 6737: axl_error_report (error, -1, "Trimmed content differs ('%s' != '%s')", trim, trim2);
! 6738: } /* end if */
! 6739:
! 6740: /* free data */
! 6741: axl_free (trim);
! 6742: axl_free (trim2);
! 6743:
! 6744: return result;
! 6745:
! 6746: }
! 6747: case ITEM_PI:
! 6748: /* pi case */
! 6749: return axl_pi_are_equal (item->data, item2->data);
! 6750: default:
! 6751: /* no case identified, not equal */
! 6752: break;
! 6753: } /* end switch */
! 6754:
! 6755: axl_error_report (error, -1, "Item type not found, unable to check");
! 6756: return axl_false;
! 6757: }
! 6758:
! 6759: /**
! 6760: * @brief Allows to check if both items are equal, considering the
! 6761: * item type and the content associated to the item type.
! 6762: *
! 6763: *
! 6764: * @param item The first item to check.
! 6765: *
! 6766: * @param item2 The second item to check.
! 6767: *
! 6768: * @param trimmed This paramenter allows to configure how equal
! 6769: * checking is performed for content element (\ref ITEM_CONTENT, \ref
! 6770: * ITEM_CDATA, \ref ITEM_COMMENT and \ref ITEM_REF).
! 6771: *
! 6772: * @return \ref axl_true if the both items represents the same
! 6773: * information, otherwise \ref axl_false is returned. If the function
! 6774: * receives a null value it will return axl_false.
! 6775: */
! 6776: axl_bool axl_item_are_equal (axlItem * item,
! 6777: axlItem * item2,
! 6778: axl_bool trimmed)
! 6779: {
! 6780: /* call to check if both items are equal */
! 6781: return axl_item_are_equal_full (item, item2, trimmed, NULL);
! 6782: }
! 6783:
! 6784: /**
! 6785: * @brief Allows to release the memory hold the item reference
! 6786: * provided, and the value stored inside it.
! 6787: *
! 6788: * @param item The item to dealloc.
! 6789: *
! 6790: * @param dealloc \ref axl_true to also dealloc the value inside.
! 6791: */
! 6792: void axl_item_free (axlItem * item,
! 6793: axl_bool dealloc)
! 6794: {
! 6795: axl_return_if_fail (item);
! 6796:
! 6797:
! 6798: /* according the type */
! 6799: switch (axl_item_get_type (item)) {
! 6800: case ITEM_NODE:
! 6801: /* free the node */
! 6802: axl_node_free (item->data);
! 6803: break;
! 6804: case ITEM_CONTENT:
! 6805: case ITEM_CDATA:
! 6806: case ITEM_COMMENT:
! 6807: case ITEM_REF:
! 6808: /* all of them, managed equally */
! 6809:
! 6810: /* check and free content */
! 6811: if ((item->type & ITEM_CONTENT_FROM_FACTORY) == 0) {
! 6812: axl_free (((axlNodeContent *)item->data)->content);
! 6813:
! 6814: /* free node */
! 6815: axl_free ((axlNodeContent *)item->data);
! 6816: }
! 6817:
! 6818: if ((item->type & ITEM_FROM_FACTORY) == 0)
! 6819: axl_free (item);
! 6820: break;
! 6821: case ITEM_PI:
! 6822: /* an process instruction */
! 6823: axl_pi_free (item->data);
! 6824:
! 6825: /* free the item */
! 6826: if ((item->type & ITEM_FROM_FACTORY) == 0)
! 6827: axl_free (item);
! 6828: break;
! 6829: case ITEM_FROM_FACTORY:
! 6830: case ITEM_CONTENT_FROM_FACTORY:
! 6831: /* never reached */
! 6832: break;
! 6833:
! 6834: } /* end switch */
! 6835:
! 6836:
! 6837: return;
! 6838: }
! 6839:
! 6840: axlFactory * axl_item_factory_create (void)
! 6841: {
! 6842: return axl_factory_create (sizeof (axlItem));
! 6843: }
! 6844:
! 6845: axlItem * axl_item_factory_get (axlFactory * factory)
! 6846: {
! 6847: return axl_factory_get (factory);
! 6848: }
! 6849:
! 6850: axlFactory * axl_node_factory_create (void)
! 6851: {
! 6852: return axl_factory_create (sizeof (axlNode));
! 6853: }
! 6854:
! 6855: axlNode * axl_node_factory_get (axlFactory * factory)
! 6856: {
! 6857: /* get a node */
! 6858: axlNode * node = axl_factory_get (factory);
! 6859:
! 6860: /* configure it */
! 6861: node->conf = NODE_FROM_FACTORY;
! 6862:
! 6863: return node;
! 6864: }
! 6865:
! 6866: axlFactory * axl_item_content_factory_create (void)
! 6867: {
! 6868: /* create a factory for axlNodeContent elements */
! 6869: return axl_factory_create (sizeof (axlNodeContent));
! 6870: }
! 6871:
! 6872: axlFactory * axl_item_attr_factory_create (void)
! 6873: {
! 6874: /* create a factory for axlNodeAttr elements */
! 6875: return axl_factory_create (sizeof (axlNodeAttr));
! 6876: }
! 6877:
! 6878: /* @} */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>