blob: 4334a3dca7fe59e6c962529839dcf6eceec9f0e4 [file] [log] [blame]
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "util.h"
#include "ezxml.h"
#include "read_xml_util.h"
/* Finds child element with given name and returns it. Errors out if
* more than one instance exists. */
ezxml_t
FindElement(INP ezxml_t Parent, INP const char *Name, INP boolean Required)
{
ezxml_t Cur;
/* Find the first node of correct name */
Cur = ezxml_child(Parent, Name);
/* Error out if node isn't found but they required it */
if(Required)
{
if(NULL == Cur)
{
printf(ERRTAG
"[LINE %d] Element '%s' not found within element '%s'.\n", Parent->line,
Name, Parent->name);
exit(1);
}
}
/* Look at next tag with same name and error out if exists */
if(Cur != NULL && Cur->next)
{
printf(ERRTAG "[LINE %d] Element '%s' found twice within element '%s'.\n", Parent->line,
Name, Parent->name);
exit(1);
}
return Cur;
}
/* Finds child element with given name and returns it. */
ezxml_t
FindFirstElement(INP ezxml_t Parent, INP const char *Name, INP boolean Required)
{
ezxml_t Cur;
/* Find the first node of correct name */
Cur = ezxml_child(Parent, Name);
/* Error out if node isn't found but they required it */
if(Required)
{
if(NULL == Cur)
{
printf(ERRTAG
"[LINE %d] Element '%s' not found within element '%s'.\n", Parent->line,
Name, Parent->name);
exit(1);
}
}
return Cur;
}
/* Checks the node is an element with name equal to one given */
void
CheckElement(INP ezxml_t Node, INP const char *Name)
{
assert(Node != NULL && Name != NULL);
if(0 != strcmp(Node->name, Name))
{
printf(ERRTAG
"[LINE %d] Element '%s' within element '%s' does match expected "
"element type of '%s'\n", Node->line, Node->name, Node->parent->name,
Name);
exit(1);
}
}
/* Checks that the node has no remaining child nodes or property nodes,
* then unlinks the node from the tree which updates pointers and
* frees the memory */
void
FreeNode(INOUTP ezxml_t Node)
{
ezxml_t Cur;
char *Txt;
/* Shouldn't have unprocessed properties */
if(Node->attr[0])
{
printf(ERRTAG "[LINE %d] Node '%s' has invalid property %s=\"%s\".\n", Node->line,
Node->name, Node->attr[0], Node->attr[1]);
exit(1);
}
/* Shouldn't have non-whitespace text */
Txt = Node->txt;
while(*Txt)
{
if(!IsWhitespace(*Txt))
{
printf(ERRTAG
"[LINE %d] Node '%s' has unexpected text '%s' within it.\n", Node->line,
Node->name, Node->txt);
exit(1);
}
++Txt;
}
/* We shouldn't have child items left */
Cur = Node->child;
if(Cur)
{
printf(ERRTAG "[LINE %d] Node '%s' has invalid child node '%s'.\n", Node->line,
Node->name, Cur->name);
exit(1);
}
/* Now actually unlink and free the node */
ezxml_remove(Node);
}
/* Returns TRUE if character is whatspace between tokens */
boolean
IsWhitespace(char c)
{
switch (c)
{
case ' ':
case '\t':
case '\r':
case '\n':
return TRUE;
default:
return FALSE;
}
}
const char *
FindProperty(INP ezxml_t Parent, INP const char *Name, INP boolean Required)
{
const char *Res;
Res = ezxml_attr(Parent, Name);
if(Required)
{
if(NULL == Res)
{
printf(ERRTAG
"[Line %d] Required property '%s' not found for element '%s'.\n", Parent->line,
Name, Parent->name);
exit(1);
}
}
return Res;
}
/* Count tokens and length in all the Text children nodes of current node. */
extern void
CountTokensInString(INP const char *Str, OUTP int *Num, OUTP int *Len)
{
boolean InToken;
*Num = 0;
*Len = 0;
InToken = FALSE;
while(*Str)
{
if(IsWhitespace(*Str))
{
InToken = FALSE;
}
else
{
if(!InToken)
{
++(*Num);
}
++(*Len);
InToken = TRUE;
}
++Str; /* Advance pointer */
}
}
/* Returns a token list of the text nodes of a given node. This
* unlinks all the text nodes from the document */
extern char **
GetNodeTokens(INP ezxml_t Node)
{
int Count, Len;
char *Cur, *Dst;
boolean InToken;
char **Tokens;
/* Count the tokens and find length of token data */
CountTokensInString(Node->txt, &Count, &Len);
/* Error out if no tokens found */
if(Count < 1)
{
return NULL;
}
Len = (sizeof(char) * Len) + /* Length of actual data */
(sizeof(char) * Count); /* Null terminators */
/* Alloc the pointer list and data list. Count the final
* empty string we will use as list terminator */
Tokens = (char **)my_malloc(sizeof(char *) * (Count + 1));
Dst = (char *)my_malloc(sizeof(char) * Len);
Count = 0;
/* Copy data to tokens */
Cur = Node->txt;
InToken = FALSE;
while(*Cur)
{
if(IsWhitespace(*Cur))
{
if(InToken)
{
*Dst = '\0';
++Dst;
}
InToken = FALSE;
}
else
{
if(!InToken)
{
Tokens[Count] = Dst;
++Count;
}
*Dst = *Cur;
++Dst;
InToken = TRUE;
}
++Cur;
}
if(InToken)
{ /* Null term final token */
*Dst = '\0';
++Dst;
}
ezxml_set_txt(Node, "");
Tokens[Count] = NULL; /* End of tokens marker is a NULL */
/* Return the list */
return Tokens;
}
/* Returns a token list of the text nodes of a given node. This
* does not unlink the text nodes from the document */
extern char **
LookaheadNodeTokens(INP ezxml_t Node)
{
int Count, Len;
char *Cur, *Dst;
boolean InToken;
char **Tokens;
/* Count the tokens and find length of token data */
CountTokensInString(Node->txt, &Count, &Len);
/* Error out if no tokens found */
if(Count < 1)
{
return NULL;
}
Len = (sizeof(char) * Len) + /* Length of actual data */
(sizeof(char) * Count); /* Null terminators */
/* Alloc the pointer list and data list. Count the final
* empty string we will use as list terminator */
Tokens = (char **)my_malloc(sizeof(char *) * (Count + 1));
Dst = (char *)my_malloc(sizeof(char) * Len);
Count = 0;
/* Copy data to tokens */
Cur = Node->txt;
InToken = FALSE;
while(*Cur)
{
if(IsWhitespace(*Cur))
{
if(InToken)
{
*Dst = '\0';
++Dst;
}
InToken = FALSE;
}
else
{
if(!InToken)
{
Tokens[Count] = Dst;
++Count;
}
*Dst = *Cur;
++Dst;
InToken = TRUE;
}
++Cur;
}
if(InToken)
{ /* Null term final token */
*Dst = '\0';
++Dst;
}
Tokens[Count] = NULL; /* End of tokens marker is a NULL */
/* Return the list */
return Tokens;
}
/* Find integer attribute matching Name in XML tag Parent and return it if exists.
Removes attribute from Parent */
extern int GetIntProperty(INP ezxml_t Parent,
INP const char *Name,
INP boolean Required,
INP int default_value)
{
const char * Prop;
int property_value;
property_value = default_value;
Prop = FindProperty(Parent, Name, Required);
if(Prop)
{
property_value = my_atoi(Prop);
ezxml_set_attr(Parent, Name, NULL);
}
return property_value;
}
/* Find floating-point attribute matching Name in XML tag Parent and return it if exists.
Removes attribute from Parent */
extern float GetFloatProperty(INP ezxml_t Parent,
INP const char *Name,
INP boolean Required,
INP float default_value)
{
const char * Prop;
float property_value;
property_value = default_value;
Prop = FindProperty(Parent, Name, Required);
if(Prop)
{
property_value = atof(Prop);
ezxml_set_attr(Parent, Name, NULL);
}
return property_value;
}
/* Find boolean attribute matching Name in XML tag Parent and return it if exists.
Removes attribute from Parent */
extern boolean GetBooleanProperty(INP ezxml_t Parent,
INP const char *Name,
INP boolean Required,
INP boolean default_value)
{
const char * Prop;
boolean property_value;
property_value = default_value;
Prop = FindProperty(Parent, Name, Required);
if(Prop)
{
if((strcmp(Prop, "false") == 0) ||
(strcmp(Prop, "FALSE") == 0) ||
(strcmp(Prop, "False") == 0)) {
property_value = FALSE;
} else if ((strcmp(Prop, "true") == 0) ||
(strcmp(Prop, "TRUE") == 0) ||
(strcmp(Prop, "True") == 0)) {
property_value = TRUE;
} else {
printf(ERRTAG "[LINE %d] Unknown value %s for boolean attribute %s in %s", Parent->line,
Prop, Name, Parent->name);
exit(1);
}
ezxml_set_attr(Parent, Name, NULL);
}
return property_value;
}
/* Counts number of child elements in a container element.
* Name is the name of the child element.
* Errors if no occurances found. */
extern int
CountChildren(INP ezxml_t Node, INP const char *Name, INP int min_count)
{
ezxml_t Cur, sibling;
int Count;
Count = 0;
Cur = Node->child;
sibling = NULL;
if(Cur)
{
sibling = Cur->sibling;
}
while(Cur)
{
if(strcmp(Cur->name, Name) == 0)
{
++Count;
}
Cur = Cur->next;
if(Cur == NULL)
{
Cur = sibling;
if(Cur != NULL)
{
sibling = Cur->sibling;
}
}
}
/* Error if no occurances found */
if(Count < min_count)
{
printf(ERRTAG "[Line %d] Expected node '%s' to have %d "
"child elements, but none found.\n", Node->line, Node->name, min_count);
exit(1);
}
return Count;
}