2006-09-01 Miguel de Icaza <miguel@novell.com>
authorMiguel de Icaza <miguel@gnome.org>
Fri, 1 Sep 2006 04:16:31 +0000 (04:16 -0000)
committerMiguel de Icaza <miguel@gnome.org>
Fri, 1 Sep 2006 04:16:31 +0000 (04:16 -0000)
* src/gmarkup.c: Builds and does minimal parsing.

* test/markup.c: Sample test cases I have been using.

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

eglib/ChangeLog
eglib/src/Makefile.am
eglib/src/gmarkup.c
eglib/test/Makefile.am
eglib/test/markup.c
eglib/test/tests.h

index a9b9d8008205dbff83ef924991dc432f527bd569..08c8dd75895083891f503a68c82223109ff63462 100644 (file)
@@ -1,3 +1,9 @@
+2006-09-01  Miguel de Icaza  <miguel@novell.com>
+
+       * src/gmarkup.c: Builds and does minimal parsing.
+
+       * test/markup.c: Sample test cases I have been using
+
 2006-08-31 Atsushi Enomoto <atsushi@ximian.com>
 
        * src/gerror.h,
index 789a08a6e32677343dc8a2af531261f96bf436cf..e62aff919c0fea63a70136fff83f6f71edbf0ce2 100644 (file)
@@ -25,6 +25,7 @@ libeglib_la_SOURCES = \
        gfile.c         \
        gpattern.c      \
        gdir.c          \
+       gmarkup.c       \
        gutf8.c
 
 libeglib_la_CFLAGS = -Wall -Werror -D_FORTIFY_SOURCE=2
index a7b03d0237bddfd1fd0b9ed0b657aecdbee11651..ed0b79b77ad0be42b1b5c061dbfe0ac67b2a2152 100644 (file)
 #include <stdio.h>
 #include <glib.h>
 
-#define set_error(msg...) do { if (error != NULL) *error = g_error_new (1, 1, msg); } while (0);
+#define set_error(msg...) do { if (error != NULL) *error = g_error_new (GINT_TO_POINTER (1), 1, msg); } while (0);
 
 typedef enum {
        START,
+       START_ELEMENT,
+       TEXT
 } ParseState;
 
 struct _GMarkupParseContext {
@@ -65,11 +67,114 @@ g_markup_parse_context_free (GMarkupParseContext *context)
        g_free (context);
 }
 
+static const char *
+skip_space (const char *p, const char *end)
+{
+       for (; p < end && isspace (*p); p++)
+               ;
+       return p;
+}
+
+static const char *
+parse_value (const char *p, const char *end, char **value, GError **error)
+{
+       const char *start;
+       int l;
+       
+       if (*p != '"'){
+               set_error ("Expected the attribute value to start with a quote");
+               return end;
+       }
+       start = ++p;
+       for (++p; p < end && *p != '"'; p++)
+       if (p == end)
+               return end;
+       l = p - start;
+       p++;
+       *value = malloc (l + 1);
+       if (*value == NULL)
+               return end;
+       strncpy (*value, start, l);
+       (*value) [l] = 0;
+       return p;
+}
+
+static const char *
+parse_name (const char *p, const char *end, char **value)
+{
+       const char *start = p;
+       int l;
+       
+       for (; p < end && isalnum (*p); p++)
+               ;
+       if (p == end)
+               return end;
+
+       l = p - start;
+       *value = malloc (l + 1);
+       if (*value == NULL)
+               return end;
+       strncpy (*value, start, l);
+       (*value) [l] = 0;
+       return p;
+}
+
+static const char *
+parse_attributes (const char *p, const char *end, char ***names, char ***values, GError **error, int *full_stop)
+{
+       int nnames = 0;
+
+       while (TRUE){
+               p = skip_space (p, end);
+               if (p == end)
+                       return end;
+                       
+               if (*p == '>'){
+                       *full_stop = 0;
+                       return p; 
+               }
+               if (*p == '/' && ((p+1) < end && *p == '>')){
+                       *full_stop = 1;
+                       return p+1;
+               } else {
+                       char *name, *value;
+                       
+                       p = parse_name (p, end, &name);
+                       if (p == end)
+                               return p;
+                       p = skip_space (p, end);
+                       if (p == end)
+                               return p;
+                       if (*p != '='){
+                               set_error ("Expected an = after the attribute name `%s'", name);
+                               return end;
+                       }
+                       p++;
+                       p = skip_space (p, end);
+                       if (p == end)
+                               return end;
+
+                       p = parse_value (p, end, &value, error);
+                       if (p == end)
+                               return p;
+
+                       ++nnames;
+                       *names = g_realloc (*names, sizeof (char **) * (nnames+1));
+                       *values = g_realloc (*values, sizeof (char **) * (nnames+1));
+                       (*names) [nnames-1] = name;
+                       (*values) [nnames-1] = name;                    
+                       (*names) [nnames] = NULL;
+                       (*values) [nnames] = NULL;                      
+               }
+       } 
+}
+
 gboolean
 g_markup_parse_context_parse (GMarkupParseContext *context,
-                             const gchar *text, gssize text_len, GError **error)
+                             const gchar *text, gssize text_len,
+                             GError **error)
 {
-       char *p, *end;
+       const char *p,  *end;
        
        g_return_val_if_fail (context != NULL, FALSE);
        g_return_val_if_fail (text != NULL, FALSE);
@@ -94,8 +199,9 @@ g_markup_parse_context_parse (GMarkupParseContext *context,
 
 
                case START_ELEMENT: {
-                       char *element_start = p;
-                       char **names, *values;
+                       const char *element_start = p, *element_end;
+                       int full_stop = 0;
+                       gchar **names = NULL, **values = NULL;
 
                        if (!(isascii (*p) && isalpha (*p)))
                                set_error ("Must start with a letter");
@@ -106,20 +212,53 @@ g_markup_parse_context_parse (GMarkupParseContext *context,
                                set_error ("Expected an element");
                                return FALSE;
                        }
+                       element_end = p;
+                       
                        for (; p < end && isspace (*p); p++)
                                ;
                        if (p == end){
                                set_error ("Unfinished element");
                                return FALSE;
                        }
-                       p = parse_attributes (p, end, &names, &values);
+                       p = parse_attributes (p, end, &names, &values, error, &full_stop);
                        if (p == end){
-                               set_error ("unfinished element");
+                               if (*error == NULL)
+                                       set_error ("Unfinished sequence");
+                               
                                return FALSE;
                        }
-                       
+                       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;
+                               
+                               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;
+                       break;
+               } /* case START_ELEMENT */
+
+               case TEXT: {
+                       break;
                }
+                       
                }
        }
