[gnome-software] Split out the appstream markup functionality into its own module



commit c6f570458d90029059fde270a14a01847f71c25a
Author: Richard Hughes <richard hughsie com>
Date:   Mon Oct 21 10:39:07 2013 +0100

    Split out the appstream markup functionality into its own module

 src/plugins/Makefile.am         |    2 +
 src/plugins/appstream-markup.c  |  202 +++++++++++++++++++++++++++++++++++++++
 src/plugins/appstream-markup.h  |   62 ++++++++++++
 src/plugins/gs-plugin-appdata.c |  163 ++++++--------------------------
 4 files changed, 295 insertions(+), 134 deletions(-)
---
diff --git a/src/plugins/Makefile.am b/src/plugins/Makefile.am
index a5ec830..c2759a8 100644
--- a/src/plugins/Makefile.am
+++ b/src/plugins/Makefile.am
@@ -85,6 +85,8 @@ libgs_plugin_appstream_la_CFLAGS = $(GS_PLUGIN_CFLAGS) $(WARNINGFLAGS_C)
 libgs_plugin_appdata_la_SOURCES =                      \
        appstream-common.c                              \
        appstream-common.h                              \
+       appstream-markup.c                              \
+       appstream-markup.h                              \
        gs-plugin-appdata.c
 libgs_plugin_appdata_la_LIBADD = $(GS_PLUGIN_LIBS)
 libgs_plugin_appdata_la_LDFLAGS = -module -avoid-version
