]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/basic/xml.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 Copyright 2013 Lennart Poettering
11 #include "string-util.h"
21 static void inc_lines(unsigned *line
, const char *s
, size_t n
) {
30 f
= memchr(p
, '\n', n
);
40 /* We don't actually do real XML here. We only read a simplistic
41 * subset, that is a bit less strict that XML and lacks all the more
42 * complex features, like entities, or namespaces. However, we do
43 * support some HTML5-like simplifications */
45 int xml_tokenize(const char **p
, char **name
, void **state
, unsigned *line
) {
46 const char *c
, *e
, *b
;
55 t
= PTR_TO_INT(*state
);
58 if (t
== STATE_NULL
) {
73 e
= strchrnul(c
, '<');
76 ret
= strndup(c
, e
- c
);
80 inc_lines(line
, c
, e
- c
);
84 *state
= INT_TO_PTR(STATE_TEXT
);
92 if (startswith(b
, "!--")) {
94 e
= strstr(b
+ 3, "-->");
98 inc_lines(line
, b
, e
+ 3 - b
);
105 /* Processing instruction */
107 e
= strstr(b
+ 1, "?>");
111 inc_lines(line
, b
, e
+ 2 - b
);
120 e
= strchr(b
+ 1, '>');
124 inc_lines(line
, b
, e
+ 1 - b
);
137 e
= strpbrk(b
, WHITESPACE
"/>");
141 ret
= strndup(b
, e
- b
);
147 *state
= INT_TO_PTR(STATE_TAG
);
154 b
= c
+ strspn(c
, WHITESPACE
);
158 inc_lines(line
, c
, b
- c
);
160 e
= b
+ strcspn(b
, WHITESPACE
"=/>");
164 ret
= strndup(b
, e
- b
);
170 *state
= INT_TO_PTR(STATE_ATTRIBUTE
);
172 return XML_ATTRIBUTE_NAME
;
175 if (startswith(b
, "/>")) {
178 *name
= NULL
; /* For empty tags we return a NULL name, the caller must be prepared for that */
180 *state
= INT_TO_PTR(STATE_TEXT
);
182 return XML_TAG_CLOSE_EMPTY
;
192 case STATE_ATTRIBUTE
:
197 if (IN_SET(*c
, '\'', '\"')) {
198 /* Tag with a quoted value */
204 inc_lines(line
, c
, e
- c
);
206 ret
= strndup(c
+1, e
- c
- 1);
212 *state
= INT_TO_PTR(STATE_TAG
);
214 return XML_ATTRIBUTE_VALUE
;
218 /* Tag with a value without quotes */
220 b
= strpbrk(c
, WHITESPACE
">");
224 ret
= strndup(c
, b
- c
);
230 *state
= INT_TO_PTR(STATE_TAG
);
231 return XML_ATTRIBUTE_VALUE
;
240 assert_not_reached("Bad state");