forked from analogdevicesinc/iio-oscilloscope
-
Notifications
You must be signed in to change notification settings - Fork 0
/
xml_utils.c
298 lines (263 loc) · 7.07 KB
/
xml_utils.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
/**
* Copyright 2012-2013(c) Analog Devices, Inc.
*
* Licensed under the GPL-2.
*
**/
#include <stdbool.h>
#include <stdio.h>
#include <dirent.h>
#include <string.h>
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>
#include <libxml/xpath.h>
#include "xml_utils.h"
#define MAX_STR_LEN 512
/*
* Open a xml file with the given name and store in the root variable a pointer
* to the first element of the xml file. Add extension to the filename if it
* does not have one.
* Return a reference to the opened xml file or NULL if an error occurs.
*/
xmlDocPtr open_xml_file(char *file_name, xmlNodePtr *root)
{
char *has_ext;
char *extension = ".xml";
char *temp;
xmlDocPtr doc;
if ((root == NULL) || (file_name == NULL))
return NULL;
if (strlen(file_name) == 0)
return NULL;
temp = (char *)malloc(strlen(file_name) +
strlen(extension) +
1); /* for the null terminator */
if (temp == NULL) {
printf("Memory allocation failed");
return NULL;
}
/* Add extension to a path without one. */
has_ext = strstr(file_name, extension);
if (has_ext == NULL)
sprintf(temp, "%s%s", file_name, extension);
else
sprintf(temp, "%s", file_name);
doc = xmlParseFile(temp);
if (doc == NULL){
free(temp);
return NULL;
}
*root = xmlDocGetRootElement(doc);
if (*root == NULL){
printf("%s is empty (%d)\n", temp, __LINE__);
xmlFreeDoc(doc);
free(temp);
return NULL;
}
free(temp);
return doc;
}
/*
* Create a list of char arrays that hold the names of the xml files stored in
* the directory provided by the caller.
* Pass to the caller the number of elements in the list, using list_size.
* Return a pointer to the list.
*/
char **get_xml_list(char * buf_dir_name, int *list_size)
{
const struct dirent *ent;
DIR *d;
char **list = NULL;
char *extension_ptr;
int cnt = 0;
int n = 0;
d = opendir(buf_dir_name);
if (!d) {
printf("Cannot open dir %s\n", buf_dir_name);
return NULL;
}
while (ent = readdir(d), ent != NULL) {
bool is_regular_file;
#ifdef _DIRENT_HAVE_D_TYPE
is_regular_file = ent->d_type == DT_REG;
#else
is_regular_file = true;
#endif
if (is_regular_file) {
extension_ptr = strstr(ent->d_name, ".xml");
if (extension_ptr != NULL) { /* if the entry has a ".xml" extension */
cnt++;
list = (char **)realloc(list, sizeof(char *) * cnt);
n = extension_ptr - ent->d_name;
n += 1; /* 1 is for the termination character */
list[cnt - 1] = (char *)malloc(sizeof(char) * n);
if (list[cnt - 1] == NULL) {
printf("Memory allocation failed\n");
for (; cnt >= 2; cnt--)
free(list[cnt - 2]);
free(list);
return NULL;
}
snprintf(list[cnt - 1], n, "%s", ent->d_name);
list[cnt - 1][n - 1] = '\0'; /* Required on MinGW */
}
}
}
closedir(d);
*list_size = cnt;
return list;
}
/*
* Free the memory allocated by get_xml_list().
*/
void free_xml_list(char **list, int list_size)
{
int i;
for (i = 0; i < list_size; i++) {
free(list[i]);
}
free(list);
}
/*
* Search for the xml file designed for the device provided by the caller.
* This is done by checking if the name of the device contains the name
* of the xml file.
* Return none, but use xml_name to return the name of the xml file that
* is found.
*/
void find_device_xml_file(char *dir_path, char *device_name, char *xml_name)
{
char **xmls_list;
char *xml_elem;
int size = 0;
int i;
xmls_list = get_xml_list(dir_path, &size);
for(i = 0; i < size; i++) {
xml_elem = strstr(device_name, xmls_list[i]);
if (xml_elem != NULL) { /* if the element name from the xml list exist within the device name */
snprintf(xml_name, MAX_STR_LEN, "%s", xmls_list[i]);
break;
}
}
free_xml_list(xmls_list, size);
/* Empty the string if no names were found */
if (i >= size) {
snprintf(xml_name, MAX_STR_LEN, "%s", "");
}
}
/*
* Search the content of specified element that belongs to the node. The search
* stops at the first found element.
* Return - the element value as a char array. Returns an empty string ("") if
* no element is found.
*/
char* read_string_element(xmlDocPtr doc, xmlNodePtr node, char *element)
{
char *text = NULL;
node = node->xmlChildrenNode;
while (node != NULL){
if (!xmlStrcmp(node->name, (xmlChar *)element)){
text = (char *)xmlNodeListGetString(doc, node->xmlChildrenNode, 1);
break;
}
node = node->next;
}
if (text == NULL){
text = (char *)calloc(1, sizeof(char)); /* Create an empty string */
}
return text;
}
/*
* Search the content of specified element that belongs to the node. The search
* stops at the first found element.
* Return - the element value as an integer. Returns 0 if no element is found.
*/
int read_integer_element(xmlDocPtr doc, xmlNodePtr node, char *element)
{
char *text = NULL;
int result;
int ret;
text = read_string_element(doc, node, element);
if (*text == 0) { /* Check if the string is empty */
xmlFree(text);
return 0;
}
ret = sscanf(text, "%d", &result);
xmlFree(text);
if (ret != 1){
printf("Could not convert xml string to integer \n");
return 0;
}
return result;
}
/*
* Use XPath for the search. Find all elements with the name specified by user.
* Return - pointer to the list of elements or NULL if an error occurred.
*/
xmlXPathObjectPtr retrieve_all_elements(xmlDocPtr doc, char *element)
{
xmlXPathContextPtr context;
xmlXPathObjectPtr result;
context = xmlXPathNewContext(doc);
if (context == NULL){
printf("Error in xmlXPathNewContext\n");
return NULL;
}
result = xmlXPathEvalExpression((xmlChar *)element, context);
xmlXPathFreeContext(context);
if (result == NULL){
printf("Error in xmlXPathEvalExpression\n");
return NULL;
}
if (xmlXPathNodeSetIsEmpty(result->nodesetval)){
xmlXPathFreeObject(result);
printf("No result.\n");
return NULL;
}
return result;
}
/*
* Search for the child with the specified name. The search stops at the first
* found child.
* Return - the child reference or NULL when none are found.
*/
xmlNodePtr get_child_by_name(xmlNodePtr parent_node, char* tag_name)
{
xmlNodePtr child_node;
child_node = parent_node->xmlChildrenNode;
/* Search through the list of the available children */
while (child_node != NULL){
if (!xmlStrcmp(child_node->name, (xmlChar *)tag_name)){
return child_node;
}
child_node = child_node->next;
}
return NULL;
}
/*
* Search for all children with the specified name and create a children list.
* The size of the list is stored in the children_cnt parameter.
* Return - a pointer to the list, the caller must free it with free().
*/
xmlNodePtr* get_children_by_name(xmlNodePtr parent_node, char* tag_name, int *children_cnt)
{
xmlNodePtr *children_list = NULL;
xmlNodePtr child_node;
int n = 0;
child_node = parent_node->xmlChildrenNode;
/* Search through the list of the available children */
while (child_node != NULL){
if (!xmlStrcmp(child_node->name, (xmlChar *)tag_name)){
n++;
children_list = (xmlNodePtr *)realloc(children_list, sizeof(xmlNodePtr) * n);
children_list[n - 1] = child_node;
}
child_node = child_node->next;
}
*children_cnt = n;
return children_list;
}
void close_xml_file(xmlDocPtr doc)
{
xmlFreeDoc(doc);
}