diff --git a/src/plugins/appstream-markup.c b/src/plugins/appstream-markup.c
new file mode 100644
index 0000000..f3624f3
--- /dev/null
+++ b/src/plugins/appstream-markup.c
@@ -0,0 +1,202 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Richard Hughes <richard hughsie com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include "config.h"
+
+#include "appstream-common.h"
+#include "appstream-markup.h"
+
+struct AppstreamMarkup
+{
+       AppstreamMarkupMode      mode;
+       GString                 *string;
+       gboolean                 enabled;
+       gchar                   *lang;
+       guint                    locale_value;
+};
+
+/**
+ * appstream_markup_free:
+ */
+void
+appstream_markup_free (AppstreamMarkup *app)
+{
+       g_free (app->lang);
+       g_string_free (app->string, TRUE);
+       g_slice_free (AppstreamMarkup, app);
+}
+
+/**
+ * appstream_markup_new:
+ */
+AppstreamMarkup *
+appstream_markup_new (void)
+{
+       AppstreamMarkup *markup;
+       markup = g_slice_new0 (AppstreamMarkup);
+       markup->enabled = TRUE;
+       markup->locale_value = G_MAXUINT;
+       markup->string = g_string_new("");
+       return markup;
+}
+
+/**
+ * appstream_markup_process_locale:
+ */
+static gboolean
+appstream_markup_process_locale (AppstreamMarkup *markup)
+{
+       guint locale_value;
+
+       /* is this worse than the locale we're already showing */
+       locale_value = appstream_get_locale_value (markup->lang);
+       if (locale_value > markup->locale_value)
+               return FALSE;
+
+       /* is this better than the previous locale */
+       if (locale_value < markup->locale_value) {
+               g_debug ("Dumping existing string for locale %s!", markup->lang);
+               g_string_set_size (markup->string, 0);
+               markup->locale_value = locale_value;
+       }
+       return TRUE;
+}
+
+/**
+ * appstream_markup_set_mode:
+ */
+void
+appstream_markup_set_mode (AppstreamMarkup *markup, AppstreamMarkupMode mode)
+{
+       if (!markup->enabled)
+               return;
+
+       /* format markup in the same way as the distro pre-processor */
+       switch (mode) {
+       case APPSTREAM_MARKUP_MODE_P_START:
+               if (appstream_markup_process_locale (markup) &&
+                   markup->string->len > 0)
+                       g_string_append (markup->string, "\n");
+               markup->mode = APPSTREAM_MARKUP_MODE_P_CONTENT;
+               break;
+       case APPSTREAM_MARKUP_MODE_UL_START:
+               markup->mode = APPSTREAM_MARKUP_MODE_UL_CONTENT;
+               break;
+       case APPSTREAM_MARKUP_MODE_LI_START:
+               markup->mode = APPSTREAM_MARKUP_MODE_LI_CONTENT;
+               break;
+       case APPSTREAM_MARKUP_MODE_START:
+               markup->locale_value = G_MAXUINT;
+               g_string_truncate (markup->string, 0);
+               markup->mode = mode;
+               break;
+       case APPSTREAM_MARKUP_MODE_END:
+               /* remove trailing newline if not distro-formatted */
+               if (markup->mode != APPSTREAM_MARKUP_MODE_START) {
+                       g_string_truncate (markup->string,
+                                          markup->string->len - 1);
+               }
+               markup->mode = mode;
+               break;
+       default:
+               markup->mode = mode;
+               break;
+       }
+}
+
+/**
+ * appstream_markup_add_content:
+ */
+void
+appstream_markup_add_content (AppstreamMarkup *markup,
+                             const gchar *text,
+                             gssize length)
+{
+       gchar *tmp = NULL;
+
+       if (!markup->enabled)
+               return;
+
+       /* lang not good enough */
+       if (!appstream_markup_process_locale (markup))
+               return;
+
+       switch (markup->mode) {
+       case APPSTREAM_MARKUP_MODE_START:
+               /* this is for pre-formatted text */
+               tmp = appstream_xml_unmunge (text, length);
+               if (tmp == NULL)
+                       break;
+               g_string_append_printf (markup->string, "%s", tmp);
+               break;
+       case APPSTREAM_MARKUP_MODE_P_CONTENT:
+               tmp = appstream_xml_unmunge (text, length);
+               if (tmp == NULL)
+                       break;
+               g_string_append_printf (markup->string, "%s\n", tmp);
+               break;
+       case APPSTREAM_MARKUP_MODE_LI_CONTENT:
+               tmp = appstream_xml_unmunge (text, length);
+               if (tmp == NULL)
+                       break;
+               g_string_append_printf (markup->string, " • %s\n", tmp);
+               break;
+       default:
+               break;
+       }
+       g_free (tmp);
+}
+
+/**
+ * appstream_markup_set_lang:
+ */
+void
+appstream_markup_set_lang (AppstreamMarkup *markup, const gchar *lang)
+{
+       if (!markup->enabled)
+               return;
+       if (lang == NULL)
+               lang = "C";
+       if (g_strcmp0 (lang, markup->lang) == 0)
+               return;
+       g_free (markup->lang);
+       markup->lang = g_strdup (lang);
+}
+
+/**
+ * appstream_markup_get_text:
+ */
+const gchar *
+appstream_markup_get_text (AppstreamMarkup *markup)
+{
+       if (markup->string->len == 0)
+               return NULL;
+       return markup->string->str;
+}
+
+/**
+ * appstream_markup_set_enabled:
+ */
+void
+appstream_markup_set_enabled (AppstreamMarkup *markup, gboolean enabled)
+{
+       markup->enabled = enabled;
+}
diff --git a/src/plugins/appstream-markup.h b/src/plugins/appstream-markup.h
new file mode 100644
index 0000000..65e3973
--- /dev/null
+++ b/src/plugins/appstream-markup.h
@@ -0,0 +1,62 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
+ *
+ * Copyright (C) 2013 Richard Hughes <richard hughsie com>
+ *
+ * Licensed under the GNU General Public License Version 2
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#ifndef __APPSTREAM_MARKUP_H
+#define __APPSTREAM_MARKUP_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+       APPSTREAM_MARKUP_MODE_START,
+       APPSTREAM_MARKUP_MODE_END,
+       APPSTREAM_MARKUP_MODE_P_START,
+       APPSTREAM_MARKUP_MODE_P_CONTENT,
+       APPSTREAM_MARKUP_MODE_P_END,
+       APPSTREAM_MARKUP_MODE_UL_START,
+       APPSTREAM_MARKUP_MODE_UL_CONTENT,
+       APPSTREAM_MARKUP_MODE_UL_END,
+       APPSTREAM_MARKUP_MODE_LI_START,
+       APPSTREAM_MARKUP_MODE_LI_CONTENT,
+       APPSTREAM_MARKUP_MODE_LI_END,
+       APPSTREAM_MARKUP_MODE_LAST
+} AppstreamMarkupMode;
+
+typedef struct AppstreamMarkup AppstreamMarkup;
+
+AppstreamMarkup        *appstream_markup_new           (void);
+void            appstream_markup_free          (AppstreamMarkup        *markup);
+void            appstream_markup_set_enabled   (AppstreamMarkup        *markup,
+                                                gboolean                enabled);
+void            appstream_markup_set_mode      (AppstreamMarkup        *markup,
+                                                AppstreamMarkupMode     mode);
+void            appstream_markup_set_lang      (AppstreamMarkup        *markup,
+                                                const gchar            *lang);
+void            appstream_markup_add_content   (AppstreamMarkup        *markup,
+                                                const gchar            *text,
+                                                gssize                  length);
+const gchar    *appstream_markup_get_text      (AppstreamMarkup        *markup);
+
+G_END_DECLS
+
+#endif /* __APPSTREAM_MARKUP_H */
+
diff --git a/src/plugins/gs-plugin-appdata.c b/src/plugins/gs-plugin-appdata.c
index f6fa380..223fd49 100644
--- a/src/plugins/gs-plugin-appdata.c
+++ b/src/plugins/gs-plugin-appdata.c
@@ -24,6 +24,7 @@
 #include <gs-plugin.h>
 
 #include "appstream-common.h"
