LCOV - code coverage report
Current view: top level - mxml - mxml.cxx (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 1237 0
Test Date: 2025-11-11 10:26:08 Functions: 0.0 % 64 0

            Line data    Source code
       1              : /********************************************************************\
       2              : 
       3              :    Name:         mxml.c
       4              :    Created by:   Stefan Ritt
       5              :    Copyright 2000 + Stefan Ritt
       6              : 
       7              :    Contents:     Midas XML Library
       8              : 
       9              :    This is a simple implementation of XML functions for writing and
      10              :    reading XML files. For writing an XML file from scratch, following
      11              :    functions can be used:
      12              : 
      13              :    writer = mxml_open_file(file_name);
      14              :      mxml_start_element(writer, name);
      15              :      mxml_write_attribute(writer, name, value);
      16              :      mxml_write_value(writer, value);
      17              :      mxml_end_element(writer); 
      18              :      ...
      19              :    mxml_close_file(writer);
      20              : 
      21              :    To read an XML file, the function
      22              : 
      23              :    tree = mxml_parse_file(file_name, error, sizeof(error));
      24              : 
      25              :    is used. It parses the complete XML file and stores it in a
      26              :    hierarchical tree in memory. Nodes in that tree can be searched
      27              :    for with
      28              : 
      29              :    mxml_find_node(tree, xml_path);
      30              : 
      31              :    or
      32              : 
      33              :    mxml_find_nodes(tree, xml_path, &nodelist);
      34              : 
      35              :    which support a subset of the XPath specification. Another set of
      36              :    functions is available to retrieve attributes and values from nodes
      37              :    in the tree and for manipulating nodes, like replacing, adding and
      38              :    deleting nodes.
      39              :    
      40              :    
      41              :    This file is part of MIDAS XML Library.
      42              : 
      43              :    MIDAS XML Library is free software: you can redistribute it and/or modify
      44              :    it under the terms of the GNU General Public License as published by
      45              :    the Free Software Foundation, either version 2 of the License, or
      46              :    (at your option) any later version.
      47              : 
      48              :    MIDAS XML Library is distributed in the hope that it will be useful,
      49              :    but WITHOUT ANY WARRANTY; without even the implied warranty of
      50              :    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      51              :    GNU General Public License for more details.
      52              : 
      53              :    You should have received a copy of the GNU General Public License
      54              :    along with MIDAS XML Library.  If not, see <http://www.gnu.org/licenses/>.
      55              : 
      56              : \********************************************************************/
      57              : 
      58              : #include <stdio.h>
      59              : #include <fcntl.h>
      60              : #include <string.h>
      61              : #include <assert.h>
      62              : 
      63              : #include <string>
      64              : 
      65              : #ifdef _MSC_VER
      66              : 
      67              : #include <windows.h>
      68              : #include <io.h>
      69              : #include <time.h>
      70              : 
      71              : #pragma warning( disable: 4996) /* disable "deprecated" warning */
      72              : 
      73              : #else
      74              : 
      75              : #define TRUE 1
      76              : #define FALSE 0
      77              : 
      78              : #ifndef O_TEXT
      79              : #define O_TEXT 0
      80              : #define O_BINARY 0
      81              : #endif
      82              : 
      83              : #include <stdlib.h>
      84              : #include <unistd.h>
      85              : #include <ctype.h>
      86              : #include <stdarg.h>
      87              : #include <errno.h>
      88              : #ifndef OS_VXWORKS
      89              : #include <sys/time.h>
      90              : #endif
      91              : #include <time.h>
      92              : 
      93              : #endif
      94              : 
      95              : #include "mxml.h"
      96              : 
      97              : #define XML_INDENT "  "
      98              : 
      99              : #if defined(__GNUC__) && !defined(__MAKECINT__)
     100              : #   define MXML_GNUC_PRINTF( format_idx, arg_idx )          \
     101              :    __attribute__((format (printf, format_idx, arg_idx)))
     102              : #   define MXML_GNUC_SCANF( format_idx, arg_idx )           \
     103              :    __attribute__((format (scanf, format_idx, arg_idx)))
     104              : #   define MXML_GNUC_FORMAT( arg_idx )                      \
     105              :    __attribute__((format_arg (arg_idx)))
     106              : #else
     107              : #   define MXML_GNUC_PRINTF( format_idx, arg_idx )
     108              : #   define MXML_GNUC_SCANF( format_idx, arg_idx )
     109              : #   define MXML_GNUC_FORMAT( arg_idx )
     110              : #endif
     111              : 
     112              : static int mxml_suppress_date_flag = 0; /* suppress writing date at the top of file. */
     113              : 
     114              : /* local prototypes */
     115              : static PMXML_NODE read_error(PMXML_NODE root, const char *file_name, int line_number, char *error, int error_size, int *error_line, const char *format, ...) MXML_GNUC_PRINTF(7, 8);
     116              : static void mxml_encode(char* buf, int buf_size, const char *src, int src_len, int translate);
     117              : static void mxml_decode(char *str);
     118              : static int mxml_write_subtree(MXML_WRITER *writer, PMXML_NODE tree, int indent);
     119              : static int mxml_write_line(MXML_WRITER *writer, const char *line);
     120              : static int mxml_start_element1(MXML_WRITER *writer, const char *name, int indent);
     121              : static int mxml_add_resultnode(PMXML_NODE node, const char *xml_path, PMXML_NODE **nodelist, int *found);
     122              : static int mxml_find_nodes1(PMXML_NODE tree, const char *xml_path, PMXML_NODE **nodelist, int *found);
     123              : static void *mxml_malloc(size_t size);
     124              : static void *mxml_realloc(void *p, size_t size);
     125              : static void mxml_free(void *p);
     126              : 
     127              : /*
     128              : * Copy src to string dst of size siz.  At most siz-1 characters
     129              : * will be copied.  Always NUL terminates (unless size == 0).
     130              : * Returns strlen(src); if retval >= siz, truncation occurred.
     131              : */
     132              : 
     133            0 : static size_t mxml_strlcpy(char *dst, const char *src, size_t size)
     134              : {
     135            0 :    char *d = dst;
     136            0 :    const char *s = src;
     137            0 :    size_t n = size;
     138              : 
     139              :    /* Copy as many bytes as will fit */
     140            0 :    if (n != 0 && --n != 0) {
     141              :       do {
     142            0 :          if ((*d++ = *s++) == 0)
     143            0 :             break;
     144            0 :       } while (--n != 0);
     145              :    }
     146              : 
     147              :    /* Not enough room in dst, add NUL and traverse rest of src */
     148            0 :    if (n == 0) {
     149            0 :       if (size != 0)
     150            0 :          *d = '\0';             /* NUL-terminate dst */
     151            0 :       while (*s++);
     152              :    }
     153              : 
     154            0 :    return (s - src - 1);        /* count does not include NUL */
     155              : }
     156              : 
     157              : /*------------------------------------------------------------------*/
     158              : 
     159            0 : static std::string toString(int i)
     160              : {
     161              :    char buf[100];
     162            0 :    snprintf(buf, sizeof(buf), "%d", i);
     163            0 :    return buf;
     164              : }
     165              : 
     166              : /*------------------------------------------------------------------*/
     167              : 
     168            0 : static std::string toStrerror(int err)
     169              : {
     170              :    char buf[256];
     171            0 :    snprintf(buf, sizeof(buf), "errno %d (%s)", err, strerror(err));
     172            0 :    return buf;
     173              : }
     174              : 
     175              : /*------------------------------------------------------------------*/
     176              : 
     177            0 : void *mxml_malloc(size_t size)
     178              : {
     179            0 :    return malloc(size);
     180              : }
     181              : 
     182              : /*------------------------------------------------------------------*/
     183              : 
     184            0 : void *mxml_realloc(void *p, size_t size)
     185              : {
     186            0 :    return realloc(p, size);
     187              : }
     188              : 
     189              : /*------------------------------------------------------------------*/
     190              : 
     191            0 : void mxml_free(void *p)
     192              : {
     193            0 :    free(p);
     194            0 : }
     195              : 
     196              : /*------------------------------------------------------------------*/
     197              : 
     198            0 : int mxml_write_line(MXML_WRITER *writer, const char *line)
     199              : {
     200            0 :    int len = strlen(line);
     201              : 
     202            0 :    if (writer->buffer) {
     203            0 :       if (writer->buffer_len + len >= writer->buffer_size) {
     204            0 :          writer->buffer_size += len + 10000;
     205            0 :          writer->buffer = (char *)mxml_realloc(writer->buffer, writer->buffer_size);
     206            0 :          assert(writer->buffer);
     207              :       }
     208            0 :       memcpy(writer->buffer + writer->buffer_len, line, len+1);
     209            0 :       writer->buffer_len += len;
     210            0 :       return len;
     211              :    } else {
     212            0 :       return (int)write(writer->fh, line, len);
     213              :    }
     214              : 
     215              :    return 0;
     216              : }
     217              : 
     218              : /*------------------------------------------------------------------*/
     219              : 
     220              : /**
     221              :  * open a memory buffer and write XML header
     222              :  */
     223            0 : MXML_WRITER *mxml_open_buffer(void)
     224              : {
     225            0 :    MXML_WRITER *writer = (MXML_WRITER *)mxml_malloc(sizeof(MXML_WRITER));
     226            0 :    memset(writer, 0, sizeof(MXML_WRITER));
     227            0 :    writer->translate = 1;
     228              : 
     229            0 :    writer->buffer_size = 10000;
     230            0 :    writer->buffer = (char *)mxml_malloc(writer->buffer_size);
     231            0 :    assert(writer->buffer != NULL);
     232            0 :    writer->buffer[0] = 0;
     233            0 :    writer->buffer_len = 0;
     234              : 
     235              :    /* write XML header */
     236            0 :    mxml_write_line(writer, "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n");
     237              : 
     238            0 :    if (mxml_suppress_date_flag == 0) {
     239            0 :       time_t now = time(NULL);
     240            0 :       std::string str = ctime(&now);
     241            0 :       str.resize(24);
     242            0 :       std::string line = "";
     243            0 :       line +=  "<!-- created by MXML on ";
     244            0 :       line += str;
     245            0 :       line += " -->\n";
     246            0 :       mxml_write_line(writer, line.c_str());
     247            0 :    }
     248              : 
     249              :    /* initialize stack */
     250            0 :    writer->level = 0;
     251            0 :    writer->element_is_open = 0;
     252              : 
     253            0 :    return writer;
     254              : }
     255              : 
     256              : /*------------------------------------------------------------------*/
     257              : 
     258              : /**
     259              :  * suppress writing date at the top of file.
     260              :  */
     261            0 : void mxml_suppress_date(int suppress)
     262              : {
     263            0 :    mxml_suppress_date_flag = suppress;
     264            0 : }
     265              : 
     266              : /*------------------------------------------------------------------*/
     267              : 
     268              : /**
     269              :  * open a file and write XML header
     270              :  */
     271            0 : MXML_WRITER *mxml_open_file(const char *file_name) 
     272              : {
     273            0 :    MXML_WRITER* writer = (MXML_WRITER *)mxml_malloc(sizeof(MXML_WRITER));
     274            0 :    memset(writer, 0, sizeof(MXML_WRITER));
     275            0 :    writer->translate = 1;
     276              : 
     277            0 :    writer->fh = open(file_name, O_RDWR | O_CREAT | O_TRUNC | O_TEXT, 0644);
     278              : 
     279            0 :    if (writer->fh == -1) {
     280            0 :       std::string line = "";
     281            0 :       line += "Unable to open file \"";
     282            0 :       line += file_name;
     283            0 :       line += "\": ";
     284            0 :       line += toStrerror(errno);
     285            0 :       fprintf(stderr, "%s\n", line.c_str());
     286            0 :       mxml_free(writer);
     287            0 :       return NULL;
     288            0 :    }
     289              : 
     290              :    /* write XML header */
     291            0 :    mxml_write_line(writer, "<?xml version=\"1.0\" encoding=\"ISO-8859-1\"?>\n");
     292            0 :    if (mxml_suppress_date_flag == 0) {
     293            0 :       time_t now = time(NULL);
     294            0 :       std::string str = ctime(&now);
     295            0 :       str.resize(24);
     296            0 :       std::string line = "";
     297            0 :       line += "<!-- created by MXML on ";
     298            0 :       line += str;
     299            0 :       line += " -->\n";
     300            0 :       mxml_write_line(writer, line.c_str());
     301            0 :    }
     302              : 
     303              :    /* initialize stack */
     304            0 :    writer->level = 0;
     305            0 :    writer->element_is_open = 0;
     306              : 
     307            0 :    return writer;
     308              : }
     309              : 
     310              : /*------------------------------------------------------------------*/
     311              : 
     312              : /**
     313              :  * convert '<' '>' '&' '"' ''' into &xx;
     314              :  */
     315            0 : void mxml_encode(char* buf, int buf_size, const char *src, int src_len, int translate)
     316              : {
     317            0 :    if (buf_size <= 6*src_len) {
     318            0 :       printf("mxml_encode: buffer size too small\n");
     319            0 :       exit(0);
     320              :    }
     321            0 :    char *pd = buf;
     322              :    const char* ps;
     323            0 :    for (ps = src ; *ps ; ps++) {
     324              : 
     325            0 :      if (translate) { /* tranlate "<", ">", "&", """, "'" */
     326            0 :          switch (*ps) {
     327            0 :          case '<':
     328            0 :             strcpy(pd, "&lt;");
     329            0 :             pd += 4;
     330            0 :             break;
     331            0 :          case '>':
     332            0 :             strcpy(pd, "&gt;");
     333            0 :             pd += 4;
     334            0 :             break;
     335            0 :          case '&':
     336            0 :             strcpy(pd, "&amp;");
     337            0 :             pd += 5;
     338            0 :             break;
     339            0 :          case '\"':
     340            0 :             strcpy(pd, "&quot;");
     341            0 :             pd += 6;
     342            0 :             break;
     343            0 :          case '\'':
     344            0 :             strcpy(pd, "&apos;");
     345            0 :             pd += 6;
     346            0 :             break;
     347            0 :          default:
     348            0 :             *pd++ = *ps;
     349              :          }
     350              :       } else {
     351            0 :        switch (*ps) { /* translate only special XML characters "<" and "&" */
     352            0 :          case '<':
     353            0 :             strcpy(pd, "&lt;");
     354            0 :             pd += 4;
     355            0 :             break;
     356            0 :          case '&':
     357            0 :             strcpy(pd, "&amp;");
     358            0 :             pd += 5;
     359            0 :             break;
     360            0 :          default:
     361            0 :             *pd++ = *ps;
     362              :          }
     363              :       }
     364              :    }
     365            0 :    *pd = 0;
     366              : 
     367              :    //printf("mxml_encode: size %d, in %d, out %d, [%s] -> [%s]\n", buf_size, src_len, (int)strlen(buf), src, buf);
     368            0 : }
     369              : 
     370              : /*------------------------------------------------------------------*/
     371              : 
     372              : /**
     373              :  * reverse of mxml_encode, strip leading or trailing '"'
     374              :  */
     375            0 : void mxml_decode(char *str)
     376              : {
     377              :    char *p;
     378              : 
     379            0 :    p = str;
     380            0 :    while ((p = strchr(p, '&')) != NULL) {
     381            0 :       if (strncmp(p, "&lt;", 4) == 0) {
     382            0 :          *(p++) = '<';
     383            0 :          memmove(p, p+3, strlen(p+3) + 1);
     384              :       }
     385            0 :       else if (strncmp(p, "&gt;", 4) == 0) {
     386            0 :          *(p++) = '>';
     387            0 :          memmove(p, p+3, strlen(p+3) + 1);
     388              :       }
     389            0 :       else if (strncmp(p, "&amp;", 5) == 0) {
     390            0 :          *(p++) = '&';
     391            0 :          memmove(p, p+4, strlen(p+4) + 1);
     392              :       }
     393            0 :       else if (strncmp(p, "&quot;", 6) == 0) {
     394            0 :          *(p++) = '\"';
     395            0 :          memmove(p, p+5, strlen(p+5) + 1);
     396              :       }
     397            0 :       else if (strncmp(p, "&apos;", 6) == 0) {
     398            0 :          *(p++) = '\'';
     399            0 :          memmove(p, p+5, strlen(p+5) + 1);
     400              :       }
     401              :       else {
     402            0 :          p++; // skip unknown entity
     403              :       }
     404              :    }
     405              : /*   if (str[0] == '\"' && str[strlen(str)-1] == '\"') {
     406              :       memmove(str, str+1, strlen(str+1) + 1);
     407              :       str[strlen(str)-1] = 0;
     408              :    }*/
     409            0 : }
     410              : 
     411              : /*------------------------------------------------------------------*/
     412              : 
     413              : /**
     414              :  * set translation of <,>,",',&, on/off in writer
     415              :  */
     416            0 : int mxml_set_translate(MXML_WRITER *writer, int flag)
     417              : {
     418              :    int old_flag;
     419              : 
     420            0 :    old_flag = writer->translate;
     421            0 :    writer->translate = flag;
     422            0 :    return old_flag;
     423              : }
     424              : /*------------------------------------------------------------------*/
     425              : 
     426              : /**
     427              :  * start a new XML element, must be followed by mxml_end_elemnt
     428              :  */
     429            0 : int mxml_start_element1(MXML_WRITER *writer, const char *name, int indent)
     430              : {
     431              :    int i;
     432              : 
     433            0 :    if (writer->element_is_open) {
     434            0 :       mxml_write_line(writer, ">\n");
     435            0 :       writer->element_is_open = FALSE;
     436              :    }
     437              : 
     438            0 :    std::string line = "";
     439            0 :    if (indent)
     440            0 :       for (i=0 ; i<writer->level ; i++)
     441            0 :          line += XML_INDENT;
     442            0 :    line += "<";
     443              : 
     444            0 :    unsigned len = strlen(name);
     445            0 :    unsigned name_enc_size = len*6+10;
     446            0 :    char* name_enc = (char*)mxml_malloc(name_enc_size);
     447            0 :    mxml_encode(name_enc, name_enc_size, name, strlen(name), writer->translate);
     448            0 :    line += name_enc;
     449              : 
     450              :    /* put element on stack */
     451            0 :    if (writer->level == 0)
     452            0 :       writer->stack = (char **)mxml_malloc(sizeof(char *));
     453              :    else
     454            0 :       writer->stack = (char **)mxml_realloc(writer->stack, sizeof(char *)*(writer->level+1));
     455              :    
     456            0 :    writer->stack[writer->level] = name_enc;
     457            0 :    writer->level++;
     458            0 :    writer->element_is_open = TRUE;
     459            0 :    writer->data_was_written = FALSE;
     460              : 
     461            0 :    return mxml_write_line(writer, line.c_str()) == (int)line.length();
     462            0 : }
     463              : 
     464              : /*------------------------------------------------------------------*/
     465              : 
     466            0 : int mxml_start_element(MXML_WRITER *writer, const char *name)
     467              : {
     468            0 :    return mxml_start_element1(writer, name, TRUE);
     469              : }
     470              : 
     471              : /*------------------------------------------------------------------*/
     472              : 
     473            0 : int mxml_start_element_noindent(MXML_WRITER *writer, const char *name)
     474              : {
     475            0 :    return mxml_start_element1(writer, name, FALSE);
     476              : }
     477              : 
     478              : /*------------------------------------------------------------------*/
     479              : 
     480              : /**
     481              :  * close an open XML element
     482              :  */
     483            0 : int mxml_end_element(MXML_WRITER *writer)
     484              : {
     485              :    int i;
     486              : 
     487            0 :    if (writer->level == 0)
     488            0 :       return 0;
     489              :    
     490            0 :    writer->level--;
     491              : 
     492            0 :    if (writer->element_is_open) {
     493            0 :       writer->element_is_open = FALSE;
     494            0 :       mxml_free(writer->stack[writer->level]);
     495            0 :       if (writer->level == 0)
     496            0 :          mxml_free(writer->stack);
     497            0 :       const char* line = "/>\n";
     498            0 :       return mxml_write_line(writer, line) == (int)strlen(line);
     499              :    }
     500              : 
     501            0 :    std::string line = "";
     502            0 :    if (!writer->data_was_written) {
     503            0 :       for (i=0 ; i<writer->level ; i++)
     504            0 :          line += XML_INDENT;
     505              :    }
     506              : 
     507            0 :    line += "</";
     508            0 :    line += writer->stack[writer->level];
     509            0 :    mxml_free(writer->stack[writer->level]);
     510            0 :    if (writer->level == 0)
     511            0 :       mxml_free(writer->stack);
     512            0 :    line += ">\n";
     513            0 :    writer->data_was_written = FALSE;
     514              : 
     515            0 :    return mxml_write_line(writer, line.c_str()) == (int)line.length();
     516            0 : }
     517              : 
     518              : /*------------------------------------------------------------------*/
     519              : 
     520              : /**
     521              :  * write an attribute to the currently open XML element
     522              :  */
     523            0 : int mxml_write_attribute(MXML_WRITER *writer, const char *name, const char *value)
     524              : {
     525              :    char buf[6*4096+10];
     526              : 
     527            0 :    if (!writer->element_is_open)
     528            0 :       return FALSE;
     529              : 
     530            0 :    std::string line = "";
     531            0 :    line += " ";
     532            0 :    mxml_encode(buf, sizeof(buf), name, strlen(name), writer->translate);
     533            0 :    line += buf;
     534            0 :    line += "=\"";
     535            0 :    mxml_encode(buf, sizeof(buf), value, strlen(value), writer->translate);
     536            0 :    line += buf;
     537            0 :    line += "\"";
     538              : 
     539            0 :    return mxml_write_line(writer, line.c_str()) == (int)line.length();
     540            0 : }
     541              : 
     542              : /*------------------------------------------------------------------*/
     543              : 
     544              : /**
     545              :  * write value of an XML element, like <[name]>[value]</[name]>
     546              :  */
     547            0 : int mxml_write_value(MXML_WRITER *writer, const char *data)
     548              : {
     549            0 :    if (!writer->element_is_open)
     550            0 :       return FALSE;
     551              : 
     552            0 :    if (mxml_write_line(writer, ">") != 1)
     553            0 :       return FALSE;
     554            0 :    writer->element_is_open = FALSE;
     555            0 :    writer->data_was_written = TRUE;
     556              : 
     557            0 :    unsigned len = strlen(data);
     558            0 :    unsigned size = 6*len + 1000;
     559            0 :    char* buf = (char*)mxml_malloc(size);
     560            0 :    memcpy(buf, data, len+1);
     561            0 :    mxml_encode(buf, size, data, len, writer->translate);
     562            0 :    int v = mxml_write_line(writer, buf) == (int)strlen(buf);
     563            0 :    mxml_free(buf);
     564            0 :    return v;
     565              : }
     566              : 
     567              : /*------------------------------------------------------------------*/
     568              : 
     569              : /**
     570              :  * write empty line
     571              :  */
     572            0 : int mxml_write_empty_line(MXML_WRITER *writer)
     573              : {
     574            0 :    if (writer->element_is_open) {
     575            0 :       mxml_write_line(writer, ">\n");
     576            0 :       writer->element_is_open = FALSE;
     577              :    }
     578              : 
     579            0 :    if (mxml_write_line(writer, "\n") != 1)
     580            0 :       return FALSE;
     581              : 
     582            0 :    return TRUE;
     583              : }
     584              : 
     585              : /*------------------------------------------------------------------*/
     586              : 
     587              : /**
     588              :  * write a comment to an XML file, enclosed in "<!--" and "-->"
     589              :  */
     590            0 : int mxml_write_comment(MXML_WRITER *writer, const char *string)
     591              : {
     592              :    int  i;
     593              : 
     594            0 :    if (writer->element_is_open) {
     595            0 :       mxml_write_line(writer, ">\n");
     596            0 :       writer->element_is_open = FALSE;
     597              :    }
     598              : 
     599            0 :    std::string line = "";
     600            0 :    for (i=0 ; i<writer->level ; i++)
     601            0 :       line += XML_INDENT;
     602              : 
     603            0 :    line += "<!-- ";
     604            0 :    line += string;
     605            0 :    line += " -->\n";
     606            0 :    if (mxml_write_line(writer, line.c_str()) != (int)line.length())
     607            0 :       return FALSE;
     608              : 
     609            0 :    return TRUE;
     610            0 : }
     611              : 
     612              : /*------------------------------------------------------------------*/
     613              : 
     614              : /**
     615              :  * shortcut to write an element with a value but without attribute
     616              :  */
     617            0 : int mxml_write_element(MXML_WRITER *writer, const char *name, const char *value)
     618              : {
     619              :    int i;
     620              : 
     621            0 :    i = mxml_start_element(writer, name);
     622            0 :    i += mxml_write_value(writer, value);
     623            0 :    i += mxml_end_element(writer);
     624            0 :    return i;
     625              : }
     626              : 
     627              : /*------------------------------------------------------------------*/
     628              : 
     629              : /**
     630              :  * close a file opened with mxml_open_writer
     631              :  */
     632            0 : char *mxml_close_buffer(MXML_WRITER *writer)
     633              : {
     634              :    int i;
     635              :    char *p;
     636              : 
     637            0 :    if (writer->element_is_open) {
     638            0 :       writer->element_is_open = FALSE;
     639            0 :       if (mxml_write_line(writer, ">\n") != 2)
     640            0 :          return NULL;
     641              :    }
     642              : 
     643              :    /* close remaining open levels */
     644            0 :    for (i = 0 ; i<writer->level ; i++)
     645            0 :       mxml_end_element(writer);
     646              : 
     647            0 :    p = writer->buffer;
     648            0 :    mxml_free(writer);
     649            0 :    return p;
     650              : }
     651              : 
     652              : /*------------------------------------------------------------------*/
     653              : 
     654              : /**
     655              :  * close a file opened with mxml_open_writer
     656              :  */
     657            0 : int mxml_close_file(MXML_WRITER *writer)
     658              : {
     659              :    int i;
     660              : 
     661            0 :    if (writer->element_is_open) {
     662            0 :       writer->element_is_open = FALSE;
     663            0 :       if (mxml_write_line(writer, ">\n") != 2)
     664            0 :          return 0;
     665              :    }
     666              : 
     667              :    /* close remaining open levels */
     668            0 :    for (i = 0 ; i<writer->level ; i++)
     669            0 :       mxml_end_element(writer);
     670              : 
     671            0 :    close(writer->fh);
     672            0 :    mxml_free(writer);
     673            0 :    return 1;
     674              : }
     675              : 
     676              : /*------------------------------------------------------------------*/
     677              : 
     678              : /**
     679              :  * create root node of an XML tree
     680              :  */
     681            0 : PMXML_NODE mxml_create_root_node(void)
     682              : {
     683              :    PMXML_NODE root;
     684              : 
     685            0 :    root = (PMXML_NODE)calloc(1, sizeof(MXML_NODE));
     686            0 :    strcpy(root->name, "root"); // SAFE
     687            0 :    root->node_type = DOCUMENT_NODE;
     688              : 
     689            0 :    return root;
     690              : }
     691              : 
     692              : /*------------------------------------------------------------------*/
     693              : 
     694              : /**
     695              :  * add a subnode (child) to an existing parent node as a specific position
     696              :  */
     697            0 : PMXML_NODE mxml_add_special_node_at(PMXML_NODE parent, int node_type, const char *node_name, const char *value, int idx)
     698              : {
     699              :    PMXML_NODE pnode, pchild;
     700              :    int i, j;
     701              : 
     702            0 :    assert(parent);
     703            0 :    if (parent->n_children == 0)
     704            0 :       parent->child = (PMXML_NODE)mxml_malloc(sizeof(MXML_NODE));
     705              :    else
     706            0 :       parent->child = (PMXML_NODE)mxml_realloc(parent->child, sizeof(MXML_NODE)*(parent->n_children+1));
     707            0 :    assert(parent->child);
     708              : 
     709              :    /* move following nodes one down */
     710            0 :    if (idx < parent->n_children) 
     711            0 :       for (i=parent->n_children ; i > idx ; i--)
     712            0 :          memcpy(&parent->child[i], &parent->child[i-1], sizeof(MXML_NODE));
     713              : 
     714              :    /* correct parent pointer for children */
     715            0 :    for (i=0 ; i<parent->n_children ; i++) {
     716            0 :       pchild = parent->child+i;
     717            0 :       for (j=0 ; j<pchild->n_children ; j++)
     718            0 :          pchild->child[j].parent = pchild;
     719              :    }
     720              : 
     721              :    /* initialize new node */
     722            0 :    pnode = &parent->child[idx];
     723            0 :    memset(pnode, 0, sizeof(MXML_NODE));
     724            0 :    mxml_strlcpy(pnode->name, node_name, sizeof(pnode->name));
     725            0 :    pnode->node_type = node_type;
     726            0 :    pnode->parent = parent;
     727              :    
     728            0 :    parent->n_children++;
     729              : 
     730            0 :    if (value && *value) {
     731            0 :       int len = strlen(value);
     732            0 :       pnode->value = (char *)mxml_malloc(len+1);
     733            0 :       assert(pnode->value);
     734            0 :       memcpy(pnode->value, value, len+1);
     735              :    }
     736              : 
     737            0 :    return pnode;
     738              : }
     739              : 
     740              : /*------------------------------------------------------------------*/
     741              : 
     742              : /**
     743              :  * add a subnode (child) to an existing parent node at the end
     744              :  */
     745            0 : PMXML_NODE mxml_add_special_node(PMXML_NODE parent, int node_type, const char *node_name, const char *value)
     746              : {
     747            0 :    return mxml_add_special_node_at(parent, node_type, node_name, value, parent->n_children);
     748              : }
     749              : 
     750              : /*------------------------------------------------------------------*/
     751              : 
     752              : /**
     753              :  * write value of an XML element, like <[name]>[value]</[name]>
     754              :  */
     755            0 : PMXML_NODE mxml_add_node(PMXML_NODE parent, const char *node_name, const char *value)
     756              : {
     757            0 :    return mxml_add_special_node_at(parent, ELEMENT_NODE, node_name, value, parent->n_children);
     758              : }
     759              : 
     760              : /*------------------------------------------------------------------*/
     761              : 
     762              : /**
     763              :  * add a subnode (child) to an existing parent node at the end
     764              :  */
     765            0 : PMXML_NODE mxml_add_node_at(PMXML_NODE parent, const char *node_name, const char *value, int idx)
     766              : {
     767            0 :    return mxml_add_special_node_at(parent, ELEMENT_NODE, node_name, value, idx);
     768              : }
     769              : 
     770              : /*------------------------------------------------------------------*/
     771              : 
     772              : /**
     773              :  * add a whole node tree to an existing parent node at a specific position
     774              :  */
     775            0 : int mxml_add_tree_at(PMXML_NODE parent, PMXML_NODE tree, int idx)
     776              : {
     777              :    PMXML_NODE pchild;
     778              :    int i, j, k;
     779              : 
     780            0 :    assert(parent);
     781            0 :    assert(tree);
     782            0 :    if (parent->n_children == 0)
     783            0 :       parent->child = (PMXML_NODE)mxml_malloc(sizeof(MXML_NODE));
     784              :    else {
     785            0 :       pchild = parent->child;
     786            0 :       parent->child = (PMXML_NODE)mxml_realloc(parent->child, sizeof(MXML_NODE)*(parent->n_children+1));
     787              : 
     788            0 :       if (parent->child != pchild) {
     789              :          /* correct parent pointer for children */
     790            0 :          for (i=0 ; i<parent->n_children ; i++) {
     791            0 :             pchild = parent->child+i;
     792            0 :             for (j=0 ; j<pchild->n_children ; j++)
     793            0 :                pchild->child[j].parent = pchild;
     794              :          }
     795              :       }
     796              :    }
     797            0 :    assert(parent->child);
     798              : 
     799            0 :    if (idx < parent->n_children) 
     800            0 :       for (i=parent->n_children ; i > idx ; i--) {
     801              :          /* move following nodes one down */
     802            0 :          memcpy(&parent->child[i], &parent->child[i-1], sizeof(MXML_NODE));
     803              : 
     804              :          /* correct parent pointer for children */
     805            0 :          for (j=0 ; j<parent->n_children ; j++) {
     806            0 :             pchild = parent->child+j;
     807            0 :             for (k=0 ; k<pchild->n_children ; k++)
     808            0 :                pchild->child[k].parent = pchild;
     809              :          }
     810              :       }
     811              : 
     812              :    /* initialize new node */
     813            0 :    memcpy(parent->child+idx, tree, sizeof(MXML_NODE));
     814            0 :    parent->n_children++;
     815            0 :    parent->child[idx].parent = parent;
     816              : 
     817              :    /* correct parent pointer for children */
     818            0 :    for (i=0 ; i<parent->n_children ; i++) {
     819            0 :       pchild = parent->child+i;
     820            0 :       for (j=0 ; j<pchild->n_children ; j++)
     821            0 :          pchild->child[j].parent = pchild;
     822              :    }
     823              : 
     824            0 :    return TRUE;
     825              : }
     826              : 
     827              : /*------------------------------------------------------------------*/
     828              : 
     829              : /**
     830              :  * add a whole node tree to an existing parent node at the end
     831              :  */
     832            0 : int mxml_add_tree(PMXML_NODE parent, PMXML_NODE tree)
     833              : {
     834            0 :    return mxml_add_tree_at(parent, tree, parent->n_children);
     835              : }
     836              : 
     837              : /*------------------------------------------------------------------*/
     838              : 
     839              : /**
     840              :  * add an attribute to an existing node
     841              :  */
     842            0 : int mxml_add_attribute(PMXML_NODE pnode, const char *attrib_name, const char *attrib_value)
     843              : {
     844            0 :    if (pnode->n_attributes == 0) {
     845            0 :       pnode->attribute_name  = (char*)mxml_malloc(MXML_NAME_LENGTH);
     846            0 :       pnode->attribute_value = (char**)mxml_malloc(sizeof(char *));
     847              :    } else {
     848            0 :       pnode->attribute_name  = (char*)mxml_realloc(pnode->attribute_name,  MXML_NAME_LENGTH*(pnode->n_attributes+1));
     849            0 :       pnode->attribute_value = (char**)mxml_realloc(pnode->attribute_value, sizeof(char *)*(pnode->n_attributes+1));
     850              :    }
     851              : 
     852            0 :    mxml_strlcpy(pnode->attribute_name+pnode->n_attributes*MXML_NAME_LENGTH, attrib_name, MXML_NAME_LENGTH);
     853            0 :    int len = strlen(attrib_value);
     854            0 :    pnode->attribute_value[pnode->n_attributes] = (char *)mxml_malloc(len+1);
     855            0 :    assert(pnode->attribute_value[pnode->n_attributes] != NULL);
     856            0 :    memcpy(pnode->attribute_value[pnode->n_attributes], attrib_value, len+1);
     857            0 :    pnode->n_attributes++;
     858              : 
     859            0 :    return TRUE;
     860              : }
     861              : 
     862              : /*------------------------------------------------------------------*/
     863              : 
     864              : /**
     865              :  * return number of subnodes (children) of a node
     866              :  */
     867            0 : int mxml_get_number_of_children(PMXML_NODE pnode)
     868              : {
     869            0 :    assert(pnode);
     870            0 :    return pnode->n_children;
     871              : }
     872              : 
     873              : /*------------------------------------------------------------------*/
     874              : 
     875              : /**
     876              :  * return number of subnodes (children) of a node
     877              :  */
     878            0 : PMXML_NODE mxml_subnode(PMXML_NODE pnode, int idx)
     879              : {
     880            0 :    assert(pnode);
     881            0 :    if (idx < pnode->n_children)
     882            0 :       return &pnode->child[idx];
     883            0 :    return NULL;
     884              : }
     885              : 
     886              : /*------------------------------------------------------------------*/
     887              : 
     888              : 
     889              : int mxml_find_nodes1(PMXML_NODE tree, const char *xml_path, PMXML_NODE **nodelist, int *found);
     890              : 
     891            0 : int mxml_add_resultnode(PMXML_NODE node, const char *xml_path, PMXML_NODE **nodelist, int *found)
     892              : {
     893              :    /* if at end of path, add this node */
     894            0 :    if (*xml_path == 0) {
     895            0 :       if (*found == 0)
     896            0 :          *nodelist = (PMXML_NODE *)mxml_malloc(sizeof(PMXML_NODE));
     897              :       else
     898            0 :          *nodelist = (PMXML_NODE *)mxml_realloc(*nodelist, sizeof(PMXML_NODE)*(*found + 1));
     899              : 
     900            0 :       (*nodelist)[*found] = node;
     901            0 :       (*found)++;
     902              :    } else {
     903              :       /* if not at end of path, branch into subtree */
     904            0 :       return mxml_find_nodes1(node, xml_path+1, nodelist, found);
     905              :    }
     906              : 
     907            0 :    return 1;
     908              : }
     909              : 
     910              : /*------------------------------------------------------------------*/
     911              : 
     912              : /**
     913              :    Return list of XML nodes with a subset of XPATH specifications.
     914              :    Following elemets are possible
     915              : 
     916              :    /<node>/<node>/..../<node>          Find a node in the tree hierarchy
     917              :    /<node>[idx]                        Find child #[idx] of node (index starts from 1)
     918              :    /<node>[idx]/<node>                 Find subnode of the above
     919              :    /<node>[<subnode>=<value>]          Find a node which has a specific subnode
     920              :    /<node>[<subnode>=<value>]/<node>   Find subnode of the above
     921              :    /<node>[@<attrib>=<value>]/<node>   Find a node which has a specific attribute
     922              : */
     923            0 : int mxml_find_nodes1(PMXML_NODE tree, const char *xml_path, PMXML_NODE **nodelist, int *found)
     924              : {
     925              :    PMXML_NODE pnode;
     926              :    const char *p1,*p2;
     927              :    char *p3, node_name[256], condition[256];
     928              :    char cond_name[MXML_MAX_CONDITION][256], cond_value[MXML_MAX_CONDITION][256];
     929              :    int  cond_type[MXML_MAX_CONDITION];
     930              :    int i, j, k, idx, num_cond;
     931              :    int cond_satisfied,cond_index;
     932              :    size_t len;
     933              : 
     934            0 :    p1 = xml_path;
     935            0 :    pnode = tree;
     936              : 
     937              :    /* skip leading '/' */
     938            0 :    if (*p1 && *p1 == '/')
     939            0 :       p1++;
     940              : 
     941              :    do {
     942            0 :       p2 = p1;
     943            0 :       while (*p2 && *p2 != '/' && *p2 != '[')
     944            0 :          p2++;
     945            0 :       len = (size_t)p2 - (size_t)p1;
     946            0 :       if (len >= sizeof(node_name))
     947            0 :          return 0;
     948              : 
     949            0 :       memcpy(node_name, p1, len);
     950            0 :       node_name[len] = 0;
     951            0 :       idx = 0;
     952            0 :       num_cond = 0;
     953            0 :       while (*p2 == '[') {
     954            0 :          cond_name[num_cond][0] = cond_value[num_cond][0] = cond_type[num_cond] = 0;
     955            0 :          p2++;
     956            0 :          if (isdigit(*p2)) {
     957              :             /* evaluate [idx] */
     958            0 :             idx = atoi(p2);
     959            0 :             p2 = strchr(p2, ']');
     960            0 :             if (p2 == NULL)
     961            0 :                return 0;
     962            0 :             p2++;
     963              :          } else {
     964              :             /* evaluate [<@attrib>/<subnode>=<value>] */
     965            0 :             while (*p2 && isspace((unsigned char)*p2))
     966            0 :                p2++;
     967            0 :             mxml_strlcpy(condition, p2, sizeof(condition));
     968            0 :             if (strchr(condition, ']'))
     969            0 :                *strchr(condition, ']') = 0;
     970              :             else
     971            0 :                return 0;
     972            0 :             p2 = strchr(p2, ']')+1;
     973            0 :             if ((p3 = strchr(condition, '=')) != NULL) {
     974            0 :                if (condition[0] == '@') {
     975            0 :                   cond_type[num_cond] = 1;
     976            0 :                   mxml_strlcpy(cond_name[num_cond], &condition[1], sizeof(cond_name[num_cond]));
     977              :                } else {
     978            0 :                   mxml_strlcpy(cond_name[num_cond], condition, sizeof(cond_name[num_cond]));
     979              :                }
     980              : 
     981            0 :                *strchr(cond_name[num_cond], '=') = 0;
     982            0 :                while (cond_name[num_cond][0] && isspace(cond_name[num_cond][strlen(cond_name[num_cond])-1]))
     983            0 :                   cond_name[num_cond][strlen(cond_name[num_cond])-1] = 0;
     984              : 
     985            0 :                p3++;
     986            0 :                while (*p3 && isspace(*p3))
     987            0 :                   p3++;
     988            0 :                if (*p3 == '\"') {
     989            0 :                   mxml_strlcpy(cond_value[num_cond], p3+1, sizeof(cond_value[num_cond]));
     990            0 :                   while (cond_value[num_cond][0] && isspace(cond_value[num_cond][strlen(cond_value[num_cond])-1]))
     991            0 :                      cond_value[num_cond][strlen(cond_value[num_cond])-1] = 0;
     992            0 :                   if (cond_value[num_cond][0] && cond_value[num_cond][strlen(cond_value[num_cond])-1] == '\"')
     993            0 :                      cond_value[num_cond][strlen(cond_value[num_cond])-1] = 0;
     994            0 :                } else if (*p3 == '\'') {
     995            0 :                   mxml_strlcpy(cond_value[num_cond], p3+1, sizeof(cond_value[num_cond]));
     996            0 :                   while (cond_value[num_cond][0] && isspace(cond_value[num_cond][strlen(cond_value[num_cond])-1]))
     997            0 :                      cond_value[num_cond][strlen(cond_value[num_cond])-1] = 0;
     998            0 :                   if (cond_value[num_cond][0] && cond_value[num_cond][strlen(cond_value[num_cond])-1] == '\'')
     999            0 :                      cond_value[num_cond][strlen(cond_value[num_cond])-1] = 0;
    1000              :                } else {
    1001            0 :                   mxml_strlcpy(cond_value[num_cond], p3, sizeof(cond_value[num_cond]));
    1002            0 :                   while (cond_value[num_cond][0] && isspace(cond_value[num_cond][strlen(cond_value[num_cond])-1]))
    1003            0 :                      cond_value[num_cond][strlen(cond_value[num_cond])-1] = 0;
    1004              :                }
    1005            0 :                num_cond++;
    1006              :             }
    1007              :          }
    1008              :       }
    1009              : 
    1010            0 :       cond_index = 0;
    1011            0 :       for (i=j=0 ; i<pnode->n_children ; i++) {
    1012            0 :          if (num_cond) {
    1013            0 :             cond_satisfied = 0;
    1014            0 :             for (k=0;k<num_cond;k++) {
    1015            0 :                if (cond_type[k]) {
    1016              :                   /* search node with attribute */
    1017            0 :                   if (strcmp(pnode->child[i].name, node_name) == 0)
    1018            0 :                      if (mxml_get_attribute(pnode->child+i, cond_name[k]) &&
    1019            0 :                         strcmp(mxml_get_attribute(pnode->child+i, cond_name[k]), cond_value[k]) == 0)
    1020            0 :                         cond_satisfied++;
    1021              :                }
    1022              :                else {
    1023              :                   /* search subnode */
    1024            0 :                   for (j=0 ; j<pnode->child[i].n_children ; j++)
    1025            0 :                      if (strcmp(pnode->child[i].child[j].name, cond_name[k]) == 0)
    1026            0 :                         if (strcmp(pnode->child[i].child[j].value, cond_value[k]) == 0)
    1027            0 :                            cond_satisfied++;
    1028              :                }
    1029              :             }
    1030            0 :             if (cond_satisfied==num_cond) {
    1031            0 :                cond_index++;
    1032            0 :                if (idx == 0 || cond_index == idx) {
    1033            0 :                   if (!mxml_add_resultnode(pnode->child+i, p2, nodelist, found))
    1034            0 :                      return 0;
    1035              :                }
    1036              :             }
    1037              :          } else {
    1038            0 :             if (strcmp(pnode->child[i].name, node_name) == 0)
    1039            0 :                if (idx == 0 || ++j == idx)
    1040            0 :                   if (!mxml_add_resultnode(pnode->child+i, p2, nodelist, found))
    1041            0 :                      return 0;
    1042              :          }
    1043              :       }
    1044              : 
    1045            0 :       if (i == pnode->n_children)
    1046            0 :          return 1;
    1047              : 
    1048            0 :       pnode = &pnode->child[i];
    1049            0 :       p1 = p2;
    1050            0 :       if (*p1 == '/')
    1051            0 :          p1++;
    1052              : 
    1053            0 :    } while (*p2);
    1054              : 
    1055            0 :    return 1;
    1056              : }
    1057              : 
    1058              : /*------------------------------------------------------------------*/
    1059              : 
    1060            0 : int mxml_find_nodes(PMXML_NODE tree, const char *xml_path, PMXML_NODE **nodelist)
    1061              : {
    1062            0 :    int status, found = 0;
    1063              :    
    1064            0 :    status = mxml_find_nodes1(tree, xml_path, nodelist, &found);
    1065              : 
    1066            0 :    if (status == 0)
    1067            0 :       return -1;
    1068              : 
    1069            0 :    return found;
    1070              : }
    1071              : 
    1072              : /*------------------------------------------------------------------*/
    1073              : 
    1074              : /**
    1075              :  *  Search for a specific XML node with a subset of XPATH specifications.
    1076              :  *  Return first found node. For syntax see mxml_find_nodes()
    1077              :  */
    1078            0 : PMXML_NODE mxml_find_node(PMXML_NODE tree, const char *xml_path)
    1079              : {
    1080              :    PMXML_NODE *node, pnode;
    1081              :    int n;
    1082              : 
    1083            0 :    n = mxml_find_nodes(tree, xml_path, &node);
    1084            0 :    if (n > 0) {
    1085            0 :       pnode = node[0];
    1086            0 :       mxml_free(node);
    1087              :    } else 
    1088            0 :       pnode = NULL;
    1089              : 
    1090            0 :    return pnode;
    1091              : }
    1092              : 
    1093              : /*------------------------------------------------------------------*/
    1094              : 
    1095            0 : PMXML_NODE mxml_get_parent(PMXML_NODE pnode)
    1096              : {
    1097            0 :    assert(pnode);
    1098            0 :    return pnode->parent;
    1099              : }
    1100              : 
    1101              : /*------------------------------------------------------------------*/
    1102              : 
    1103            0 : char *mxml_get_name(PMXML_NODE pnode)
    1104              : {
    1105            0 :    assert(pnode);
    1106            0 :    return pnode->name;
    1107              : }
    1108              : 
    1109              : /*------------------------------------------------------------------*/
    1110              : 
    1111            0 : char *mxml_get_value(PMXML_NODE pnode)
    1112              : {
    1113            0 :    assert(pnode);
    1114            0 :    return pnode->value;
    1115              : }
    1116              : 
    1117              : /*------------------------------------------------------------------*/
    1118              : 
    1119            0 : int mxml_get_line_number_start(PMXML_NODE pnode)
    1120              : {
    1121            0 :    assert(pnode);
    1122            0 :    return pnode->line_number_start;
    1123              : }
    1124              : 
    1125              : /*------------------------------------------------------------------*/
    1126              : 
    1127            0 : int mxml_get_line_number_end(PMXML_NODE pnode)
    1128              : {
    1129            0 :    assert(pnode);
    1130            0 :    return pnode->line_number_end;
    1131              : }
    1132              : 
    1133              : /*------------------------------------------------------------------*/
    1134              : 
    1135            0 : char *mxml_get_attribute(PMXML_NODE pnode, const char *name)
    1136              : {
    1137              :    int i;
    1138              : 
    1139            0 :    assert(pnode);
    1140            0 :    for (i=0 ; i<pnode->n_attributes ; i++) 
    1141            0 :       if (strcmp(pnode->attribute_name+i*MXML_NAME_LENGTH, name) == 0)
    1142            0 :          return pnode->attribute_value[i];
    1143              : 
    1144            0 :    return NULL;
    1145              : }
    1146              : 
    1147              : /*------------------------------------------------------------------*/
    1148              : 
    1149            0 : int mxml_replace_node_name(PMXML_NODE pnode, const char *name)
    1150              : {
    1151            0 :    mxml_strlcpy(pnode->name, name, sizeof(pnode->name));
    1152            0 :    return TRUE;
    1153              : }
    1154              : 
    1155              : /*------------------------------------------------------------------*/
    1156              : 
    1157            0 : int mxml_replace_node_value(PMXML_NODE pnode, const char *value)
    1158              : {
    1159            0 :    int len = strlen(value);
    1160            0 :    if (pnode->value)
    1161            0 :       pnode->value = (char *)mxml_realloc(pnode->value, len+1);
    1162            0 :    else if (value)
    1163            0 :       pnode->value = (char *)mxml_malloc(len+1);
    1164              :    else
    1165            0 :       pnode->value = NULL;
    1166              :    
    1167            0 :    if (value)
    1168            0 :       memcpy(pnode->value, value, len+1);
    1169              : 
    1170            0 :    return TRUE;
    1171              : }
    1172              : 
    1173              : /*------------------------------------------------------------------*/
    1174              : 
    1175              : /**
    1176              :    replace value os a subnode, like
    1177              : 
    1178              :    <parent>
    1179              :      <child>value</child>
    1180              :    </parent>
    1181              : 
    1182              :    if pnode=parent, and "name"="child", then "value" gets replaced
    1183              : */
    1184            0 : int mxml_replace_subvalue(PMXML_NODE pnode, const char *name, const char *value)
    1185              : {
    1186              :    int i;
    1187              : 
    1188            0 :    for (i=0 ; i<pnode->n_children ; i++) 
    1189            0 :       if (strcmp(pnode->child[i].name, name) == 0)
    1190            0 :          break;
    1191              : 
    1192            0 :    if (i == pnode->n_children)
    1193            0 :       return FALSE;
    1194              : 
    1195            0 :    return mxml_replace_node_value(&pnode->child[i], value);
    1196              : }
    1197              : 
    1198              : /*------------------------------------------------------------------*/
    1199              : 
    1200              : /**
    1201              :  * change the name of an attribute, keep its value
    1202              :  */
    1203            0 : int mxml_replace_attribute_name(PMXML_NODE pnode, const char *old_name, const char *new_name)
    1204              : {
    1205              :    int i;
    1206              : 
    1207            0 :    for (i=0 ; i<pnode->n_attributes ; i++) 
    1208            0 :       if (strcmp(pnode->attribute_name+i*MXML_NAME_LENGTH, old_name) == 0)
    1209            0 :          break;
    1210              : 
    1211            0 :    if (i == pnode->n_attributes)
    1212            0 :       return FALSE;
    1213              : 
    1214            0 :    mxml_strlcpy(pnode->attribute_name+i*MXML_NAME_LENGTH, new_name, MXML_NAME_LENGTH);
    1215            0 :    return TRUE;
    1216              : }
    1217              : 
    1218              : /*------------------------------------------------------------------*/
    1219              : 
    1220              : /**
    1221              :  * change the value of an attribute
    1222              :  */
    1223            0 : int mxml_replace_attribute_value(PMXML_NODE pnode, const char *attrib_name, const char *attrib_value)
    1224              : {
    1225              :    int i;
    1226              : 
    1227            0 :    for (i=0 ; i<pnode->n_attributes ; i++) 
    1228            0 :       if (strcmp(pnode->attribute_name+i*MXML_NAME_LENGTH, attrib_name) == 0)
    1229            0 :          break;
    1230              : 
    1231            0 :    if (i == pnode->n_attributes)
    1232            0 :       return FALSE;
    1233              : 
    1234            0 :    int len = strlen(attrib_value);
    1235            0 :    pnode->attribute_value[i] = (char *)mxml_realloc(pnode->attribute_value[i], len+1);
    1236            0 :    memcpy(pnode->attribute_value[i], attrib_value, len+1);
    1237            0 :    return TRUE;
    1238              : }
    1239              : 
    1240              : /*------------------------------------------------------------------*/
    1241              : 
    1242              : /**
    1243              :  * free memory of a node and remove it from the parent's child list
    1244              :  */
    1245            0 : int mxml_delete_node(PMXML_NODE pnode)
    1246              : {
    1247              :    PMXML_NODE parent;
    1248              :    int i, j;
    1249              : 
    1250              :    /* remove node from parent's list */
    1251            0 :    parent = pnode->parent;
    1252              : 
    1253            0 :    if (parent) {
    1254            0 :       for (i=0 ; i<parent->n_children ; i++)
    1255            0 :          if (&parent->child[i] == pnode)
    1256            0 :             break;
    1257              : 
    1258              :       /* free allocated node memory recursively */
    1259            0 :       mxml_free_tree(pnode);
    1260              : 
    1261            0 :       if (i < parent->n_children) {
    1262            0 :          for (j=i ; j<parent->n_children-1 ; j++)
    1263            0 :             memcpy(&parent->child[j], &parent->child[j+1], sizeof(MXML_NODE));
    1264            0 :          parent->n_children--;
    1265            0 :          if (parent->n_children)
    1266            0 :             parent->child = (PMXML_NODE)mxml_realloc(parent->child, sizeof(MXML_NODE)*(parent->n_children));
    1267              :          else
    1268            0 :             mxml_free(parent->child);
    1269              :       }
    1270              :    } else 
    1271            0 :       mxml_free_tree(pnode);
    1272              : 
    1273            0 :    return TRUE;
    1274              : }
    1275              : 
    1276              : /*------------------------------------------------------------------*/
    1277              : 
    1278            0 : int mxml_delete_attribute(PMXML_NODE pnode, const char *attrib_name)
    1279              : {
    1280              :    int i, j;
    1281              : 
    1282            0 :    for (i=0 ; i<pnode->n_attributes ; i++) 
    1283            0 :       if (strcmp(pnode->attribute_name+i*MXML_NAME_LENGTH, attrib_name) == 0)
    1284            0 :          break;
    1285              : 
    1286            0 :    if (i == pnode->n_attributes)
    1287            0 :       return FALSE;
    1288              : 
    1289            0 :    mxml_free(pnode->attribute_value[i]);
    1290            0 :    for (j=i ; j<pnode->n_attributes-1 ; j++) {
    1291            0 :       mxml_strlcpy(pnode->attribute_name+j*MXML_NAME_LENGTH, pnode->attribute_name+(j+1)*MXML_NAME_LENGTH, MXML_NAME_LENGTH);
    1292            0 :       pnode->attribute_value[j] = pnode->attribute_value[j+1];
    1293              :    }
    1294              : 
    1295            0 :    if (pnode->n_attributes > 0) {
    1296            0 :       pnode->attribute_name  = (char *)mxml_realloc(pnode->attribute_name,  MXML_NAME_LENGTH*(pnode->n_attributes-1));
    1297            0 :       pnode->attribute_value = (char **)mxml_realloc(pnode->attribute_value, sizeof(char *)*(pnode->n_attributes-1));
    1298              :    } else {
    1299            0 :       mxml_free(pnode->attribute_name);
    1300            0 :       mxml_free(pnode->attribute_value);
    1301              :    }
    1302              : 
    1303            0 :    return TRUE;
    1304              : }
    1305              : 
    1306              : /*------------------------------------------------------------------*/
    1307              : 
    1308              : #define HERE root, file_name, line_number, error, error_size, error_line
    1309              : 
    1310              : /**
    1311              :  * used inside mxml_parse_file for reporting errors
    1312              :  */
    1313            0 : PMXML_NODE read_error(PMXML_NODE root, const char *file_name, int line_number, char *error, int error_size, int *error_line, const char *format, ...)
    1314              : {
    1315            0 :    std::string msg;
    1316            0 :    if (file_name && file_name[0]) {
    1317            0 :       msg += "XML read error in file \"";
    1318            0 :       msg += file_name;
    1319            0 :       msg += "\", line ";
    1320            0 :       msg += toString(line_number);
    1321            0 :       msg += ": ";
    1322              :    } else {
    1323            0 :       msg += "XML read error, line ";
    1324            0 :       msg += toString(line_number);
    1325            0 :       msg += ": ";
    1326              :    }
    1327              : 
    1328              :    char str[1000];
    1329              :    va_list argptr;
    1330            0 :    va_start(argptr, format);
    1331            0 :    vsnprintf(str, sizeof(str), (char *) format, argptr);
    1332            0 :    va_end(argptr);
    1333              : 
    1334            0 :    msg += str;
    1335              : 
    1336            0 :    if (error) {
    1337            0 :       mxml_strlcpy(error, msg.c_str(), error_size);
    1338              :    }
    1339            0 :    if (error_line) {
    1340            0 :       *error_line = line_number;
    1341              :    }
    1342              :    
    1343            0 :    mxml_free_tree(root);
    1344              : 
    1345            0 :    return NULL;
    1346            0 : }
    1347              : 
    1348              : /*------------------------------------------------------------------*/
    1349              : 
    1350              : /**
    1351              :  * Parse a XML buffer and convert it into a tree of MXML_NODE's.
    1352              :  * Return NULL in case of an error, return error description.
    1353              :  * Optional file_name is used for error reporting if called from mxml_parse_file()
    1354              :  */
    1355            0 : PMXML_NODE mxml_parse_buffer(const char *buf, char *error, int error_size, int *error_line)
    1356              : {
    1357              :    char node_name[256], attrib_name[256], attrib_value[1000], quote;
    1358              :    const char *p, *pv;
    1359              :    int i,j, line_number;
    1360              :    PMXML_NODE root, ptree, pnew;
    1361              :    int end_element;
    1362              :    size_t len;
    1363            0 :    char *file_name = NULL; /* dummy for 'HERE' */
    1364              : 
    1365            0 :    p = buf;
    1366            0 :    line_number = 1;
    1367              : 
    1368            0 :    root = mxml_create_root_node();
    1369            0 :    ptree = root;
    1370              : 
    1371              :    /* parse file contents */
    1372              :    do {
    1373            0 :       if (*p == '<') {
    1374              : 
    1375            0 :          end_element = FALSE;
    1376              : 
    1377              :          /* found new element */
    1378            0 :          p++;
    1379            0 :          while (*p && isspace(*p)) {
    1380            0 :             if (*p == '\n')
    1381            0 :                line_number++;
    1382            0 :             p++;
    1383              :          }
    1384            0 :          if (!*p)
    1385            0 :             return read_error(HERE, "Unexpected end of file");
    1386              : 
    1387            0 :          if (strncmp(p, "!--", 3) == 0) {
    1388              :             
    1389              :             /* found comment */
    1390              : 
    1391            0 :             pnew = mxml_add_special_node(ptree, COMMENT_NODE, "Comment", NULL);
    1392            0 :             pnew->line_number_start = line_number;
    1393            0 :             pv = p+3;
    1394            0 :             while (*pv == ' ')
    1395            0 :                pv++;
    1396              : 
    1397            0 :             p += 3;
    1398            0 :             if (strstr(p, "-->") == NULL)
    1399            0 :                return read_error(HERE, "Unterminated comment");
    1400              :             
    1401            0 :             while (strncmp(p, "-->", 3) != 0) {
    1402            0 :                if (*p == '\n')
    1403            0 :                   line_number++;
    1404            0 :                p++;
    1405              :             }
    1406              : 
    1407            0 :             len = (size_t)p - (size_t)pv;
    1408            0 :             pnew->value = (char *)mxml_malloc(len+1);
    1409            0 :             memcpy(pnew->value, pv, len);
    1410            0 :             pnew->value[len] = 0;
    1411            0 :             pnew->line_number_end = line_number;
    1412            0 :             mxml_decode(pnew->value);
    1413              : 
    1414            0 :             p += 3;
    1415              : 
    1416            0 :          } else if (*p == '?') {
    1417              : 
    1418              :             /* found ?...? element */
    1419            0 :             pnew = mxml_add_special_node(ptree, PROCESSING_INSTRUCTION_NODE, "PI", NULL);
    1420            0 :             pnew->line_number_start = line_number;
    1421            0 :             pv = p+1;
    1422              : 
    1423            0 :             p++;
    1424            0 :             if (strstr(p, "?>") == NULL)
    1425            0 :                return read_error(HERE, "Unterminated ?...? element");
    1426              :             
    1427            0 :             while (strncmp(p, "?>", 2) != 0) {
    1428            0 :                if (*p == '\n')
    1429            0 :                   line_number++;
    1430            0 :                p++;
    1431              :             }
    1432              : 
    1433            0 :             len = (size_t)p - (size_t)pv;
    1434            0 :             pnew->value = (char *)mxml_malloc(len+1);
    1435            0 :             memcpy(pnew->value, pv, len);
    1436            0 :             pnew->value[len] = 0;
    1437            0 :             pnew->line_number_end = line_number;
    1438            0 :             mxml_decode(pnew->value);
    1439              : 
    1440            0 :             p += 2;
    1441              : 
    1442            0 :          } else if (strncmp(p, "!DOCTYPE", 8) == 0 ) {
    1443              : 
    1444              :             /* found !DOCTYPE element , skip it */
    1445            0 :             p += 8;
    1446            0 :             if (strstr(p, ">") == NULL)
    1447            0 :                return read_error(HERE, "Unterminated !DOCTYPE element");
    1448              : 
    1449            0 :             j = 0;
    1450            0 :             while (*p && (*p != '>' || j > 0)) {
    1451            0 :                if (*p == '\n')
    1452            0 :                   line_number++;
    1453            0 :                else if (*p == '<')
    1454            0 :                   j++;
    1455            0 :                else if (*p == '>')
    1456            0 :                   j--;
    1457            0 :                p++;
    1458              :             }
    1459            0 :             if (!*p)
    1460            0 :                return read_error(HERE, "Unexpected end of file");
    1461              : 
    1462            0 :             p++;
    1463              : 
    1464              :          } else {
    1465              :             
    1466              :             /* found normal element */
    1467            0 :             if (*p == '/') {
    1468            0 :                end_element = TRUE;
    1469            0 :                p++;
    1470            0 :                while (*p && isspace((unsigned char)*p)) {
    1471            0 :                   if (*p == '\n')
    1472            0 :                      line_number++;
    1473            0 :                   p++;
    1474              :                }
    1475            0 :                if (!*p)
    1476            0 :                   return read_error(HERE, "Unexpected end of file");
    1477              :             }
    1478              : 
    1479              :             /* extract node name */
    1480            0 :             i = 0;
    1481            0 :             node_name[i] = 0;
    1482            0 :             while (*p && !isspace((unsigned char)*p) && *p != '/' && *p != '>' && *p != '<')
    1483            0 :                node_name[i++] = *p++;
    1484            0 :             node_name[i] = 0;
    1485            0 :             if (!*p)
    1486            0 :                return read_error(HERE, "Unexpected end of file");
    1487            0 :             if (*p == '<')
    1488            0 :                return read_error(HERE, "Unexpected \'<\' inside element \"%s\"", node_name);
    1489              : 
    1490            0 :             mxml_decode(node_name);
    1491              : 
    1492            0 :             if (end_element) {
    1493              : 
    1494            0 :                if (!ptree)
    1495            0 :                   return read_error(HERE, "Found unexpected </%s>", node_name);
    1496              : 
    1497              :                /* close previously opened element */
    1498            0 :                if (strcmp(ptree->name, node_name) != 0)
    1499            0 :                   return read_error(HERE, "Found </%s>, expected </%s>", node_name, ptree->name);
    1500            0 :                ptree->line_number_end = line_number;
    1501              :                
    1502              :                /* go up one level on the tree */
    1503            0 :                ptree = ptree->parent;
    1504              : 
    1505              :             } else {
    1506              :             
    1507            0 :                if (ptree == NULL)
    1508            0 :                   return read_error(HERE, "Unexpected second top level node");
    1509              : 
    1510              :                /* allocate new element structure in parent tree */
    1511            0 :                pnew = mxml_add_node(ptree, node_name, NULL);
    1512            0 :                pnew->line_number_start = line_number;
    1513            0 :                pnew->line_number_end = line_number;
    1514              : 
    1515            0 :                while (*p && isspace((unsigned char)*p)) {
    1516            0 :                   if (*p == '\n')
    1517            0 :                      line_number++;
    1518            0 :                   p++;
    1519              :                }
    1520            0 :                if (!*p)
    1521            0 :                   return read_error(HERE, "Unexpected end of file");
    1522              : 
    1523            0 :                while (*p != '>' && *p != '/') {
    1524              : 
    1525              :                   /* found attribute */
    1526            0 :                   pv = p;
    1527            0 :                   while (*pv && !isspace((unsigned char)*pv) && *pv != '=' && *pv != '<' && *pv != '>')
    1528            0 :                      pv++;
    1529            0 :                   if (!*pv)
    1530            0 :                      return read_error(HERE, "Unexpected end of file");
    1531            0 :                   if (*pv == '<' || *pv == '>')
    1532            0 :                      return read_error(HERE, "Unexpected \'%c\' inside element \"%s\"", *pv, node_name);
    1533              : 
    1534              :                   /* extract attribute name */
    1535            0 :                   len = (size_t)pv - (size_t)p;
    1536            0 :                   if (len > sizeof(attrib_name)-1)
    1537            0 :                      len = sizeof(attrib_name)-1;
    1538            0 :                   memcpy(attrib_name, p, len);
    1539            0 :                   attrib_name[len] = 0;
    1540            0 :                   mxml_decode(attrib_name);
    1541              : 
    1542            0 :                   p = pv;
    1543            0 :                   while (*p && isspace((unsigned char)*p)) {
    1544            0 :                      if (*p == '\n')
    1545            0 :                         line_number++;
    1546            0 :                      p++;
    1547              :                   }
    1548            0 :                   if (!*p)
    1549            0 :                      return read_error(HERE, "Unexpected end of file");
    1550            0 :                   if (*p != '=')
    1551            0 :                      return read_error(HERE, "Expect \"=\" here");
    1552              : 
    1553            0 :                   p++;
    1554            0 :                   while (*p && isspace((unsigned char)*p)) {
    1555            0 :                      if (*p == '\n')
    1556            0 :                         line_number++;
    1557            0 :                      p++;
    1558              :                   }
    1559            0 :                   if (!*p)
    1560            0 :                      return read_error(HERE, "Unexpected end of file");
    1561            0 :                   if (*p != '\"' && *p != '\'')
    1562            0 :                      return read_error(HERE, "Expect \" or \' here");
    1563            0 :                   quote = *p;
    1564            0 :                   p++;
    1565              : 
    1566              :                   /* extract attribute value */
    1567            0 :                   pv = p;
    1568            0 :                   while (*pv && *pv != quote)
    1569            0 :                      pv++;
    1570            0 :                   if (!*pv)
    1571            0 :                      return read_error(HERE, "Unexpected end of file");
    1572              : 
    1573            0 :                   len = (size_t)pv - (size_t)p;
    1574            0 :                   if (len > sizeof(attrib_value)-1)
    1575            0 :                      len = sizeof(attrib_value)-1;
    1576            0 :                   memcpy(attrib_value, p, len);
    1577            0 :                   attrib_value[len] = 0;
    1578            0 :                   mxml_decode(attrib_value);
    1579              : 
    1580              :                   /* add attribute to current node */
    1581            0 :                   mxml_add_attribute(pnew, attrib_name, attrib_value);
    1582              : 
    1583            0 :                   p = pv+1;
    1584            0 :                   while (*p && isspace((unsigned char)*p)) {
    1585            0 :                      if (*p == '\n')
    1586            0 :                         line_number++;
    1587            0 :                      p++;
    1588              :                   }
    1589            0 :                   if (!*p)
    1590            0 :                      return read_error(HERE, "Unexpected end of file");
    1591              :                }
    1592              : 
    1593            0 :                if (*p == '/') {
    1594              : 
    1595              :                   /* found empty node, like <node/>, just skip closing bracket */
    1596            0 :                   p++;
    1597              : 
    1598            0 :                   while (*p && isspace((unsigned char)*p)) {
    1599            0 :                      if (*p == '\n')
    1600            0 :                         line_number++;
    1601            0 :                      p++;
    1602              :                   }
    1603            0 :                   if (!*p)
    1604            0 :                      return read_error(HERE, "Unexpected end of file");
    1605            0 :                   if (*p != '>')
    1606            0 :                      return read_error(HERE, "Expected \">\" after \"/\"");
    1607            0 :                   p++;
    1608              :                }
    1609              : 
    1610            0 :                if (*p == '>') {
    1611              : 
    1612            0 :                   p++;
    1613              : 
    1614              :                   /* check if we have sub-element or value */
    1615            0 :                   pv = p;
    1616            0 :                   while (*pv && isspace((unsigned char)*pv)) {
    1617            0 :                      if (*pv == '\n')
    1618            0 :                         line_number++;
    1619            0 :                      pv++;
    1620              :                   }
    1621            0 :                   if (!*pv)
    1622            0 :                      return read_error(HERE, "Unexpected end of file");
    1623              : 
    1624            0 :                   if (*pv == '<' && *(pv+1) != '/') {
    1625              : 
    1626              :                      /* start new subtree */
    1627            0 :                      ptree = pnew;
    1628            0 :                      p = pv;
    1629              : 
    1630              :                   } else {
    1631              : 
    1632              :                      /* extract value */
    1633            0 :                      while (*pv && *pv != '<') {
    1634            0 :                         if (*pv == '\n')
    1635            0 :                            line_number++;
    1636            0 :                         pv++;
    1637              :                      }
    1638            0 :                      if (!*pv)
    1639            0 :                         return read_error(HERE, "Unexpected end of file");
    1640              : 
    1641            0 :                      len = (size_t)pv - (size_t)p;
    1642            0 :                      pnew->value = (char *)mxml_malloc(len+1);
    1643            0 :                      memcpy(pnew->value, p, len);
    1644            0 :                      pnew->value[len] = 0;
    1645            0 :                      mxml_decode(pnew->value);
    1646            0 :                      p = pv;
    1647              : 
    1648            0 :                      ptree = pnew;
    1649              :                   }
    1650              :                }
    1651              :             }
    1652              :          }
    1653              :       }
    1654              : 
    1655              :       /* go to next element */
    1656            0 :       while (*p && *p != '<') {
    1657            0 :          if (*p == '\n')
    1658            0 :             line_number++;
    1659            0 :          p++;
    1660              :       }
    1661            0 :    } while (*p);
    1662              : 
    1663            0 :    return root;
    1664              : }
    1665              : 
    1666              : /*------------------------------------------------------------------*/
    1667              : 
    1668              : /**
    1669              :  * parse !ENTYTY entries of XML files and replace with references.
    1670              :  * Return 0 in case of no errors, return error description.
    1671              :  * Optional file_name is used for error reporting if called from mxml_parse_file()
    1672              :  */
    1673            0 : int mxml_parse_entity(char **buf, const char *file_name, char *error, int error_size, int *error_line)
    1674              : {
    1675              :    char *p;
    1676              :    char *pv;
    1677              :    char delimiter;
    1678              :    int i, j, k, line_number, status;
    1679              :    char *replacement;
    1680              :    char entity_name[MXML_MAX_ENTITY][256];
    1681              :    char entity_reference_name[MXML_MAX_ENTITY][256];
    1682              :    char *entity_value[MXML_MAX_ENTITY];
    1683              :    int entity_type[MXML_MAX_ENTITY];    /* internal or external */
    1684              :    int entity_line_number[MXML_MAX_ENTITY];
    1685              :    int nentity;
    1686              :    int fh, length;
    1687              :    int entity_value_length[MXML_MAX_ENTITY];
    1688              :    int entity_name_length[MXML_MAX_ENTITY];
    1689              : 
    1690            0 :    PMXML_NODE root = mxml_create_root_node();   /* dummy for 'HERE' */
    1691              : 
    1692            0 :    for (int ip = 0; ip < MXML_MAX_ENTITY; ip++)
    1693            0 :       entity_value[ip] = NULL;
    1694              : 
    1695            0 :    line_number = 1;
    1696            0 :    nentity = -1;
    1697            0 :    status = 0;
    1698              : 
    1699            0 :    if (!buf || !(*buf) || !strlen(*buf))
    1700            0 :       return 0;
    1701              : 
    1702              :    char directoryname[FILENAME_MAX];
    1703            0 :    mxml_strlcpy(directoryname, file_name, FILENAME_MAX);
    1704            0 :    mxml_dirname(directoryname);
    1705              : 
    1706              :    /* copy string to temporary space */
    1707            0 :    int len = strlen(*buf);
    1708            0 :    char* buffer = (char *) mxml_malloc(len+1);
    1709            0 :    if (buffer == NULL) {
    1710            0 :       read_error(HERE, "Cannot allocate memory.");
    1711            0 :       status = 1;
    1712            0 :       goto error;
    1713              :    }
    1714            0 :    memcpy(buffer, *buf, len+1);
    1715              : 
    1716            0 :    p = strstr(buffer, "!DOCTYPE");
    1717            0 :    if (p == NULL) {             /* no entities */
    1718            0 :       status = 0;
    1719            0 :       goto error;
    1720              :    }
    1721              : 
    1722            0 :    pv = strstr(p, "[");
    1723            0 :    if (pv == NULL) {            /* no entities */
    1724            0 :       status = 1;
    1725            0 :       goto error;
    1726              :    }
    1727              : 
    1728            0 :    p = pv + 1;
    1729              : 
    1730              :    /* search !ENTITY */
    1731              :    do {
    1732            0 :       if (*p == ']')
    1733            0 :          break;
    1734              : 
    1735            0 :       if (*p == '<') {
    1736              : 
    1737              :          /* found new entity */
    1738            0 :          p++;
    1739            0 :          while (*p && isspace((unsigned char)*p)) {
    1740            0 :             if (*p == '\n')
    1741            0 :                line_number++;
    1742            0 :             p++;
    1743              :          }
    1744            0 :          if (!*p) {
    1745            0 :             read_error(HERE, "Unexpected end of file");
    1746            0 :             status = 1;
    1747            0 :             goto error;
    1748              :          }
    1749              : 
    1750            0 :          if (strncmp(p, "!--", 3) == 0) {
    1751              :             /* found comment */
    1752            0 :             p += 3;
    1753            0 :             if (strstr(p, "-->") == NULL) {
    1754            0 :                read_error(HERE, "Unterminated comment");
    1755            0 :                status = 1;
    1756            0 :                goto error;
    1757              :             }
    1758              : 
    1759            0 :             while (strncmp(p, "-->", 3) != 0) {
    1760            0 :                if (*p == '\n')
    1761            0 :                   line_number++;
    1762            0 :                p++;
    1763              :             }
    1764            0 :             p += 3;
    1765              :          }
    1766              : 
    1767            0 :          else if (strncmp(p, "!ENTITY", 7) == 0) {
    1768              :             /* found entity */
    1769            0 :             nentity++;
    1770            0 :             if (nentity >= MXML_MAX_ENTITY) {
    1771            0 :                read_error(HERE, "Too much entities");
    1772            0 :                status = 1;
    1773            0 :                goto error;
    1774              :             }
    1775              :   
    1776            0 :             entity_line_number[nentity] = line_number;
    1777              :             
    1778            0 :             pv = p + 7;
    1779            0 :             while (*pv == ' ')
    1780            0 :                pv++;
    1781              : 
    1782              :             /* extract entity name */
    1783            0 :             p = pv;
    1784              : 
    1785            0 :             while (*p && isspace((unsigned char)*p) && *p != '<' && *p != '>') {
    1786            0 :                if (*p == '\n')
    1787            0 :                   line_number++;
    1788            0 :                p++;
    1789              :             }
    1790            0 :             if (!*p) {
    1791            0 :                read_error(HERE, "Unexpected end of file");
    1792            0 :                status = 1;
    1793            0 :                goto error;
    1794              :             }
    1795            0 :             if (*p == '<' || *p == '>') {
    1796            0 :                read_error(HERE, "Unexpected \'%c\' inside !ENTITY", *p);
    1797            0 :                status = 1;
    1798            0 :                goto error;
    1799              :             }
    1800              : 
    1801            0 :             pv = p;
    1802            0 :             while (*pv && !isspace((unsigned char)*pv) && *pv != '<' && *pv != '>')
    1803            0 :                pv++;
    1804              : 
    1805            0 :             if (!*pv) {
    1806            0 :                read_error(HERE, "Unexpected end of file");
    1807            0 :                status = 1;
    1808            0 :                goto error;
    1809              :             }
    1810            0 :             if (*pv == '<' || *pv == '>') {
    1811            0 :                read_error(HERE, "Unexpected \'%c\' inside entity \"%s\"", *pv, &entity_name[nentity][1]);
    1812            0 :                status = 1;
    1813            0 :                goto error;
    1814              :             }
    1815              : 
    1816            0 :             entity_name[nentity][0] = '&';
    1817            0 :             i = 1;
    1818            0 :             entity_name[nentity][i] = 0;
    1819            0 :             while (*p && !isspace((unsigned char)*p) && *p != '/' && *p != '>' && *p != '<' && i < 253)
    1820            0 :                entity_name[nentity][i++] = *p++;
    1821            0 :             entity_name[nentity][i++] = ';';
    1822            0 :             entity_name[nentity][i] = 0;
    1823              : 
    1824            0 :             if (!*p) {
    1825            0 :                read_error(HERE, "Unexpected end of file");
    1826            0 :                status = 1;
    1827            0 :                goto error;
    1828              :             }
    1829            0 :             if (*p == '<') {
    1830            0 :                read_error(HERE, "Unexpected \'<\' inside entity \"%s\"", &entity_name[nentity][1]);
    1831            0 :                status = 1;
    1832            0 :                goto error;
    1833              :             }
    1834              : 
    1835              :             /* extract replacement or SYSTEM */
    1836            0 :             while (*p && isspace((unsigned char)*p)) {
    1837            0 :                if (*p == '\n')
    1838            0 :                   line_number++;
    1839            0 :                p++;
    1840              :             }
    1841            0 :             if (!*p) {
    1842            0 :                read_error(HERE, "Unexpected end of file");
    1843            0 :                status = 1;
    1844            0 :                goto error;
    1845              :             }
    1846            0 :             if (*p == '>') {
    1847            0 :                read_error(HERE, "Unexpected \'>\' inside entity \"%s\"", &entity_name[nentity][1]);
    1848            0 :                status = 1;
    1849            0 :                goto error;
    1850              :             }
    1851              : 
    1852              :             /* check if SYSTEM */
    1853            0 :             if (strncmp(p, "SYSTEM", 6) == 0) {
    1854            0 :                entity_type[nentity] = EXTERNAL_ENTITY;
    1855            0 :                p += 6;
    1856              :             } else {
    1857            0 :                entity_type[nentity] = INTERNAL_ENTITY;
    1858              :             }
    1859              : 
    1860              :             /* extract replacement */
    1861            0 :             while (*p && isspace((unsigned char)*p)) {
    1862            0 :                if (*p == '\n')
    1863            0 :                   line_number++;
    1864            0 :                p++;
    1865              :             }
    1866            0 :             if (!*p) {
    1867            0 :                read_error(HERE, "Unexpected end of file");
    1868            0 :                status = 1;
    1869            0 :                goto error;
    1870              :             }
    1871            0 :             if (*p == '>') {
    1872            0 :                read_error(HERE, "Unexpected \'>\' inside entity \"%s\"", &entity_name[nentity][1]);
    1873            0 :                status = 1;
    1874            0 :                goto error;
    1875              :             }
    1876              : 
    1877            0 :             if (*p != '\"' && *p != '\'') {
    1878            0 :                read_error(HERE, "Replacement was not found for entity \"%s\"", &entity_name[nentity][1]);
    1879            0 :                status = 1;
    1880            0 :                goto error;
    1881              :             }
    1882            0 :             delimiter = *p;
    1883            0 :             p++;
    1884            0 :             if (!*p) {
    1885            0 :                read_error(HERE, "Unexpected end of file");
    1886            0 :                status = 1;
    1887            0 :                goto error;
    1888              :             }
    1889            0 :             pv = p;
    1890            0 :             while (*pv && *pv != delimiter)
    1891            0 :                pv++;
    1892              : 
    1893            0 :             if (!*pv) {
    1894            0 :                read_error(HERE, "Unexpected end of file");
    1895            0 :                status = 1;
    1896            0 :                goto error;
    1897              :             }
    1898            0 :             if (*pv == '<') {
    1899            0 :                read_error(HERE, "Unexpected \'%c\' inside entity \"%s\"", *pv, &entity_name[nentity][1]);
    1900            0 :                status = 1;
    1901            0 :                goto error;
    1902              :             }
    1903              : 
    1904            0 :             len = (int)((size_t) pv - (size_t) p);
    1905            0 :             replacement = (char *) mxml_malloc(len + 1);
    1906            0 :             if (replacement == NULL) {
    1907            0 :                read_error(HERE, "Cannot allocate memory.");
    1908            0 :                status = 1;
    1909            0 :                goto error;
    1910              :             }
    1911              : 
    1912            0 :             memcpy(replacement, p, len);
    1913            0 :             replacement[len] = 0;
    1914            0 :             mxml_decode(replacement);
    1915              : 
    1916            0 :             if (entity_type[nentity] == EXTERNAL_ENTITY) {
    1917            0 :                mxml_strlcpy(entity_reference_name[nentity], replacement, sizeof(entity_reference_name[nentity]));
    1918              :             } else {
    1919            0 :                int rlen = strlen(replacement);
    1920            0 :                entity_value[nentity] = (char *) mxml_malloc(rlen+1);
    1921            0 :                if (entity_value[nentity] == NULL) {
    1922            0 :                   read_error(HERE, "Cannot allocate memory.");
    1923            0 :                   status = 1;
    1924            0 :                   goto error;
    1925              :                }
    1926            0 :                memcpy(entity_value[nentity], replacement, rlen+1);
    1927              :             }
    1928            0 :             mxml_free(replacement);
    1929              : 
    1930            0 :             p = pv;
    1931            0 :             while (*p && isspace((unsigned char)*p)) {
    1932            0 :                if (*p == '\n')
    1933            0 :                   line_number++;
    1934            0 :                p++;
    1935              :             }
    1936            0 :             if (!*p) {
    1937            0 :                read_error(HERE, "Unexpected end of file");
    1938            0 :                status = 1;
    1939            0 :                goto error;
    1940              :             }
    1941              :          }
    1942              :       }
    1943              : 
    1944              :       /* go to next element */
    1945            0 :       while (*p && *p != '<') {
    1946            0 :          if (*p == '\n')
    1947            0 :             line_number++;
    1948            0 :          p++;
    1949              :       }
    1950            0 :    } while (*p);
    1951            0 :    nentity++;
    1952              : 
    1953              :    /* read external file */
    1954            0 :    for (i = 0; i < nentity; i++) {
    1955            0 :       if (entity_type[i] == EXTERNAL_ENTITY) {
    1956            0 :          std::string filename;
    1957            0 :          if ( entity_reference_name[i][0] == DIR_SEPARATOR ) { /* absolute path */
    1958            0 :             filename = entity_reference_name[i];
    1959              :          } else { /* relative path */
    1960            0 :             filename += directoryname;
    1961            0 :             filename += DIR_SEPARATOR;
    1962            0 :             filename += entity_reference_name[i];
    1963              :          }
    1964            0 :          fh = open(filename.c_str(), O_RDONLY | O_TEXT, 0644);
    1965              : 
    1966            0 :          if (fh == -1) {
    1967            0 :             line_number = entity_line_number[i];
    1968            0 :             read_error(HERE, "%s is missing", entity_reference_name[i]);
    1969            0 :             status = 1;
    1970            0 :             goto error;
    1971              :          } else {
    1972            0 :             length = (int)lseek(fh, 0, SEEK_END);
    1973            0 :             lseek(fh, 0, SEEK_SET);
    1974            0 :             if (length == 0) {
    1975            0 :                entity_value[i] = (char *) mxml_malloc(1);
    1976            0 :                if (entity_value[i] == NULL) {
    1977            0 :                   read_error(HERE, "Cannot allocate memory.");
    1978            0 :                   close(fh);
    1979            0 :                   status = 1;
    1980            0 :                   goto error;
    1981              :                }
    1982            0 :                entity_value[i][0] = 0;
    1983              :             } else {
    1984            0 :                entity_value[i] = (char *) mxml_malloc(length);
    1985            0 :                if (entity_value[i] == NULL) {
    1986            0 :                   read_error(HERE, "Cannot allocate memory.");
    1987            0 :                   close(fh);
    1988            0 :                   status = 1;
    1989            0 :                   goto error;
    1990              :                }
    1991              : 
    1992              :                /* read complete file at once */
    1993            0 :                length = (int)read(fh, entity_value[i], length);
    1994            0 :                entity_value[i][length - 1] = 0;
    1995            0 :                close(fh);
    1996              : 
    1997              :                /* recursive parse */
    1998            0 :                if (mxml_parse_entity(&entity_value[i], filename.c_str(), error, error_size, error_line) != 0) {
    1999            0 :                   status = 1;
    2000            0 :                   goto error;
    2001              :                }
    2002              :             }
    2003              :          }
    2004            0 :       }
    2005              :    }
    2006              : 
    2007              :    /* count length of output string */
    2008            0 :    length = (int)strlen(buffer);
    2009            0 :    for (i = 0; i < nentity; i++) {
    2010            0 :       p = buffer;
    2011            0 :       entity_value_length[i] = (int)strlen(entity_value[i]);
    2012            0 :       entity_name_length[i] = (int)strlen(entity_name[i]);
    2013              :       while (1) {
    2014            0 :          pv = strstr(p, entity_name[i]);
    2015            0 :          if (pv) {
    2016            0 :             length += entity_value_length[i] - entity_name_length[i];
    2017            0 :             p = pv + 1;
    2018              :          } else {
    2019            0 :             break;
    2020              :          }
    2021              :       }
    2022              :    }
    2023              : 
    2024              :    /* re-allocate memory */
    2025            0 :    *buf = (char *) mxml_realloc(*buf, length + 1);
    2026            0 :    if (*buf == NULL) {
    2027            0 :       read_error(HERE, "Cannot allocate memory.");
    2028            0 :       status = 1;
    2029            0 :       goto error;
    2030              :    }
    2031              : 
    2032              :    /* replace entities */
    2033            0 :    p = buffer;
    2034            0 :    pv = *buf;
    2035              :    do {
    2036            0 :       if (*p == '&') {
    2037              :          /* found entity */
    2038            0 :          for (j = 0; j < nentity; j++) {
    2039            0 :             if (strncmp(p, entity_name[j], entity_name_length[j]) == 0) {
    2040            0 :                for (k = 0; k < (int) entity_value_length[j]; k++)
    2041            0 :                   *pv++ = entity_value[j][k];
    2042            0 :                p += entity_name_length[j];
    2043            0 :                break;
    2044              :             }
    2045              :          }
    2046              :       }
    2047            0 :       *pv++ = *p++;
    2048            0 :    } while (*p);
    2049            0 :    *pv = 0;
    2050              : 
    2051            0 :    mxml_free_tree(root);
    2052              : 
    2053            0 : error:
    2054              : 
    2055            0 :    if (buffer != NULL)
    2056            0 :       mxml_free(buffer);
    2057            0 :    for (int ip = 0; ip < MXML_MAX_ENTITY; ip++)
    2058            0 :       if (entity_value[ip] != NULL)
    2059            0 :          mxml_free(entity_value[ip]);
    2060              : 
    2061            0 :    return status;
    2062              : }
    2063              : 
    2064              : /*------------------------------------------------------------------*/
    2065              : 
    2066              : /**
    2067              :  * parse a XML file and convert it into a tree of MXML_NODE's.
    2068              :  * Return NULL in case of an error, return error description
    2069              :  */
    2070            0 : PMXML_NODE mxml_parse_file(const char *file_name, char *error, int error_size, int *error_line)
    2071              : {
    2072            0 :    if (error)
    2073            0 :       error[0] = 0;
    2074              : 
    2075            0 :    int fh = open(file_name, O_RDONLY | O_TEXT, 0644);
    2076              : 
    2077            0 :    if (fh == -1) {
    2078            0 :       std::string msg = "";
    2079            0 :       msg += "Cannot open file \"";
    2080            0 :       msg += file_name;
    2081            0 :       msg += "\": ";
    2082            0 :       msg += toStrerror(errno);
    2083            0 :       mxml_strlcpy(error, msg.c_str(), error_size);
    2084            0 :       return NULL;
    2085            0 :    }
    2086              : 
    2087            0 :    off_t length = lseek(fh, 0, SEEK_END);
    2088            0 :    lseek(fh, 0, SEEK_SET);
    2089              : 
    2090            0 :    char* buf = (char *)mxml_malloc(length+1);
    2091            0 :    if (buf == NULL) {
    2092            0 :       close(fh);
    2093            0 :       std::string msg = "";
    2094            0 :       msg += "Cannot allocate buffer size ";
    2095            0 :       msg += toString(length);
    2096            0 :       msg += " for file \"";
    2097            0 :       msg += file_name;
    2098            0 :       msg += "\": ";
    2099            0 :       msg += toStrerror(errno);
    2100            0 :       mxml_strlcpy(error, msg.c_str(), error_size);
    2101            0 :       return NULL;
    2102            0 :    }
    2103              : 
    2104              :    /* read complete file at once */
    2105            0 :    int rd = read(fh, buf, length);
    2106            0 :    if (rd != length) {
    2107            0 :       std::string msg = "";
    2108            0 :       msg += "Cannot read file \"";
    2109            0 :       msg += file_name;
    2110            0 :       msg += "\", read of ";
    2111            0 :       msg += toString(length);
    2112            0 :       msg += " returned ";
    2113            0 :       msg += toString(rd);
    2114            0 :       msg += ": ";
    2115            0 :       msg += toStrerror(errno);
    2116            0 :       mxml_strlcpy(error, msg.c_str(), error_size);
    2117            0 :       mxml_free(buf);
    2118            0 :       return NULL;
    2119            0 :    }
    2120              : 
    2121            0 :    buf[length] = 0;
    2122            0 :    close(fh);
    2123              : 
    2124            0 :    if (mxml_parse_entity(&buf, file_name, error, error_size, error_line) != 0) {
    2125            0 :       mxml_free(buf);
    2126            0 :       return NULL;
    2127              :    }
    2128              : 
    2129            0 :    PMXML_NODE root = mxml_parse_buffer(buf, error, error_size, error_line);
    2130              : 
    2131            0 :    mxml_free(buf);
    2132              : 
    2133            0 :    return root;
    2134              : }
    2135              : 
    2136              : /*------------------------------------------------------------------*/
    2137              : 
    2138              : /**
    2139              :  * write complete subtree recursively into file opened with mxml_open_document()
    2140              :  */
    2141            0 : int mxml_write_subtree(MXML_WRITER *writer, PMXML_NODE tree, int indent)
    2142              : {
    2143              :    int i;
    2144              : 
    2145            0 :    mxml_start_element1(writer, tree->name, indent);
    2146            0 :    for (i=0 ; i<tree->n_attributes ; i++)
    2147            0 :       if (!mxml_write_attribute(writer, tree->attribute_name+i*MXML_NAME_LENGTH, tree->attribute_value[i]))
    2148            0 :          return FALSE;
    2149              :    
    2150            0 :    if (tree->value)
    2151            0 :       if (!mxml_write_value(writer, tree->value))
    2152            0 :          return FALSE;
    2153              : 
    2154            0 :    for (i=0 ; i<tree->n_children ; i++)
    2155            0 :       if (!mxml_write_subtree(writer, &tree->child[i], (tree->value == NULL) || i > 0))
    2156            0 :          return FALSE;
    2157              : 
    2158            0 :    return mxml_end_element(writer);
    2159              : }
    2160              : 
    2161              : /*------------------------------------------------------------------*/
    2162              : 
    2163              : /**
    2164              :  * write a complete XML tree to a file
    2165              :  */
    2166            0 : int mxml_write_tree(const char *file_name, PMXML_NODE tree)
    2167              : {
    2168              :    MXML_WRITER *writer;
    2169              :    int i;
    2170              : 
    2171            0 :    assert(tree);
    2172            0 :    writer = mxml_open_file(file_name);
    2173            0 :    if (!writer)
    2174            0 :       return FALSE;
    2175              : 
    2176            0 :    for (i=0 ; i<tree->n_children ; i++)
    2177            0 :      if (tree->child[i].node_type == ELEMENT_NODE) /* skip PI and comments */
    2178            0 :          if (!mxml_write_subtree(writer, &tree->child[i], TRUE))
    2179            0 :             return FALSE;
    2180              : 
    2181            0 :    if (!mxml_close_file(writer))
    2182            0 :       return FALSE;
    2183              : 
    2184            0 :    return TRUE;
    2185              : }
    2186              : 
    2187              : /*------------------------------------------------------------------*/
    2188              : 
    2189              : /**
    2190              :  * write a complete XML tree to a buffer
    2191              :  */
    2192            0 : int mxml_print_tree(char *buffer, int *buffer_size, PMXML_NODE tree)
    2193              : {
    2194              :    int len;
    2195              :    char *p;
    2196              :    MXML_WRITER *writer;
    2197              : 
    2198              :    /* open file */
    2199            0 :    writer = mxml_open_buffer();
    2200            0 :    if (writer == NULL)
    2201            0 :       return FALSE;
    2202              : 
    2203            0 :    for (int i=0 ; i<tree->n_children ; i++)
    2204            0 :       if (tree->child[i].node_type == ELEMENT_NODE) /* skip PI and comments */
    2205            0 :          if (!mxml_write_subtree(writer, &tree->child[i], TRUE))
    2206            0 :             return FALSE;
    2207              : 
    2208            0 :    p = mxml_close_buffer(writer);
    2209            0 :    len = strlen(p) + 1;
    2210            0 :    if (len > *buffer_size) {
    2211            0 :       free(p);
    2212            0 :       *buffer_size = 0;
    2213            0 :       return FALSE;
    2214              :    }
    2215              : 
    2216            0 :    mxml_strlcpy(buffer, p, *buffer_size);
    2217            0 :    free(p);
    2218            0 :    *buffer_size = len;
    2219            0 :    return TRUE;
    2220              : }
    2221              : 
    2222              : /*------------------------------------------------------------------*/
    2223              : 
    2224            0 : PMXML_NODE mxml_clone_tree(PMXML_NODE tree)
    2225              : {
    2226              :    PMXML_NODE clone;
    2227              :    int i;
    2228              : 
    2229            0 :    clone = (PMXML_NODE)calloc(1, sizeof(MXML_NODE));
    2230              : 
    2231              :    /* copy name, node_type, n_attributes and n_children */
    2232            0 :    memcpy(clone, tree, sizeof(MXML_NODE));
    2233              : 
    2234            0 :    clone->value = NULL;
    2235            0 :    mxml_replace_node_value(clone, tree->value);
    2236              : 
    2237            0 :    clone->attribute_name = NULL;
    2238            0 :    clone->attribute_value = NULL;
    2239            0 :    for (i=0 ; i<tree->n_attributes ; i++)
    2240            0 :       mxml_add_attribute(clone, tree->attribute_name+i*MXML_NAME_LENGTH, tree->attribute_value[i]);
    2241              : 
    2242            0 :    clone->child = NULL;
    2243            0 :    clone->n_children = 0;
    2244            0 :    for (i=0 ; i<tree->n_children ; i++)
    2245            0 :       mxml_add_tree(clone, mxml_clone_tree(mxml_subnode(tree, i)));
    2246              : 
    2247            0 :    return clone;
    2248              : }
    2249              : 
    2250              : /*------------------------------------------------------------------*/
    2251              : 
    2252              : /**
    2253              :  * print XML tree for debugging
    2254              :  */
    2255            0 : void mxml_debug_tree(PMXML_NODE tree, int level)
    2256              : {
    2257              :    int i, j;
    2258              : 
    2259            0 :    for (i=0 ; i<level ; i++)
    2260            0 :       printf("  ");
    2261            0 :    printf("Name: %s\n", tree->name);
    2262            0 :    for (i=0 ; i<level ; i++)
    2263            0 :       printf("  ");
    2264            0 :    printf("Valu: %s\n", tree->value);
    2265            0 :    for (i=0 ; i<level ; i++)
    2266            0 :       printf("  ");
    2267            0 :    printf("Type: %d\n", tree->node_type);
    2268            0 :    for (i=0 ; i<level ; i++)
    2269            0 :       printf("  ");
    2270            0 :    printf("Lin1: %d\n", tree->line_number_start);
    2271            0 :    for (i=0 ; i<level ; i++)
    2272            0 :       printf("  ");
    2273            0 :    printf("Lin2: %d\n", tree->line_number_end);
    2274              : 
    2275            0 :    for (j=0 ; j<tree->n_attributes ; j++) {
    2276            0 :       for (i=0 ; i<level ; i++)
    2277            0 :          printf("  ");
    2278            0 :       printf("%s: %s\n", tree->attribute_name+j*MXML_NAME_LENGTH, 
    2279            0 :          tree->attribute_value[j]);
    2280              :    }
    2281              : 
    2282            0 :    for (i=0 ; i<level ; i++)
    2283            0 :       printf("  ");
    2284            0 :    printf("Addr: %08zX\n", (size_t)tree);
    2285            0 :    for (i=0 ; i<level ; i++)
    2286            0 :       printf("  ");
    2287            0 :    printf("Prnt: %08zX\n", (size_t)tree->parent);
    2288            0 :    for (i=0 ; i<level ; i++)
    2289            0 :       printf("  ");
    2290            0 :    printf("NCld: %d\n", tree->n_children);
    2291              : 
    2292            0 :    for (i=0 ; i<tree->n_children ; i++)
    2293            0 :       mxml_debug_tree(tree->child+i, level+1);
    2294              : 
    2295            0 :    if (level == 0)
    2296            0 :       printf("\n");
    2297            0 : }
    2298              : 
    2299              : /*------------------------------------------------------------------*/
    2300              : 
    2301              : /**
    2302              :  * free memory of XML tree, must be called after any 
    2303              :  * mxml_create_root_node() or mxml_parse_file()
    2304              :  */
    2305            0 : void mxml_free_tree(PMXML_NODE tree)
    2306              : {
    2307              :    int i;
    2308              : 
    2309              :    /* first free children recursively */
    2310            0 :    for (i=0 ; i<tree->n_children ; i++)
    2311            0 :       mxml_free_tree(&tree->child[i]);
    2312            0 :    if (tree->n_children)
    2313            0 :       mxml_free(tree->child);
    2314              : 
    2315              :    /* now free dynamic data */
    2316            0 :    for (i=0 ; i<tree->n_attributes ; i++)
    2317            0 :       mxml_free(tree->attribute_value[i]);
    2318              : 
    2319            0 :    if (tree->n_attributes) {
    2320            0 :       mxml_free(tree->attribute_name);
    2321            0 :       mxml_free(tree->attribute_value);
    2322              :    }
    2323              :    
    2324            0 :    if (tree->value)
    2325            0 :       mxml_free(tree->value);
    2326              : 
    2327              :    /* if we are the root node, free it */
    2328            0 :    if (tree->parent == NULL)
    2329            0 :       mxml_free(tree);
    2330            0 : }
    2331              : 
    2332              : /*------------------------------------------------------------------*/
    2333              : 
    2334              : /*
    2335              : void mxml_test()
    2336              : {
    2337              :    char err[256];
    2338              :    PMXML_NODE tree, tree2, node;
    2339              : 
    2340              :    tree = mxml_parse_file("c:\\tmp\\test.xml", err, sizeof(err));
    2341              :    tree2 = mxml_clone_tree(tree);
    2342              : 
    2343              :    printf("Orig:\n");
    2344              :    mxml_debug_tree(tree, 0);
    2345              : 
    2346              :    printf("\nClone:\n");
    2347              :    mxml_debug_tree(tree2, 0);
    2348              : 
    2349              :    printf("\nCombined:\n");
    2350              :    node = mxml_find_node(tree2, "cddb"); 
    2351              :    mxml_add_tree(tree, node);
    2352              :    mxml_debug_tree(tree, 0);
    2353              : 
    2354              :    mxml_free_tree(tree);
    2355              : }
    2356              : */
    2357              : 
    2358              : /*------------------------------------------------------------------*/
    2359              :  /**
    2360              :    mxml_basename deletes any prefix ending with the last slash '/' character
    2361              :    present in path. mxml_dirname deletes the filename portion, beginning with
    2362              :    the last slash '/' character to the end of path. Followings are examples
    2363              :    from these functions
    2364              : 
    2365              :     path               dirname   basename
    2366              :     "/"                "/"       ""
    2367              :     "."                "."       "."
    2368              :     ""                 ""        ""
    2369              :     "/test.txt"        "/"       "test.txt"
    2370              :     "path/to/test.txt" "path/to" "test.txt"
    2371              :     "test.txt          "."       "test.txt"
    2372              : 
    2373              :    Under Windows, '\\' and ':' are recognized ad separator too.
    2374              :  */
    2375              : 
    2376            0 : void mxml_basename(char *path)
    2377              : {
    2378              :    char str[FILENAME_MAX];
    2379              :    char *p;
    2380              :    char *name;
    2381              : 
    2382            0 :    if (path) {
    2383            0 :       strcpy(str, path);
    2384            0 :       p = str;
    2385            0 :       name = str;
    2386              :       while (1) {
    2387            0 :          if (*p == 0)
    2388            0 :             break;
    2389            0 :          if (*p == '/'
    2390              : #ifdef _MSC_VER
    2391              :              || *p == ':' || *p == '\\'
    2392              : #endif
    2393              :              )
    2394            0 :             name = p + 1;
    2395            0 :          p++;
    2396              :       }
    2397            0 :       strcpy(path, name);
    2398              :    }
    2399              : 
    2400            0 :    return;
    2401              : }
    2402              : 
    2403            0 : void mxml_dirname(char *path)
    2404              : {
    2405              :    char *p;
    2406              : #ifdef _MSC_VER
    2407              :    char *pv;
    2408              : #endif
    2409              : 
    2410            0 :    if (!path || strlen(path) == 0)
    2411            0 :       return;
    2412              : 
    2413            0 :    p = strrchr(path, '/');
    2414              : #ifdef _MSC_VER
    2415              :    pv = strrchr(path, ':');
    2416              :    if (pv > p)
    2417              :       p = pv;
    2418              :    pv = strrchr(path, '\\');
    2419              :    if (pv > p)
    2420              :       p = pv;
    2421              : #endif
    2422              : 
    2423            0 :    if (p == 0)                  /* current directory */
    2424            0 :       strcpy(path, ".");
    2425            0 :    else if (p == path)          /* root directory */
    2426            0 :       snprintf(path, FILENAME_MAX, "%c", *p);
    2427              :    else
    2428            0 :       *p = 0;
    2429              : 
    2430            0 :    return;
    2431              : }
    2432              : 
    2433              : /*------------------------------------------------------------------*/
    2434              : 
    2435              : /**
    2436              :  * Retieve node at a certain line number
    2437              :  */
    2438            0 : PMXML_NODE mxml_get_node_at_line(PMXML_NODE tree, int line_number)
    2439              : {
    2440              :    int i;
    2441              :    PMXML_NODE pn;
    2442              : 
    2443            0 :    if (tree->line_number_start == line_number)
    2444            0 :       return tree;
    2445              :    
    2446            0 :    for (i=0 ; i<tree->n_children ; i++) {
    2447            0 :       pn = mxml_get_node_at_line(&tree->child[i], line_number);
    2448            0 :       if (pn)
    2449            0 :          return pn;
    2450              :    }
    2451              :     
    2452            0 :    return NULL;
    2453              : }
    2454              : 
    2455              : /* emacs
    2456              :  * Local Variables:
    2457              :  * tab-width: 8
    2458              :  * c-basic-offset: 3
    2459              :  * indent-tabs-mode: nil
    2460              :  * End:
    2461              :  */
        

Generated by: LCOV version 2.0-1