Library for interfacing with IIO devices. Licensed under the LGPLv2+
Dependencies: libserialport libxml2
xml.c@4:ad69b39bf124, 2017-06-26 (annotated)
- Committer:
- pcercuei
- Date:
- Mon Jun 26 14:30:10 2017 +0000
- Revision:
- 4:ad69b39bf124
- Parent:
- 3:d147beabba0e
Update to upstream version v0.10
Who changed what in which revision?
User | Revision | Line number | New contents of line |
---|---|---|---|
pcercuei | 0:df031b60ca29 | 1 | /* |
pcercuei | 0:df031b60ca29 | 2 | * libiio - Library for interfacing industrial I/O (IIO) devices |
pcercuei | 0:df031b60ca29 | 3 | * |
pcercuei | 0:df031b60ca29 | 4 | * Copyright (C) 2014 Analog Devices, Inc. |
pcercuei | 0:df031b60ca29 | 5 | * Author: Paul Cercueil <paul.cercueil@analog.com> |
pcercuei | 0:df031b60ca29 | 6 | * |
pcercuei | 0:df031b60ca29 | 7 | * This library is free software; you can redistribute it and/or |
pcercuei | 0:df031b60ca29 | 8 | * modify it under the terms of the GNU Lesser General Public |
pcercuei | 0:df031b60ca29 | 9 | * License as published by the Free Software Foundation; either |
pcercuei | 0:df031b60ca29 | 10 | * version 2.1 of the License, or (at your option) any later version. |
pcercuei | 0:df031b60ca29 | 11 | * |
pcercuei | 0:df031b60ca29 | 12 | * This library is distributed in the hope that it will be useful, |
pcercuei | 0:df031b60ca29 | 13 | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
pcercuei | 0:df031b60ca29 | 14 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
pcercuei | 0:df031b60ca29 | 15 | * Lesser General Public License for more details. |
pcercuei | 0:df031b60ca29 | 16 | * |
pcercuei | 0:df031b60ca29 | 17 | * */ |
pcercuei | 0:df031b60ca29 | 18 | |
pcercuei | 0:df031b60ca29 | 19 | #include "debug.h" |
pcercuei | 0:df031b60ca29 | 20 | #include "iio-private.h" |
pcercuei | 0:df031b60ca29 | 21 | |
pcercuei | 2:9eb0a9a1f958 | 22 | #include <errno.h> |
pcercuei | 0:df031b60ca29 | 23 | #include <libxml/tree.h> |
pcercuei | 0:df031b60ca29 | 24 | #include <string.h> |
pcercuei | 0:df031b60ca29 | 25 | |
pcercuei | 0:df031b60ca29 | 26 | static int add_attr_to_channel(struct iio_channel *chn, xmlNode *n) |
pcercuei | 0:df031b60ca29 | 27 | { |
pcercuei | 0:df031b60ca29 | 28 | xmlAttr *attr; |
pcercuei | 0:df031b60ca29 | 29 | char *name = NULL, *filename = NULL; |
pcercuei | 0:df031b60ca29 | 30 | struct iio_channel_attr *attrs; |
pcercuei | 0:df031b60ca29 | 31 | |
pcercuei | 0:df031b60ca29 | 32 | for (attr = n->properties; attr; attr = attr->next) { |
pcercuei | 0:df031b60ca29 | 33 | if (!strcmp((char *) attr->name, "name")) { |
pcercuei | 0:df031b60ca29 | 34 | name = iio_strdup((char *) attr->children->content); |
pcercuei | 0:df031b60ca29 | 35 | } else if (!strcmp((char *) attr->name, "filename")) { |
pcercuei | 0:df031b60ca29 | 36 | filename = iio_strdup((char *) attr->children->content); |
pcercuei | 0:df031b60ca29 | 37 | } else { |
pcercuei | 0:df031b60ca29 | 38 | WARNING("Unknown field \'%s\' in channel %s\n", |
pcercuei | 0:df031b60ca29 | 39 | attr->name, chn->id); |
pcercuei | 0:df031b60ca29 | 40 | } |
pcercuei | 0:df031b60ca29 | 41 | } |
pcercuei | 0:df031b60ca29 | 42 | |
pcercuei | 0:df031b60ca29 | 43 | if (!name) { |
pcercuei | 0:df031b60ca29 | 44 | ERROR("Incomplete attribute in channel %s\n", chn->id); |
pcercuei | 0:df031b60ca29 | 45 | goto err_free; |
pcercuei | 0:df031b60ca29 | 46 | } |
pcercuei | 0:df031b60ca29 | 47 | |
pcercuei | 0:df031b60ca29 | 48 | if (!filename) { |
pcercuei | 0:df031b60ca29 | 49 | filename = iio_strdup(name); |
pcercuei | 0:df031b60ca29 | 50 | if (!filename) |
pcercuei | 0:df031b60ca29 | 51 | goto err_free; |
pcercuei | 0:df031b60ca29 | 52 | } |
pcercuei | 0:df031b60ca29 | 53 | |
pcercuei | 0:df031b60ca29 | 54 | attrs = realloc(chn->attrs, (1 + chn->nb_attrs) * |
pcercuei | 0:df031b60ca29 | 55 | sizeof(struct iio_channel_attr)); |
pcercuei | 0:df031b60ca29 | 56 | if (!attrs) |
pcercuei | 0:df031b60ca29 | 57 | goto err_free; |
pcercuei | 0:df031b60ca29 | 58 | |
pcercuei | 0:df031b60ca29 | 59 | attrs[chn->nb_attrs].filename = filename; |
pcercuei | 0:df031b60ca29 | 60 | attrs[chn->nb_attrs++].name = name; |
pcercuei | 0:df031b60ca29 | 61 | chn->attrs = attrs; |
pcercuei | 0:df031b60ca29 | 62 | return 0; |
pcercuei | 0:df031b60ca29 | 63 | |
pcercuei | 0:df031b60ca29 | 64 | err_free: |
pcercuei | 0:df031b60ca29 | 65 | if (name) |
pcercuei | 0:df031b60ca29 | 66 | free(name); |
pcercuei | 0:df031b60ca29 | 67 | if (filename) |
pcercuei | 0:df031b60ca29 | 68 | free(filename); |
pcercuei | 0:df031b60ca29 | 69 | return -1; |
pcercuei | 0:df031b60ca29 | 70 | } |
pcercuei | 0:df031b60ca29 | 71 | |
pcercuei | 0:df031b60ca29 | 72 | static int add_attr_to_device(struct iio_device *dev, xmlNode *n, bool is_debug) |
pcercuei | 0:df031b60ca29 | 73 | { |
pcercuei | 0:df031b60ca29 | 74 | xmlAttr *attr; |
pcercuei | 0:df031b60ca29 | 75 | char **attrs, *name = NULL; |
pcercuei | 0:df031b60ca29 | 76 | |
pcercuei | 0:df031b60ca29 | 77 | for (attr = n->properties; attr; attr = attr->next) { |
pcercuei | 0:df031b60ca29 | 78 | if (!strcmp((char *) attr->name, "name")) { |
pcercuei | 0:df031b60ca29 | 79 | name = iio_strdup((char *) attr->children->content); |
pcercuei | 0:df031b60ca29 | 80 | } else { |
pcercuei | 0:df031b60ca29 | 81 | WARNING("Unknown field \'%s\' in device %s\n", |
pcercuei | 0:df031b60ca29 | 82 | attr->name, dev->id); |
pcercuei | 0:df031b60ca29 | 83 | } |
pcercuei | 0:df031b60ca29 | 84 | } |
pcercuei | 0:df031b60ca29 | 85 | |
pcercuei | 0:df031b60ca29 | 86 | if (!name) { |
pcercuei | 0:df031b60ca29 | 87 | ERROR("Incomplete attribute in device %s\n", dev->id); |
pcercuei | 0:df031b60ca29 | 88 | goto err_free; |
pcercuei | 0:df031b60ca29 | 89 | } |
pcercuei | 0:df031b60ca29 | 90 | |
pcercuei | 0:df031b60ca29 | 91 | if (is_debug) |
pcercuei | 0:df031b60ca29 | 92 | attrs = realloc(dev->debug_attrs, |
pcercuei | 0:df031b60ca29 | 93 | (1 + dev->nb_debug_attrs) * sizeof(char *)); |
pcercuei | 0:df031b60ca29 | 94 | else |
pcercuei | 0:df031b60ca29 | 95 | attrs = realloc(dev->attrs, |
pcercuei | 0:df031b60ca29 | 96 | (1 + dev->nb_attrs) * sizeof(char *)); |
pcercuei | 0:df031b60ca29 | 97 | if (!attrs) |
pcercuei | 0:df031b60ca29 | 98 | goto err_free; |
pcercuei | 0:df031b60ca29 | 99 | |
pcercuei | 0:df031b60ca29 | 100 | if (is_debug) { |
pcercuei | 0:df031b60ca29 | 101 | attrs[dev->nb_debug_attrs++] = name; |
pcercuei | 0:df031b60ca29 | 102 | dev->debug_attrs = attrs; |
pcercuei | 0:df031b60ca29 | 103 | } else { |
pcercuei | 0:df031b60ca29 | 104 | attrs[dev->nb_attrs++] = name; |
pcercuei | 0:df031b60ca29 | 105 | dev->attrs = attrs; |
pcercuei | 0:df031b60ca29 | 106 | } |
pcercuei | 0:df031b60ca29 | 107 | return 0; |
pcercuei | 0:df031b60ca29 | 108 | |
pcercuei | 0:df031b60ca29 | 109 | err_free: |
pcercuei | 0:df031b60ca29 | 110 | if (name) |
pcercuei | 0:df031b60ca29 | 111 | free(name); |
pcercuei | 0:df031b60ca29 | 112 | return -1; |
pcercuei | 0:df031b60ca29 | 113 | } |
pcercuei | 0:df031b60ca29 | 114 | |
pcercuei | 0:df031b60ca29 | 115 | static void setup_scan_element(struct iio_channel *chn, xmlNode *n) |
pcercuei | 0:df031b60ca29 | 116 | { |
pcercuei | 0:df031b60ca29 | 117 | xmlAttr *attr; |
pcercuei | 0:df031b60ca29 | 118 | |
pcercuei | 0:df031b60ca29 | 119 | for (attr = n->properties; attr; attr = attr->next) { |
pcercuei | 0:df031b60ca29 | 120 | const char *name = (const char *) attr->name, |
pcercuei | 0:df031b60ca29 | 121 | *content = (const char *) attr->children->content; |
pcercuei | 0:df031b60ca29 | 122 | if (!strcmp(name, "index")) { |
pcercuei | 0:df031b60ca29 | 123 | chn->index = atol(content); |
pcercuei | 0:df031b60ca29 | 124 | } else if (!strcmp(name, "format")) { |
pcercuei | 0:df031b60ca29 | 125 | char e, s; |
pcercuei | 3:d147beabba0e | 126 | if (strchr(content, 'X')) { |
pcercuei | 3:d147beabba0e | 127 | sscanf(content, "%ce:%c%u/%uX%u>>%u", &e, &s, |
pcercuei | 3:d147beabba0e | 128 | &chn->format.bits, |
pcercuei | 3:d147beabba0e | 129 | &chn->format.length, |
pcercuei | 3:d147beabba0e | 130 | &chn->format.repeat, |
pcercuei | 3:d147beabba0e | 131 | &chn->format.shift); |
pcercuei | 3:d147beabba0e | 132 | } else { |
pcercuei | 3:d147beabba0e | 133 | chn->format.repeat = 1; |
pcercuei | 3:d147beabba0e | 134 | sscanf(content, "%ce:%c%u/%u>>%u", &e, &s, |
pcercuei | 0:df031b60ca29 | 135 | &chn->format.bits, |
pcercuei | 0:df031b60ca29 | 136 | &chn->format.length, |
pcercuei | 0:df031b60ca29 | 137 | &chn->format.shift); |
pcercuei | 3:d147beabba0e | 138 | } |
pcercuei | 0:df031b60ca29 | 139 | chn->format.is_be = e == 'b'; |
pcercuei | 0:df031b60ca29 | 140 | chn->format.is_signed = (s == 's' || s == 'S'); |
pcercuei | 0:df031b60ca29 | 141 | chn->format.is_fully_defined = (s == 'S' || s == 'U' || |
pcercuei | 0:df031b60ca29 | 142 | chn->format.bits == chn->format.length); |
pcercuei | 0:df031b60ca29 | 143 | } else if (!strcmp(name, "scale")) { |
pcercuei | 0:df031b60ca29 | 144 | chn->format.with_scale = true; |
pcercuei | 0:df031b60ca29 | 145 | chn->format.scale = atof(content); |
pcercuei | 0:df031b60ca29 | 146 | } else { |
pcercuei | 0:df031b60ca29 | 147 | WARNING("Unknown attribute \'%s\' in <scan-element>\n", |
pcercuei | 0:df031b60ca29 | 148 | name); |
pcercuei | 0:df031b60ca29 | 149 | } |
pcercuei | 0:df031b60ca29 | 150 | } |
pcercuei | 0:df031b60ca29 | 151 | } |
pcercuei | 0:df031b60ca29 | 152 | |
pcercuei | 0:df031b60ca29 | 153 | static struct iio_channel * create_channel(struct iio_device *dev, xmlNode *n) |
pcercuei | 0:df031b60ca29 | 154 | { |
pcercuei | 0:df031b60ca29 | 155 | xmlAttr *attr; |
pcercuei | 0:df031b60ca29 | 156 | struct iio_channel *chn = zalloc(sizeof(*chn)); |
pcercuei | 0:df031b60ca29 | 157 | if (!chn) |
pcercuei | 0:df031b60ca29 | 158 | return NULL; |
pcercuei | 0:df031b60ca29 | 159 | |
pcercuei | 0:df031b60ca29 | 160 | chn->dev = dev; |
pcercuei | 0:df031b60ca29 | 161 | |
pcercuei | 0:df031b60ca29 | 162 | /* Set the default index value < 0 (== no index) */ |
pcercuei | 0:df031b60ca29 | 163 | chn->index = -ENOENT; |
pcercuei | 0:df031b60ca29 | 164 | |
pcercuei | 0:df031b60ca29 | 165 | for (attr = n->properties; attr; attr = attr->next) { |
pcercuei | 0:df031b60ca29 | 166 | const char *name = (const char *) attr->name, |
pcercuei | 0:df031b60ca29 | 167 | *content = (const char *) attr->children->content; |
pcercuei | 0:df031b60ca29 | 168 | if (!strcmp(name, "name")) { |
pcercuei | 0:df031b60ca29 | 169 | chn->name = iio_strdup(content); |
pcercuei | 0:df031b60ca29 | 170 | } else if (!strcmp(name, "id")) { |
pcercuei | 0:df031b60ca29 | 171 | chn->id = iio_strdup(content); |
pcercuei | 0:df031b60ca29 | 172 | } else if (!strcmp(name, "type")) { |
pcercuei | 0:df031b60ca29 | 173 | if (!strcmp(content, "output")) |
pcercuei | 0:df031b60ca29 | 174 | chn->is_output = true; |
pcercuei | 0:df031b60ca29 | 175 | else if (strcmp(content, "input")) |
pcercuei | 0:df031b60ca29 | 176 | WARNING("Unknown channel type %s\n", content); |
pcercuei | 0:df031b60ca29 | 177 | } else { |
pcercuei | 0:df031b60ca29 | 178 | WARNING("Unknown attribute \'%s\' in <channel>\n", |
pcercuei | 0:df031b60ca29 | 179 | name); |
pcercuei | 0:df031b60ca29 | 180 | } |
pcercuei | 0:df031b60ca29 | 181 | } |
pcercuei | 0:df031b60ca29 | 182 | |
pcercuei | 0:df031b60ca29 | 183 | if (!chn->id) { |
pcercuei | 0:df031b60ca29 | 184 | ERROR("Incomplete <attribute>\n"); |
pcercuei | 0:df031b60ca29 | 185 | goto err_free_channel; |
pcercuei | 0:df031b60ca29 | 186 | } |
pcercuei | 0:df031b60ca29 | 187 | |
pcercuei | 0:df031b60ca29 | 188 | for (n = n->children; n; n = n->next) { |
pcercuei | 0:df031b60ca29 | 189 | if (!strcmp((char *) n->name, "attribute")) { |
pcercuei | 0:df031b60ca29 | 190 | if (add_attr_to_channel(chn, n) < 0) |
pcercuei | 0:df031b60ca29 | 191 | goto err_free_channel; |
pcercuei | 0:df031b60ca29 | 192 | } else if (!strcmp((char *) n->name, "scan-element")) { |
pcercuei | 0:df031b60ca29 | 193 | chn->is_scan_element = true; |
pcercuei | 0:df031b60ca29 | 194 | setup_scan_element(chn, n); |
pcercuei | 0:df031b60ca29 | 195 | } else if (strcmp((char *) n->name, "text")) { |
pcercuei | 0:df031b60ca29 | 196 | WARNING("Unknown children \'%s\' in <channel>\n", |
pcercuei | 0:df031b60ca29 | 197 | n->name); |
pcercuei | 0:df031b60ca29 | 198 | continue; |
pcercuei | 0:df031b60ca29 | 199 | } |
pcercuei | 0:df031b60ca29 | 200 | } |
pcercuei | 0:df031b60ca29 | 201 | |
pcercuei | 0:df031b60ca29 | 202 | iio_channel_init_finalize(chn); |
pcercuei | 0:df031b60ca29 | 203 | |
pcercuei | 0:df031b60ca29 | 204 | return chn; |
pcercuei | 0:df031b60ca29 | 205 | |
pcercuei | 0:df031b60ca29 | 206 | err_free_channel: |
pcercuei | 0:df031b60ca29 | 207 | free_channel(chn); |
pcercuei | 0:df031b60ca29 | 208 | return NULL; |
pcercuei | 0:df031b60ca29 | 209 | } |
pcercuei | 0:df031b60ca29 | 210 | |
pcercuei | 0:df031b60ca29 | 211 | static struct iio_device * create_device(struct iio_context *ctx, xmlNode *n) |
pcercuei | 0:df031b60ca29 | 212 | { |
pcercuei | 0:df031b60ca29 | 213 | xmlAttr *attr; |
pcercuei | 0:df031b60ca29 | 214 | struct iio_device *dev = zalloc(sizeof(*dev)); |
pcercuei | 0:df031b60ca29 | 215 | if (!dev) |
pcercuei | 0:df031b60ca29 | 216 | return NULL; |
pcercuei | 0:df031b60ca29 | 217 | |
pcercuei | 0:df031b60ca29 | 218 | dev->ctx = ctx; |
pcercuei | 0:df031b60ca29 | 219 | |
pcercuei | 0:df031b60ca29 | 220 | for (attr = n->properties; attr; attr = attr->next) { |
pcercuei | 0:df031b60ca29 | 221 | if (!strcmp((char *) attr->name, "name")) { |
pcercuei | 0:df031b60ca29 | 222 | dev->name = iio_strdup( |
pcercuei | 0:df031b60ca29 | 223 | (char *) attr->children->content); |
pcercuei | 0:df031b60ca29 | 224 | } else if (!strcmp((char *) attr->name, "id")) { |
pcercuei | 0:df031b60ca29 | 225 | dev->id = iio_strdup((char *) attr->children->content); |
pcercuei | 0:df031b60ca29 | 226 | } else { |
pcercuei | 0:df031b60ca29 | 227 | WARNING("Unknown attribute \'%s\' in <device>\n", |
pcercuei | 0:df031b60ca29 | 228 | attr->name); |
pcercuei | 0:df031b60ca29 | 229 | } |
pcercuei | 0:df031b60ca29 | 230 | } |
pcercuei | 0:df031b60ca29 | 231 | |
pcercuei | 0:df031b60ca29 | 232 | if (!dev->id) { |
pcercuei | 0:df031b60ca29 | 233 | ERROR("Unable to read device ID\n"); |
pcercuei | 0:df031b60ca29 | 234 | goto err_free_device; |
pcercuei | 0:df031b60ca29 | 235 | } |
pcercuei | 0:df031b60ca29 | 236 | |
pcercuei | 0:df031b60ca29 | 237 | for (n = n->children; n; n = n->next) { |
pcercuei | 0:df031b60ca29 | 238 | if (!strcmp((char *) n->name, "channel")) { |
pcercuei | 0:df031b60ca29 | 239 | struct iio_channel **chns, |
pcercuei | 0:df031b60ca29 | 240 | *chn = create_channel(dev, n); |
pcercuei | 0:df031b60ca29 | 241 | if (!chn) { |
pcercuei | 0:df031b60ca29 | 242 | ERROR("Unable to create channel\n"); |
pcercuei | 0:df031b60ca29 | 243 | goto err_free_device; |
pcercuei | 0:df031b60ca29 | 244 | } |
pcercuei | 0:df031b60ca29 | 245 | |
pcercuei | 0:df031b60ca29 | 246 | chns = realloc(dev->channels, (1 + dev->nb_channels) * |
pcercuei | 0:df031b60ca29 | 247 | sizeof(struct iio_channel *)); |
pcercuei | 0:df031b60ca29 | 248 | if (!chns) { |
pcercuei | 0:df031b60ca29 | 249 | ERROR("Unable to allocate memory\n"); |
pcercuei | 0:df031b60ca29 | 250 | free(chn); |
pcercuei | 0:df031b60ca29 | 251 | goto err_free_device; |
pcercuei | 0:df031b60ca29 | 252 | } |
pcercuei | 0:df031b60ca29 | 253 | |
pcercuei | 0:df031b60ca29 | 254 | chns[dev->nb_channels++] = chn; |
pcercuei | 0:df031b60ca29 | 255 | dev->channels = chns; |
pcercuei | 0:df031b60ca29 | 256 | } else if (!strcmp((char *) n->name, "attribute")) { |
pcercuei | 0:df031b60ca29 | 257 | if (add_attr_to_device(dev, n, false) < 0) |
pcercuei | 0:df031b60ca29 | 258 | goto err_free_device; |
pcercuei | 0:df031b60ca29 | 259 | } else if (!strcmp((char *) n->name, "debug-attribute")) { |
pcercuei | 0:df031b60ca29 | 260 | if (add_attr_to_device(dev, n, true) < 0) |
pcercuei | 0:df031b60ca29 | 261 | goto err_free_device; |
pcercuei | 0:df031b60ca29 | 262 | } else if (strcmp((char *) n->name, "text")) { |
pcercuei | 0:df031b60ca29 | 263 | WARNING("Unknown children \'%s\' in <device>\n", |
pcercuei | 0:df031b60ca29 | 264 | n->name); |
pcercuei | 0:df031b60ca29 | 265 | continue; |
pcercuei | 0:df031b60ca29 | 266 | } |
pcercuei | 0:df031b60ca29 | 267 | } |
pcercuei | 0:df031b60ca29 | 268 | |
pcercuei | 0:df031b60ca29 | 269 | dev->words = (dev->nb_channels + 31) / 32; |
pcercuei | 0:df031b60ca29 | 270 | if (dev->words) { |
pcercuei | 0:df031b60ca29 | 271 | dev->mask = calloc(dev->words, sizeof(*dev->mask)); |
pcercuei | 0:df031b60ca29 | 272 | if (!dev->mask) { |
pcercuei | 0:df031b60ca29 | 273 | errno = ENOMEM; |
pcercuei | 0:df031b60ca29 | 274 | goto err_free_device; |
pcercuei | 0:df031b60ca29 | 275 | } |
pcercuei | 0:df031b60ca29 | 276 | } |
pcercuei | 0:df031b60ca29 | 277 | |
pcercuei | 0:df031b60ca29 | 278 | return dev; |
pcercuei | 0:df031b60ca29 | 279 | |
pcercuei | 0:df031b60ca29 | 280 | err_free_device: |
pcercuei | 0:df031b60ca29 | 281 | free_device(dev); |
pcercuei | 0:df031b60ca29 | 282 | return NULL; |
pcercuei | 0:df031b60ca29 | 283 | } |
pcercuei | 0:df031b60ca29 | 284 | |
pcercuei | 0:df031b60ca29 | 285 | static struct iio_context * xml_clone(const struct iio_context *ctx) |
pcercuei | 0:df031b60ca29 | 286 | { |
pcercuei | 0:df031b60ca29 | 287 | return xml_create_context_mem(ctx->xml, strlen(ctx->xml)); |
pcercuei | 0:df031b60ca29 | 288 | } |
pcercuei | 0:df031b60ca29 | 289 | |
pcercuei | 0:df031b60ca29 | 290 | static const struct iio_backend_ops xml_ops = { |
pcercuei | 0:df031b60ca29 | 291 | .clone = xml_clone, |
pcercuei | 0:df031b60ca29 | 292 | }; |
pcercuei | 0:df031b60ca29 | 293 | |
pcercuei | 3:d147beabba0e | 294 | static int parse_context_attr(struct iio_context *ctx, xmlNode *n) |
pcercuei | 3:d147beabba0e | 295 | { |
pcercuei | 3:d147beabba0e | 296 | xmlAttr *attr; |
pcercuei | 3:d147beabba0e | 297 | const char *name = NULL, *value = NULL; |
pcercuei | 3:d147beabba0e | 298 | |
pcercuei | 3:d147beabba0e | 299 | for (attr = n->properties; attr; attr = attr->next) { |
pcercuei | 3:d147beabba0e | 300 | if (!strcmp((const char *) attr->name, "name")) { |
pcercuei | 3:d147beabba0e | 301 | name = (const char *) attr->children->content; |
pcercuei | 3:d147beabba0e | 302 | } else if (!strcmp((const char *) attr->name, "value")) { |
pcercuei | 3:d147beabba0e | 303 | value = (const char *) attr->children->content; |
pcercuei | 3:d147beabba0e | 304 | } |
pcercuei | 3:d147beabba0e | 305 | } |
pcercuei | 3:d147beabba0e | 306 | |
pcercuei | 3:d147beabba0e | 307 | if (!name || !value) |
pcercuei | 3:d147beabba0e | 308 | return -EINVAL; |
pcercuei | 3:d147beabba0e | 309 | else |
pcercuei | 3:d147beabba0e | 310 | return iio_context_add_attr(ctx, name, value); |
pcercuei | 3:d147beabba0e | 311 | } |
pcercuei | 3:d147beabba0e | 312 | |
pcercuei | 0:df031b60ca29 | 313 | static struct iio_context * iio_create_xml_context_helper(xmlDoc *doc) |
pcercuei | 0:df031b60ca29 | 314 | { |
pcercuei | 0:df031b60ca29 | 315 | unsigned int i; |
pcercuei | 0:df031b60ca29 | 316 | xmlNode *root, *n; |
pcercuei | 0:df031b60ca29 | 317 | xmlAttr *attr; |
pcercuei | 3:d147beabba0e | 318 | int err = -ENOMEM; |
pcercuei | 0:df031b60ca29 | 319 | struct iio_context *ctx = zalloc(sizeof(*ctx)); |
pcercuei | 0:df031b60ca29 | 320 | if (!ctx) |
pcercuei | 0:df031b60ca29 | 321 | goto err_set_errno; |
pcercuei | 0:df031b60ca29 | 322 | |
pcercuei | 0:df031b60ca29 | 323 | ctx->name = "xml"; |
pcercuei | 0:df031b60ca29 | 324 | ctx->ops = &xml_ops; |
pcercuei | 0:df031b60ca29 | 325 | |
pcercuei | 0:df031b60ca29 | 326 | root = xmlDocGetRootElement(doc); |
pcercuei | 0:df031b60ca29 | 327 | if (strcmp((char *) root->name, "context")) { |
pcercuei | 0:df031b60ca29 | 328 | ERROR("Unrecognized XML file\n"); |
pcercuei | 3:d147beabba0e | 329 | err = -EINVAL; |
pcercuei | 0:df031b60ca29 | 330 | goto err_free_ctx; |
pcercuei | 0:df031b60ca29 | 331 | } |
pcercuei | 0:df031b60ca29 | 332 | |
pcercuei | 0:df031b60ca29 | 333 | for (attr = root->properties; attr; attr = attr->next) { |
pcercuei | 0:df031b60ca29 | 334 | if (!strcmp((char *) attr->name, "description")) |
pcercuei | 0:df031b60ca29 | 335 | ctx->description = iio_strdup( |
pcercuei | 0:df031b60ca29 | 336 | (char *) attr->children->content); |
pcercuei | 0:df031b60ca29 | 337 | else if (strcmp((char *) attr->name, "name")) |
pcercuei | 0:df031b60ca29 | 338 | WARNING("Unknown parameter \'%s\' in <context>\n", |
pcercuei | 0:df031b60ca29 | 339 | (char *) attr->children->content); |
pcercuei | 0:df031b60ca29 | 340 | } |
pcercuei | 0:df031b60ca29 | 341 | |
pcercuei | 0:df031b60ca29 | 342 | for (n = root->children; n; n = n->next) { |
pcercuei | 0:df031b60ca29 | 343 | struct iio_device **devs, *dev; |
pcercuei | 0:df031b60ca29 | 344 | |
pcercuei | 3:d147beabba0e | 345 | if (!strcmp((char *) n->name, "context-attribute")) { |
pcercuei | 3:d147beabba0e | 346 | err = parse_context_attr(ctx, n); |
pcercuei | 3:d147beabba0e | 347 | if (err) |
pcercuei | 3:d147beabba0e | 348 | goto err_free_devices; |
pcercuei | 3:d147beabba0e | 349 | else |
pcercuei | 3:d147beabba0e | 350 | continue; |
pcercuei | 3:d147beabba0e | 351 | } else if (strcmp((char *) n->name, "device")) { |
pcercuei | 0:df031b60ca29 | 352 | if (strcmp((char *) n->name, "text")) |
pcercuei | 0:df031b60ca29 | 353 | WARNING("Unknown children \'%s\' in " |
pcercuei | 0:df031b60ca29 | 354 | "<context>\n", n->name); |
pcercuei | 0:df031b60ca29 | 355 | continue; |
pcercuei | 0:df031b60ca29 | 356 | } |
pcercuei | 0:df031b60ca29 | 357 | |
pcercuei | 0:df031b60ca29 | 358 | dev = create_device(ctx, n); |
pcercuei | 0:df031b60ca29 | 359 | if (!dev) { |
pcercuei | 0:df031b60ca29 | 360 | ERROR("Unable to create device\n"); |
pcercuei | 0:df031b60ca29 | 361 | goto err_free_devices; |
pcercuei | 0:df031b60ca29 | 362 | } |
pcercuei | 0:df031b60ca29 | 363 | |
pcercuei | 0:df031b60ca29 | 364 | devs = realloc(ctx->devices, (1 + ctx->nb_devices) * |
pcercuei | 0:df031b60ca29 | 365 | sizeof(struct iio_device *)); |
pcercuei | 0:df031b60ca29 | 366 | if (!devs) { |
pcercuei | 0:df031b60ca29 | 367 | ERROR("Unable to allocate memory\n"); |
pcercuei | 0:df031b60ca29 | 368 | free(dev); |
pcercuei | 0:df031b60ca29 | 369 | goto err_free_devices; |
pcercuei | 0:df031b60ca29 | 370 | } |
pcercuei | 0:df031b60ca29 | 371 | |
pcercuei | 0:df031b60ca29 | 372 | devs[ctx->nb_devices++] = dev; |
pcercuei | 0:df031b60ca29 | 373 | ctx->devices = devs; |
pcercuei | 0:df031b60ca29 | 374 | } |
pcercuei | 0:df031b60ca29 | 375 | |
pcercuei | 0:df031b60ca29 | 376 | err = iio_context_init(ctx); |
pcercuei | 0:df031b60ca29 | 377 | if (err) |
pcercuei | 0:df031b60ca29 | 378 | goto err_free_devices; |
pcercuei | 0:df031b60ca29 | 379 | |
pcercuei | 0:df031b60ca29 | 380 | return ctx; |
pcercuei | 0:df031b60ca29 | 381 | |
pcercuei | 0:df031b60ca29 | 382 | err_free_devices: |
pcercuei | 0:df031b60ca29 | 383 | for (i = 0; i < ctx->nb_devices; i++) |
pcercuei | 0:df031b60ca29 | 384 | free_device(ctx->devices[i]); |
pcercuei | 0:df031b60ca29 | 385 | if (ctx->nb_devices) |
pcercuei | 0:df031b60ca29 | 386 | free(ctx->devices); |
pcercuei | 3:d147beabba0e | 387 | for (i = 0; i < ctx->nb_attrs; i++) { |
pcercuei | 3:d147beabba0e | 388 | free(ctx->attrs[i]); |
pcercuei | 3:d147beabba0e | 389 | free(ctx->values[i]); |
pcercuei | 3:d147beabba0e | 390 | } |
pcercuei | 3:d147beabba0e | 391 | free(ctx->attrs); |
pcercuei | 3:d147beabba0e | 392 | free(ctx->values); |
pcercuei | 0:df031b60ca29 | 393 | err_free_ctx: |
pcercuei | 0:df031b60ca29 | 394 | free(ctx); |
pcercuei | 0:df031b60ca29 | 395 | err_set_errno: |
pcercuei | 3:d147beabba0e | 396 | errno = -err; |
pcercuei | 0:df031b60ca29 | 397 | return NULL; |
pcercuei | 0:df031b60ca29 | 398 | } |
pcercuei | 0:df031b60ca29 | 399 | |
pcercuei | 0:df031b60ca29 | 400 | struct iio_context * xml_create_context(const char *xml_file) |
pcercuei | 0:df031b60ca29 | 401 | { |
pcercuei | 0:df031b60ca29 | 402 | struct iio_context *ctx; |
pcercuei | 0:df031b60ca29 | 403 | xmlDoc *doc; |
pcercuei | 0:df031b60ca29 | 404 | |
pcercuei | 0:df031b60ca29 | 405 | LIBXML_TEST_VERSION; |
pcercuei | 0:df031b60ca29 | 406 | |
pcercuei | 0:df031b60ca29 | 407 | doc = xmlReadFile(xml_file, NULL, XML_PARSE_DTDVALID); |
pcercuei | 0:df031b60ca29 | 408 | if (!doc) { |
pcercuei | 0:df031b60ca29 | 409 | ERROR("Unable to parse XML file\n"); |
pcercuei | 3:d147beabba0e | 410 | errno = EINVAL; |
pcercuei | 0:df031b60ca29 | 411 | return NULL; |
pcercuei | 0:df031b60ca29 | 412 | } |
pcercuei | 0:df031b60ca29 | 413 | |
pcercuei | 0:df031b60ca29 | 414 | ctx = iio_create_xml_context_helper(doc); |
pcercuei | 0:df031b60ca29 | 415 | xmlFreeDoc(doc); |
pcercuei | 0:df031b60ca29 | 416 | return ctx; |
pcercuei | 0:df031b60ca29 | 417 | } |
pcercuei | 0:df031b60ca29 | 418 | |
pcercuei | 0:df031b60ca29 | 419 | struct iio_context * xml_create_context_mem(const char *xml, size_t len) |
pcercuei | 0:df031b60ca29 | 420 | { |
pcercuei | 0:df031b60ca29 | 421 | struct iio_context *ctx; |
pcercuei | 0:df031b60ca29 | 422 | xmlDoc *doc; |
pcercuei | 0:df031b60ca29 | 423 | |
pcercuei | 0:df031b60ca29 | 424 | LIBXML_TEST_VERSION; |
pcercuei | 0:df031b60ca29 | 425 | |
pcercuei | 0:df031b60ca29 | 426 | doc = xmlReadMemory(xml, (int) len, NULL, NULL, XML_PARSE_DTDVALID); |
pcercuei | 0:df031b60ca29 | 427 | if (!doc) { |
pcercuei | 0:df031b60ca29 | 428 | ERROR("Unable to parse XML file\n"); |
pcercuei | 3:d147beabba0e | 429 | errno = EINVAL; |
pcercuei | 0:df031b60ca29 | 430 | return NULL; |
pcercuei | 0:df031b60ca29 | 431 | } |
pcercuei | 0:df031b60ca29 | 432 | |
pcercuei | 0:df031b60ca29 | 433 | ctx = iio_create_xml_context_helper(doc); |
pcercuei | 0:df031b60ca29 | 434 | xmlFreeDoc(doc); |
pcercuei | 0:df031b60ca29 | 435 | return ctx; |
pcercuei | 0:df031b60ca29 | 436 | } |
pcercuei | 0:df031b60ca29 | 437 |