Re: Escaping in (#51382)



Tim Janik <timj gtk org> writes:

> > > >  * GScanner and hence RC files support C-string like
> > > >    escaping with \n \r \t \b \f and octal escapes.
> > > > 
> > > >    This would imply:
> > > > 
> > > >    "/_File/\\/var\\/log\\/messages"
> > > 
> > > we don't actually have an option here, the item factory
> > > dumps are supposed to be GScanner parsable, so we'll have
> > > to use this style.
> > 
> > OK, I'll do that then.
> 
> that's not much, i.e. it shouldn't be more than just:
 
> + name = g_strescape (string, NULL);
> + g_free (string);
> + string = name;
>   data->print_func (data->func_data, string);

Well, considering that g_strescape() mangles UTF-8 pretty
badly, I just wrote my own escaper in a few lines.

Complete patch to:

 - Allow / in GtkItemFactory
 - Escape \n and " when dumping accelerators
 - Fix problem with __ in item factory paths 

is attached. With all the typical ugliness of multiple levels
of escaping, of course.

Regards,
                                        Owen

Index: gtkitemfactory.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/gtkitemfactory.c,v
retrieving revision 1.33
diff -u -r1.33 gtkitemfactory.c
--- gtkitemfactory.c	2001/03/07 14:49:19	1.33
+++ gtkitemfactory.c	2001/03/18 00:44:46
@@ -723,6 +723,37 @@
   return gtk_object_get_data_by_id (GTK_OBJECT (widget), quark_item_path);
 }
 
+static gchar *
+item_factory_escape_path (const gchar *path)
+{
+  GString *str = g_string_new (NULL);
+
+  while (*path)
+    {
+      gchar c = *path;
+
+      switch (c)
+	{
+	case '\n':
+	  g_string_append (str, "\\n");
+	  break;
+	case '\r':
+	  g_string_append (str, "\\r");
+	  break;
+	case '"':
+	case '\\':
+	  g_string_append_c (str, '\\');
+	  /* Fall through */
+	default:
+	  g_string_append_c (str, c);
+	}
+      
+      path++;
+    }
+
+  return g_string_free (str, FALSE);
+}
+
 static void
 gtk_item_factory_foreach (gpointer hash_key,
 			  gpointer value,
@@ -731,6 +762,7 @@
   GtkItemFactoryItem *item;
   GtkIFDumpData *data;
   gchar *string;
+  gchar *path;
   gchar *name;
   gchar comment_prefix[2] = "\000\000";
 
@@ -742,14 +774,16 @@
 
   comment_prefix[0] = gtk_item_factory_class->cpair_comment_single[0];
 
+  path = item_factory_escape_path (hash_key);
   name = gtk_accelerator_name (item->accelerator_key, item->accelerator_mods);
   string = g_strconcat (item->modified ? "" : comment_prefix,
 			"(menu-path \"",
-			hash_key,
+			path,
 			"\" \"",
 			name,
 			"\")",
 			NULL);
+  g_free (path);
   g_free (name);
 
   data->print_func (data->func_data, string);
@@ -942,6 +976,60 @@
   return GTK_IS_ITEM (widget) ? widget : NULL;
 }
 