+#include "appstream-markup.h"
 
 struct GsPluginPrivate {
        gchar                   *cachedir;
@@ -118,89 +119,13 @@ out:
        return ret;
 }
 
-typedef enum {
-       APPSTREAM_DESCRIPTION_TAG_START,
-       APPSTREAM_DESCRIPTION_TAG_END,
-       APPSTREAM_DESCRIPTION_TAG_P_START,
-       APPSTREAM_DESCRIPTION_TAG_P_CONTENT,
-       APPSTREAM_DESCRIPTION_TAG_P_END,
-       APPSTREAM_DESCRIPTION_TAG_UL_START,
-       APPSTREAM_DESCRIPTION_TAG_UL_CONTENT,
-       APPSTREAM_DESCRIPTION_TAG_UL_END,
-       APPSTREAM_DESCRIPTION_TAG_LI_START,
-       APPSTREAM_DESCRIPTION_TAG_LI_CONTENT,
-       APPSTREAM_DESCRIPTION_TAG_LI_END,
-       APPSTREAM_DESCRIPTION_TAG_LAST
-} AppStreamDescriptionTag;
-
 typedef struct {
        AppstreamTag             tag;
        GsApp                   *app;
-       GString                 *string;
-       AppStreamDescriptionTag  description_tag;
-       gchar                   *lang;
-       guint                    locale_value;
+       AppstreamMarkup         *markup;
 } AppstreamCacheHelper;
 
 /**
- * appstream_description_build:
- */
-static void
-appstream_description_build (AppstreamCacheHelper *helper,
-                            AppStreamDescriptionTag tag,
-                            const gchar *text)
-{
-       guint locale_value;
-
-       /* we are not interested */
-       if (helper->string == NULL)
-               return;
-
-       /* is this worse than the locale we're already showing */
-       locale_value = appstream_get_locale_value (helper->lang);
-       if (locale_value > helper->locale_value)
-               return;
-
-       /* is this better than the previous locale */
-       if (locale_value < helper->locale_value) {
-               g_debug ("Dumping existing string for locale %s!", helper->lang);
-               g_string_set_size (helper->string, 0);
-               helper->locale_value = locale_value;
-       }
-
-
-       /* format markup in the same way as the distro pre-processor */
-       switch (tag) {
-       case APPSTREAM_DESCRIPTION_TAG_START:
-       case APPSTREAM_DESCRIPTION_TAG_P_END:
-       case APPSTREAM_DESCRIPTION_TAG_UL_START:
-       case APPSTREAM_DESCRIPTION_TAG_UL_CONTENT:
-       case APPSTREAM_DESCRIPTION_TAG_UL_END:
-       case APPSTREAM_DESCRIPTION_TAG_LI_START:
-       case APPSTREAM_DESCRIPTION_TAG_LI_END:
-               /* ignore */
-               break;
-       case APPSTREAM_DESCRIPTION_TAG_END:
-               /* remove trailing newline */
-               g_string_truncate (helper->string, helper->string->len - 1);
-               break;
-               break;
-       case APPSTREAM_DESCRIPTION_TAG_P_CONTENT:
-               g_string_append_printf (helper->string, "%s\n", text);
-               break;
-       case APPSTREAM_DESCRIPTION_TAG_LI_CONTENT:
-               g_string_append_printf (helper->string, " • %s\n", text);
-               break;
-       case APPSTREAM_DESCRIPTION_TAG_P_START:
-               if (helper->string->len > 0)
-                       g_string_append (helper->string, "\n");
-               break;
-       default:
-               break;
-       }
-}
-
-/**
  * appdata_parse_start_element_cb:
  */
 static void