+
+       return TRUE;
 }
 
index a5ed71edfb7ea4ac4d4f4e4a07535c9b3c599e4d..579461453ce9482943190c6a9c76f69bc58ed657 100644 (file)
@@ -22,6 +22,7 @@ SOURCES = \
        file.c          \
        pattern.c       \
        dir.c           \
+       markup.c        \
        utf8.c
 
 test_eglib_SOURCES = $(SOURCES)
index cd37d7e38cc4d44606bb66be6e2bde9d9712d8ce..11cc886ba42fb5c574895efe14fca94d1ccfb5fc 100644 (file)
@@ -3,7 +3,8 @@
 #include <glib.h>
 #include "test.h"
 
-#define do_test(s) do { char *r = markup_test (s); if (r != NULL) FAILED (r); } while (0)
+#define do_bad_test(s) do { char *r = markup_test (s); if (r == NULL) return FAILED ("Failed on test " # s); } while (0)
+#define do_ok_test(s) do { char *r = markup_test (s); if (r != NULL) return FAILED ("Could not parse valid " # s); } while (0)
 
 static char *
 markup_test (const char *s)
@@ -17,29 +18,43 @@ markup_test (const char *s)
        g_markup_parse_context_parse (context, s, strlen (s), &error);
        g_markup_parse_context_free (context);
 
-       if (error != NULL)
-               return error->message;
+       if (error != NULL){
+               char *msg = g_strdup (error->message);
+               g_error_free (error);
+
+               return msg;
+       }
        return NULL;
 }
 
 RESULT invalid_documents (void)
 {
        /* These should fail */
-       do_test ("<1>");
-       do_test ("<a<");
-       do_test ("</a>");
+       do_bad_test ("<1>");
+       do_bad_test ("<a<");
+       do_bad_test ("</a>");
+       do_bad_test ("<a b>");
+       do_bad_test ("<a b=>");
+       do_bad_test ("<a b=c>");
+       
+       return OK;
+}
+
+
+RESULT valid_documents (void)
+{
+       /* These should fail */
+       do_ok_test ("<a>");
+       do_ok_test ("<a a=\"b\">");
        
        return OK;
 }
 
 static Test markup_tests [] = {
        {"invalid_documents", invalid_documents},
-       {"t2", hash_t2},
-       {"grow", hash_grow},
-       {"default", hash_default},
-       {"null_lookup", hash_null_lookup},
+       {"good_documents", valid_documents},
        {NULL, NULL}
 };
 
-DEFINE_TEST_GROUP_INIT(hashtable_tests_init, hashtable_tests)
+DEFINE_TEST_GROUP_INIT(markup_tests_init, markup_tests)
 
index 157eb768408b6b459d78dd0dab09d4767bfe7cf7..5a19072444cb623724d57f1d22516e082901c8f7 100644 (file)
@@ -17,6 +17,7 @@ DEFINE_TEST_GROUP_INIT_H(timer_tests_init);
 DEFINE_TEST_GROUP_INIT_H(file_tests_init);
 DEFINE_TEST_GROUP_INIT_H(pattern_tests_init);
 DEFINE_TEST_GROUP_INIT_H(dir_tests_init);
+DEFINE_TEST_GROUP_INIT_H(markup_tests_init);
 DEFINE_TEST_GROUP_INIT_H(utf8_tests_init);
 
 static Group test_groups [] = {        
@@ -32,6 +33,7 @@ static Group test_groups [] = {
        {"queue",     queue_tests_init},
        {"path",      path_tests_init},
        {"shell",     shell_tests_init},
+       {"markup",    markup_tests_init},
        {"spawn",     spawn_tests_init},
        {"timer",     timer_tests_init},
        {"file",      file_tests_init},