xml.c revision b26fa1a2fbcfee7d03b0c8fd15ec3aa64ae70b9f
/***
This file is part of systemd.
Copyright 2013 Lennart Poettering
under the terms of the GNU Lesser General Public License as published by
the Free Software Foundation; either version 2.1 of the License, or
(at your option) any later version.
systemd is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with systemd; If not, see <http://www.gnu.org/licenses/>.
***/
#include <errno.h>
#include <stddef.h>
#include <string.h>
#include "macro.h"
#include "string-util.h"
#include "xml.h"
enum {
};
const char *p = s;
if (!line)
return;
for (;;) {
const char *f;
f = memchr(p, '\n', n);
if (!f)
return;
n -= (f - p) + 1;
p = f + 1;
(*line)++;
}
}
/* We don't actually do real XML here. We only read a simplistic
* subset, that is a bit less strict that XML and lacks all the more
* complex features, like entities, or namespaces. However, we do
* support some HTML5-like simplifications */
const char *c, *e, *b;
char *ret;
int t;
assert(p);
assert(*p);
t = PTR_TO_INT(*state);
c = *p;
if (t == STATE_NULL) {
if (line)
*line = 1;
t = STATE_TEXT;
}
for (;;) {
if (*c == 0)
return XML_END;
switch (t) {
case STATE_TEXT: {
int x;
e = strchrnul(c, '<');
if (e > c) {
/* More text... */
if (!ret)
return -ENOMEM;
*p = e;
return XML_TEXT;
}
assert(*e == '<');
b = c + 1;
if (startswith(b, "!--")) {
/* A comment */
if (!e)
return -EINVAL;
c = e + 3;
continue;
}
if (*b == '?') {
/* Processing instruction */
if (!e)
return -EINVAL;
c = e + 2;
continue;
}
if (*b == '!') {
/* DTD */
if (!e)
return -EINVAL;
c = e + 1;
continue;
}
if (*b == '/') {
/* A closing tag */
x = XML_TAG_CLOSE;
b++;
} else
x = XML_TAG_OPEN;
if (!e)
return -EINVAL;
if (!ret)
return -ENOMEM;
*p = e;
return x;
}
case STATE_TAG:
b = c + strspn(c, WHITESPACE);
if (*b == 0)
return -EINVAL;
if (e > b) {
/* An attribute */
if (!ret)
return -ENOMEM;
*p = e;
return XML_ATTRIBUTE_NAME;
}
if (startswith(b, "/>")) {
/* An empty tag */
*p = b + 2;
return XML_TAG_CLOSE_EMPTY;
}
if (*b != '>')
return -EINVAL;
c = b + 1;
t = STATE_TEXT;
continue;
case STATE_ATTRIBUTE:
if (*c == '=') {
c++;
if (*c == '\'' || *c == '\"') {
/* Tag with a quoted value */
e = strchr(c+1, *c);
if (!e)
return -EINVAL;
if (!ret)
return -ENOMEM;
*p = e + 1;
return XML_ATTRIBUTE_VALUE;
}
/* Tag with a value without quotes */
if (!b)
b = c;
if (!ret)
return -ENOMEM;
*p = b;
return XML_ATTRIBUTE_VALUE;
}
t = STATE_TAG;
continue;
}
}
assert_not_reached("Bad state");
}