changeset 1478:3cc98d5c6907

Improve editors through .desktop files implementation: - stricter Exec parameters detection - correct Icon key handling (absolute file vs name and --icon prefix) - improved escape, single, double quotes handling and escaping
author zas_
date Thu, 26 Mar 2009 21:49:20 +0000
parents 29aa897ea540
children d062522699dc
files src/editors.c
diffstat 1 files changed, 128 insertions(+), 28 deletions(-) [+]
line wrap: on
line diff
--- a/src/editors.c	Thu Mar 26 07:56:01 2009 +0000
+++ b/src/editors.c	Thu Mar 26 21:49:20 2009 +0000
@@ -144,6 +144,36 @@
 	return list;
 }
 
+static gboolean editor_accepts_parameters(EditorDescription *editor)
+{
+	const gchar *p = editor->exec;
+
+	if (!p) return FALSE;
+
+	while (*p)
+		{
+		if (*p == '%' && p[1])
+			{
+			switch (p[1])
+				{
+				case 'F':
+				case 'f':
+				case 'U':
+				case 'u':
+				case 'i':
+				case 'k':
+				case 'c':
+			    		return TRUE;
+				default:
+					break;
+				}
+			}
+		p++;
+		}
+	
+	return FALSE;
+}
+
 static gboolean editor_read_desktop_file(const gchar *path)
 {
 	GKeyFile *key_file;
@@ -256,12 +286,28 @@
 	
 	editor->name = g_key_file_get_locale_string(key_file, DESKTOP_GROUP, "Name", NULL, NULL);
 	editor->icon = g_key_file_get_string(key_file, DESKTOP_GROUP, "Icon", NULL);
+	
+	/* Icon key can be either a full path (absolute with file name extension) or an icon name (without extension) */
+	if (editor->icon && !g_path_is_absolute(editor->icon))
+		{
+		gchar *ext = strrchr(editor->icon, '.');
+		
+		if (ext && strlen(ext) == 4 && 
+		    (!strcmp(ext, ".png") || !strcmp(ext, ".xpm") || !strcmp(ext, ".svg")))
+			{
+			log_printf(_("Desktop file '%s' should not include extension in Icon key: '%s'\n"),
+				   editor->file, editor->icon);
+	  		
+			// drop extension
+			*ext = '\0';
+			}
+		}
 
 	editor->exec = g_key_file_get_string(key_file, DESKTOP_GROUP, "Exec", NULL);
 	
-	/* we take only editors that accept parameters, FIXME: the test can be improved */
-	if (!strchr(editor->exec, '%')) editor->hidden = TRUE; 
-	
+	/* we take only editors that accept parameters */
+	if (!editor_accepts_parameters(editor)) editor->hidden = TRUE;
+
 	editor->menu_path = g_key_file_get_string(key_file, DESKTOP_GROUP, "X-Geeqie-Menu-Path", NULL);
 	if (!editor->menu_path) editor->menu_path = g_strdup("EditMenu/ExternalMenu");
 	
@@ -628,18 +674,7 @@
 		}
 
 	g_assert(p);
-	while (*p != '\0')
-		{
-		/* must escape \, ", `, and $ to avoid problems,
-		 * we assume system shell supports bash-like escaping
-		 */
-		if (strchr("\\\"`$", *p) != NULL)
-			{
-			string = g_string_append_c(string, '\\');
-			}
-		string = g_string_append_c(string, *p);
-		p++;
-		}
+	string = g_string_append(string, p);
 
 	if (type == PATH_FILE_URL) g_string_prepend(string, "file://");
 	pathl = path_from_utf8(string->str);
@@ -654,12 +689,46 @@
 	return pathl;
 }
 
