From daa3fc2b78cc47c583bc6526a47bfb2b8d010a0c Mon Sep 17 00:00:00 2001 From: Michael R Sweet Date: Wed, 4 Jun 2003 02:34:30 +0000 Subject: [PATCH] Whitespace using newlines when possible... --- CHANGES | 2 + mxml-file.c | 288 ++++++++++++++++++++++++++++++++++++---------------- mxml.h | 5 +- 3 files changed, 205 insertions(+), 90 deletions(-) diff --git a/CHANGES b/CHANGES index 9950adc..3006f21 100644 --- a/CHANGES +++ b/CHANGES @@ -7,6 +7,8 @@ CHANGES IN Mini-XML 0.93 - mxmlLoadFile() now correctly handles comments. - mxmlLoadFile() now supports the "gt" and "nbsp" character entities. + - mxmlSaveFile() now uses newlines as whitespace + when valid to do so. CHANGES IN Mini-XML 0.92 diff --git a/mxml-file.c b/mxml-file.c index 5c8d968..aed38e3 100644 --- a/mxml-file.c +++ b/mxml-file.c @@ -1,5 +1,5 @@ /* - * "$Id: mxml-file.c,v 1.4 2003/06/04 01:26:34 mike Exp $" + * "$Id: mxml-file.c,v 1.5 2003/06/04 02:34:29 mike Exp $" * * File loading code for mini-XML, a small XML-like file parsing library. * @@ -20,6 +20,7 @@ * mxmlLoadFile() - Load a file into an XML node tree. * mxmlSaveFile() - Save an XML tree to a file. * mxml_parse_element() - Parse an element for any attributes... + * mxml_write_node() - Save an XML node to a file. * mxml_write_string() - Write a string, escaping & and < as needed. */ @@ -35,6 +36,7 @@ */ static int mxml_parse_element(mxml_node_t *node, FILE *fp); +static int mxml_write_node(mxml_node_t *node, FILE *fp, int col); static int mxml_write_string(const char *s, FILE *fp); @@ -79,12 +81,11 @@ mxmlLoadFile(mxml_node_t *top, /* I - Top node */ */ *bufptr = '\0'; - bufptr = buffer; switch (type) { case MXML_INTEGER : - node = mxmlNewInteger(parent, strtol(buffer, NULL, 0)); + node = mxmlNewInteger(parent, strtol(buffer, &bufptr, 0)); break; case MXML_OPAQUE : @@ -92,7 +93,7 @@ mxmlLoadFile(mxml_node_t *top, /* I - Top node */ break; case MXML_REAL : - node = mxmlNewReal(parent, strtod(buffer, NULL)); + node = mxmlNewReal(parent, strtod(buffer, &bufptr)); break; case MXML_TEXT : @@ -104,7 +105,20 @@ mxmlLoadFile(mxml_node_t *top, /* I - Top node */ break; } - whitespace = isspace(ch) != 0; + if (*bufptr) + { + /* + * Bad integer/real number value... + */ + + fprintf(stderr, "Bad %s value '%s' in parent <%s>!\n", + type == MXML_INTEGER ? "integer" : "real", buffer, + parent ? parent->value.element.name : "null"); + break; + } + + bufptr = buffer; + whitespace = isspace(ch) && type == MXML_TEXT; if (!node) { @@ -393,90 +407,15 @@ int /* O - 0 on success, -1 on error */ mxmlSaveFile(mxml_node_t *node, /* I - Node to write */ FILE *fp) /* I - File to write to */ { - int i; /* Looping var */ - - - while (node != NULL) - { - /* - * Print the node value... - */ - - switch (node->type) - { - case MXML_ELEMENT : - if (fprintf(fp, "<%s", node->value.element.name) < 0) - return (-1); - - for (i = 0; i < node->value.element.num_attrs; i ++) - if (fprintf(fp, " %s=\"%s\"", node->value.element.attrs[i].name, - node->value.element.attrs[i].value) < 0) - return (-1); - - if (node->child) - { - /* - * The ?xml element is a special-case and has no end tag... - */ - - if (node->value.element.name[0] == '?') - { - if (fputs("?>\n", fp) < 0) - return (-1); - } - else if (putc('>', fp) < 0) - return (-1); - - if (mxmlSaveFile(node->child, fp) < 0) - return (-1); - - if (node->value.element.name[0] != '?') - if (fprintf(fp, "", node->value.element.name) < 0) - return (-1); - } - else if (fputs("/>", fp) < 0) - return (-1); - break; - - case MXML_INTEGER : - if (node->prev) - if (putc(' ', fp) < 0) - return (-1); - - if (fprintf(fp, "%d", node->value.integer) < 0) - return (-1); - break; - - case MXML_OPAQUE : - if (mxml_write_string(node->value.opaque, fp) < 0) - return (-1); - break; - - case MXML_REAL : - if (node->prev) - if (putc(' ', fp) < 0) - return (-1); - - if (fprintf(fp, "%f", node->value.real) < 0) - return (-1); - break; - - case MXML_TEXT : - if (node->value.text.whitespace) - if (putc(' ', fp) < 0) - return (-1); - - if (mxml_write_string(node->value.text.string, fp) < 0) - return (-1); - break; - } + /* + * Write the node... + */ - /* - * Next node... - */ + if (mxml_write_node(node, fp, 0) < 0) + return (-1); - node = node->next; - } + if (putc('\n', fp) < 0) + return (-1); /* * Return 0 (success)... @@ -640,6 +579,179 @@ mxml_parse_element(mxml_node_t *node, /* I - Element node */ } +/* + * 'mxml_write_node()' - Save an XML node to a file. + */ + +static int /* O - Column or -1 on error */ +mxml_write_node(mxml_node_t *node, /* I - Node to write */ + FILE *fp, /* I - File to write to */ + int col) /* I - Current column */ +{ + int i; /* Looping var */ + int n; /* Chars written */ + mxml_attr_t *attr; /* Current attribute */ + + + while (node != NULL) + { + /* + * Print the node value... + */ + + switch (node->type) + { + case MXML_ELEMENT : + if ((n = fprintf(fp, "<%s", node->value.element.name)) < 0) + return (-1); + + col += n; + + for (i = node->value.element.num_attrs, attr = node->value.element.attrs; + i > 0; + i --, attr ++) + { + if ((col + strlen(attr->name) + strlen(attr->value) + 3) > MXML_WRAP) + { + if (putc('\n', fp) < 0) + return (-1); + + col = 0; + } + else + { + if (putc(' ', fp) < 0) + return (-1); + + col ++; + } + + if ((n = fprintf(fp, "%s=\"%s\"", attr->name, attr->value)) < 0) + return (-1); + + col += n; + } + + if (node->child) + { + /* + * The ?xml element is a special-case and has no end tag... + */ + + if (node->value.element.name[0] == '?') + { + if (fputs("?>\n", fp) < 0) + return (-1); + + col = 0; + } + else if (putc('>', fp) < 0) + return (-1); + else + col ++; + + if ((col = mxml_write_node(node->child, fp, col)) < 0) + return (-1); + + if (node->value.element.name[0] != '?') + { + if ((n = fprintf(fp, "", node->value.element.name)) < 0) + return (-1); + + col += n; + } + } + else if (fputs("/>", fp) < 0) + return (-1); + else + col += 2; + break; + + case MXML_INTEGER : + if (node->prev) + { + if (col > MXML_WRAP) + { + if (putc('\n', fp) < 0) + return (-1); + + col = 0; + } + else if (putc(' ', fp) < 0) + return (-1); + else + col ++; + } + + if ((n = fprintf(fp, "%d", node->value.integer)) < 0) + return (-1); + + col += n; + break; + + case MXML_OPAQUE : + if (mxml_write_string(node->value.opaque, fp) < 0) + return (-1); + + col += strlen(node->value.opaque); + break; + + case MXML_REAL : + if (node->prev) + { + if (col > MXML_WRAP) + { + if (putc('\n', fp) < 0) + return (-1); + + col = 0; + } + else if (putc(' ', fp) < 0) + return (-1); + else + col ++; + } + + if ((n = fprintf(fp, "%f", node->value.real)) < 0) + return (-1); + + col += n; + break; + + case MXML_TEXT : + if (node->value.text.whitespace) + { + if (col > MXML_WRAP) + { + if (putc('\n', fp) < 0) + return (-1); + + col = 0; + } + else if (putc(' ', fp) < 0) + return (-1); + else + col ++; + } + + if (mxml_write_string(node->value.text.string, fp) < 0) + return (-1); + + col += strlen(node->value.text.string); + break; + } + + /* + * Next node... + */ + + node = node->next; + } + + return (col); +} + + /* * 'mxml_write_string()' - Write a string, escaping & and < as needed. */ @@ -672,5 +784,5 @@ mxml_write_string(const char *s, /* I - String to write */ /* - * End of "$Id: mxml-file.c,v 1.4 2003/06/04 01:26:34 mike Exp $". + * End of "$Id: mxml-file.c,v 1.5 2003/06/04 02:34:29 mike Exp $". */ diff --git a/mxml.h b/mxml.h index 3e8547b..0d2d1d4 100644 --- a/mxml.h +++ b/mxml.h @@ -1,5 +1,5 @@ /* - * "$Id: mxml.h,v 1.3 2003/06/04 00:30:04 mike Exp $" + * "$Id: mxml.h,v 1.4 2003/06/04 02:34:30 mike Exp $" * * Header file for mini-XML, a small XML-like file parsing library. * @@ -38,6 +38,7 @@ */ # define MXML_NO_CALLBACK (mxml_type_t (*)(mxml_node_t *))0 +# define MXML_WRAP 72 /* @@ -133,5 +134,5 @@ extern mxml_node_t *mxmlWalkPrev(mxml_node_t *node, mxml_node_t *top); /* - * End of "$Id: mxml.h,v 1.3 2003/06/04 00:30:04 mike Exp $". + * End of "$Id: mxml.h,v 1.4 2003/06/04 02:34:30 mike Exp $". */