VPR-7.0
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
read_xml_util.c
Go to the documentation of this file.
1 #include <assert.h>
2 #include <stdio.h>
3 #include <stdlib.h>
4 #include <string.h>
5 #include "util.h"
6 #include "ezxml.h"
7 #include "read_xml_util.h"
8 
9 /* Finds child element with given name and returns it. Errors out if
10  * more than one instance exists. */
11 ezxml_t FindElement(INP ezxml_t Parent, INP const char *Name,
12  INP boolean Required) {
13  ezxml_t Cur;
14 
15  /* Find the first node of correct name */
16  Cur = ezxml_child(Parent, Name);
17 
18  /* Error out if node isn't found but they required it */
19  if (Required) {
20  if (NULL == Cur) {
21  vpr_printf(TIO_MESSAGE_ERROR,
22  "[LINE %d] Element '%s' not found within element '%s'.\n",
23  Parent->line, Name, Parent->name);
24  exit(1);
25  }
26  }
27 
28  /* Look at next tag with same name and error out if exists */
29  if (Cur != NULL && Cur->next) {
30  vpr_printf(
31  TIO_MESSAGE_ERROR, "[LINE %d] Element '%s' found twice within element '%s'.\n",
32  Parent->line, Name, Parent->name);
33  exit(1);
34  }
35  return Cur;
36 }
37 /* Finds child element with given name and returns it. */
38 ezxml_t FindFirstElement(INP ezxml_t Parent, INP const char *Name,
39  INP boolean Required) {
40  ezxml_t Cur;
41 
42  /* Find the first node of correct name */
43  Cur = ezxml_child(Parent, Name);
44 
45  /* Error out if node isn't found but they required it */
46  if (Required) {
47  if (NULL == Cur) {
48  vpr_printf(TIO_MESSAGE_ERROR,
49  "[LINE %d] Element '%s' not found within element '%s'.\n",
50  Parent->line, Name, Parent->name);
51  exit(1);
52  }
53  }
54 
55  return Cur;
56 }
57 
58 /* Checks the node is an element with name equal to one given */
59 void CheckElement(INP ezxml_t Node, INP const char *Name) {
60  assert(Node != NULL && Name != NULL);
61  if (0 != strcmp(Node->name, Name)) {
62  vpr_printf(TIO_MESSAGE_ERROR,
63  "[LINE %d] Element '%s' within element '%s' does match expected "
64  "element type of '%s'\n", Node->line, Node->name, Node->parent->name,
65  Name);
66  exit(1);
67  }
68 }
69 
70 /* Checks that the node has no remaining child nodes or property nodes,
71  * then unlinks the node from the tree which updates pointers and
72  * frees the memory */
73 void FreeNode(INOUTP ezxml_t Node) {
74  ezxml_t Cur;
75  char *Txt;
76 
77  /* Shouldn't have unprocessed properties */
78  if (Node->attr[0]) {
79  vpr_printf(TIO_MESSAGE_ERROR, "[LINE %d] Node '%s' has invalid property %s=\"%s\".\n",
80  Node->line, Node->name, Node->attr[0], Node->attr[1]);
81  exit(1);
82  }
83 
84  /* Shouldn't have non-whitespace text */
85  Txt = Node->txt;
86  while (*Txt) {
87  if (!IsWhitespace(*Txt)) {
88  vpr_printf(TIO_MESSAGE_ERROR,
89  "[LINE %d] Node '%s' has unexpected text '%s' within it.\n",
90  Node->line, Node->name, Node->txt);
91  exit(1);
92  }
93  ++Txt;
94  }
95 
96  /* We shouldn't have child items left */
97  Cur = Node->child;
98  if (Cur) {
99  vpr_printf(TIO_MESSAGE_ERROR, "[LINE %d] Node '%s' has invalid child node '%s'.\n",
100  Node->line, Node->name, Cur->name);
101  exit(1);
102  }
103 
104  /* Now actually unlink and free the node */
105  ezxml_remove(Node);
106 }
107 
108 /* Returns TRUE if character is whatspace between tokens */
109 boolean IsWhitespace(char c) {
110  switch (c) {
111  case ' ':
112  case '\t':
113  case '\r':
114  case '\n':
115  return TRUE;
116  default:
117  return FALSE;
118  }
119 }
120 
121 const char *
122 FindProperty(INP ezxml_t Parent, INP const char *Name, INP boolean Required) {
123  const char *Res;
124 
125  Res = ezxml_attr(Parent, Name);
126  if (Required) {
127  if (NULL == Res) {
128  vpr_printf(TIO_MESSAGE_ERROR,
129  "[Line %d] Required property '%s' not found for element '%s'.\n",
130  Parent->line, Name, Parent->name);
131  exit(1);
132  }
133  }
134  return Res;
135 }
136 
137 /* Count tokens and length in all the Text children nodes of current node. */
138 extern void CountTokensInString(INP const char *Str, OUTP int *Num,
139  OUTP int *Len) {
140  boolean InToken;
141  *Num = 0;
142  *Len = 0;
143  InToken = FALSE;
144  while (*Str) {
145  if (IsWhitespace(*Str)) {
146  InToken = FALSE;
147  }
148 
149  else
150 
151  {
152  if (!InToken) {
153  ++(*Num);
154  }
155  ++(*Len);
156  InToken = TRUE;
157  }
158  ++Str; /* Advance pointer */
159  }
160 }
161 
162 /* Returns a token list of the text nodes of a given node. This
163  * unlinks all the text nodes from the document */
164 extern char **
166  int Count, Len;
167  char *Cur, *Dst;
168  boolean InToken;
169  char **Tokens;
170 
171  /* Count the tokens and find length of token data */
172  CountTokensInString(Node->txt, &Count, &Len);
173 
174  /* Error out if no tokens found */
175  if (Count < 1) {
176  return NULL;
177  }
178  Len = (sizeof(char) * Len) + /* Length of actual data */
179  (sizeof(char) * Count); /* Null terminators */
180 
181  /* Alloc the pointer list and data list. Count the final
182  * empty string we will use as list terminator */
183  Tokens = (char **) my_malloc(sizeof(char *) * (Count + 1));
184  Dst = (char *) my_malloc(sizeof(char) * Len);
185  Count = 0;
186 
187  /* Copy data to tokens */
188  Cur = Node->txt;
189  InToken = FALSE;
190  while (*Cur) {
191  if (IsWhitespace(*Cur)) {
192  if (InToken) {
193  *Dst = '\0';
194  ++Dst;
195  }
196  InToken = FALSE;
197  }
198 
199  else {
200  if (!InToken) {
201  Tokens[Count] = Dst;
202  ++Count;
203  }
204  *Dst = *Cur;
205  ++Dst;
206  InToken = TRUE;
207  }
208  ++Cur;
209  }
210  if (InToken) { /* Null term final token */
211  *Dst = '\0';
212  ++Dst;
213  }
214  ezxml_set_txt(Node, "");
215  Tokens[Count] = NULL; /* End of tokens marker is a NULL */
216 
217  /* Return the list */
218  return Tokens;
219 }
220 
221 /* Returns a token list of the text nodes of a given node. This
222  * does not unlink the text nodes from the document */
223 extern char **
225  int Count, Len;
226  char *Cur, *Dst;
227  boolean InToken;
228  char **Tokens;
229 
230  /* Count the tokens and find length of token data */
231  CountTokensInString(Node->txt, &Count, &Len);
232 
233  /* Error out if no tokens found */
234  if (Count < 1) {
235  return NULL;
236  }
237  Len = (sizeof(char) * Len) + /* Length of actual data */
238  (sizeof(char) * Count); /* Null terminators */
239 
240  /* Alloc the pointer list and data list. Count the final
241  * empty string we will use as list terminator */
242  Tokens = (char **) my_malloc(sizeof(char *) * (Count + 1));
243  Dst = (char *) my_malloc(sizeof(char) * Len);
244  Count = 0;
245 
246  /* Copy data to tokens */
247  Cur = Node->txt;
248  InToken = FALSE;
249  while (*Cur) {
250  if (IsWhitespace(*Cur)) {
251  if (InToken) {
252  *Dst = '\0';
253  ++Dst;
254  }
255  InToken = FALSE;
256  }
257 
258  else {
259  if (!InToken) {
260  Tokens[Count] = Dst;
261  ++Count;
262  }
263  *Dst = *Cur;
264  ++Dst;
265  InToken = TRUE;
266  }
267  ++Cur;
268  }
269  if (InToken) { /* Null term final token */
270  *Dst = '\0';
271  ++Dst;
272  }
273  Tokens[Count] = NULL; /* End of tokens marker is a NULL */
274 
275  /* Return the list */
276  return Tokens;
277 }
278 
279 /* Find integer attribute matching Name in XML tag Parent and return it if exists.
280  Removes attribute from Parent */
281 extern int GetIntProperty(INP ezxml_t Parent, INP char *Name,
282  INP boolean Required, INP int default_value) {
283  const char * Prop;
284  int property_value;
285 
286  property_value = default_value;
287  Prop = FindProperty(Parent, Name, Required);
288  if (Prop) {
289  property_value = my_atoi(Prop);
290  ezxml_set_attr(Parent, Name, NULL);
291  }
292  return property_value;
293 }
294 
295 /* Find floating-point attribute matching Name in XML tag Parent and return it if exists.
296  Removes attribute from Parent */
297 extern float GetFloatProperty(INP ezxml_t Parent, INP char *Name,
298  INP boolean Required, INP float default_value) {
299 
300  const char * Prop;
301  float property_value;
302 
303  property_value = default_value;
304  Prop = FindProperty(Parent, Name, Required);
305  if (Prop) {
306  property_value = (float)atof(Prop);
307  ezxml_set_attr(Parent, Name, NULL);
308  }
309  return property_value;
310 }
311 
312 /* Find boolean attribute matching Name in XML tag Parent and return it if exists.
313  Removes attribute from Parent */
314 extern boolean GetBooleanProperty(INP ezxml_t Parent, INP char *Name,
315  INP boolean Required, INP boolean default_value) {
316 
317  const char * Prop;
318  boolean property_value;
319 
320  property_value = default_value;
321  Prop = FindProperty(Parent, Name, Required);
322  if (Prop) {
323  if ((strcmp(Prop, "false") == 0) || (strcmp(Prop, "FALSE") == 0)
324  || (strcmp(Prop, "False") == 0)) {
325  property_value = FALSE;
326  } else if ((strcmp(Prop, "true") == 0) || (strcmp(Prop, "TRUE") == 0)
327  || (strcmp(Prop, "True") == 0)) {
328  property_value = TRUE;
329  } else {
330  vpr_printf(
331  TIO_MESSAGE_ERROR, "[LINE %d] Unknown value %s for boolean attribute %s in %s",
332  Parent->line, Prop, Name, Parent->name);
333  exit(1);
334  }
335  ezxml_set_attr(Parent, Name, NULL);
336  }
337  return property_value;
338 }
339 
340 /* Counts number of child elements in a container element.
341  * Name is the name of the child element.
342  * Errors if no occurances found. */
343 extern int CountChildren(INP ezxml_t Node, INP const char *Name,
344  INP int min_count) {
345  ezxml_t Cur, sibling;
346  int Count;
347 
348  Count = 0;
349  Cur = Node->child;
350  sibling = NULL;
351 
352  if (Cur) {
353  sibling = Cur->sibling;
354  }
355 
356  while (Cur) {
357  if (strcmp(Cur->name, Name) == 0) {
358  ++Count;
359  }
360  Cur = Cur->next;
361  if (Cur == NULL) {
362  Cur = sibling;
363  if (Cur != NULL) {
364  sibling = Cur->sibling;
365  }
366  }
367  }
368  /* Error if no occurances found */
369  if (Count < min_count) {
370  vpr_printf(TIO_MESSAGE_ERROR, "[Line %d] Expected node '%s' to have %d "
371  "child elements, but none found.\n", Node->line, Node->name, min_count);
372  exit(1);
373  }
374  return Count;
375 }
376 
char ** LookaheadNodeTokens(INP ezxml_t Node)
Definition: ezxml.h:44
void CountTokensInString(INP const char *Str, OUTP int *Num, OUTP int *Len)
const char * FindProperty(INP ezxml_t Parent, INP const char *Name, INP boolean Required)
int GetIntProperty(INP ezxml_t Parent, INP char *Name, INP boolean Required, INP int default_value)
void CheckElement(INP ezxml_t Node, INP const char *Name)
Definition: read_xml_util.c:59
#define INOUTP
Definition: util.h:21
void FreeNode(INOUTP ezxml_t Node)
Definition: read_xml_util.c:73
Definition: util.h:12
boolean IsWhitespace(char c)
ezxml_t next
Definition: ezxml.h:49
ezxml_t ezxml_set_attr(ezxml_t xml, char *name, char *value)
Definition: ezxml.c:1165
ezxml_t ezxml_child(ezxml_t xml, const char *name)
Definition: ezxml.c:85
static void * my_malloc(int ibytes)
Definition: graphics.c:499
ezxml_t sibling
Definition: ezxml.h:50
ezxml_t FindFirstElement(INP ezxml_t Parent, INP const char *Name, INP boolean Required)
Definition: read_xml_util.c:38
#define INP
Definition: util.h:19
#define ezxml_remove(xml)
Definition: ezxml.h:181
const char * ezxml_attr(ezxml_t xml, const char *attr)
Definition: ezxml.c:102
char ** GetNodeTokens(INP ezxml_t Node)
ezxml_t ezxml_set_txt(ezxml_t xml, char *txt)
Definition: ezxml.c:1152
boolean GetBooleanProperty(INP ezxml_t Parent, INP char *Name, INP boolean Required, INP boolean default_value)
float GetFloatProperty(INP ezxml_t Parent, INP char *Name, INP boolean Required, INP float default_value)
int CountChildren(INP ezxml_t Node, INP const char *Name, INP int min_count)
ezxml_t FindElement(INP ezxml_t Parent, INP const char *Name, INP boolean Required)
Definition: read_xml_util.c:11
char * name
Definition: ezxml.h:45
#define OUTP
Definition: util.h:20
int my_atoi(const char *str)
Definition: util.c:116
messagelogger vpr_printf
Definition: util.c:17
ezxml_t child
Definition: ezxml.h:52
Definition: util.h:12