/*

This is a very basic example of a GMarkup parser.

See also a complete example in <gimp>/app/dialogs/tips-parser.c


gcc `pkg-config --cflags --libs glib-2.0` gmarkup-parser.c -o gmarkup-parser


*/

#include <glib.h>

static gchar* foo_xml_example =
"<foo bar='baz' bir='boz'>"
"   <bar>bar text 1</bar> "
"   <bar>bar text 2</bar> "
"   foo text              "
"<!-- nothing -->         "
"</foo>                   ";

static void foo_parser_start_element (GMarkupParseContext  *context,
                                      const gchar          *element_name,
                                      const gchar         **attribute_names,
                                      const gchar         **attribute_values,
                                      gpointer              user_data,
                                      GError              **error);
static void foo_parser_end_element   (GMarkupParseContext  *context,
                                      const gchar          *element_name,
                                      gpointer              user_data,
                                      GError              **error);
static void foo_parser_characters    (GMarkupParseContext  *context,
                                      const gchar          *text,
                                      gsize                 text_len,
                                      gpointer              user_data,
                                      GError              **error);
static void foo_parser_passthrough   (GMarkupParseContext  *context,
                                      const gchar          *passthrough_text,
                                      gsize                 text_len,  
                                      gpointer              user_data,
                                      GError              **error);
static void foo_parser_error         (GMarkupParseContext  *context,
                                      GError               *error,
                                      gpointer              user_data);

/* Parser */
static const GMarkupParser foo_xml_parser = {
  foo_parser_start_element,
  foo_parser_end_element,
  foo_parser_characters,
  foo_parser_passthrough,
  foo_parser_error
};



/* Called for open tags like <foo bar="baz"> */
static void
foo_parser_start_element (GMarkupParseContext *context,
                          const gchar         *element_name,
                          const gchar        **attribute_names,
                          const gchar        **attribute_values,
                          gpointer             user_data,
                          GError             **error)
{
  int i;

  g_printerr ("ELEM | <%s>\n", element_name);

  i = 0;
  while (attribute_names[i]) {
    g_printerr ("ATTR | %s = \"%s\"\n", attribute_names[i],
                                        attribute_values[i]);
    i++;
  }
}


/* Called for close tags like </foo> */
static void
foo_parser_end_element (GMarkupParseContext *context,
                        const gchar         *element_name,
                        gpointer             user_data,
                        GError             **error)
{
  g_printerr ("ELEM | </%s>\n", element_name);
}


/* Called for character data. Text is not nul-terminated */
static void
foo_parser_characters (GMarkupParseContext *context,
                       const gchar         *text,
                       gsize                text_len,
                       gpointer             user_data,
                       GError             **error)
{
  g_printerr ("TEXT | [%s]\n", text);
}
                         

/* Called for strings that should be re-saved verbatim in this same
   position, but are not otherwise interpretable. At the moment this
   includes comments and processing instructions. Text is not
   nul-terminated. */
static void
foo_parser_passthrough    (GMarkupParseContext  *context,
                           const gchar          *passthrough_text,
                           gsize                 text_len,  
                           gpointer              user_data,
                           GError              **error)
{
  g_printerr ("PASS | %s\n", passthrough_text);
}


/* Called on error, including one set by other methods in the
   vtable. The GError should not be freed. */
static void
foo_parser_error          (GMarkupParseContext  *context,
                           GError               *error,
                           gpointer              user_data)
{
  g_printerr ("ERROR\n");
}



/* ******************************************************* */
/* ******************************************************* */
/* ******************************************************* */

int main ()
{
  GMarkupParseContext *context;
  gboolean success = FALSE;
  gint n;

  n = g_utf8_strlen (foo_xml_example, -1);
  g_printerr ("Parsing: %s\n", foo_xml_example);
  g_printerr ("(%d UTF8 characters)\n", n);
  g_printerr ("--------------------------------\n", n);

  context = g_markup_parse_context_new (&foo_xml_parser, 0, NULL,  NULL);

  success = g_markup_parse_context_parse (context, foo_xml_example, n, NULL);

  g_markup_parse_context_free (context);

  g_printerr ("--------------------------------\n", n);
  if(success) g_printerr ("done.\n");
  else        g_printerr ("error.\n");

  return 0;
}
