[glib] GAction: add function for printing detailed names



commit c04a063b781fa4a8c84ed067eaa31241fea18f86
Author: Ryan Lortie <desrt desrt ca>
Date:   Thu Jul 4 16:24:38 2013 -0400

    GAction: add function for printing detailed names
    
    A counterpart for parsing of detailed actions into (name, target) pairs,
    this new function prints them back.
    
    We also add a new function to check for validity of action names.  Only
    valid action names are allowed when printing.  Parsing accepts _some_
    invalid names for backwards compatibility.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=704157

 docs/reference/gio/gio-sections.txt |    2 +
 gio/gaction.c                       |  102 ++++++++++++++++++++++++++++++++---
 gio/gaction.h                       |    8 +++
 3 files changed, 105 insertions(+), 7 deletions(-)
---
diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt
index e18a05e..c85cfef 100644
--- a/docs/reference/gio/gio-sections.txt
+++ b/docs/reference/gio/gio-sections.txt
@@ -3107,6 +3107,7 @@ GAction
 GActionInterface
 
 <SUBSECTION>
+g_action_name_is_valid
 g_action_get_name
 g_action_get_parameter_type
 g_action_get_state_type
@@ -3122,6 +3123,7 @@ g_action_activate
 
 <SUBSECTION>
 g_action_parse_detailed_name
+g_action_print_detailed_name
 
 <SUBSECTION Standard>
 g_action_get_type
diff --git a/gio/gaction.c b/gio/gaction.c
index a3edec9..3c6a0e5 100644
--- a/gio/gaction.c
+++ b/gio/gaction.c
@@ -395,6 +395,37 @@ g_action_activate (GAction  *action,
 }
 
 /**
+ * g_action_name_is_valid:
+ * @action_name: an potential action name
+ *
+ * Checks if @action_name is valid.
+ *
+ * @action_name is valid if it consists only of alphanumeric characters,
+ * plus '-' and '.'.  The empty string is not a valid action name.
+ *
+ * It is an error to call this function with a non-utf8 @action_name.
+ * @action_name must not be %NULL.
+ *
+ * Returns: %TRUE if @action_name is valid
+ *
+ * Since: 2.38
+ **/
+gboolean
+g_action_name_is_valid (const gchar *action_name)
+{
+  gchar c;
+  gint i;
+
+  g_return_if_fail (action_name != NULL);
+
+  for (i = 0; (c = action_name[i]); i++)
+    if (!g_ascii_isalnum (c) && c != '.' && c != '-')
+      return FALSE;
+
+  return i > 0;
+}
+
+/**
  * g_action_parse_detailed_name:
  * @detailed_name: a detailed action name
  * @action_name: (out): the action name
@@ -410,16 +441,21 @@ g_action_activate (GAction  *action,
  * value and consists of just an action name containing no whitespace
  * nor the characters ':', '(' or ')'.  For example: "app.action".
  *
- * The second format is used to represent an action with a string-typed
- * target value.  The action name and target value are separated by a
- * double colon ("::").  For example: "app.action::target".
+ * The second format is used to represent an action with a target value
+ * that is a non-empty string consisting only of alphanumerics, plus '-'
+ * and '.'.  In that case, the action name and target value are
+ * separated by a double colon ("::").  For example:
+ * "app.action::target".
  *
- * The third format is used to represent an action with an
- * arbitrarily-typed target value.  The target value follows the action
+ * The third format is used to represent an action with any type of
+ * target value, including strings.  The target value follows the action
  * name, surrounded in parens.  For example: "app.action(42)".  The
  * target value is parsed using g_variant_parse().  If a tuple-typed
  * value is desired, it must be specified in the same way, resulting in
- * two sets of parens, for example: "app.action((1,2,3))".
+ * two sets of parens, for example: "app.action((1,2,3))".  A string
+ * target can be specified this way as well: "app.action('target')".
+ * For strings, this third format must be used if * target value is
+ * empty or contains characters other than alphanumerics, '-' and '.'.
  *
  * Returns: %TRUE if successful, else %FALSE with @error set
  *
@@ -435,7 +471,11 @@ g_action_parse_detailed_name (const gchar  *detailed_name,
   gsize target_len;
   gsize base_len;
 
-  /* We decide which format we have based on which we see first between
+  /* For historical (compatibility) reasons, this function accepts some
+   * cases of invalid action names as long as they don't interfere with
+   * the separation of the action from the target value.
+   *
+   * We decide which format we have based on which we see first between
    * '::' '(' and '\0'.
    */
 
@@ -491,3 +531,51 @@ bad_fmt:
 
   return FALSE;
 }
+
+/**
+ * g_action_print_detailed_name:
+ * @action_name: a valid action name
+ * @target_value: (allow-none): a #GVariant target value, or %NULL
+ *
+ * Formats a detailed action name from @action_name and @target_value.
+ *
+ * It is an error to call this function with an invalid action name.
+ *
+ * This function is the opposite of
+ * g_action_parse_detailed_action_name().  It will produce a string that
+ * can be parsed back to the @action_name and @target_value by that
+ * function.
+ *
+ * See that function for the types of strings that will be printed by
+ * this function.
+ *
+ * Returns: a detailed format string
+ *
+ * Since: 2.38
+ **/
+gchar *
+g_action_print_detailed_name (const gchar *action_name,
+                              GVariant    *target_value)
+{
+  g_return_if_fail (g_action_name_is_valid (action_name));
+
+  if (target_value == NULL)
+    return g_strdup (action_name);
+
+  if (g_variant_is_of_type (target_value, G_VARIANT_TYPE_STRING))
+    {
+      const gchar *str = g_variant_get_string (target_value, NULL);
+
+      if (g_action_name_is_valid (str))
+        return g_strconcat (action_name, "::", str, NULL);
+    }
+
+  {
+    GString *result = g_string_new (action_name);
+    g_string_append_c (result, '(');
+    g_variant_print_string (target_value, result, TRUE);
+    g_string_append_c (result, ')');
+
+    return g_string_free (result, FALSE);
+  }
+}
diff --git a/gio/gaction.h b/gio/gaction.h
index b153db6..f8e92ff 100644
--- a/gio/gaction.h
+++ b/gio/gaction.h
@@ -82,11 +82,19 @@ GLIB_AVAILABLE_IN_ALL
 void                    g_action_activate                               (GAction            *action,
                                                                          GVariant           *parameter);
 
+GLIB_AVAILABLE_IN_2_28
+gboolean                g_action_name_is_valid                          (const gchar        *action_name);
+
 GLIB_AVAILABLE_IN_2_38
 gboolean                g_action_parse_detailed_name                    (const gchar        *detailed_name,
                                                                          gchar             **action_name,
                                                                          GVariant          **target_value,
                                                                          GError            **error);
+
+GLIB_AVAILABLE_IN_2_38
+gchar *                 g_action_print_detailed_name                    (const gchar        *action_name,
+                                                                         GVariant           *parameter);
+
 G_END_DECLS
 
 #endif /* __G_ACTION_H__ */


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