uxmlstream.c

Go to the documentation of this file.
00001 /*
00002  * Copyright (C) 2008 by egnite GmbH. All rights reserved.
00003  *
00004  * Redistribution and use in source and binary forms, with or without
00005  * modification, are permitted provided that the following conditions
00006  * are met:
00007  *
00008  * 1. Redistributions of source code must retain the above copyright
00009  *    notice, this list of conditions and the following disclaimer.
00010  * 2. Redistributions in binary form must reproduce the above copyright
00011  *    notice, this list of conditions and the following disclaimer in the
00012  *    documentation and/or other materials provided with the distribution.
00013  * 3. Neither the name of the copyright holders nor the names of
00014  *    contributors may be used to endorse or promote products derived
00015  *    from this software without specific prior written permission.
00016  *
00017  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
00018  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
00019  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
00020  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
00021  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
00022  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
00023  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
00024  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
00025  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
00026  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
00027  * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
00028  * SUCH DAMAGE.
00029  *
00030  * For additional information see http://www.ethernut.de/
00031  *
00032  */
00033 
00034 /*
00035  * \file pro/uxmlstream.c
00036  * \brief Micro XML stream parser.
00037  *
00038  * \verbatim
00039  * $Id: uxmlstream.c,v 1.1 2008/02/15 16:46:09 haraldkipp Exp $
00040  * \endverbatim
00041  */
00042 
00043 #include <sys/types.h>
00044 
00045 #include <stdlib.h>
00046 #include <string.h>
00047 #include <ctype.h>
00048 
00049 #include <pro/uxml.h>
00050 
00055 
00056 #ifndef MAX_UXMLTAG_SIZE
00057 
00062 #define MAX_UXMLTAG_SIZE     512
00063 #endif
00064 
00065 #ifndef MAX_UXMLTKN_SIZE
00066 
00073 #define MAX_UXMLTKN_SIZE     64
00074 #endif
00075 
00076 static int UxmlReadTag(FILE * stream, char *data, size_t size)
00077 {
00078     int rc = -1;
00079     int ch;
00080     int qc = 0;
00081     int state = 1;
00082     char *dp = NULL;
00083 
00084     while (state) {
00085         ch = fgetc(stream);
00086         if (ch == EOF || ch == 0) {
00087             break;
00088         }
00089         switch (state) {
00090         case 1:
00091             /* Searching first bracket. */
00092             if (ch == '<') {
00093                 /* Opening bracket found. Start collecting. */
00094                 dp = data;
00095                 state = 4;
00096             } else if (ch == '"' || ch == '\'') {
00097                 /* Quote found. Skip quoted string. */
00098                 qc = ch;
00099                 state++;
00100             }
00101             break;
00102         case 2:
00103             /* Skipping quoted string. */
00104         case 5:
00105             /* Collecting quoted string. */
00106             if (ch == qc) {
00107                 /* End quote found. */
00108                 state--;
00109             }
00110             break;
00111         case 3:
00112             /* Compressing spaces. */
00113             if (isspace(ch)) {
00114                 ch = 0;
00115                 break;
00116             }
00117             state = 4;
00118             /* Fall through. */
00119         case 4:
00120             /* Collecting data. */
00121             if (ch == '>') {
00122                 rc = 0;
00123                 state = 0;
00124             } else if (ch == '"' || ch == '\'') {
00125                 qc = ch;
00126                 state++;
00127             } else if (isspace(ch)) {
00128                 ch = ' ';
00129                 state = 3;
00130             }
00131             break;
00132         }
00133         if (dp && ch) {
00134             if (size > 1) {
00135                 size--;
00136                 *dp++ = ch;
00137             } else {
00138                 break;
00139             }
00140         }
00141     }
00142     if (dp) {
00143         *dp = 0;
00144     }
00145     return rc;
00146 }
00147 
00193 UXML_NODE *UxmlParseStream(FILE * stream, char **f_tags, char **f_attr)
00194 {
00195     char *tag;
00196     char *tkn;
00197     char *tp;
00198     UXML_NODE *root = NULL;
00199     UXML_NODE *node = NULL;
00200     UXML_NODE *nn;
00201 
00202     /* Allocate the tag buffer. */
00203     if ((tag = malloc(MAX_UXMLTAG_SIZE)) == NULL) {
00204         return NULL;
00205     }
00206     /* Allocate the token buffer. */
00207     if ((tkn = malloc(MAX_UXMLTKN_SIZE)) == NULL) {
00208         free(tag);
00209         return NULL;
00210     }
00211     for (;;) {
00212         /* Read the next tag. */
00213         if (UxmlReadTag(stream, tag, MAX_UXMLTAG_SIZE)) {
00214             /* No more tags or error. */
00215             break;
00216         }
00217         /* Parse the tag. */
00218         if ((tp = UxmlParseTag(tag + 1, tkn, MAX_UXMLTKN_SIZE)) != NULL) {
00219             if (isalpha(*tkn) && UxmlFilterMatch(tkn, f_tags)) {
00220                 /* 
00221                  * New node. 
00222                  */
00223                 if ((nn = UxmlNodeCreate(tkn)) == NULL) {
00224                     break;
00225                 }
00226                 if (root == NULL) {
00227                     /* Root entry. */
00228                     root = nn;
00229                     node = nn;
00230                 } else if (node == NULL) {
00231                     /* No active node. Add root siblings. */
00232                     node = UxmlTreeAddSibling(root, nn);
00233                 } else {
00234                     /* New node is a child of the currently active one. */
00235                     node = UxmlTreeAddChild(node, nn);
00236                 }
00237                 /* Parse the attributes. */
00238                 for (;;) {
00239                     if ((tp = UxmlParseTag(tp, tkn, MAX_UXMLTKN_SIZE)) == NULL || *tkn == '>') {
00240                         /* End of this tag or error. */
00241                         break;
00242                     }
00243                     if (isalpha(*tkn) && UxmlFilterMatch(tkn, f_attr)) {
00244                         size_t len = strlen(tkn) + 1;
00245                         char *name = malloc(len);
00246 
00247                         if (name) {
00248                             memcpy(name, tkn, len);
00249                             if ((tp = UxmlParseTag(tp, tkn, MAX_UXMLTKN_SIZE)) == NULL || *tkn != '=') {
00250                                 break;
00251                             }
00252                             if ((tp = UxmlParseTag(tp, tkn, MAX_UXMLTKN_SIZE)) == NULL || *tkn == '>') {
00253                                 break;
00254                             }
00255                             UxmlNodeAddAttrib(node, name, tkn);
00256                             free(name);
00257                         }
00258                     }
00259                 }
00260             } else if (*tkn == '/') {
00261                 /* 
00262                  * End of the active node. 
00263                  */
00264                 tp = UxmlParseTag(tp, tkn, MAX_UXMLTKN_SIZE);
00265                 if (tp && node && strcasecmp(node->xmln_name, tkn) == 0) {
00266                     node = node->xmln_parent;
00267                 }
00268             }
00269         }
00270     }
00271     /* Clean up. */
00272     free(tag);
00273     free(tkn);
00274 
00275     return root;
00276 }
00277 

© 2000-2007 by egnite Software GmbH - visit http://www.ethernut.de/