1/* 2 * "$Id: mxml-node.c,v 1.7 2004/09/17 18:38:21 rleigh Exp $" 3 * 4 * Node support code for mini-XML, a small XML-like file parsing library. 5 * 6 * Copyright 2003 by Michael Sweet. 7 * 8 * This program is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Library General Public 10 * License as published by the Free Software Foundation; either 11 * version 2, or (at your option) any later version. 12 * 13 * This program is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 * GNU General Public License for more details. 17 * 18 * Contents: 19 * 20 * stp_mxmlAdd() - Add a node to a tree. 21 * stp_mxmlDelete() - Delete a node and all of its children. 22 * stp_mxmlNewElement() - Create a new element node. 23 * stp_mxmlNewInteger() - Create a new integer node. 24 * stp_mxmlNewOpaque() - Create a new opaque string. 25 * stp_mxmlNewReal() - Create a new real number node. 26 * stp_mxmlNewText() - Create a new text fragment node. 27 * stp_mxmlRemove() - Remove a node from its parent. 28 * mxml_new() - Create a new node. 29 */ 30 31/* 32 * Include necessary headers... 33 */ 34 35#include <gutenprint/mxml.h> 36#include "config.h" 37 38 39/* 40 * Local functions... 41 */ 42 43static stp_mxml_node_t *mxml_new(stp_mxml_node_t *parent, stp_mxml_type_t type); 44 45 46/* 47 * 'stp_mxmlAdd()' - Add a node to a tree. 48 * 49 * Adds the specified node to the parent. If the child argument is not 50 * NULL, puts the new node before or after the specified child depending 51 * on the value of the where argument. If the child argument is NULL, 52 * puts the new node at the beginning of the child list (STP_MXML_ADD_BEFORE) 53 * or at the end of the child list (STP_MXML_ADD_AFTER). The constant 54 * STP_MXML_ADD_TO_PARENT can be used to specify a NULL child pointer. 55 */ 56 57void 58stp_mxmlAdd(stp_mxml_node_t *parent, /* I - Parent node */ 59 int where, /* I - Where to add, STP_MXML_ADD_BEFORE or STP_MXML_ADD_AFTER */ 60 stp_mxml_node_t *child, /* I - Child node for where or STP_MXML_ADD_TO_PARENT */ 61 stp_mxml_node_t *node) /* I - Node to add */ 62{ 63/* fprintf(stderr, "stp_mxmlAdd(parent=%p, where=%d, child=%p, node=%p)\n", parent, 64 where, child, node);*/ 65 66 /* 67 * Range check input... 68 */ 69 70 if (!parent || !node) 71 return; 72 73 /* 74 * Remove the node from any existing parent... 75 */ 76 77 if (node->parent) 78 stp_mxmlRemove(node); 79 80 /* 81 * Reset pointers... 82 */ 83 84 node->parent = parent; 85 86 switch (where) 87 { 88 case STP_MXML_ADD_BEFORE : 89 if (!child || child == parent->child || child->parent != parent) 90 { 91 /* 92 * Insert as first node under parent... 93 */ 94 95 node->next = parent->child; 96 97 if (parent->child) 98 parent->child->prev = node; 99 else 100 parent->last_child = node; 101 102 parent->child = node; 103 } 104 else 105 { 106 /* 107 * Insert node before this child... 108 */ 109 110 node->next = child; 111 node->prev = child->prev; 112 113 if (child->prev) 114 child->prev->next = node; 115 else 116 parent->child = node; 117 118 child->prev = node; 119 } 120 break; 121 122 case STP_MXML_ADD_AFTER : 123 if (!child || child == parent->last_child || child->parent != parent) 124 { 125 /* 126 * Insert as last node under parent... 127 */ 128 129 node->parent = parent; 130 node->prev = parent->last_child; 131 132 if (parent->last_child) 133 parent->last_child->next = node; 134 else 135 parent->child = node; 136 137 parent->last_child = node; 138 } 139 else 140 { 141 /* 142 * Insert node after this child... 143 */ 144 145 node->prev = child; 146 node->next = child->next; 147 148 if (child->next) 149 child->next->prev = node; 150 else 151 parent->last_child = node; 152 153 child->next = node; 154 } 155 break; 156 } 157} 158 159 160/* 161 * 'stp_mxmlDelete()' - Delete a node and all of its children. 162 * 163 * If the specified node has a parent, this function first removes the 164 * node from its parent using the stp_mxmlRemove() function. 165 */ 166 167void 168stp_mxmlDelete(stp_mxml_node_t *node) /* I - Node to delete */ 169{ 170 int i; /* Looping var */ 171 172 173/* fprintf(stderr, "stp_mxmlDelete(node=%p)\n", node);*/ 174 175 /* 176 * Range check input... 177 */ 178 179 if (!node) 180 return; 181 182 /* 183 * Remove the node from its parent, if any... 184 */ 185 186 stp_mxmlRemove(node); 187 188 /* 189 * Delete children... 190 */ 191 192 while (node->child) 193 stp_mxmlDelete(node->child); 194 195 /* 196 * Now delete any node data... 197 */ 198 199 switch (node->type) 200 { 201 case STP_MXML_ELEMENT : 202 if (node->value.element.name) 203 free(node->value.element.name); 204 205 if (node->value.element.num_attrs) 206 { 207 for (i = 0; i < node->value.element.num_attrs; i ++) 208 { 209 if (node->value.element.attrs[i].name) 210 free(node->value.element.attrs[i].name); 211 if (node->value.element.attrs[i].value) 212 free(node->value.element.attrs[i].value); 213 } 214 215 free(node->value.element.attrs); 216 } 217 break; 218 case STP_MXML_INTEGER : 219 /* Nothing to do */ 220 break; 221 case STP_MXML_OPAQUE : 222 if (node->value.opaque) 223 free(node->value.opaque); 224 break; 225 case STP_MXML_REAL : 226 /* Nothing to do */ 227 break; 228 case STP_MXML_TEXT : 229 if (node->value.text.string) 230 free(node->value.text.string); 231 break; 232 } 233 234 /* 235 * Free this node... 236 */ 237 238 free(node); 239} 240 241 242/* 243 * 'stp_mxmlNewElement()' - Create a new element node. 244 * 245 * The new element node is added to the end of the specified parent's child 246 * list. The constant STP_MXML_NO_PARENT can be used to specify that the new 247 * element node has no parent. 248 */ 249 250stp_mxml_node_t * /* O - New node */ 251stp_mxmlNewElement(stp_mxml_node_t *parent, /* I - Parent node or STP_MXML_NO_PARENT */ 252 const char *name) /* I - Name of element */ 253{ 254 stp_mxml_node_t *node; /* New node */ 255 256 257 /* 258 * Range check input... 259 */ 260 261 if (!name) 262 return (NULL); 263 264 /* 265 * Create the node and set the element name... 266 */ 267 268 if ((node = mxml_new(parent, STP_MXML_ELEMENT)) != NULL) 269 node->value.element.name = strdup(name); 270 271 return (node); 272} 273 274 275/* 276 * 'stp_mxmlNewInteger()' - Create a new integer node. 277 * 278 * The new integer node is added to the end of the specified parent's child 279 * list. The constant STP_MXML_NO_PARENT can be used to specify that the new 280 * integer node has no parent. 281 */ 282 283stp_mxml_node_t * /* O - New node */ 284stp_mxmlNewInteger(stp_mxml_node_t *parent, /* I - Parent node or STP_MXML_NO_PARENT */ 285 int integer) /* I - Integer value */ 286{ 287 stp_mxml_node_t *node; /* New node */ 288 289 290 /* 291 * Range check input... 292 */ 293 294 if (!parent) 295 return (NULL); 296 297 /* 298 * Create the node and set the element name... 299 */ 300 301 if ((node = mxml_new(parent, STP_MXML_INTEGER)) != NULL) 302 node->value.integer = integer; 303 304 return (node); 305} 306 307 308/* 309 * 'stp_mxmlNewOpaque()' - Create a new opaque string. 310 * 311 * The new opaque node is added to the end of the specified parent's child 312 * list. The constant STP_MXML_NO_PARENT can be used to specify that the new 313 * opaque node has no parent. The opaque string must be nul-terminated and 314 * is copied into the new node. 315 */ 316 317stp_mxml_node_t * /* O - New node */ 318stp_mxmlNewOpaque(stp_mxml_node_t *parent, /* I - Parent node or STP_MXML_NO_PARENT */ 319 const char *opaque) /* I - Opaque string */ 320{ 321 stp_mxml_node_t *node; /* New node */ 322 323 324 /* 325 * Range check input... 326 */ 327 328 if (!parent || !opaque) 329 return (NULL); 330 331 /* 332 * Create the node and set the element name... 333 */ 334 335 if ((node = mxml_new(parent, STP_MXML_OPAQUE)) != NULL) 336 node->value.opaque = strdup(opaque); 337 338 return (node); 339} 340 341 342/* 343 * 'stp_mxmlNewReal()' - Create a new real number node. 344 * 345 * The new real number node is added to the end of the specified parent's 346 * child list. The constant STP_MXML_NO_PARENT can be used to specify that 347 * the new real number node has no parent. 348 */ 349 350stp_mxml_node_t * /* O - New node */ 351stp_mxmlNewReal(stp_mxml_node_t *parent, /* I - Parent node or STP_MXML_NO_PARENT */ 352 double real) /* I - Real number value */ 353{ 354 stp_mxml_node_t *node; /* New node */ 355 356 357 /* 358 * Range check input... 359 */ 360 361 if (!parent) 362 return (NULL); 363 364 /* 365 * Create the node and set the element name... 366 */ 367 368 if ((node = mxml_new(parent, STP_MXML_REAL)) != NULL) 369 node->value.real = real; 370 371 return (node); 372} 373 374 375/* 376 * 'stp_mxmlNewText()' - Create a new text fragment node. 377 * 378 * The new text node is added to the end of the specified parent's child 379 * list. The constant STP_MXML_NO_PARENT can be used to specify that the new 380 * text node has no parent. The whitespace parameter is used to specify 381 * whether leading whitespace is present before the node. The text 382 * string must be nul-terminated and is copied into the new node. 383 */ 384 385stp_mxml_node_t * /* O - New node */ 386stp_mxmlNewText(stp_mxml_node_t *parent, /* I - Parent node or STP_MXML_NO_PARENT */ 387 int whitespace, /* I - 1 = leading whitespace, 0 = no whitespace */ 388 const char *string) /* I - String */ 389{ 390 stp_mxml_node_t *node; /* New node */ 391 392 393 /* 394 * Range check input... 395 */ 396 397 if (!parent || !string) 398 return (NULL); 399 400 /* 401 * Create the node and set the text value... 402 */ 403 404 if ((node = mxml_new(parent, STP_MXML_TEXT)) != NULL) 405 { 406 node->value.text.whitespace = whitespace; 407 node->value.text.string = strdup(string); 408 } 409 410 return (node); 411} 412 413 414/* 415 * 'stp_mxmlRemove()' - Remove a node from its parent. 416 * 417 * Does not free memory used by the node - use stp_mxmlDelete() for that. 418 * This function does nothing if the node has no parent. 419 */ 420 421void 422stp_mxmlRemove(stp_mxml_node_t *node) /* I - Node to remove */ 423{ 424 /* 425 * Range check input... 426 */ 427 428/* fprintf(stderr, "stp_mxmlRemove(node=%p)\n", node);*/ 429 430 if (!node || !node->parent) 431 return; 432 433 /* 434 * Remove from parent... 435 */ 436 437 if (node->prev) 438 node->prev->next = node->next; 439 else 440 node->parent->child = node->next; 441 442 if (node->next) 443 node->next->prev = node->prev; 444 else 445 node->parent->last_child = node->prev; 446 447 node->parent = NULL; 448 node->prev = NULL; 449 node->next = NULL; 450} 451 452 453/* 454 * 'mxml_new()' - Create a new node. 455 */ 456 457static stp_mxml_node_t * /* O - New node */ 458mxml_new(stp_mxml_node_t *parent, /* I - Parent node */ 459 stp_mxml_type_t type) /* I - Node type */ 460{ 461 stp_mxml_node_t *node; /* New node */ 462 463 464 /* 465 * Allocate memory for the node... 466 */ 467 468 if ((node = calloc(1, sizeof(stp_mxml_node_t))) == NULL) 469 return (NULL); 470 471 /* 472 * Set the node type... 473 */ 474 475 node->type = type; 476 477 /* 478 * Add to the parent if present... 479 */ 480 481 if (parent) 482 stp_mxmlAdd(parent, STP_MXML_ADD_AFTER, STP_MXML_ADD_TO_PARENT, node); 483 484 /* 485 * Return the new node... 486 */ 487 488 return (node); 489} 490 491 492/* 493 * End of "$Id: mxml-node.c,v 1.7 2004/09/17 18:38:21 rleigh Exp $". 494 */ 495