2006-09-01 Miguel de Icaza <miguel@novell.com>
authorMiguel de Icaza <miguel@gnome.org>
Fri, 1 Sep 2006 20:30:40 +0000 (20:30 -0000)
committerMiguel de Icaza <miguel@gnome.org>
Fri, 1 Sep 2006 20:30:40 +0000 (20:30 -0000)
        * src/gmarkup.c (g_markup_parse_context_parse): Add text parsing
        support, and end-element support; not tested yet.

svn path=/trunk/mono/; revision=64742

eglib/ChangeLog
eglib/src/gmarkup.c

index 5d90e2f49964708e3bc181d6f46154d80a483ea3..2fd3014d68e08470da1ec6552c0150c0d96dcddb 100644 (file)
@@ -1,3 +1,8 @@
+2006-09-01  Miguel de Icaza  <miguel@novell.com>
+
+       * src/gmarkup.c (g_markup_parse_context_parse): Add text parsing
+       support, and end-element support; not tested yet.
+
 2006-09-01 Atsushi Enomoto <atsushi@ximian.com>
 
        * gutf8.c : bad allocation size. multiply sizeof gchar/gunichar2.
index ed0b79b77ad0be42b1b5c061dbfe0ac67b2a2152..47d859aa697f16ef2f7b29b2dd3565d7299ec4f4 100644 (file)
@@ -36,7 +36,9 @@
 typedef enum {
        START,
        START_ELEMENT,
-       TEXT
+       TEXT,
+       FLUSH_TEXT,
+       CLOSING_ELEMENT
 } ParseState;
 
 struct _GMarkupParseContext {
@@ -44,6 +46,11 @@ struct _GMarkupParseContext {
        gpointer       user_data;
        GDestroyNotify user_data_dnotify;
        ParseState     state;
+
+       /* Stores the name of the current element, so we can issue the end_element */
+       GSList         *level;
+
+       GString        *text;
 };
 
 GMarkupParseContext *
@@ -169,6 +176,21 @@ parse_attributes (const char *p, const char *end, char ***names, char ***values,
        } 
 }
 
+static void
+destroy_parse_state (GMarkupParseContext *context)
+{
+       GSList *p;
+
+       for (p = context->level; p != NULL; p = p->next)
+               g_free (p->data);
+       
+       g_slist_free (context->level);
+       if (context->text != NULL)
+               g_string_free (context->text, TRUE);
+       context->text = NULL;
+       context->level = NULL;
+}
+
 gboolean
 g_markup_parse_context_parse (GMarkupParseContext *context,
                              const gchar *text, gssize text_len,
@@ -194,23 +216,31 @@ g_markup_parse_context_parse (GMarkupParseContext *context,
                                continue;
                        }
                        set_error ("Expected < to start the document");
-                       
-                       return FALSE;
+                       goto fail;
 
 
                case START_ELEMENT: {
                        const char *element_start = p, *element_end;
-                       int full_stop = 0;
+                       char *ename = NULL;
+                       int full_stop = 0, l;
                        gchar **names = NULL, **values = NULL;
 
-                       if (!(isascii (*p) && isalpha (*p)))
-                               set_error ("Must start with a letter");
+                       for (; p < end && isspace (*p); p++)
+                               ;
+                       if (p == end){
+                               set_error ("Unfinished element");
+                               goto fail;
+                       }
+                       if (!(isascii (*p) && isalpha (*p))){
+                               set_error ("Expected an element name");
+                               goto fail;
+                       }
                        
                        for (++p; p < end && isalnum (*p); p++)
                                ;
                        if (p == end){
                                set_error ("Expected an element");
-                               return FALSE;
+                               goto fail;
                        }
                        element_end = p;
                        
@@ -218,47 +248,112 @@ g_markup_parse_context_parse (GMarkupParseContext *context,
                                ;
                        if (p == end){
                                set_error ("Unfinished element");
-                               return FALSE;
+                               goto fail;
                        }
                        p = parse_attributes (p, end, &names, &values, error, &full_stop);
                        if (p == end){
-                               if (*error == NULL)
-                                       set_error ("Unfinished sequence");
+                               if (names != NULL) {
+                                       g_strfreev (names);
+                                       g_strfreev (values);
+                               }
                                
-                               return FALSE;
+                               set_error ("Unfinished sequence");
+                               goto fail;
                        }
-                       if (context->parser.start_element != NULL){
-                               int l = element_end - element_start;
-                               char *ename = malloc (l + 1);
-
-                               if (ename == NULL)
-                                       return FALSE;
-                               strncpy (ename, element_start, l);
-                               ename [l] = 0;
-                               
+                       l = 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);
-                               free (ename);
-                       }
+
                        if (names != NULL){
                                g_strfreev (names);
                                g_strfreev (values);
                        }
+
                        if (*error != NULL)
-                               return FALSE;
-                       context->state = full_stop ? START : TEXT;
+                               goto fail;
+                       
+                       if (full_stop){
+                               if (context->parser.end_element != NULL){
+                                       context->parser.end_element (context, ename, context->user_data, error);
+                                       if (*error != NULL)
+                                               goto fail;
+                               }
+                       } else
+                               context->level = g_slist_prepend (context->level, ename);
+                       
+                       context->state = TEXT;
                        break;
                } /* case START_ELEMENT */
 
                case TEXT: {
+                       if (c == '<'){
+                               context->state = FLUSH_TEXT;
+                               break;
+                       }
+                       if (context->parser.text != NULL){
+                               if (context->text == NULL)
+                                       context->text = g_string_new ("");
+                               g_string_append_c (context->text, c);
+                       }
                        break;
                }
+
+               case FLUSH_TEXT:
+                       if (context->parser.text != NULL){
+                               context->parser.text (context, context->text->str, context->text->len,
+                                                     context->user_data, error);
+                               if (*error != NULL)
+                                       goto fail;
+                       }
                        
-               }
+                       if (c == '/')
+                               context->state = CLOSING_ELEMENT;
+                       else {
+                               p--;
+                               context->state = START_ELEMENT;
+                       }
+                       break;
+
+               case CLOSING_ELEMENT: {
+                       GSList *current = context->level;
+
+                       if (context->level == NULL){
+                               set_error ("Too many closing tags, not enough open tags");
+                               goto fail;
+                       }
+                       
+                       if (context->parser.end_element != NULL){
+                               char *text = current->data;
+                               
+                               context->parser.end_element (context, text, context->user_data, error);
+                               if (*error != NULL)
+                                       goto fail;
+                       }
+                       context->level = context->level->next;
+                       g_slist_free (current);
+                       break;
+               } /* case CLOSING_ELEMENT */
+                       
+               } /* switch */
        }
 
+
        return TRUE;
+ fail:
+       if (context->parser.error)
+               context->parser.error (context, *error, context->user_data);
+       
+       destroy_parse_state (context);
+       return FALSE;
 }
 
+