9 const char *XML_E_VALUE_NO_PARENT
= "Value without a parent!";
10 const char *XML_E_INVALID_CHAR
= "Invalid character in current parsing status!";
11 const char *XML_E_INVALID_CLOSING
= "Trying to close a tag that is not the current one!";
12 const char *XML_E_UNNAMED_TAG
= "Trying to open a tag that has no name!";
13 const char *XML_E_UNCLOSED_TAGS
= "Not all tags have been closed!";
15 // Creates an empty XmlTag
17 // * parent: the parent of the tag being created (may be NULL)
19 // An XmlTag, with all the fields ready for usage
20 XmlTag
xml_tag_new(XmlTag parent
) {
21 XmlTag tag
= malloc(sizeof(struct XmlTag
));
22 tag
->name
= mystring_new(1,1);
23 tag
->children
= myarray_new(1, 1, sizeof(XmlTag
));
25 tag
->value
= mystring_new(1,1);
30 // Frees an XmlTag and all its fields
32 // * tag: the tag to free
33 void xml_tag_free(XmlTag tag
) {
34 mystring_free(tag
->name
);
35 myarray_free(tag
->children
);
36 mystring_free(tag
->value
);
40 // Frees an entire tree of XmlTags
42 // * root: the root of the tree you wish to free
43 void xml_tree_free(XmlTag root
) {
45 for (i
= 0; i
< root
->children
->len
; i
++) {
46 xml_tree_free(myarray_get(root
->children
, XmlTag
, i
));
51 void xml_print_tree_helper(XmlTag tag
) {
54 printf("%*s%s; ", depth
*4, "\0", tag
->name
->str
);
55 if (tag
->children
->len
> 0) {
56 printf("children: %d; ", tag
->children
->len
);
58 if (tag
->value
->len
> 0) {
59 printf("value: %s; ", tag
->value
->str
);
63 for (i
= 0; i
< tag
->children
->len
; i
++) {
64 xml_print_tree_helper(myarray_get(tag
->children
, XmlTag
, i
));
69 // Prints the tag tree
71 // * tag: This should be the root of the tree, and it won't be printed.
72 void xml_tree_print(XmlTag tag
) {
74 for (i
= 0; i
< tag
->children
->len
; i
++) {
75 xml_print_tree_helper(myarray_get(tag
->children
, XmlTag
, i
));
81 // * message: the error message to print
82 // * line: the line at which the error occurred
83 // * col: the column at which the error occurred
84 void xml_error(const char *message
, unsigned int line
, int col
) {
85 printf("ERROR (%u,%d): %s\n", line
, col
+ mystring_strip(NULL
) + 1, message
);
88 // Checks a tag for validity
90 // * tag: the tag to check
91 // * line the line at which the tag was defined
92 // * the column at which the tag was defined
94 // TRUE if the tag has a nonzero length name
95 // FALSE if the tag has a zero length name
96 int xml_tag_check(XmlTag tag
, int line
, int col
) {
97 if (tag
->name
->len
== 0) {
98 XML_STATUS
= XML_UNNAMED_TAG
;
99 xml_error(XML_E_UNNAMED_TAG
, line
, col
);
105 // This will parse the tagname to extract attributes from it
106 void xml_tag_parse_attributes(XmlTag tag
) {
109 // Parses an XML file
111 // * path_to_file: path to the XML file to parse
113 // The root of the XML tree, or NULL if an error occurred.
114 // In the latter case, XML_STATUS will be set according to the
116 XmlTag
xml_parse(char *path_to_file
) {
117 FILE *input
= fopen(path_to_file
, "r");
119 XML_STATUS
= XML_FILE_ERROR
;
122 MString buffer
= mystring_new(1,1);
124 // The tag we're currently processing children/values for
125 XmlTag head
= xml_tag_new(NULL
);
126 mystring_str_append(head
->name
, "_ROOT_");
127 XmlTag currenttag
= head
;
128 // Are we parsing a tag definition?
129 unsigned short opentag
= FALSE
;
130 // Is the current character escaped?
131 unsigned short escape
= FALSE
;
134 unsigned int line
= 1;
136 while (mystring_getline(buffer
, input
) != -1) {
137 mystring_strip(buffer
);
138 for (i
= 0; i
< buffer
->len
; i
++) {
142 if (escape
) escape
= FALSE
;
150 XML_STATUS
= XML_INVALID_CHAR
;
151 xml_error(XML_E_INVALID_CHAR
, line
, i
);
152 mystring_free(buffer
);
158 currenttag
= xml_tag_new(currenttag
);
159 myarray_append(currenttag
->parent
->children
, currenttag
);
163 if (opentag
) opentag
= FALSE
;
165 XML_STATUS
= XML_INVALID_CLOSING
;
166 xml_error(XML_E_INVALID_CLOSING
, line
, i
);
167 mystring_free(buffer
);
172 if (mystring_has_prefix(currenttag
->name
, "/")) {
173 if (strcmp(currenttag
->name
->str
+ 1, currenttag
->parent
->name
->str
)) {
174 printf("%s != %s\n", currenttag
->name
->str
+ 1, currenttag
->parent
->name
->str
);
175 XML_STATUS
= XML_INVALID_CLOSING
;
176 xml_error(XML_E_INVALID_CLOSING
, line
, i
-currenttag
->name
->len
- 1);
177 mystring_free(buffer
);
182 myarray_remove_index(currenttag
->parent
->children
, currenttag
->parent
->children
->len
- 1);
183 XmlTag temp
= currenttag
;
184 currenttag
= temp
->parent
->parent
;
186 } else if (mystring_has_suffix(currenttag
->name
, " /")) {
187 mystring_truncate(currenttag
->name
, currenttag
->name
->len
- 2);
188 if (!xml_tag_check(currenttag
, line
, i
)) {
189 mystring_free(buffer
);
194 currenttag
= currenttag
->parent
;
196 if (!xml_tag_check(currenttag
, line
, i
)) {
197 mystring_free(buffer
);
205 if (currenttag
== head
) {
206 XML_STATUS
= XML_VALUE_NO_PARENT
;
207 xml_error(XML_E_VALUE_NO_PARENT
, line
, i
);
208 printf("%s\n", buffer
->str
);
209 mystring_free(buffer
);
215 mystring_char_append(currenttag
->name
, c
);
217 mystring_char_append(currenttag
->value
, c
);
222 mystring_clear(buffer
);
225 if (currenttag
!= head
) {
226 XML_STATUS
= XML_UNCLOSED_TAGS
;
227 xml_error(XML_E_UNCLOSED_TAGS
, 0, 0);
228 mystring_free(buffer
);
235 mystring_free(buffer
);