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
|
#include <stdio.h>
#include <stdlib.h>
#include <glib.h>
const char ESCAPE = '\\';
const char *XML_VALUE_NO_PARENT = "Value without a parent!";
const char *XML_INVALID_CHAR = "Invalid character in current parsing status!";
const char *XML_NOT_CLOSING_CURRENT = "Trying to close a tag that is not the current one!";
int stripped_front;
typedef struct xmltag *xmltag; struct xmltag {
GString *name;
GArray *children;
GString *value; xmltag parent; };
xmltag xml_tag_new(xmltag parent) {
xmltag tag = g_malloc(sizeof(struct xmltag));
tag->name = g_string_new(NULL);
tag->children = g_array_new(FALSE, FALSE, sizeof(xmltag));
tag->parent = parent;
tag->value = g_string_new(NULL);
return tag;
}
void xml_free_tag(xmltag tag) {
g_string_free(tag->name, TRUE);
g_array_free(tag->children, TRUE);
g_string_free(tag->value, TRUE); g_free(tag);
}
void print_tree(xmltag tag) {
static int depth = 0;
printf("%*s%s", depth*4, "\0", tag->name->str);
int i;
if (tag->children->len != 0) {
printf("; children: %d", tag->children->len);
}
if (tag->value->len != 0) {
printf("; value: %s", tag->value->str);
}
printf("\n");
depth++;
for (i = 0; i < tag->children->len; i++) {
print_tree(g_array_index(tag->children, xmltag, i));
}
depth--;
}
void error(const char *message, int line, int col) {
printf("ERROR (%d,%d): %s\n", line, col + stripped_front + 1, message);
exit(EXIT_FAILURE);
}
void g_string_strip(GString *string) {
int i;
for (i = string->len - 1; i >= 0; i--){
if (!g_ascii_isspace(string->str[i])) {
break;
}
}
if (i+1 < string->len) g_string_truncate(string, i+1);
for (i = 0; i < string->len; i++) {
if (!g_ascii_isspace(string->str[i])) {
break;
}
}
stripped_front = i;
g_string_erase(string, 0, i);
}
int main(int argc, char **argv) {
if (argc != 2) {
printf("You need to specify an xml file to be parsed\n");
exit(EXIT_FAILURE);
}
GString *buffer = g_string_new(NULL);
GIOChannel *input = g_io_channel_new_file(argv[1], "r", NULL);
if (input == NULL) {
exit(EXIT_FAILURE);
}
// The tag we're currently processing children/values for
xmltag head = xml_tag_new(NULL);
g_string_append(head->name, "_HEAD_");
xmltag currenttag = head;
// Are we parsing a tag definition?
gboolean opentag = FALSE;
// Are we parsing the closing of a tag?
gboolean closetag = FALSE;
// Was the last char an escape character ('\')?
gboolean escape = FALSE;
FILE *output = fopen("bla", "w");
int i;
int line = 1;
char c;
while (g_io_channel_read_line_string(input, buffer, NULL, NULL) == G_IO_STATUS_NORMAL) {
g_string_strip(buffer);
for (i = 0; i < buffer->len; i++) {
c = buffer->str[i];
switch (c) {
case '<':
if (opentag) {
error(XML_INVALID_CHAR, line, i);
}
opentag = TRUE;
currenttag = xml_tag_new(currenttag);
g_array_append_val(currenttag->parent->children, currenttag);
break;
case '>':
if (opentag) opentag = FALSE;
else error("no tag being created!", line, i);
g_string_ascii_down(currenttag->name);
if (g_str_has_prefix(currenttag->name->str, "/")) {
if (g_strcmp0(currenttag->name->str + 1, currenttag->parent->name->str)) {
error(XML_NOT_CLOSING_CURRENT, line, i-currenttag->name->len - 1);
}
fprintf(output, "closing tag: %s; going back to: %s\n", currenttag->name->str, currenttag->parent->parent->name->str);
fflush(output);
g_array_remove_index(currenttag->parent->children, currenttag->parent->children->len-1);
xmltag temp = currenttag;
currenttag = temp->parent->parent;
xml_free_tag(temp);
} else {
fprintf(output, "opened tag: %s; parent: %s\n", currenttag->name->str, currenttag->parent->name->str);
fflush(output);
}
break;
default:
if (currenttag == head) {
error(XML_VALUE_NO_PARENT, line, i);
}
if (opentag) {
g_string_append_c(currenttag->name, c);
} else {
g_string_append_c(currenttag->value, c);
}
}
}
line++;
}
if (currenttag != head) {
error("Not all tags have been closed!");
}
print_tree(head);
return 0;
}
|