LCOV - code coverage report
Current view: top level - basic - xml.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 107 122 87.7 %
Date: 2015-07-29 18:47:03 Functions: 2 2 100.0 %

          Line data    Source code
       1             : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
       2             : 
       3             : /***
       4             :   This file is part of systemd.
       5             : 
       6             :   Copyright 2013 Lennart Poettering
       7             : 
       8             :   systemd is free software; you can redistribute it and/or modify it
       9             :   under the terms of the GNU Lesser General Public License as published by
      10             :   the Free Software Foundation; either version 2.1 of the License, or
      11             :   (at your option) any later version.
      12             : 
      13             :   systemd is distributed in the hope that it will be useful, but
      14             :   WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
      16             :   Lesser General Public License for more details.
      17             : 
      18             :   You should have received a copy of the GNU Lesser General Public License
      19             :   along with systemd; If not, see <http://www.gnu.org/licenses/>.
      20             : ***/
      21             : 
      22             : #include <string.h>
      23             : 
      24             : #include "util.h"
      25             : #include "xml.h"
      26             : 
      27             : enum {
      28             :         STATE_NULL,
      29             :         STATE_TEXT,
      30             :         STATE_TAG,
      31             :         STATE_ATTRIBUTE,
      32             : };
      33             : 
      34         859 : static void inc_lines(unsigned *line, const char *s, size_t n) {
      35         859 :         const char *p = s;
      36             : 
      37         859 :         if (!line)
      38          13 :                 return;
      39             : 
      40             :         for (;;) {
      41             :                 const char *f;
      42             : 
      43        1177 :                 f = memchr(p, '\n', n);
      44        1177 :                 if (!f)
      45         846 :                         return;
      46             : 
      47         331 :                 n -= (f - p) + 1;
      48         331 :                 p = f + 1;
      49         331 :                 (*line)++;
      50         331 :         }
      51             : }
      52             : 
      53             : /* We don't actually do real XML here. We only read a simplistic
      54             :  * subset, that is a bit less strict that XML and lacks all the more
      55             :  * complex features, like entities, or namespaces. However, we do
      56             :  * support some HTML5-like simplifications */
      57             : 
      58         896 : int xml_tokenize(const char **p, char **name, void **state, unsigned *line) {
      59             :         const char *c, *e, *b;
      60             :         char *ret;
      61             :         int t;
      62             : 
      63         896 :         assert(p);
      64         896 :         assert(*p);
      65         896 :         assert(name);
      66         896 :         assert(state);
      67             : 
      68         896 :         t = PTR_TO_INT(*state);
      69         896 :         c = *p;
      70             : 
      71         896 :         if (t == STATE_NULL) {
      72          13 :                 if (line)
      73           9 :                         *line = 1;
      74          13 :                 t = STATE_TEXT;
      75             :         }
      76             : 
      77             :         for (;;) {
      78        1106 :                 if (*c == 0)
      79          13 :                         return XML_END;
      80             : 
      81        1093 :                 switch (t) {
      82             : 
      83             :                 case STATE_TEXT: {
      84             :                         int x;
      85             : 
      86         570 :                         e = strchrnul(c, '<');
      87         570 :                         if (e > c) {
      88             :                                 /* More text... */
      89         283 :                                 ret = strndup(c, e - c);
      90         283 :                                 if (!ret)
      91           0 :                                         return -ENOMEM;
      92             : 
      93         283 :                                 inc_lines(line, c, e - c);
      94             : 
      95         283 :                                 *name = ret;
      96         283 :                                 *p = e;
      97         283 :                                 *state = INT_TO_PTR(STATE_TEXT);
      98             : 
      99         283 :                                 return XML_TEXT;
     100             :                         }
     101             : 
     102         287 :                         assert(*e == '<');
     103         287 :                         b = c + 1;
     104             : 
     105         287 :                         if (startswith(b, "!--")) {
     106             :                                 /* A comment */
     107          40 :                                 e = strstr(b + 3, "-->");
     108          40 :                                 if (!e)
     109           0 :                                         return -EINVAL;
     110             : 
     111          40 :                                 inc_lines(line, b, e + 3 - b);
     112             : 
     113          40 :                                 c = e + 3;
     114          40 :                                 continue;
     115             :                         }
     116             : 
     117         247 :                         if (*b == '?') {
     118             :                                 /* Processing instruction */
     119             : 
     120           5 :                                 e = strstr(b + 1, "?>");
     121           5 :                                 if (!e)
     122           0 :                                         return -EINVAL;
     123             : 
     124           5 :                                 inc_lines(line, b, e + 2 - b);
     125             : 
     126           5 :                                 c = e + 2;
     127           5 :                                 continue;
     128             :                         }
     129             : 
     130         242 :                         if (*b == '!') {
     131             :                                 /* DTD */
     132             : 
     133           9 :                                 e = strchr(b + 1, '>');
     134           9 :                                 if (!e)
     135           0 :                                         return -EINVAL;
     136             : 
     137           9 :                                 inc_lines(line, b, e + 1 - b);
     138             : 
     139           9 :                                 c = e + 1;
     140           9 :                                 continue;
     141             :                         }
     142             : 
     143         233 :                         if (*b == '/') {
     144             :                                 /* A closing tag */
     145          78 :                                 x = XML_TAG_CLOSE;
     146          78 :                                 b++;
     147             :                         } else
     148         155 :                                 x = XML_TAG_OPEN;
     149             : 
     150         233 :                         e = strpbrk(b, WHITESPACE "/>");
     151         233 :                         if (!e)
     152           0 :                                 return -EINVAL;
     153             : 
     154         233 :                         ret = strndup(b, e - b);
     155         233 :                         if (!ret)
     156           0 :                                 return -ENOMEM;
     157             : 
     158         233 :                         *name = ret;
     159         233 :                         *p = e;
     160         233 :                         *state = INT_TO_PTR(STATE_TAG);
     161             : 
     162         233 :                         return x;
     163             :                 }
     164             : 
     165             :                 case STATE_TAG:
     166             : 
     167         378 :                         b = c + strspn(c, WHITESPACE);
     168         378 :                         if (*b == 0)
     169           0 :                                 return -EINVAL;
     170             : 
     171         378 :                         inc_lines(line, c, b - c);
     172             : 
     173         378 :                         e = b + strcspn(b, WHITESPACE "=/>");
     174         378 :                         if (e > b) {
     175             :                                 /* An attribute */
     176             : 
     177         145 :                                 ret = strndup(b, e - b);
     178         145 :                                 if (!ret)
     179           0 :                                         return -ENOMEM;
     180             : 
     181         145 :                                 *name = ret;
     182         145 :                                 *p = e;
     183         145 :                                 *state = INT_TO_PTR(STATE_ATTRIBUTE);
     184             : 
     185         145 :                                 return XML_ATTRIBUTE_NAME;
     186             :                         }
     187             : 
     188         233 :                         if (startswith(b, "/>")) {
     189             :                                 /* An empty tag */
     190             : 
     191          77 :                                 *name = NULL; /* For empty tags we return a NULL name, the caller must be prepared for that */
     192          77 :                                 *p = b + 2;
     193          77 :                                 *state = INT_TO_PTR(STATE_TEXT);
     194             : 
     195          77 :                                 return XML_TAG_CLOSE_EMPTY;
     196             :                         }
     197             : 
     198         156 :                         if (*b != '>')
     199           0 :                                 return -EINVAL;
     200             : 
     201         156 :                         c = b + 1;
     202         156 :                         t = STATE_TEXT;
     203         156 :                         continue;
     204             : 
     205             :                 case STATE_ATTRIBUTE:
     206             : 
     207         145 :                         if (*c == '=') {
     208         145 :                                 c++;
     209             : 
     210         145 :                                 if (*c == '\'' || *c == '\"') {
     211             :                                         /* Tag with a quoted value */
     212             : 
     213         144 :                                         e = strchr(c+1, *c);
     214         144 :                                         if (!e)
     215           0 :                                                 return -EINVAL;
     216             : 
     217         144 :                                         inc_lines(line, c, e - c);
     218             : 
     219         144 :                                         ret = strndup(c+1, e - c - 1);
     220         144 :                                         if (!ret)
     221           0 :                                                 return -ENOMEM;
     222             : 
     223         144 :                                         *name = ret;
     224         144 :                                         *p = e + 1;
     225         144 :                                         *state = INT_TO_PTR(STATE_TAG);
     226             : 
     227         144 :                                         return XML_ATTRIBUTE_VALUE;
     228             : 
     229             :                                 }
     230             : 
     231             :                                 /* Tag with a value without quotes */
     232             : 
     233           1 :                                 b = strpbrk(c, WHITESPACE ">");
     234           1 :                                 if (!b)
     235           0 :                                         b = c;
     236             : 
     237           1 :                                 ret = strndup(c, b - c);
     238           1 :                                 if (!ret)
     239           0 :                                         return -ENOMEM;
     240             : 
     241           1 :                                 *name = ret;
     242           1 :                                 *p = b;
     243           1 :                                 *state = INT_TO_PTR(STATE_TAG);
     244           1 :                                 return XML_ATTRIBUTE_VALUE;
     245             :                         }
     246             : 
     247           0 :                         t = STATE_TAG;
     248           0 :                         continue;
     249             :                 }
     250             : 
     251         210 :         }
     252             : 
     253             :         assert_not_reached("Bad state");
     254             : }

Generated by: LCOV version 1.11