@@ -212,42 +137,26 @@ appdata_parse_start_element_cb (GMarkupParseContext *context,
                                GError **error)
 {
        AppstreamCacheHelper *helper = (AppstreamCacheHelper *) user_data;
-       const gchar *lang_tmp = NULL;
        guint i;
 
        /* description markup */
        if (helper->tag == APPSTREAM_TAG_DESCRIPTION) {
-
-               /* save xml:lang if different to existing */
                for (i = 0; attribute_names[i] != NULL; i++) {
                        if (g_strcmp0 (attribute_names[i], "xml:lang") == 0) {
-                               lang_tmp = attribute_values[i];
+                               appstream_markup_set_lang (helper->markup,
+                                                          attribute_values[i]);
                                break;
                        }
                }
-               if (lang_tmp == NULL)
-                       lang_tmp = "C";
-               if (g_strcmp0 (lang_tmp, helper->lang) != 0) {
-                       g_free (helper->lang);
-                       helper->lang = g_strdup (lang_tmp);
-               }
-
-               /* build string */
                if (g_strcmp0 (element_name, "p") == 0) {
-                       appstream_description_build (helper,
-                                                    APPSTREAM_DESCRIPTION_TAG_P_START,
-                                                    NULL);
-                       helper->description_tag = APPSTREAM_DESCRIPTION_TAG_P_CONTENT;
+                       appstream_markup_set_mode (helper->markup,
+                                                  APPSTREAM_MARKUP_MODE_P_START);
                } else if (g_strcmp0 (element_name, "ul") == 0) {
-                       appstream_description_build (helper,
-                                                    APPSTREAM_DESCRIPTION_TAG_UL_START,
-                                                    NULL);
-                       helper->description_tag = APPSTREAM_DESCRIPTION_TAG_UL_CONTENT;
+                       appstream_markup_set_mode (helper->markup,
+                                                  APPSTREAM_MARKUP_MODE_UL_START);
                } else if (g_strcmp0 (element_name, "li") == 0) {
-                       appstream_description_build (helper,
-                                                    APPSTREAM_DESCRIPTION_TAG_LI_START,
-                                                    NULL);
-                       helper->description_tag = APPSTREAM_DESCRIPTION_TAG_LI_CONTENT;
+                       appstream_markup_set_mode (helper->markup,
+                                                  APPSTREAM_MARKUP_MODE_LI_START);
                }
                return;
        }
@@ -255,14 +164,12 @@ appdata_parse_start_element_cb (GMarkupParseContext *context,
        helper->tag = appstream_tag_from_string (element_name);
        switch (helper->tag) {
        case APPSTREAM_TAG_DESCRIPTION:
-               helper->string = NULL;
                /* only process the description if it's not already been set;
                 * doing all this string munging is moderately expensive */
-               if (gs_app_get_description (helper->app) == NULL)
-                       helper->string = g_string_new ("");
-               appstream_description_build (helper,
-                                            APPSTREAM_DESCRIPTION_TAG_START,
-                                            NULL);
+               appstream_markup_set_enabled (helper->markup,
+                                             gs_app_get_description (helper->app) == NULL);
+               appstream_markup_set_mode (helper->markup,
+                                          APPSTREAM_MARKUP_MODE_START);
                break;
        case APPSTREAM_TAG_UNKNOWN:
                g_warning ("AppData: tag %s unknown", element_name);
@@ -282,31 +189,24 @@ appdata_parse_end_element_cb (GMarkupParseContext *context,
                              gpointer user_data,
                              GError **error)
 {
+       const gchar *tmp;
        AppstreamCacheHelper *helper = (AppstreamCacheHelper *) user_data;
        if (helper->tag == APPSTREAM_TAG_DESCRIPTION) {
                if (g_strcmp0 (element_name, "p") == 0) {
-                       appstream_description_build (helper,
-                                                    APPSTREAM_DESCRIPTION_TAG_P_END,
-                                                    NULL);
+                       appstream_markup_set_mode (helper->markup,
+                                                  APPSTREAM_MARKUP_MODE_P_END);
                } else if (g_strcmp0 (element_name, "ul") == 0) {
-                       appstream_description_build (helper,
-                                                    APPSTREAM_DESCRIPTION_TAG_UL_END,
-                                                    NULL);
+                       appstream_markup_set_mode (helper->markup,
+                                                  APPSTREAM_MARKUP_MODE_UL_END);
                } else if (g_strcmp0 (element_name, "li") == 0) {
-                       appstream_description_build (helper,
-                                                    APPSTREAM_DESCRIPTION_TAG_LI_END,
-                                                    NULL);
+                       appstream_markup_set_mode (helper->markup,
+                                                  APPSTREAM_MARKUP_MODE_LI_END);
                } else if (g_strcmp0 (element_name, "description") == 0) {
-                       appstream_description_build (helper,
-                                                    APPSTREAM_DESCRIPTION_TAG_END,
-                                                    NULL);
-                       if (helper->string != NULL) {
-                               g_debug ("AppData: Setting description: %s",
-                                        helper->string->str);
-                               gs_app_set_description (helper->app,
-                                                       helper->string->str);
-                               g_string_free (helper->string, TRUE);
-                       }
+                       appstream_markup_set_mode (helper->markup,
+                                                  APPSTREAM_MARKUP_MODE_END);
+                       tmp = appstream_markup_get_text (helper->markup);
+                       if (tmp != NULL)
+                               gs_app_set_description (helper->app, tmp);
                        helper->tag = APPSTREAM_TAG_APPLICATION;
                }
        } else {
@@ -341,12 +241,7 @@ appdata_parse_text_cb (GMarkupParseContext *context,
                /* ignore */
                break;
        case APPSTREAM_TAG_DESCRIPTION:
-               tmp = appstream_xml_unmunge (text, text_len);
-               if (tmp == NULL)
-                       break;
-               appstream_description_build (helper,
-                                            helper->description_tag,
-                                            tmp);
+               appstream_markup_add_content (helper->markup, text, text_len);
                break;
        case APPSTREAM_TAG_SCREENSHOT:
                /* FIXME: actually add to API */
@@ -430,7 +325,7 @@ gs_plugin_refine_by_local_appdata (GsApp *app,
        /* parse file */
        helper = g_new0 (AppstreamCacheHelper, 1);
        helper->app = app;
-       helper->locale_value = G_MAXUINT;
+       helper->markup = appstream_markup_new ();
        ctx = g_markup_parse_context_new (&parser,
                                          G_MARKUP_PREFIX_ERROR_POSITION,
                                          helper,
@@ -442,7 +337,7 @@ out:
        if (ctx != NULL)
                g_markup_parse_context_free (ctx);
        if (helper != NULL)
-               g_free (helper->lang);
+               appstream_markup_free (helper->markup);
        g_free (helper);
        g_free (data);
        return ret;


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]