blob: f6b86c0b5c449c975c4fa9d0cdb1d4d1a45948d8 [file] [log] [blame]
Paul Cercueil5d9db302014-02-18 18:16:51 +01001#include "debug.h"
2#include "iio-private.h"
3
4#include <errno.h>
5#include <libxml/tree.h>
6#include <string.h>
7
Paul Cercueil5d9db302014-02-18 18:16:51 +01008static int add_attr_to_channel(struct iio_channel *chn, xmlNode *n)
9{
10 xmlAttr *attr;
Paul Cercueil5cd260e2014-02-24 13:16:01 +010011 char **attrs, *name = NULL;
Paul Cercueil5d9db302014-02-18 18:16:51 +010012
13 for (attr = n->properties; attr; attr = attr->next) {
14 if (!strcmp((char *) attr->name, "name")) {
15 name = strdup((char *) attr->children->content);
Paul Cercueil5d9db302014-02-18 18:16:51 +010016 } else {
17 WARNING("Unknown field \'%s\' in channel %s\n",
18 attr->name, chn->id);
19 }
20 }
21
Paul Cercueil5cd260e2014-02-24 13:16:01 +010022 if (!name) {
Paul Cercueil5d9db302014-02-18 18:16:51 +010023 ERROR("Incomplete attribute in channel %s\n", chn->id);
24 goto err_free;
25 }
26
27 attrs = realloc(chn->attrs, (1 + chn->nb_attrs) * sizeof(char *));
28 if (!attrs)
29 goto err_free;
30
Paul Cercueil5d9db302014-02-18 18:16:51 +010031 attrs[chn->nb_attrs++] = name;
32 chn->attrs = attrs;
33 return 0;
34
Paul Cercueil5d9db302014-02-18 18:16:51 +010035err_free:
36 if (name)
37 free(name);
Paul Cercueil5d9db302014-02-18 18:16:51 +010038 return -1;
39}
40
41static int add_attr_to_device(struct iio_device *dev, xmlNode *n)
42{
43 xmlAttr *attr;
Paul Cercueil5cd260e2014-02-24 13:16:01 +010044 char **attrs, *name = NULL;
Paul Cercueil5d9db302014-02-18 18:16:51 +010045
46 for (attr = n->properties; attr; attr = attr->next) {
47 if (!strcmp((char *) attr->name, "name")) {
48 name = strdup((char *) attr->children->content);
Paul Cercueil5d9db302014-02-18 18:16:51 +010049 } else {
50 WARNING("Unknown field \'%s\' in device %s\n",
51 attr->name, dev->id);
52 }
53 }
54
Paul Cercueil5cd260e2014-02-24 13:16:01 +010055 if (!name) {
Paul Cercueil5d9db302014-02-18 18:16:51 +010056 ERROR("Incomplete attribute in device %s\n", dev->id);
57 goto err_free;
58 }
59
60 attrs = realloc(dev->attrs, (1 + dev->nb_attrs) * sizeof(char *));
61 if (!attrs)
62 goto err_free;
63
Paul Cercueil5d9db302014-02-18 18:16:51 +010064 attrs[dev->nb_attrs++] = name;
65 dev->attrs = attrs;
66 return 0;
67
Paul Cercueil5d9db302014-02-18 18:16:51 +010068err_free:
69 if (name)
70 free(name);
Paul Cercueil5d9db302014-02-18 18:16:51 +010071 return -1;
72}
73
74static struct iio_channel * create_channel(struct iio_device *dev, xmlNode *n)
75{
76 xmlAttr *attr;
77 struct iio_channel *chn = calloc(1, sizeof(*chn));
78 if (!chn)
79 return NULL;
80
81 chn->dev = dev;
Paul Cercueil5d9db302014-02-18 18:16:51 +010082
83 for (attr = n->properties; attr; attr = attr->next) {
Paul Cercueil35a01312014-02-20 10:56:57 +010084 const char *name = (const char *) attr->name,
85 *content = (const char *) attr->children->content;
86 if (!strcmp(name, "name")) {
87 chn->name = strdup(content);
88 } else if (!strcmp(name, "id")) {
89 chn->id = strdup(content);
90 } else if (!strcmp(name, "type")) {
91 if (!strcmp(content, "output"))
92 chn->is_output = true;
93 else if (strcmp(content, "input"))
94 WARNING("Unknown channel type %s\n", content);
Paul Cercueil5d9db302014-02-18 18:16:51 +010095 } else {
96 WARNING("Unknown attribute \'%s\' in <channel>\n",
Paul Cercueil35a01312014-02-20 10:56:57 +010097 name);
Paul Cercueil5d9db302014-02-18 18:16:51 +010098 }
99 }
100
101 if (!chn->id) {
102 ERROR("Incomplete <attribute>\n");
103 goto err_free_channel;
104 }
105
106 for (n = n->children; n; n = n->next) {
107 if (!strcmp((char *) n->name, "attribute")) {
108 if (add_attr_to_channel(chn, n) < 0)
109 goto err_free_channel;
110 } else if (strcmp((char *) n->name, "text")) {
111 WARNING("Unknown children \'%s\' in <device>\n",
112 n->name);
113 continue;
114 }
115 }
116
117 return chn;
118
119err_free_channel:
120 free_channel(chn);
121 return NULL;
122}
123
124static struct iio_device * create_device(struct iio_context *ctx, xmlNode *n)
125{
126 xmlAttr *attr;
127 struct iio_device *dev = calloc(1, sizeof(*dev));
128 if (!dev)
129 return NULL;
130
131 dev->ctx = ctx;
132
133 for (attr = n->properties; attr; attr = attr->next) {
134 if (!strcmp((char *) attr->name, "name")) {
135 dev->name = strdup((char *) attr->children->content);
136 } else if (!strcmp((char *) attr->name, "id")) {
137 dev->id = strdup((char *) attr->children->content);
138 } else {
139 WARNING("Unknown attribute \'%s\' in <context>\n",
140 attr->name);
141 }
142 }
143
144 if (!dev->id) {
145 ERROR("Unable to read device ID\n");
146 goto err_free_device;
147 }
148
149 for (n = n->children; n; n = n->next) {
150 if (!strcmp((char *) n->name, "channel")) {
151 struct iio_channel **chns,
152 *chn = create_channel(dev, n);
153 if (!chn) {
154 ERROR("Unable to create channel\n");
155 goto err_free_device;
156 }
157
158 chns = realloc(dev->channels, (1 + dev->nb_channels) *
159 sizeof(struct iio_channel *));
160 if (!chns) {
161 ERROR("Unable to allocate memory\n");
162 free(chn);
163 goto err_free_device;
164 }
165
166 chns[dev->nb_channels++] = chn;
167 dev->channels = chns;
168 } else if (!strcmp((char *) n->name, "attribute")) {
169 if (add_attr_to_device(dev, n) < 0)
170 goto err_free_device;
171 } else if (strcmp((char *) n->name, "text")) {
172 WARNING("Unknown children \'%s\' in <device>\n",
173 n->name);
174 continue;
175 }
176 }
177
178 return dev;
179
180err_free_device:
181 free_device(dev);
182 return NULL;
183}
184
Paul Cercueil5d9db302014-02-18 18:16:51 +0100185static struct iio_backend_ops xml_ops = {
Paul Cercueil5d9db302014-02-18 18:16:51 +0100186};
187
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100188static struct iio_context * iio_create_xml_context_helper(xmlDoc *doc)
Paul Cercueil5d9db302014-02-18 18:16:51 +0100189{
190 unsigned int i;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100191 xmlNode *root, *n;
192 struct iio_context *ctx = calloc(1, sizeof(*ctx));
193 if (!ctx)
194 return NULL;
195
Paul Cercueil5d9db302014-02-18 18:16:51 +0100196 ctx->name = "xml";
197 ctx->ops = &xml_ops;
198
Paul Cercueil5d9db302014-02-18 18:16:51 +0100199 root = xmlDocGetRootElement(doc);
200 if (strcmp((char *) root->name, "context")) {
201 ERROR("Unrecognized XML file\n");
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100202 goto err_free_ctx;
Paul Cercueil5d9db302014-02-18 18:16:51 +0100203 }
204
205 for (n = root->children; n; n = n->next) {
206 struct iio_device **devs, *dev;
207
208 if (strcmp((char *) n->name, "device")) {
209 if (strcmp((char *) n->name, "text"))
210 WARNING("Unknown children \'%s\' in "
211 "<context>\n", n->name);
212 continue;
213 }
214
215 dev = create_device(ctx, n);
216 if (!dev) {
217 ERROR("Unable to create device\n");
218 goto err_free_devices;
219 }
220
221 devs = realloc(ctx->devices, (1 + ctx->nb_devices) *
222 sizeof(struct iio_device *));
223 if (!devs) {
224 ERROR("Unable to allocate memory\n");
225 free(dev);
226 goto err_free_devices;
227 }
228
229 devs[ctx->nb_devices++] = dev;
230 ctx->devices = devs;
231 }
232
233 return ctx;
234
235err_free_devices:
236 for (i = 0; i < ctx->nb_devices; i++)
237 free_device(ctx->devices[i]);
238 if (ctx->nb_devices)
239 free(ctx->devices);
Paul Cercueil5d9db302014-02-18 18:16:51 +0100240err_free_ctx:
241 free(ctx);
242 return NULL;
243}
Paul Cercueil8b1f9d02014-02-21 16:24:51 +0100244
245struct iio_context * iio_create_xml_context(const char *xml_file)
246{
247 struct iio_context *ctx;
248 xmlDoc *doc;
249
250 LIBXML_TEST_VERSION;
251
252 doc = xmlReadFile(xml_file, NULL, XML_PARSE_DTDVALID);
253 if (!doc) {
254 ERROR("Unable to parse XML file\n");
255 return NULL;
256 }
257
258 ctx = iio_create_xml_context_helper(doc);
259 xmlFreeDoc(doc);
260 xmlCleanupParser();
261 return ctx;
262}
263
264struct iio_context * iio_create_xml_context_mem(const char *xml)
265{
266 struct iio_context *ctx;
267 xmlDoc *doc;
268
269 LIBXML_TEST_VERSION;
270
271 doc = xmlReadMemory(xml, strlen(xml), NULL, NULL, XML_PARSE_DTDVALID);
272 if (!doc) {
273 ERROR("Unable to parse XML file\n");
274 return NULL;
275 }
276
277 ctx = iio_create_xml_context_helper(doc);
278 xmlFreeDoc(doc);
279 xmlCleanupParser();
280 return ctx;
281}