Annotation of embedaddon/libpdel/structs/structs_xml.c, revision 1.1
1.1 ! misho 1:
! 2: /*
! 3: * Copyright (c) 2001-2002 Packet Design, LLC.
! 4: * All rights reserved.
! 5: *
! 6: * Subject to the following obligations and disclaimer of warranty,
! 7: * use and redistribution of this software, in source or object code
! 8: * forms, with or without modifications are expressly permitted by
! 9: * Packet Design; provided, however, that:
! 10: *
! 11: * (i) Any and all reproductions of the source or object code
! 12: * must include the copyright notice above and the following
! 13: * disclaimer of warranties; and
! 14: * (ii) No rights are granted, in any manner or form, to use
! 15: * Packet Design trademarks, including the mark "PACKET DESIGN"
! 16: * on advertising, endorsements, or otherwise except as such
! 17: * appears in the above copyright notice or in the software.
! 18: *
! 19: * THIS SOFTWARE IS BEING PROVIDED BY PACKET DESIGN "AS IS", AND
! 20: * TO THE MAXIMUM EXTENT PERMITTED BY LAW, PACKET DESIGN MAKES NO
! 21: * REPRESENTATIONS OR WARRANTIES, EXPRESS OR IMPLIED, REGARDING
! 22: * THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY AND ALL IMPLIED
! 23: * WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE,
! 24: * OR NON-INFRINGEMENT. PACKET DESIGN DOES NOT WARRANT, GUARANTEE,
! 25: * OR MAKE ANY REPRESENTATIONS REGARDING THE USE OF, OR THE RESULTS
! 26: * OF THE USE OF THIS SOFTWARE IN TERMS OF ITS CORRECTNESS, ACCURACY,
! 27: * RELIABILITY OR OTHERWISE. IN NO EVENT SHALL PACKET DESIGN BE
! 28: * LIABLE FOR ANY DAMAGES RESULTING FROM OR ARISING OUT OF ANY USE
! 29: * OF THIS SOFTWARE, INCLUDING WITHOUT LIMITATION, ANY DIRECT,
! 30: * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, PUNITIVE, OR CONSEQUENTIAL
! 31: * DAMAGES, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, LOSS OF
! 32: * USE, DATA OR PROFITS, HOWEVER CAUSED AND UNDER ANY THEORY OF
! 33: * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 34: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
! 35: * THE USE OF THIS SOFTWARE, EVEN IF PACKET DESIGN IS ADVISED OF
! 36: * THE POSSIBILITY OF SUCH DAMAGE.
! 37: *
! 38: * Author: Archie Cobbs <archie@freebsd.org>
! 39: */
! 40:
! 41: #include <sys/types.h>
! 42: #include <net/ethernet.h>
! 43: #include <netinet/in.h>
! 44:
! 45: #include <stdlib.h>
! 46: #include <stdio.h>
! 47: #include <stdarg.h>
! 48: #include <assert.h>
! 49: #include <ctype.h>
! 50: #include <syslog.h>
! 51: #include <string.h>
! 52: #include <errno.h>
! 53: #include <pthread.h>
! 54:
! 55: #include <expat.h>
! 56:
! 57: #include "structs/structs.h"
! 58: #include "structs/xml.h"
! 59: #include "structs/type/array.h"
! 60: #include "structs/type/struct.h"
! 61: #include "structs/type/union.h"
! 62: #include "util/typed_mem.h"
! 63: #include "sys/alog.h"
! 64:
! 65: /* Standard XML header */
! 66: #define XML_HEADER "<?xml version=\"1.0\" standalone=\"yes\"?>\n"
! 67:
! 68: /* Max parse depth */
! 69: #define MAX_XML_STACK 128
! 70:
! 71: #define INPUT_MEM_TYPE "structs_xml_input"
! 72: #define INFO_MEM_TYPE "structs_xml_input.info"
! 73: #define CHARDATA_MEM_TYPE "structs_xml_input.chardata"
! 74: #define OUTPUT_MEM_TYPE "structs_xml_output"
! 75:
! 76: /* Parse private context */
! 77: struct xmlinput_stackframe {
! 78: const struct structs_type *type; /* type we're parsing */
! 79: void *data; /* data pointer */
! 80: char *s; /* character data */
! 81: u_int s_len; /* strlen(s) */
! 82: u_int index; /* fixed array index */
! 83: u_char combined; /* was a combined tag */
! 84: };
! 85:
! 86: struct xml_input_info {
! 87: XML_Parser p;
! 88: int error;
! 89: int depth;
! 90: int flags;
! 91: u_int skip;
! 92: const char *elem_tag;
! 93: char **attrp;
! 94: const char *attr_mtype;
! 95: int attr_len;
! 96: struct xmlinput_stackframe stack[MAX_XML_STACK];
! 97: structs_xmllog_t *logger;
! 98: };
! 99:
! 100: /*
! 101: * Internal functions
! 102: */
! 103: static void *structs_xml_malloc(size_t size);
! 104: static void *structs_xml_realloc(void *ptr, size_t size);
! 105: static void structs_xml_free(void *ptr);
! 106:
! 107: static void structs_xml_output_cleanup(void *arg);
! 108: static void structs_xml_output_prefix(FILE *fp, int depth);
! 109: static void structs_xml_encode(FILE *fp, const char *s);
! 110:
! 111: static structs_xmllog_t structs_xml_null_logger;
! 112: static structs_xmllog_t structs_xml_stderr_logger;
! 113: static structs_xmllog_t structs_xml_alog_logger;
! 114:
! 115: /*
! 116: * Internal variables
! 117: */
! 118: static const XML_Memory_Handling_Suite memsuite = {
! 119: structs_xml_malloc,
! 120: structs_xml_realloc,
! 121: structs_xml_free
! 122: };
! 123:
! 124: static const char separator_string[] = { STRUCTS_SEPARATOR, '\0' };
! 125: static const char double_separator_string[] = {
! 126: STRUCTS_SEPARATOR, STRUCTS_SEPARATOR, '\0'
! 127: };
! 128:
! 129: /*********************************************************************
! 130: XML INPUT ROUTINES
! 131: *********************************************************************/
! 132:
! 133: /*
! 134: * Internal functions
! 135: */
! 136: static void structs_xml_input_cleanup(void *arg);
! 137: static void structs_xml_input_start(void *userData,
! 138: const XML_Char *name, const XML_Char **atts);
! 139: static void structs_xml_input_end(void *userData, const XML_Char *name);
! 140: static void structs_xml_input_chardata(void *userData,
! 141: const XML_Char *s, int len);
! 142: static void structs_xml_input_nest(struct xml_input_info *info,
! 143: const char *name, const struct structs_type **typep,
! 144: void **datap);
! 145: static void structs_xml_input_prep(struct xml_input_info *info,
! 146: const struct structs_type *type, void *data,
! 147: int combined);
! 148: static void structs_xml_unnest(struct xml_input_info *info,
! 149: const XML_Char *name);
! 150: static void structs_xml_pop(struct xml_input_info *info);
! 151:
! 152: /* Context for one XML parse run */
! 153: struct structs_xml_input_ctx {
! 154: struct xml_input_info *info;
! 155: XML_Parser p;
! 156: int data_init;
! 157: int rtn;
! 158: const struct structs_type *type;
! 159: void *data;
! 160: char **attrp;
! 161: const char *attr_mtype;
! 162: };
! 163:
! 164: /*
! 165: * Input a type from XML.
! 166: *
! 167: * Note: it is safe for the calling thread to be canceled.
! 168: */
! 169: int
! 170: structs_xml_input(const struct structs_type *type,
! 171: const char *elem_tag, char **attrp, const char *attr_mtype,
! 172: FILE *fp, void *data, int flags, structs_xmllog_t *logger)
! 173: {
! 174: struct structs_xml_input_ctx *ctx;
! 175: int esave;
! 176: int r;
! 177:
! 178: /* Special cases for logger */
! 179: if (logger == STRUCTS_LOGGER_NONE)
! 180: logger = structs_xml_null_logger;
! 181: else if (logger == STRUCTS_LOGGER_STDERR)
! 182: logger = structs_xml_stderr_logger;
! 183: else if (logger == STRUCTS_LOGGER_ALOG)
! 184: logger = structs_xml_alog_logger;
! 185:
! 186: /* Create context */
! 187: if ((ctx = MALLOC(INPUT_MEM_TYPE, sizeof(*ctx))) == NULL)
! 188: return (-1);
! 189: memset(ctx, 0, sizeof(*ctx));
! 190: ctx->attrp = attrp;
! 191: ctx->attr_mtype = attr_mtype;
! 192: ctx->type = type;
! 193: ctx->data = data;
! 194: ctx->rtn = -1;
! 195: pthread_cleanup_push(structs_xml_input_cleanup, ctx);
! 196:
! 197: /* Initialize attributes */
! 198: if (ctx->attrp != NULL
! 199: && (*ctx->attrp = STRDUP(ctx->attr_mtype, "")) == NULL)
! 200: goto done;
! 201:
! 202: /* Initialize data object if desired */
! 203: if (ctx->type != NULL && (flags & STRUCTS_XML_UNINIT) != 0) {
! 204: if ((*type->init)(ctx->type, ctx->data) == -1) {
! 205: esave = errno;
! 206: (*logger)(LOG_ERR, "error initializing data: %s",
! 207: strerror(errno));
! 208: errno = esave;
! 209: goto done;
! 210: }
! 211: ctx->data_init = 1;
! 212: }
! 213:
! 214: /* Allocate info structure */
! 215: if ((ctx->info = MALLOC(INFO_MEM_TYPE, sizeof(*ctx->info))) == NULL) {
! 216: esave = errno;
! 217: (*logger)(LOG_ERR, "%s: %s", "malloc", strerror(errno));
! 218: errno = esave;
! 219: goto done;
! 220: }
! 221: memset(ctx->info, 0, sizeof(*ctx->info));
! 222: ctx->info->logger = logger;
! 223: ctx->info->attrp = attrp;
! 224: ctx->info->attr_len = 0;
! 225: ctx->info->attr_mtype = attr_mtype;
! 226: ctx->info->elem_tag = elem_tag;
! 227: ctx->info->stack[0].type = type;
! 228: ctx->info->stack[0].data = data;
! 229: ctx->info->flags = flags;
! 230:
! 231: /* Create a new parser */
! 232: if ((ctx->p = XML_ParserCreate_MM(NULL, &memsuite, NULL)) == NULL) {
! 233: esave = errno;
! 234: (*logger)(LOG_ERR,
! 235: "error creating XML parser: %s", strerror(errno));
! 236: errno = esave;
! 237: goto done;
! 238: }
! 239: ctx->info->p = ctx->p;
! 240: XML_SetUserData(ctx->p, ctx->info);
! 241: XML_SetElementHandler(ctx->p,
! 242: structs_xml_input_start, structs_xml_input_end);
! 243: XML_SetCharacterDataHandler(ctx->p, structs_xml_input_chardata);
! 244:
! 245: /* Parse it */
! 246: while (1) {
! 247: const int bufsize = 1024;
! 248: size_t len;
! 249: void *buf;
! 250:
! 251: /* Get buffer */
! 252: if ((buf = XML_GetBuffer(ctx->p, bufsize)) == NULL) {
! 253: esave = errno;
! 254: (*logger)(LOG_ERR,
! 255: "error from XML_GetBuffer: %s", strerror(errno));
! 256: errno = esave;
! 257: break;
! 258: }
! 259:
! 260: /* Read more bytes. Note: we could get canceled here. */
! 261: len = fread(buf, 1, bufsize, fp);
! 262:
! 263: /* Check for error */
! 264: if (ferror(fp)) {
! 265: esave = errno;
! 266: (*logger)(LOG_ERR, "read error: %s", strerror(errno));
! 267: errno = esave;
! 268: break;
! 269: }
! 270:
! 271: /* Process them */
! 272: if (len > 0 && !XML_ParseBuffer(ctx->p, len, feof(fp))) {
! 273: (*logger)(LOG_ERR, "line %d:%d: %s",
! 274: XML_GetCurrentLineNumber(ctx->p),
! 275: XML_GetCurrentColumnNumber(ctx->p),
! 276: XML_ErrorString(XML_GetErrorCode(ctx->p)));
! 277: errno = EINVAL;
! 278: break;
! 279: }
! 280:
! 281: /* Done? */
! 282: if (feof(fp)) {
! 283: if (ctx->info->error != 0)
! 284: errno = ctx->info->error;
! 285: else
! 286: ctx->rtn = 0;
! 287: break;
! 288: }
! 289: }
! 290:
! 291: done:
! 292: /* Clean up and exit */
! 293: r = ctx->rtn;
! 294: pthread_cleanup_pop(1);
! 295: return (r);
! 296: }
! 297:
! 298: /*
! 299: * Cleanup for structs_xml_input()
! 300: */
! 301: static void
! 302: structs_xml_input_cleanup(void *arg)
! 303: {
! 304: struct structs_xml_input_ctx *const ctx = arg;
! 305: const int esave = errno;
! 306:
! 307: /* Free private parse info */
! 308: if (ctx->info != NULL) {
! 309: while (ctx->info->depth >= 0)
! 310: structs_xml_pop(ctx->info);
! 311: FREE(INFO_MEM_TYPE, ctx->info);
! 312: }
! 313:
! 314: /* Free parser */
! 315: if (ctx->p != NULL)
! 316: XML_ParserFree(ctx->p);
! 317:
! 318: /* If error, free returned attributes and initialized data */
! 319: if (ctx->rtn != 0) {
! 320: if (ctx->attrp != NULL && *ctx->attrp != NULL) {
! 321: FREE(ctx->attr_mtype, *ctx->attrp);
! 322: *ctx->attrp = NULL;
! 323: }
! 324: if (ctx->data_init)
! 325: (*ctx->type->uninit)(ctx->type, ctx->data);
! 326: }
! 327:
! 328: /* Free context */
! 329: FREE(INPUT_MEM_TYPE, ctx);
! 330: errno = esave;
! 331: }
! 332:
! 333: /*
! 334: * Start tag handler
! 335: */
! 336: static void
! 337: structs_xml_input_start(void *userData,
! 338: const XML_Char *name, const XML_Char **attrs)
! 339: {
! 340: struct xml_input_info *const info = userData;
! 341: struct xmlinput_stackframe *const frame = &info->stack[info->depth];
! 342: const struct structs_type *type = frame->type;
! 343: void *data = frame->data;
! 344: char *namebuf;
! 345: char *ctx;
! 346: int first;
! 347: char *s;
! 348: int sev;
! 349:
! 350: /* Skip if any errors */
! 351: if (info->error)
! 352: return;
! 353: if (info->skip) {
! 354: info->skip++;
! 355: return;
! 356: }
! 357:
! 358: /* Handle the top level tag specially */
! 359: if (info->depth == 0) {
! 360: int i;
! 361:
! 362: /* The top level tag must match what we expect */
! 363: if (strcmp(name, info->elem_tag) != 0) {
! 364: (*info->logger)(LOG_ERR,
! 365: "line %d:%d: expecting element \"%s\" here",
! 366: XML_GetCurrentLineNumber(info->p),
! 367: XML_GetCurrentColumnNumber(info->p),
! 368: info->elem_tag);
! 369: info->error = EINVAL;
! 370: return;
! 371: }
! 372:
! 373: /* Extract attributes */
! 374: for (i = 0; info->attrp != NULL && attrs[i] != NULL; i += 2) {
! 375: const char *const name = attrs[i];
! 376: const char *const value = attrs[i + 1];
! 377: void *mem;
! 378:
! 379: if ((mem = REALLOC(info->attr_mtype,
! 380: *info->attrp, info->attr_len + strlen(name) + 1
! 381: + strlen(value) + 1 + 1)) == NULL) {
! 382: info->error = errno;
! 383: (*info->logger)(LOG_ERR, "line %d:%d: %s: %s",
! 384: XML_GetCurrentLineNumber(info->p),
! 385: XML_GetCurrentColumnNumber(info->p),
! 386: "malloc", strerror(errno));
! 387: return;
! 388: }
! 389: *info->attrp = mem;
! 390: strcpy(*info->attrp + info->attr_len, name);
! 391: strcpy(*info->attrp + info->attr_len
! 392: + strlen(name) + 1, value);
! 393: (*info->attrp)[info->attr_len + strlen(name) + 1
! 394: + strlen(value) + 1] = '\0';
! 395: info->attr_len += strlen(name) + 1 + strlen(value) + 1;
! 396: }
! 397:
! 398: /* Are we only scanning? */
! 399: if ((info->flags & STRUCTS_XML_SCAN) != 0) {
! 400: info->skip++;
! 401: return;
! 402: }
! 403:
! 404: /* Prep the top level data structure */
! 405: structs_xml_input_prep(info, type, data, 0);
! 406: return;
! 407: }
! 408:
! 409: /* We don't allow attributes with non top level elements */
! 410: if (attrs[0] != NULL) {
! 411: sev = (info->flags & STRUCTS_XML_LOOSE) == 0 ?
! 412: LOG_ERR : LOG_WARNING;
! 413: (*info->logger)(sev, "line %d:%d: element \"%s\""
! 414: " contains attributes (not allowed)",
! 415: XML_GetCurrentLineNumber(info->p),
! 416: XML_GetCurrentColumnNumber(info->p), name);
! 417: if (sev == LOG_ERR) {
! 418: info->error = EINVAL;
! 419: return;
! 420: }
! 421: }
! 422:
! 423: /*
! 424: * Check the case of a structure or union field name
! 425: * containing the separator character. Such fields take
! 426: * precedence over combined XML tags.
! 427: */
! 428: if (strchr(name, STRUCTS_SEPARATOR) != NULL) {
! 429: switch (type->tclass) {
! 430: case STRUCTS_TYPE_STRUCTURE:
! 431: {
! 432: const struct structs_field *field;
! 433:
! 434: for (field = frame->type->args[0].v;
! 435: field->name != NULL; field++) {
! 436: if (strcmp(field->name, name) == 0)
! 437: goto not_combined;
! 438: }
! 439: }
! 440: case STRUCTS_TYPE_UNION:
! 441: {
! 442: const struct structs_ufield *field;
! 443:
! 444: for (field = frame->type->args[0].v;
! 445: field->name != NULL; field++) {
! 446: if (strcmp(field->name, name) == 0)
! 447: goto not_combined;
! 448: }
! 449: }
! 450: default:
! 451: break;
! 452: }
! 453: }
! 454:
! 455: /* Check whether we need to consider this as a combined tag */
! 456: if ((info->flags & STRUCTS_XML_COMB_TAGS) == 0
! 457: || strchr(name, STRUCTS_SEPARATOR) == NULL)
! 458: goto not_combined;
! 459:
! 460: /* Check that the combined XML tag is well-formed */
! 461: if (name[0] == STRUCTS_SEPARATOR
! 462: || (name[0] != '\0' && name[strlen(name) - 1] == STRUCTS_SEPARATOR)
! 463: || strstr(name, double_separator_string) != NULL) {
! 464: (*info->logger)(LOG_ERR, "line %d:%d: invalid combined"
! 465: " element tag \"%s\"", XML_GetCurrentLineNumber(info->p),
! 466: XML_GetCurrentColumnNumber(info->p), name);
! 467: info->error = EINVAL;
! 468: return;
! 469: }
! 470:
! 471: /* Copy XML tag so we can parse it */
! 472: if ((namebuf = STRDUP(TYPED_MEM_TEMP, name)) == NULL) {
! 473: info->error = errno;
! 474: return;
! 475: }
! 476:
! 477: /* Parse combined XML tag into individual tag names */
! 478: for (first = 1, s = strtok_r(namebuf, separator_string, &ctx);
! 479: s != NULL; first = 0, s = strtok_r(NULL, separator_string, &ctx)) {
! 480: struct xmlinput_stackframe *const frame
! 481: = &info->stack[info->depth];
! 482:
! 483: type = frame->type;
! 484: data = frame->data;
! 485: structs_xml_input_nest(info, s, &type, &data);
! 486: if (info->error != 0) {
! 487: FREE(TYPED_MEM_TEMP, namebuf);
! 488: return;
! 489: }
! 490: structs_xml_input_prep(info, type, data, !first);
! 491: if (info->error != 0) {
! 492: FREE(TYPED_MEM_TEMP, namebuf);
! 493: return;
! 494: }
! 495: }
! 496: FREE(TYPED_MEM_TEMP, namebuf);
! 497: return;
! 498:
! 499: not_combined:
! 500: /* Handle a non-combined tag */
! 501: structs_xml_input_nest(info, name, &type, &data);
! 502: if (info->error != 0)
! 503: return;
! 504: structs_xml_input_prep(info, type, data, 0);
! 505: if (info->error != 0)
! 506: return;
! 507: }
! 508:
! 509: /*
! 510: * Nest one level deeper into the data structure we're inputting
! 511: * using the sub-field "name".
! 512: */
! 513: static void
! 514: structs_xml_input_nest(struct xml_input_info *info, const char *name,
! 515: const struct structs_type **typep, void **datap)
! 516: {
! 517: struct xmlinput_stackframe *const frame = &info->stack[info->depth];
! 518: const struct structs_type *type;
! 519: void *data;
! 520: int sev;
! 521:
! 522: /* Check type type */
! 523: switch (frame->type->tclass) {
! 524: case STRUCTS_TYPE_STRUCTURE:
! 525: case STRUCTS_TYPE_UNION:
! 526: {
! 527: /* Find field; for unions, adjust the field type if necessary */
! 528: type = frame->type;
! 529: data = frame->data;
! 530: if ((type = structs_find(type, name, &data, 1)) == NULL) {
! 531: if (errno == ENOENT) {
! 532: sev = (info->flags & STRUCTS_XML_LOOSE) == 0 ?
! 533: LOG_ERR : LOG_WARNING;
! 534: (*info->logger)(sev,
! 535: "line %d:%d: element \"%s\" is not"
! 536: " expected here",
! 537: XML_GetCurrentLineNumber(info->p),
! 538: XML_GetCurrentColumnNumber(info->p), name);
! 539: if (sev == LOG_ERR) {
! 540: info->error = EINVAL;
! 541: return;
! 542: }
! 543: info->skip++;
! 544: return;
! 545: }
! 546: (*info->logger)(LOG_ERR, "line %d:%d: error"
! 547: " initializing union field \"%s\": %s",
! 548: XML_GetCurrentLineNumber(info->p),
! 549: XML_GetCurrentColumnNumber(info->p),
! 550: name, strerror(errno));
! 551: info->error = errno;
! 552: return;
! 553: }
! 554: break;
! 555: }
! 556:
! 557: case STRUCTS_TYPE_ARRAY:
! 558: {
! 559: const struct structs_type *const etype = frame->type->args[0].v;
! 560: const char *mtype = frame->type->args[1].s;
! 561: const char *elem_name = frame->type->args[2].s;
! 562: struct structs_array *const ary = frame->data;
! 563: void *mem;
! 564:
! 565: /* Check tag name */
! 566: if (strcmp(name, elem_name) != 0) {
! 567: (*info->logger)(LOG_ERR, "line %d:%d: expected element"
! 568: " \"%s\" instead of \"%s\"",
! 569: XML_GetCurrentLineNumber(info->p),
! 570: XML_GetCurrentColumnNumber(info->p),
! 571: elem_name, name);
! 572: info->error = EINVAL;
! 573: return;
! 574: }
! 575:
! 576: /* Expand the array by one */
! 577: if ((mem = REALLOC(mtype,
! 578: ary->elems, (ary->length + 1) * etype->size)) == NULL) {
! 579: info->error = errno;
! 580: (*info->logger)(LOG_ERR, "line %d:%d: %s: %s",
! 581: XML_GetCurrentLineNumber(info->p),
! 582: XML_GetCurrentColumnNumber(info->p),
! 583: "realloc", strerror(errno));
! 584: return;
! 585: }
! 586: ary->elems = mem;
! 587:
! 588: /* Initialize the new element */
! 589: memset((char *)ary->elems + (ary->length * etype->size),
! 590: 0, etype->size);
! 591: if ((*etype->init)(etype,
! 592: (char *)ary->elems + (ary->length * etype->size)) == -1) {
! 593: info->error = errno;
! 594: (*info->logger)(LOG_ERR, "line %d:%d: %s: %s",
! 595: XML_GetCurrentLineNumber(info->p),
! 596: XML_GetCurrentColumnNumber(info->p),
! 597: "error initializing new array element",
! 598: strerror(errno));
! 599: return;
! 600: }
! 601:
! 602: /* Parse the element next */
! 603: type = etype;
! 604: data = (char *)ary->elems + (ary->length * etype->size);
! 605: ary->length++;
! 606: break;
! 607: }
! 608:
! 609: case STRUCTS_TYPE_FIXEDARRAY:
! 610: {
! 611: const struct structs_type *const etype = frame->type->args[0].v;
! 612: const char *elem_name = frame->type->args[1].s;
! 613: const u_int length = frame->type->args[2].i;
! 614:
! 615: /* Check tag name */
! 616: if (strcmp(name, elem_name) != 0) {
! 617: (*info->logger)(LOG_ERR, "line %d:%d: expected element"
! 618: " \"%s\" instead of \"%s\"",
! 619: XML_GetCurrentLineNumber(info->p),
! 620: XML_GetCurrentColumnNumber(info->p),
! 621: elem_name, name);
! 622: info->error = EINVAL;
! 623: return;
! 624: }
! 625:
! 626: /* Check index vs. array length */
! 627: if (frame->index >= length) {
! 628: sev = (info->flags & STRUCTS_XML_LOOSE) == 0 ?
! 629: LOG_ERR : LOG_WARNING;
! 630: (*info->logger)(sev, "line %d:%d: too many"
! 631: " elements in fixed array (length %u)",
! 632: XML_GetCurrentLineNumber(info->p),
! 633: XML_GetCurrentColumnNumber(info->p), length);
! 634: if (sev == LOG_ERR) {
! 635: info->error = EINVAL;
! 636: return;
! 637: }
! 638: info->skip++;
! 639: return;
! 640: }
! 641:
! 642: /* Parse the element next */
! 643: type = etype;
! 644: data = (char *)frame->data + (frame->index * etype->size);
! 645: frame->index++;
! 646: break;
! 647: }
! 648:
! 649: case STRUCTS_TYPE_PRIMITIVE:
! 650: sev = (info->flags & STRUCTS_XML_LOOSE) == 0 ?
! 651: LOG_ERR : LOG_WARNING;
! 652: (*info->logger)(sev,
! 653: "line %d:%d: element \"%s\" is not expected here",
! 654: XML_GetCurrentLineNumber(info->p),
! 655: XML_GetCurrentColumnNumber(info->p), name);
! 656: if (sev == LOG_ERR) {
! 657: info->error = EINVAL;
! 658: return;
! 659: }
! 660: info->skip++;
! 661: return;
! 662:
! 663: default:
! 664: assert(0);
! 665: return;
! 666: }
! 667:
! 668: /* Done */
! 669: *typep = type;
! 670: *datap = data;
! 671: }
! 672:
! 673: /*
! 674: * Prepare the next level of nesting for parsing.
! 675: */
! 676: static void
! 677: structs_xml_input_prep(struct xml_input_info *info,
! 678: const struct structs_type *type, void *data, int combined)
! 679: {
! 680: /* Dereference through pointer(s) */
! 681: while (type->tclass == STRUCTS_TYPE_POINTER) {
! 682: type = type->args[0].v;
! 683: data = *((void **)data);
! 684: }
! 685:
! 686: /* If next item is an array, re-initialize it */
! 687: switch (type->tclass) {
! 688: case STRUCTS_TYPE_ARRAY:
! 689: (*type->uninit)(type, data);
! 690: memset(data, 0, type->size);
! 691: break;
! 692: case STRUCTS_TYPE_FIXEDARRAY:
! 693: {
! 694: void *mem;
! 695:
! 696: /* Get temporary region for newly initialized array */
! 697: if ((mem = MALLOC(TYPED_MEM_TEMP, type->size)) == NULL) {
! 698: info->error = errno;
! 699: (*info->logger)(LOG_ERR, "line %d:%d: %s: %s",
! 700: XML_GetCurrentLineNumber(info->p),
! 701: XML_GetCurrentColumnNumber(info->p),
! 702: "error initializing new array", strerror(errno));
! 703: return;
! 704: }
! 705:
! 706: /* Initialize new array */
! 707: if ((*type->init)(type, mem) == -1) {
! 708: info->error = errno;
! 709: (*info->logger)(LOG_ERR, "line %d:%d: %s: %s",
! 710: XML_GetCurrentLineNumber(info->p),
! 711: XML_GetCurrentColumnNumber(info->p),
! 712: "error initializing new array", strerror(errno));
! 713: FREE(TYPED_MEM_TEMP, mem);
! 714: return;
! 715: }
! 716:
! 717: /* Replace existing array with fresh one */
! 718: (*type->uninit)(type, data);
! 719: memcpy(data, mem, type->size);
! 720: FREE(TYPED_MEM_TEMP, mem);
! 721:
! 722: /* Remember that we're on the first element */
! 723: info->stack[info->depth + 1].index = 0;
! 724: break;
! 725: }
! 726: default:
! 727: break;
! 728: }
! 729:
! 730: /* Check stack overflow */
! 731: if (info->depth == MAX_XML_STACK - 1) {
! 732: (*info->logger)(LOG_ERR,
! 733: "line %d:%d: maximum parse stack depth (%d) exceeded",
! 734: XML_GetCurrentLineNumber(info->p),
! 735: XML_GetCurrentColumnNumber(info->p), MAX_XML_STACK);
! 736: info->error = EMLINK;
! 737: return;
! 738: }
! 739:
! 740: /* Continue in a new stack frame */
! 741: info->depth++;
! 742: info->stack[info->depth].type = type;
! 743: info->stack[info->depth].data = data;
! 744: info->stack[info->depth].combined = combined;
! 745: }
! 746:
! 747: /*
! 748: * Character data handler
! 749: */
! 750: static void
! 751: structs_xml_input_chardata(void *userData, const XML_Char *s, int len)
! 752: {
! 753: struct xml_input_info *const info = userData;
! 754: struct xmlinput_stackframe *const frame = &info->stack[info->depth];
! 755: void *mem;
! 756:
! 757: /* Skip if any errors */
! 758: if (info->error || info->skip)
! 759: return;
! 760:
! 761: /* Expand buffer and append character data */
! 762: if ((mem = REALLOC(CHARDATA_MEM_TYPE,
! 763: frame->s, frame->s_len + len + 1)) == NULL) {
! 764: info->error = errno;
! 765: (*info->logger)(LOG_ERR, "%s: %s",
! 766: "realloc", strerror(errno));
! 767: return;
! 768: }
! 769: frame->s = mem;
! 770: memcpy(frame->s + frame->s_len, (char *)s, len);
! 771: frame->s[frame->s_len + len] = '\0';
! 772: frame->s_len += len;
! 773: }
! 774:
! 775: /*
! 776: * End tag handler
! 777: */
! 778: static void
! 779: structs_xml_input_end(void *userData, const XML_Char *name)
! 780: {
! 781: struct xml_input_info *const info = userData;
! 782: struct xmlinput_stackframe *frame;
! 783: int was_combined;
! 784:
! 785: /* Un-nest once for each structs tag */
! 786: do {
! 787: frame = &info->stack[info->depth];
! 788: was_combined = frame->combined;
! 789: structs_xml_unnest(info, name);
! 790: } while (was_combined);
! 791: }
! 792:
! 793: /*
! 794: * Unnest one level
! 795: */
! 796: static void
! 797: structs_xml_unnest(struct xml_input_info *info, const XML_Char *name)
! 798: {
! 799: struct xmlinput_stackframe *const frame = &info->stack[info->depth];
! 800: const struct structs_type *type;
! 801: const char *s;
! 802: char ebuf[64];
! 803: void *data;
! 804:
! 805: /* Skip if any errors */
! 806: if (info->error)
! 807: return;
! 808: if (info->skip) {
! 809: info->skip--;
! 810: return;
! 811: }
! 812:
! 813: /* Get current type and data */
! 814: data = frame->data;
! 815: type = frame->type;
! 816:
! 817: /*
! 818: * Convert from ASCII if possible, otherwise check only whitespace.
! 819: * For unions, we allow the field name tag to be omitted if you
! 820: * want to use the default field, which must have primitive type.
! 821: */
! 822: switch (type->tclass) {
! 823: case STRUCTS_TYPE_UNION:
! 824: {
! 825: const struct structs_ufield *const field = type->args[0].v;
! 826:
! 827: /* Check to see if there's any non-whitespace text */
! 828: if (frame->s == NULL)
! 829: goto done;
! 830: for (s = frame->s; *s != '\0' && isspace(*s); s++);
! 831: if (*s == '\0')
! 832: goto done;
! 833:
! 834: /* Default field must have primitive type */
! 835: if (field->type->tclass != STRUCTS_TYPE_PRIMITIVE)
! 836: break;
! 837:
! 838: /* Switch the union to the default field */
! 839: if (structs_union_set(type, NULL, data, field->name) == -1) {
! 840: info->error = errno;
! 841: (*info->logger)(LOG_ERR,
! 842: "%s: %s", "structs_union_set", strerror(errno));
! 843: return;
! 844: }
! 845:
! 846: /* Point at the field instead of the union */
! 847: type = field->type;
! 848: data = ((const struct structs_union *)data)->un;
! 849:
! 850: /* FALLTHROUGH */
! 851: }
! 852: case STRUCTS_TYPE_PRIMITIVE:
! 853: if (structs_set_string(type, NULL,
! 854: frame->s, data, ebuf, sizeof(ebuf)) == -1) {
! 855: info->error = errno;
! 856: (*info->logger)(LOG_ERR,
! 857: "line %d:%d: error in \"%s\" element data"
! 858: " \"%s\": %s",
! 859: XML_GetCurrentLineNumber(info->p),
! 860: XML_GetCurrentColumnNumber(info->p),
! 861: name, frame->s == NULL ? "" : frame->s, ebuf);
! 862: return;
! 863: }
! 864: goto done;
! 865: default:
! 866: break;
! 867: }
! 868:
! 869: /* There shouldn't be any non-whitespace text here */
! 870: if (frame->s != NULL) {
! 871: for (s = frame->s; *s != '\0' && isspace(*s); s++);
! 872: if (*s != '\0') {
! 873: (*info->logger)(LOG_ERR, "line %d:%d:"
! 874: " extra garbage within \"%s\" element",
! 875: XML_GetCurrentLineNumber(info->p),
! 876: XML_GetCurrentColumnNumber(info->p),
! 877: name);
! 878: info->error = EINVAL;
! 879: return;
! 880: }
! 881: }
! 882:
! 883: done:
! 884: /* Pop stack frame */
! 885: structs_xml_pop(info);
! 886: }
! 887:
! 888: /*
! 889: * Pop the XML parse stack
! 890: */
! 891: static void
! 892: structs_xml_pop(struct xml_input_info *info)
! 893: {
! 894: struct xmlinput_stackframe *const frame = &info->stack[info->depth];
! 895:
! 896: assert(info->depth >= 0);
! 897: if (frame->s != NULL)
! 898: FREE(CHARDATA_MEM_TYPE, frame->s);
! 899: memset(frame, 0, sizeof(*frame));
! 900: info->depth--;
! 901: }
! 902:
! 903: /*********************************************************************
! 904: XML OUTPUT ROUTINES
! 905: *********************************************************************/
! 906:
! 907: #define STRUCTS_XML_SHOWONE 0x0100 /* show elem for next level only */
! 908: #define STRUCTS_XML_SHOWALL 0x0200 /* show elem and all sub elems */
! 909:
! 910: /*
! 911: * Internal functions
! 912: */
! 913: static int structs_xml_output_sub(const struct structs_type *type,
! 914: const void *data, const char *tag, const char *attrs,
! 915: FILE *fp, const char **elems, const char *posn,
! 916: int flags, int depth);
! 917: static void structs_xml_output_openelem(FILE *fp,
! 918: int depth, const char *tag, const char *attrs);
! 919:
! 920: /*
! 921: * Output a structure in XML
! 922: *
! 923: * Note: it is safe for the calling thread to be canceled.
! 924: */
! 925: int
! 926: structs_xml_output(const struct structs_type *type, const char *elem_tag,
! 927: const char *attrs, const void *data, FILE *fp, const char **elems,
! 928: int flags)
! 929: {
! 930: static const char *all[] = { "", NULL };
! 931:
! 932: /* Output standard XML header */
! 933: fputs(XML_HEADER, fp);
! 934:
! 935: /* NULL elems list means "show everything" */
! 936: if (elems == NULL)
! 937: elems = all;
! 938:
! 939: /* Output structure, and always show the opening and closing tags */
! 940: return (structs_xml_output_sub(type, data, elem_tag, attrs, fp,
! 941: elems, "", flags | STRUCTS_XML_SHOWONE, 0));
! 942: }
! 943:
! 944: /*
! 945: * Output a sub-structure in XML
! 946: */
! 947: static int
! 948: structs_xml_output_sub(const struct structs_type *type, const void *data,
! 949: const char *tag, const char *attrs, FILE *fp, const char **elems,
! 950: const char *posn, int flags, int depth)
! 951: {
! 952: int r = 0;
! 953: int i;
! 954:
! 955: /* Dereference through pointer(s) */
! 956: while (type->tclass == STRUCTS_TYPE_POINTER) {
! 957: type = type->args[0].v;
! 958: data = *((void **)data);
! 959: }
! 960:
! 961: /* Determine whether to show this element */
! 962: if ((flags & STRUCTS_XML_SHOWALL) == 0) {
! 963: const size_t plen = strlen(posn);
! 964:
! 965: for (i = 0; elems[i] != NULL; i++) {
! 966: if (strncmp(elems[i], posn, plen) == 0
! 967: && (elems[i][plen] == '\0'
! 968: || elems[i][plen] == STRUCTS_SEPARATOR)) {
! 969: if (elems[i][plen] == '\0')
! 970: flags |= STRUCTS_XML_SHOWALL;
! 971: break;
! 972: }
! 973: }
! 974: if (elems[i] == NULL && depth > 0
! 975: && (flags & STRUCTS_XML_SHOWONE) == 0)
! 976: return (0); /* not matched, skip element */
! 977: }
! 978:
! 979: /* If doing abbreviated version, compare with default value */
! 980: if (depth > 0
! 981: && (flags & (STRUCTS_XML_FULL|STRUCTS_XML_SHOWONE)) == 0) {
! 982: void *init_value;
! 983: int equal;
! 984:
! 985: if ((init_value = MALLOC(TYPED_MEM_TEMP, type->size)) == NULL)
! 986: return (-1);
! 987: if ((*type->init)(type, init_value) == -1) {
! 988: FREE(TYPED_MEM_TEMP, init_value);
! 989: return (-1);
! 990: }
! 991: equal = (*type->equal)(type, data, init_value);
! 992: (*type->uninit)(type, init_value);
! 993: FREE(TYPED_MEM_TEMP, init_value);
! 994: if (equal)
! 995: return (0);
! 996: }
! 997:
! 998: /* The STRUCTS_XML_SHOWONE flag only applies to the next level down */
! 999: flags &= ~STRUCTS_XML_SHOWONE;
! 1000:
! 1001: /* Output element */
! 1002: switch (type->tclass) {
! 1003: case STRUCTS_TYPE_UNION:
! 1004: {
! 1005: const struct structs_union *const un = data;
! 1006: const struct structs_ufield *const fields = type->args[0].v;
! 1007: const struct structs_ufield *field;
! 1008: char *sposn;
! 1009:
! 1010: /* Find field */
! 1011: for (field = fields; field->name != NULL
! 1012: && strcmp(un->field_name, field->name) != 0; field++);
! 1013: if (field->name == NULL)
! 1014: assert(0);
! 1015:
! 1016: /* Generate new position tag */
! 1017: ASPRINTF(OUTPUT_MEM_TYPE, &sposn, "%s%s%s", posn,
! 1018: *posn != '\0' ? separator_string : "", field->name);
! 1019: if (sposn == NULL)
! 1020: return (-1);
! 1021: pthread_cleanup_push(structs_xml_output_cleanup, sposn);
! 1022:
! 1023: /* Opening tag */
! 1024: structs_xml_output_openelem(fp, depth, tag, attrs);
! 1025: fprintf(fp, "\n");
! 1026:
! 1027: /*
! 1028: * If the union field is not the default choice for this union,
! 1029: * then it must always be shown so the recipient knows that.
! 1030: */
! 1031: if (strcmp(un->field_name, fields[0].name) != 0)
! 1032: flags |= STRUCTS_XML_SHOWONE;
! 1033:
! 1034: /* Output chosen union field */
! 1035: r = structs_xml_output_sub(field->type, un->un, field->name,
! 1036: NULL, fp, elems, sposn, flags, depth + 1);
! 1037:
! 1038: /* Free position tag */
! 1039: pthread_cleanup_pop(1);
! 1040:
! 1041: /* Bail out if there was an error */
! 1042: if (r == -1)
! 1043: break;
! 1044:
! 1045: /* Closing tag */
! 1046: structs_xml_output_prefix(fp, depth);
! 1047: fprintf(fp, "</%s>\n", tag);
! 1048: break;
! 1049: }
! 1050:
! 1051: case STRUCTS_TYPE_STRUCTURE:
! 1052: {
! 1053: const struct structs_field *field;
! 1054:
! 1055: /* Opening tag */
! 1056: structs_xml_output_openelem(fp, depth, tag, attrs);
! 1057: fprintf(fp, "\n");
! 1058:
! 1059: /* Do each structure field */
! 1060: for (field = type->args[0].v; field->name != NULL; field++) {
! 1061: char *sposn;
! 1062:
! 1063: /* Generate new position tag */
! 1064: ASPRINTF(OUTPUT_MEM_TYPE, &sposn, "%s%s%s", posn,
! 1065: *posn != '\0' ? separator_string : "", field->name);
! 1066: if (sposn == NULL)
! 1067: return (-1);
! 1068: pthread_cleanup_push(structs_xml_output_cleanup, sposn);
! 1069:
! 1070: /* Do structure field */
! 1071: r = structs_xml_output_sub(field->type,
! 1072: (char *)data + field->offset, field->name, NULL,
! 1073: fp, elems, sposn, flags, depth + 1);
! 1074:
! 1075: /* Free position tag */
! 1076: pthread_cleanup_pop(1);
! 1077:
! 1078: /* Bail out if there was an error */
! 1079: if (r == -1)
! 1080: break;
! 1081: }
! 1082:
! 1083: /* Closing tag */
! 1084: structs_xml_output_prefix(fp, depth);
! 1085: fprintf(fp, "</%s>\n", tag);
! 1086: break;
! 1087: }
! 1088:
! 1089: case STRUCTS_TYPE_ARRAY:
! 1090: {
! 1091: const struct structs_type *const etype = type->args[0].v;
! 1092: const char *elem_name = type->args[2].s;
! 1093: const struct structs_array *const ary = data;
! 1094: int i;
! 1095:
! 1096: /* Opening tag */
! 1097: structs_xml_output_openelem(fp, depth, tag, attrs);
! 1098: fprintf(fp, "\n");
! 1099:
! 1100: /* All array elements must be shown to keep proper ordering */
! 1101: flags |= STRUCTS_XML_SHOWONE;
! 1102:
! 1103: /* Do elements in order */
! 1104: for (i = 0; i < ary->length; i++) {
! 1105: char *sposn;
! 1106:
! 1107: /* Generate new position tag */
! 1108: ASPRINTF(OUTPUT_MEM_TYPE, &sposn, "%s%s%u",
! 1109: posn, *posn != '\0' ? separator_string : "", i);
! 1110: if (sposn == NULL)
! 1111: return (-1);
! 1112: pthread_cleanup_push(structs_xml_output_cleanup, sposn);
! 1113:
! 1114: /* Output array element */
! 1115: r = structs_xml_output_sub(etype, (char *)ary->elems
! 1116: + (i * etype->size), elem_name, NULL, fp, elems,
! 1117: sposn, flags, depth + 1);
! 1118:
! 1119: /* Free position tag */
! 1120: pthread_cleanup_pop(1);
! 1121:
! 1122: /* Bail out if there was an error */
! 1123: if (r == -1)
! 1124: break;
! 1125: }
! 1126:
! 1127: /* Closing tag */
! 1128: structs_xml_output_prefix(fp, depth);
! 1129: fprintf(fp, "</%s>\n", tag);
! 1130: break;
! 1131: }
! 1132:
! 1133: case STRUCTS_TYPE_FIXEDARRAY:
! 1134: {
! 1135: const struct structs_type *const etype = type->args[0].v;
! 1136: const char *elem_name = type->args[1].s;
! 1137: const u_int length = type->args[2].i;
! 1138: u_int i;
! 1139:
! 1140: /* Opening tag */
! 1141: structs_xml_output_openelem(fp, depth, tag, attrs);
! 1142: fprintf(fp, "\n");
! 1143:
! 1144: /* All array elements must be shown to keep proper ordering */
! 1145: flags |= STRUCTS_XML_SHOWONE;
! 1146:
! 1147: /* Do elements in order */
! 1148: for (i = 0; i < length; i++) {
! 1149: char *sposn;
! 1150:
! 1151: /* Generate new position tag */
! 1152: ASPRINTF(OUTPUT_MEM_TYPE, &sposn, "%s%s%u",
! 1153: posn, *posn != '\0' ? separator_string : "", i);
! 1154: if (sposn == NULL)
! 1155: return (-1);
! 1156: pthread_cleanup_push(structs_xml_output_cleanup, sposn);
! 1157:
! 1158: /* Output array element */
! 1159: r = structs_xml_output_sub(etype, (char *)data
! 1160: + (i * etype->size), elem_name, NULL, fp, elems,
! 1161: sposn, flags, depth + 1);
! 1162:
! 1163: /* Free position tag */
! 1164: pthread_cleanup_pop(1);
! 1165:
! 1166: /* Bail out if there was an error */
! 1167: if (r == -1)
! 1168: break;
! 1169: }
! 1170:
! 1171: /* Closing tag */
! 1172: structs_xml_output_prefix(fp, depth);
! 1173: fprintf(fp, "</%s>\n", tag);
! 1174: break;
! 1175: }
! 1176:
! 1177: case STRUCTS_TYPE_PRIMITIVE:
! 1178: {
! 1179: char *ascii;
! 1180:
! 1181: /* Get ascii string */
! 1182: if ((ascii = (*type->ascify)(type,
! 1183: OUTPUT_MEM_TYPE, data)) == NULL)
! 1184: return (-1);
! 1185:
! 1186: /* Push cleanup hook to handle cancellation */
! 1187: pthread_cleanup_push(structs_xml_output_cleanup, ascii);
! 1188:
! 1189: /* Output element */
! 1190: structs_xml_output_openelem(fp, depth, tag, attrs);
! 1191: structs_xml_encode(fp, ascii);
! 1192: fprintf(fp, "</%s>\n", tag);
! 1193:
! 1194: /* Free ascii string */
! 1195: pthread_cleanup_pop(1);
! 1196: break;
! 1197: }
! 1198:
! 1199: default:
! 1200: assert(0);
! 1201: }
! 1202: return (r);
! 1203: }
! 1204:
! 1205: /*
! 1206: * Cleanup for structs_xml_output_sub()
! 1207: */
! 1208: static void
! 1209: structs_xml_output_cleanup(void *arg)
! 1210: {
! 1211: FREE(OUTPUT_MEM_TYPE, arg);
! 1212: }
! 1213:
! 1214: /*
! 1215: * Output opening element tag with optional attributes
! 1216: */
! 1217: static void
! 1218: structs_xml_output_openelem(FILE *fp,
! 1219: int depth, const char *tag, const char *attrs)
! 1220: {
! 1221: structs_xml_output_prefix(fp, depth);
! 1222: fprintf(fp, "<%s", tag);
! 1223: if (attrs != NULL) {
! 1224: while (*attrs != '\0') {
! 1225: fprintf(fp, " ");
! 1226: structs_xml_encode(fp, attrs);
! 1227: attrs += strlen(attrs) + 1;
! 1228: fprintf(fp, "=\"");
! 1229: structs_xml_encode(fp, attrs);
! 1230: attrs += strlen(attrs) + 1;
! 1231: fprintf(fp, "\"");
! 1232: }
! 1233: }
! 1234: fprintf(fp, ">");
! 1235: }
! 1236:
! 1237: /*********************************************************************
! 1238: UTILITY STUFF
! 1239: *********************************************************************/
! 1240:
! 1241: /*
! 1242: * Output whitespace prefix
! 1243: */
! 1244: static void
! 1245: structs_xml_output_prefix(FILE *fp, int depth)
! 1246: {
! 1247: while (depth >= 2) {
! 1248: putc('\t', fp);
! 1249: depth -= 2;
! 1250: }
! 1251: if (depth > 0) {
! 1252: fputs(" ", fp);
! 1253: }
! 1254: }
! 1255:
! 1256: /*
! 1257: * Output text XML-encoded
! 1258: */
! 1259: static void
! 1260: structs_xml_encode(FILE *fp, const char *s)
! 1261: {
! 1262: for ( ; *s != '\0'; s++) {
! 1263: switch (*s) {
! 1264: case '<':
! 1265: fprintf(fp, "<");
! 1266: break;
! 1267: case '>':
! 1268: fprintf(fp, ">");
! 1269: break;
! 1270: case '"':
! 1271: fprintf(fp, """);
! 1272: break;
! 1273: case '&':
! 1274: fprintf(fp, "&");
! 1275: break;
! 1276: break;
! 1277: default:
! 1278: if (!isprint(*s)) {
! 1279: fprintf(fp, "&#%d;", (u_char)*s);
! 1280: break;
! 1281: }
! 1282: /* fall through */
! 1283: case '\n':
! 1284: case '\t':
! 1285: putc(*s, fp);
! 1286: break;
! 1287: }
! 1288: }
! 1289: }
! 1290:
! 1291: /*********************************************************************
! 1292: BUILT-IN LOGGERS
! 1293: *********************************************************************/
! 1294:
! 1295: static void
! 1296: structs_xml_null_logger(int sev, const char *fmt, ...)
! 1297: {
! 1298: }
! 1299:
! 1300: static void
! 1301: structs_xml_stderr_logger(int sev, const char *fmt, ...)
! 1302: {
! 1303: static const char *const sevs[] = {
! 1304: "emerg", "alert", "crit", "err",
! 1305: "warning", "notice", "info", "debug"
! 1306: };
! 1307: static const int num_sevs = sizeof(sevs) / sizeof(*sevs);
! 1308: va_list args;
! 1309:
! 1310: va_start(args, fmt);
! 1311: if (sev < 0)
! 1312: sev = 0;
! 1313: if (sev >= num_sevs)
! 1314: sev = num_sevs - 1;
! 1315: fprintf(stderr, "%s: ", sevs[sev]);
! 1316: vfprintf(stderr, fmt, args);
! 1317: fprintf(stderr, "\n");
! 1318: va_end(args);
! 1319: }
! 1320:
! 1321: static void
! 1322: structs_xml_alog_logger(int sev, const char *fmt, ...)
! 1323: {
! 1324: va_list args;
! 1325:
! 1326: va_start(args, fmt);
! 1327: valog(sev, fmt, args);
! 1328: va_end(args);
! 1329: }
! 1330:
! 1331: /*********************************************************************
! 1332: MEMORY WRAPPERS
! 1333: *********************************************************************/
! 1334:
! 1335: #define EXPAT_MEM_TYPE "structs_xml_input.expat"
! 1336:
! 1337: static void *
! 1338: structs_xml_malloc(size_t size)
! 1339: {
! 1340: return (MALLOC(EXPAT_MEM_TYPE, size));
! 1341: }
! 1342:
! 1343: static void *
! 1344: structs_xml_realloc(void *ptr, size_t size)
! 1345: {
! 1346: return (REALLOC(EXPAT_MEM_TYPE, ptr, size));
! 1347: }
! 1348:
! 1349: static void
! 1350: structs_xml_free(void *ptr)
! 1351: {
! 1352: FREE(EXPAT_MEM_TYPE, ptr);
! 1353: }
! 1354:
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>