+static GString *append_quoted(GString *str, const char *s, gboolean single_quotes, gboolean double_quotes)
+{
+	const char *p;
+	
+	if (!single_quotes)
+		{
+		if (!double_quotes)
+			g_string_append_c(str, '\'');
+		else
+			g_string_append(str, "\"'");
+		}
+
+	for (p = s; *p != '\0'; p++)
+		{
+		if (*p == '\'')
+			g_string_append(str, "'\\''");
+		else
+			g_string_append_c(str, *p);
+		}
+	
+	if (!single_quotes)
+		{
+		if (!double_quotes)
+			g_string_append_c(str, '\'');
+		else
+			g_string_append(str, "'\"");
+		}
+
+	return str;
+}
+
 
 EditorFlags editor_command_parse(const EditorDescription *editor, GList *list, gchar **output)
 {
 	EditorFlags flags = 0;
 	const gchar *p;
 	GString *result = NULL;
+	gboolean escape = FALSE;
+	gboolean single_quotes = FALSE;
+	gboolean double_quotes = FALSE;
 
 	if (output)
 		result = g_string_new("");
@@ -678,11 +747,33 @@
 
 	while (*p)
 		{
-		if (*p != '%')
+		if (escape)
+			{
+			escape = FALSE;
+			if (output) result = g_string_append_c(result, *p);
+			}
+		else if (*p == '\\')
+			{
+			if (!single_quotes) escape = TRUE;
+			if (output) result = g_string_append_c(result, *p);
+			}
+		else if (*p == '\'')
 			{
 			if (output) result = g_string_append_c(result, *p);
+			if (!single_quotes && !double_quotes)
+				single_quotes = TRUE;
+			else if (single_quotes)
+				single_quotes = FALSE;
 			}
-		else /* *p == '%' */
+		else if (*p == '"')
+			{
+			if (output) result = g_string_append_c(result, *p);
+			if (!single_quotes && !double_quotes)
+				double_quotes = TRUE;
+			else if (double_quotes)
+				double_quotes = FALSE;
+			}
+		else if (*p == '%' && p[1])
 			{
 			gchar *pathl = NULL;
 
@@ -716,9 +807,7 @@
 							}
 						if (output)
 							{
-							result = g_string_append_c(result, '"');
-							result = g_string_append(result, pathl);
-							result = g_string_append_c(result, '"');
+							result = append_quoted(result, pathl, single_quotes, double_quotes);
 							}
 						g_free(pathl);
 						}
@@ -751,9 +840,7 @@
 									{
 									ok = TRUE;
 									if (work != list) g_string_append_c(result, ' ');
-									result = g_string_append_c(result, '"');
-									result = g_string_append(result, pathl);
-									result = g_string_append_c(result, '"');
+									result = append_quoted(result, pathl, single_quotes, double_quotes);
 									}
 								g_free(pathl);
 								}
@@ -767,21 +854,25 @@
 						}
 					break;
 				case 'i':
-					if (output)
+					if (editor->icon && *editor->icon)
 						{
-						result = g_string_append(result, editor->icon);
+						if (output)
+							{
+							result = g_string_append(result, "--icon ");
+							result = append_quoted(result, editor->icon, single_quotes, double_quotes);
+							}
 						}
 					break;
 				case 'c':
 					if (output)
 						{
-						result = g_string_append(result, editor->name);
+						result = append_quoted(result, editor->name, single_quotes, double_quotes);
 						}
 					break;
 				case 'k':
 					if (output)
 						{
-						result = g_string_append(result, editor->file);
+						result = append_quoted(result, editor->file, single_quotes, double_quotes);
 						}
 					break;
 				case '%':
@@ -801,10 +892,19 @@
 					goto err;
 				}
 			}
+		else
+			{
+			if (output) result = g_string_append_c(result, *p);
+			}
 		p++;
 		}
 
-	if (output) *output = g_string_free(result, FALSE);
+	if (output)
+		{
+		*output = g_string_free(result, FALSE);
+		DEBUG_3("Editor cmd: %s", *output);
+		}
+
 	return flags;