#include <stdio.h>
#include <glib.h>
-#define set_error(msg...) do { if (error != NULL) *error = g_error_new (GINT_TO_POINTER (1), 1, msg); } while (0);
+#define set_error(msg, ...) do { if (error != NULL) *error = g_error_new (GINT_TO_POINTER (1), 1, msg, __VA_ARGS__); } while (0);
typedef enum {
START,
TEXT,
FLUSH_TEXT,
CLOSING_ELEMENT,
- COMMENT
+ COMMENT,
+ SKIP_XML_DECLARATION
} ParseState;
struct _GMarkupParseContext {
int l;
if (*p != '"'){
- set_error ("Expected the attribute value to start with a quote");
+ set_error ("%s", "Expected the attribute value to start with a quote");
return end;
}
start = ++p;
- for (++p; p < end && *p != '"'; p++)
+ for (; p < end && *p != '"'; p++)
+ ;
if (p == end)
return end;
- l = p - start;
+ l = (int)(p - start);
p++;
*value = malloc (l + 1);
if (*value == NULL)
if (p == end)
return end;
- l = p - start;
+ l = (int)(p - start);
*value = malloc (l + 1);
if (*value == NULL)
return end;
}
static const char *
-parse_attributes (const char *p, const char *end, char ***names, char ***values, GError **error, int *full_stop)
+parse_attributes (const char *p, const char *end, char ***names, char ***values, GError **error, int *full_stop, int state)
{
int nnames = 0;
*full_stop = 0;
return p;
}
+ if (state == SKIP_XML_DECLARATION && *p == '?' && ((p+1) < end) && *(p+1) == '>'){
+ *full_stop = 0;
+ return p+1;
+ }
+
if (*p == '/' && ((p+1) < end && *(p+1) == '>')){
*full_stop = 1;
return p+1;
for (p = text; p < end; p++){
char c = *p;
-
+
switch (context->state){
case START:
if (c == ' ' || c == '\t' || c == '\f' || c == '\n')
continue;
if (c == '<'){
- context->state = START_ELEMENT;
+ if (p+1 < end && p [1] == '?'){
+ context->state = SKIP_XML_DECLARATION;
+ p++;
+ } else
+ context->state = START_ELEMENT;
continue;
}
- set_error ("Expected < to start the document");
+ set_error ("%s", "Expected < to start the document");
goto fail;
-
+ case SKIP_XML_DECLARATION:
case START_ELEMENT: {
const char *element_start = p, *element_end;
char *ename = NULL;
for (; p < end && isspace (*p); p++)
;
if (p == end){
- set_error ("Unfinished element");
+ set_error ("%s", "Unfinished element");
goto fail;
}
}
if (!(isascii (*p) && isalpha (*p))){
- set_error ("Expected an element name");
+ set_error ("%s", "Expected an element name");
goto fail;
}
- for (++p; p < end && isalnum (*p); p++)
+ for (++p; p < end && (isalnum (*p) || (*p == '.')); p++)
;
if (p == end){
- set_error ("Expected an element");
+ set_error ("%s", "Expected an element");
goto fail;
}
element_end = p;
for (; p < end && isspace (*p); p++)
;
if (p == end){
- set_error ("Unfinished element");
+ set_error ("%s", "Unfinished element");
goto fail;
}
- p = parse_attributes (p, end, &names, &values, error, &full_stop);
+ p = parse_attributes (p, end, &names, &values, error, &full_stop, context->state);
if (p == end){
if (names != NULL) {
g_strfreev (names);
}
/* Only set the error if parse_attributes did not */
if (error != NULL && *error == NULL)
- set_error ("Unfinished sequence");
+ set_error ("%s", "Unfinished sequence");
goto fail;
}
- l = element_end - element_start;
+ l = (int)(element_end - element_start);
ename = malloc (l + 1);
if (ename == NULL)
goto fail;
strncpy (ename, element_start, l);
ename [l] = 0;
-
- if (context->parser.start_element != NULL)
- context->parser.start_element (context, ename,
- (const gchar **) names,
- (const gchar **) values,
- context->user_data, error);
+
+ if (context->state == START_ELEMENT)
+ if (context->parser.start_element != NULL)
+ context->parser.start_element (context, ename,
+ (const gchar **) names,
+ (const gchar **) values,
+ context->user_data, error);
if (names != NULL){
g_strfreev (names);
}
if (full_stop){
- if (context->parser.end_element != NULL){
+ if (context->parser.end_element != NULL && context->state == START_ELEMENT){
context->parser.end_element (context, ename, context->user_data, error);
if (error != NULL && *error != NULL){
free (ename);
}
}
free (ename);
- } else
+ } else {
context->level = g_slist_prepend (context->level, ename);
+ }
context->state = TEXT;
break;
p += 2;
break;
}
-
+ break;
case FLUSH_TEXT:
if (context->parser.text != NULL){
char *text;
if (context->level == NULL){
- set_error ("Too many closing tags, not enough open tags");
+ set_error ("%s", "Too many closing tags, not enough open tags");
goto fail;
}
- text = current->data;
+ text = current->data;
if (context->parser.end_element != NULL){
context->parser.end_element (context, text, context->user_data, error);
if (error != NULL && *error != NULL){
}
}
free (text);
+
+ while (p < end && *p != '>')
+ p++;
context->level = context->level->next;
g_slist_free_1 (current);
+ context->state = TEXT;
break;
} /* case CLOSING_ELEMENT */
return TRUE;
fail:
- if (context->parser.error)
+ if (context->parser.error && error != NULL && *error)
context->parser.error (context, *error, context->user_data);
destroy_parse_state (context);