+static char *
+item_factory_find_separator_r (char *path)
+{
+  gchar *result = NULL;
+  gboolean escaped = FALSE;
+
+  while (*path)
+    {
+      if (escaped)
+	escaped = FALSE;
+      else
+	{
+	  if (*path == '\\')
+	    escaped = TRUE;
+	  else if (*path == '/')
+	    result = path;
+	}
+      
+      path++;
+    }
+
+  return result;
+}
+
+static char *
+item_factory_unescape_label (const char *label)
+{
+  char *new = g_malloc (strlen (label) + 1);
+  char *p = new;
+  gboolean escaped = FALSE;
+  
+  while (*label)
+    {
+      if (escaped)
+	{
+	  *p++ = *label;
+	  escaped = FALSE;
+	}
+      else
+	{
+	  if (*label == '\\')
+	    escaped = TRUE;
+	  else
+	    *p++ = *label;
+	}
+      
+      label++;
+    }
+
+  *p = '\0';
+
+  return new;
+}
+
 static gboolean
 gtk_item_factory_parse_path (GtkItemFactory *ifactory,
 			     gchar          *str,
@@ -951,14 +1039,21 @@
 {
   gchar *translation;
   gchar *p, *q;
-
+  
   *path = g_strdup (str);
 
-  /* FIXME: This does not handle __ correctly !!! */
   p = q = *path;
   while (*p)
     {
-      if (*p != '_')
+      if (*p == '_')
+	{
+	  if (p[1] == '_')
+	    {
+	      p++;
+	      *q++ = '_';
+	    }
+	}
+      else
 	{
 	  *q++ = *p;
 	}
@@ -967,7 +1062,7 @@
   *q = 0;
 
   *parent_path = g_strdup (*path);
-  p = strrchr (*parent_path, '/');
+  p = item_factory_find_separator_r (*parent_path);
   if (!p)
     {
       g_warning ("GtkItemFactory: invalid entry path `%s'", str);
@@ -980,13 +1075,13 @@
   else
     translation = str;
 			      
-  p = strrchr (translation, '/');
+  p = item_factory_find_separator_r (translation);
   if (p)
     p++;
   else
     p = translation;
 
-  *item = g_strdup (p);
+  *item = item_factory_unescape_label (p);
 
   return TRUE;
 }
@@ -1077,7 +1172,7 @@
       gchar *ppath, *p;
 
       ppath = g_strdup (entry->path);
-      p = strrchr (ppath, '/');
+      p = item_factory_find_separator_r (ppath);
       g_return_if_fail (p != NULL);
       *p = 0;
       pentry.path = ppath;
Index: testgtk.c
===================================================================
RCS file: /cvs/gnome/gtk+/gtk/testgtk.c,v
retrieving revision 1.228
diff -u -r1.228 testgtk.c
--- testgtk.c	2001/03/08 17:13:11	1.228
+++ testgtk.c	2001/03/18 00:44:46
@@ -2969,16 +2969,27 @@
   g_message ("ItemFactory: activated \"%s\"", gtk_item_factory_path_from_widget (widget));
 }
 
+static void
+dump_accels (gpointer             callback_data,
+	     guint                callback_action,
+	     GtkWidget           *widget)
+{
+  gtk_item_factory_dump_items (NULL, FALSE, gtk_item_factory_print_func, stdout);
+}
+    
 static GtkItemFactoryEntry menu_items[] =
 {
-  { "/_File",            NULL,         0,                     0, "<Branch>" },
-  { "/File/tearoff1",    NULL,         gtk_ifactory_cb,       0, "<Tearoff>" },
-  { "/File/_New",        "<control>N", gtk_ifactory_cb,       0 },
-  { "/File/_Open",       "<control>O", gtk_ifactory_cb,       0 },
-  { "/File/_Save",       "<control>S", gtk_ifactory_cb,       0 },
-  { "/File/Save _As...", NULL,         gtk_ifactory_cb,       0 },
-  { "/File/sep1",        NULL,         gtk_ifactory_cb,       0, "<Separator>" },
-  { "/File/_Quit",       "<control>Q", gtk_ifactory_cb,       0 },
+  { "/_File",                   NULL,         0,                     0, "<Branch>" },
+  { "/File/tearoff1",           NULL,         gtk_ifactory_cb,       0, "<Tearoff>" },
+  { "/File/_New",               "<control>N", gtk_ifactory_cb,       0 },
+  { "/File/_Open",              "<control>O", gtk_ifactory_cb,       0 },
+  { "/File/_Save",              "<control>S", gtk_ifactory_cb,       0 },
+  { "/File/Save _As...",        NULL,         gtk_ifactory_cb,       0 },
+  { "/File/_Dump \"_Accels\"",  NULL,         dump_accels,           0 },
+  { "/File/\\/Test__Escaping/And\\/\n\tWei\\\\rdly",
+                                NULL,         gtk_ifactory_cb,       0 },
+  { "/File/sep1",               NULL,         gtk_ifactory_cb,       0, "<Separator>" },
+  { "/File/_Quit",                "<control>Q", gtk_ifactory_cb,       0 },
 
   { "/_Preferences",     		NULL, 0,               0, "<Branch>" },
   { "/_Preferences/_Color", 		NULL, 0,               0, "<Branch>" },


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