Converted tooling to C.

This commit is contained in:
2021-11-07 23:34:05 -08:00
parent a2a839cbac
commit a6bae07e38
18 changed files with 637 additions and 394 deletions

View File

@ -7,88 +7,204 @@
#include "xml.h"
void xmlParseElement(xmlnode_t *node, char *string) {
int32_t xmlLoadChild(xml_t *xml, char *data, int32_t i) {
char c;
int32_t i, j;
uint8_t state;
int32_t level = 0;
uint8_t doing = XML_DOING_NOTHING;
bool insideTag = false;
char* buffer = malloc(sizeof(char) * XML_TEXT_BUFFER_MAX);
int32_t bufferLength = 0;
node->attributeCount = 0;
xml->value = NULL;
xml->attributeCount = 0;
i = 0;
state = XML_STATE_NOTHING;
while(c = string[i++]) {
switch(state) {
case XML_STATE_NOTHING:
if(c != '<') continue;
node->start = string + (i - 1);
state = XML_STATE_PARSING_NAME;
break;
xml->children = malloc(sizeof(xml_t) * XML_CHILD_COUNT_MAX);
xml->childrenCount = 0;
case XML_STATE_PARSING_NAME:
if(c == ' ' || c == '\n' || c == '\r') continue;
j = i - 1;
while(c = string[j++]) {
if(c == ' ') break;
node->name[j] = c;
}
i = j;
state = XML_STATE_PARSING_ATTRIBUTES;
break;
case XML_STATE_PARSING_ATTRIBUTES:
if(c == ' ' || c == '\n' || c == '\r') continue;
if(c == '>') {
node->internal = string + i;
break;
continue;
}
// Parse Name
node->attributeNames[node->attributeCount] = string + (i - 1);
node->attributeNameLengths[node->attributeCount] = 0;
while(c == ' ' && c == '\n' && c == '\r' && c != '>' && c != '=' && c != '\0') {
c = string[i++];
node->attributeNameLengths[node->attributeCount]++;
}
if(c == '>') {
i--;
node->attributeValues[node->attributeCount] = NULL;
node->attributeValueLengths[node->attributeCount] = 0;
node->attributeCount++;
continue;
}
// Wait for = sign
while(c == ' ' || c == '\n' || c == '\r') c = string[i++];
// Handle booleans
if(c != '=') {
node->attributeValues[node->attributeCount] = NULL;
node->attributeValueLengths[node->attributeCount] = 0;
node->attributeCount++;
i--;
continue;
}
node->attributeValues[node->attributeCount] = string + i;
node->attributeValueLengths[node->attributeCount] = 0;
do {
c = string[i++];
node->attributeNameLengths[node->attributeCount]++;
if(c == '\0' || c == '"') break;
if(c == '\\') {
i++;
node->attributeNameLengths[node->attributeCount]++;
while(c = data[i++]) {
switch(doing) {
case XML_DOING_NOTHING:
// Look for either an opening tag (<) or a word for a value.
if(c == '>') continue;
if(c == '<') {
if(insideTag) {
i = xmlLoadChild(xml->children + xml->childrenCount++, data, i-1);
doing = XML_PARSING_CHILD;
} else {
doing = XML_PARSING_TAG_NAME;
level++;
insideTag = true;
}
} while(c);
node->attributeCount++;
continue;
}
if(xmlIsWhitespace(c)) continue;
doing = XML_PARSING_VALUE;
buffer[bufferLength++] = c;
break;
case XML_PARSING_TAG_NAME:
// Just keep reading until we either hit a space (end of the tag name)
// or a closing tag value, either / or >
if(xmlIsWhitespace(c) || c == '>' || c == '/') {
buffer[bufferLength] = '\0';
xml->node = buffer;
buffer = malloc(sizeof(char) * XML_TEXT_BUFFER_MAX);
bufferLength = 0;
if(c == '/') {
level--;
insideTag = false;
doing = XML_PARSING_CLOSE;
} else {
doing = c == '>' ? XML_DOING_NOTHING : XML_LOOKING_FOR_ATTRIBUTE;
}
continue;
}
buffer[bufferLength++] = c;
break;
case XML_LOOKING_FOR_ATTRIBUTE:
// Look until we hit either the end of a tag, or the attribute itself
if(xmlIsWhitespace(c) || c == '>' || c == '/' || c == '=') {
if(c == '>' || c == '/') {
doing = XML_DOING_NOTHING;
if(c == '/') {
level--;
insideTag = false;
doing = XML_PARSING_CLOSE;
}
} else if(c == '=') {
doing = XML_LOOKING_FOR_ATTRIBUTE_VALUE;
} else {
doing = XML_LOOKING_FOR_ATTRIBUTE;
}
if(bufferLength > 0) {
buffer[bufferLength] = '\0';
xml->attributeNames[xml->attributeCount++] = buffer;
xml->attributeDatas[xml->attributeCount] = NULL;
buffer = malloc(sizeof(char) * XML_TEXT_BUFFER_MAX);
bufferLength = 0;
}
continue;
}
buffer[bufferLength++] = c;
break;
case XML_LOOKING_FOR_ATTRIBUTE_VALUE:
// Keep looking until we find a quote mark
if(xmlIsWhitespace(c)) continue;
if(c == '>' || c == '/') {
doing = XML_DOING_NOTHING;
insideTag = false;
continue;
}
if(c != '"') continue;
doing = XML_PARSING_ATTRIBUTE_VALUE;
break;
case XML_PARSING_ATTRIBUTE_VALUE:
// Parse the attribute value until we find a quote mark.
if(c == '"') {
doing = XML_LOOKING_FOR_ATTRIBUTE;
buffer[bufferLength] = '\0';
xml->attributeDatas[xml->attributeCount - 1] = buffer;
buffer = malloc(sizeof(char) * XML_TEXT_BUFFER_MAX);
bufferLength = 0;
continue;
}
buffer[bufferLength++] = c;
break;
case XML_PARSING_VALUE:
// Keep parsing child until we find a < for an opening/closing tag.
if(c == '<') {
// In HTML Spec there could be a child here but not in XML spec.
doing = XML_PARSING_CLOSE;
buffer[bufferLength] = '\0';
bufferLength = 0;
xml->value = buffer;
buffer = malloc(sizeof(char) * XML_TEXT_BUFFER_MAX);
continue;
}
buffer[bufferLength++] = c;
break;
case XML_PARSING_CHILD:
if(c == '<') {
// Read ahead and confirm this is a close or not
if(data[i] == '/') {
doing = XML_PARSING_CLOSE;
continue;
}
// Likely another child.
i = xmlLoadChild(xml->children + xml->childrenCount++, data, i-1);
}
if(xmlIsWhitespace(c)) continue;
// In HTML Spec there's a chance for there to be a value here, but not
// in the XML spec.
break;
case XML_PARSING_CLOSE:
// Just keep parsing until the tag closer finishes.
if(c != '>') continue;
doing = XML_DOING_NOTHING;
//TODO: Return index or something?
free(buffer);
return i;
default:
break;
}
}
free(buffer);
return i;
}
void xmlLoad(xml_t *xml, char *data) {
xmlLoadChild(xml, data, 0);
}
void xmlDispose(xml_t *xml) {
uint8_t i;
// Dispose children recursively
for(i = 0; i < xml->childrenCount; i++) {
xmlDispose(xml->children + i);
}
// Free children array.
free(xml->children);
// Dispose attributes
for(i = 0; i < xml->attributeCount; i++) {
free(xml->attributeNames[i]);
if((xml->attributeDatas + i) != NULL) {
free(xml->attributeDatas[i]);
}
}
free(xml->node);
if(xml-> value != NULL) free(xml->value);
}
int16_t xmlGetAttributeByName(xml_t *xml, char *name) {
int16_t i;
for(i = 0; i < xml->attributeCount; i++) {
if(strcmp(xml->attributeNames[i], name) == 0) return i;
}
return -1;
}
bool xmlIsWhitespace(char c) {
return c == ' ' || c == '\r' || c == '\n' || c == '\t';
}