Skip to content

Instantly share code, notes, and snippets.

@himanshugoel2797
Created March 26, 2015 19:41
Show Gist options
  • Save himanshugoel2797/0be2cf60167bb7b042b5 to your computer and use it in GitHub Desktop.
Save himanshugoel2797/0be2cf60167bb7b042b5 to your computer and use it in GitHub Desktop.
C XML Parser
#include <stdio.h>
#include <stdlib.h>
typedef struct {
void(*error)();
void(*openTag)(char*, int);
void(*closeTag)(char*, int);
void(*contentHit)(char*, int);
void(*attributeHit)(char*, int, char*, int);
} _eventHandlers;
_eventHandlers* handlers;
char* stringStack;
int stringStackLen = 0;
int stringStackPos = 0;
int maxStringLength = 0;
void error()
{
printf("Error\n");
}
void openTag(char* tagName, int len)
{
printf("OPEN TAG: %.*s\n", len, tagName);
}
void closeTag(char* tagName, int len)
{
printf("CLOSE TAG: %.*s\n", len, tagName);
}
void contentHit(char* content, int len)
{
printf("\tCONTENT: %.*s\n", len, content);
}
void attributeHit(char* attrName, int attrName_len, char* attrVal, int attrVal_len)
{
printf("ATTRIBUTE NAME: %.*s \nATTRIBUTE VALUE: %.*s\n", attrName_len, attrName, attrVal_len, attrVal);
}
void pushStack(char* val, int len)
{
if (len > maxStringLength)maxStringLength = len;
for (int i = stringStackPos; i < stringStackLen && i < len + stringStackPos; i++){
stringStack[i] = val[i - stringStackPos];
}
stringStackPos += len;
stringStack[stringStackPos++] = '\0';
}
char* popStack()
{
char* str = malloc(maxStringLength);
int i = stringStackPos - 2;
for (; i > 0 && stringStack[i] != '\0'; i--){
str[stringStackPos - i - 2] = stringStack[i];
}
str[stringStackPos - i - 2] = '\0';
i = stringStackPos - i - 2;
char* toRet = malloc(i);
for (int j = 0; j < i; j++){
toRet[j] = str[i - j - 1];
}
toRet[i] = '\0';
stringStackPos -= ++i;
free(str);
return toRet;
}
int strcmp(char* a, char* b, int len){
for (int i = 0; i < len; i++){
if (a[i] != b[i])return 0;
}
return 1;
}
int addToStack(char* piece, int len){
int tag_name_len;
int attribute_hit = -1;
for (tag_name_len = 0; piece[tag_name_len] != '>' && tag_name_len < len; tag_name_len++)
{
if (piece[tag_name_len] == ' '){
attribute_hit = 0;
break;
}
}
if (piece[0] != '/'){
handlers->openTag(piece, tag_name_len);
pushStack(piece, tag_name_len);
}else{
handlers->closeTag(piece + 1, tag_name_len - 1);
char* shouldBe = popStack();
if (!strcmp(shouldBe, piece + 1, tag_name_len - 1))handlers->error();
free(shouldBe);
}
int end_pos = tag_name_len;
if (!attribute_hit){
int attribute_name_pos = 0;
int attribute_name_len = 0;
int is_in_attr = 1;
for (attribute_hit = 0; attribute_hit + tag_name_len < len; attribute_hit++){
if (piece[attribute_hit + tag_name_len] == '=')attribute_name_len = attribute_hit - attribute_name_pos;
if ((piece[attribute_hit + tag_name_len] == ' ' || piece[attribute_hit + tag_name_len] == '>') && is_in_attr == 3){
handlers->attributeHit(piece + attribute_name_pos + tag_name_len, attribute_name_len, piece + tag_name_len + attribute_name_pos + attribute_name_len + 1, attribute_hit - attribute_name_len - 1 - attribute_name_pos);
is_in_attr = 1;
if (piece[attribute_hit + tag_name_len] == '>'){
end_pos = attribute_hit + tag_name_len;
break;
}
if (piece[attribute_hit + tag_name_len] == ' ')attribute_name_pos = attribute_hit;
}
if (piece[attribute_hit + tag_name_len] == '"')is_in_attr++;
}
}
return end_pos;
}
int checkRangeForWhitespace(char* str, int min, int max){
for (int i = min; i < max; i++){
if (str[i] != ' ' && str[i] != '\n' && str[i] != '\r' && str[i] != '\t')return 0;
}
return 1;
}
int xmlParse(char* xml, int len)
{
stringStackLen = len / 2;
stringStack = malloc(stringStackLen);
int prevTag = 0;
for (int i = 0; i < len; i++){
if (xml[i] == '<'){
if (prevTag != 0 && i - prevTag > 0 && !checkRangeForWhitespace(xml, prevTag, i)){
handlers->contentHit(xml + prevTag, i - prevTag);
}
i += addToStack(xml + i + 1, len - i - 1);
prevTag = i + 2;
}
}
return 0;
}
int main(int argc, char** args){
FILE* file = fopen("xml.txt", "r");
fseek(file, 0, SEEK_END);
int length = ftell(file);
char* xmlFile = malloc(++length);
fseek(file, 0, SEEK_SET);
fread(xmlFile, 1, length, file);
handlers = malloc(sizeof(_eventHandlers));
handlers->attributeHit = &attributeHit;
handlers->closeTag = &closeTag;
handlers->error = &error;
handlers->openTag = &openTag;
handlers->contentHit = &contentHit;
return xmlParse(xmlFile, length);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment