chiark / gitweb /
core: add new ConditionArchitecture() that checks the architecture returned by uname...
[elogind.git] / src / shared / xml.c
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_TEXT,
29         STATE_TAG,
30         STATE_ATTRIBUTE,
31 };
32
33 /* We don't actually do real XML here. We only read a simplistic
34  * subset, that is a bit less strict that XML and lacks all the more
35  * complex features, like entities, or namespaces. However, we do
36  * support some HTML5-like simplifications */
37
38 int xml_tokenize(const char **p, char **name, void **state) {
39         const char *c, *e, *b;
40         char *ret;
41         int t;
42
43         assert(p);
44         assert(*p);
45         assert(name);
46         assert(state);
47
48         t = PTR_TO_INT(*state);
49         c = *p;
50
51         for (;;) {
52                 if (*c == 0)
53                         return XML_END;
54
55                 switch (t) {
56
57                 case STATE_TEXT: {
58                         int x;
59
60                         e = strchrnul(c, '<');
61                         if (e > c) {
62                                 /* More text... */
63                                 ret = strndup(c, e - c);
64                                 if (!ret)
65                                         return -ENOMEM;
66
67                                 *name = ret;
68                                 *p = e;
69                                 *state = INT_TO_PTR(STATE_TEXT);
70
71                                 return XML_TEXT;
72                         }
73
74                         assert(*e == '<');
75                         b = c + 1;
76
77                         if (startswith(b, "!--")) {
78                                 /* A comment */
79                                 e = strstr(b + 3, "-->");
80                                 if (!e)
81                                         return -EINVAL;
82
83                                 c = e + 3;
84                                 continue;
85                         }
86
87                         if (*b == '?') {
88                                 /* Processing instruction */
89
90                                 e = strstr(b + 1, "?>");
91                                 if (!e)
92                                         return -EINVAL;
93
94                                 c = e + 2;
95                                 continue;
96                         }
97
98                         if (*b == '!') {
99                                 /* DTD */
100
101                                 e = strchr(b + 1, '>');
102                                 if (!e)
103                                         return -EINVAL;
104
105                                 c = e + 1;
106                                 continue;
107                         }
108
109                         if (*b == '/') {
110                                 /* A closing tag */
111                                 x = XML_TAG_CLOSE;
112                                 b++;
113                         } else
114                                 x = XML_TAG_OPEN;
115
116                         e = strpbrk(b, WHITESPACE "/>");
117                         if (!e)
118                                 return -EINVAL;
119
120                         ret = strndup(b, e - b);
121                         if (!ret)
122                                 return -ENOMEM;
123
124                         *name = ret;
125                         *p = e;
126                         *state = INT_TO_PTR(STATE_TAG);
127
128                         return x;
129                 }
130
131                 case STATE_TAG:
132
133                         b = c + strspn(c, WHITESPACE);
134                         if (*b == 0)
135                                 return -EINVAL;
136
137                         e = b + strcspn(b, WHITESPACE "=/>");
138                         if (e > b) {
139                                 /* An attribute */
140
141                                 ret = strndup(b, e - b);
142                                 if (!ret)
143                                         return -ENOMEM;
144
145                                 *name = ret;
146                                 *p = e;
147                                 *state = INT_TO_PTR(STATE_ATTRIBUTE);
148
149                                 return XML_ATTRIBUTE_NAME;
150                         }
151
152                         if (startswith(b, "/>")) {
153                                 /* An empty tag */
154
155                                 *name = NULL; /* For empty tags we return a NULL name, the caller must be prepared for that */
156                                 *p = b + 2;
157                                 *state = INT_TO_PTR(STATE_TEXT);
158
159                                 return XML_TAG_CLOSE_EMPTY;
160                         }
161
162                         if (*b != '>')
163                                 return -EINVAL;
164
165                         c = b + 1;
166                         t = STATE_TEXT;
167                         continue;
168
169                 case STATE_ATTRIBUTE:
170
171                         if (*c == '=') {
172                                 c++;
173
174                                 if (*c == '\'' || *c == '\"') {
175                                         /* Tag with a quoted value */
176
177                                         e = strchr(c+1, *c);
178                                         if (!e)
179                                                 return -EINVAL;
180
181                                         ret = strndup(c+1, e - c - 1);
182                                         if (!ret)
183                                                 return -ENOMEM;
184
185                                         *name = ret;
186                                         *p = e + 1;
187                                         *state = INT_TO_PTR(STATE_TAG);
188
189                                         return XML_ATTRIBUTE_VALUE;
190
191                                 }
192
193                                 /* Tag with a value without quotes */
194
195                                 b = strpbrk(c, WHITESPACE ">");
196                                 if (!b)
197                                         b = c;
198
199                                 ret = strndup(c, b - c);
200                                 if (!ret)
201                                         return -ENOMEM;
202
203                                 *name = ret;
204                                 *p = b;
205                                 *state = INT_TO_PTR(STATE_TAG);
206                                 return XML_ATTRIBUTE_VALUE;
207                         }
208
209                         t = STATE_TAG;
210                         continue;
211                 }
212
213         }
214
215         assert_not_reached("Bad state");
216 }