Mercurial > geeqie
comparison src/editors.c @ 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 | e9f9d3da3f43 |
children | d062522699dc |
comparison
equal
deleted
inserted
replaced
1477:29aa897ea540 | 1478:3cc98d5c6907 |
---|---|
142 list = g_list_concat(list, filter_to_list(conv_table[j][1])); | 142 list = g_list_concat(list, filter_to_list(conv_table[j][1])); |
143 | 143 |
144 return list; | 144 return list; |
145 } | 145 } |
146 | 146 |
147 static gboolean editor_accepts_parameters(EditorDescription *editor) | |
148 { | |
149 const gchar *p = editor->exec; | |
150 | |
151 if (!p) return FALSE; | |
152 | |
153 while (*p) | |
154 { | |
155 if (*p == '%' && p[1]) | |
156 { | |
157 switch (p[1]) | |
158 { | |
159 case 'F': | |
160 case 'f': | |
161 case 'U': | |
162 case 'u': | |
163 case 'i': | |
164 case 'k': | |
165 case 'c': | |
166 return TRUE; | |
167 default: | |
168 break; | |
169 } | |
170 } | |
171 p++; | |
172 } | |
173 | |
174 return FALSE; | |
175 } | |
176 | |
147 static gboolean editor_read_desktop_file(const gchar *path) | 177 static gboolean editor_read_desktop_file(const gchar *path) |
148 { | 178 { |
149 GKeyFile *key_file; | 179 GKeyFile *key_file; |
150 EditorDescription *editor; | 180 EditorDescription *editor; |
151 gchar *extensions; | 181 gchar *extensions; |
254 return TRUE; | 284 return TRUE; |
255 } | 285 } |
256 | 286 |
257 editor->name = g_key_file_get_locale_string(key_file, DESKTOP_GROUP, "Name", NULL, NULL); | 287 editor->name = g_key_file_get_locale_string(key_file, DESKTOP_GROUP, "Name", NULL, NULL); |
258 editor->icon = g_key_file_get_string(key_file, DESKTOP_GROUP, "Icon", NULL); | 288 editor->icon = g_key_file_get_string(key_file, DESKTOP_GROUP, "Icon", NULL); |
289 | |
290 /* Icon key can be either a full path (absolute with file name extension) or an icon name (without extension) */ | |
291 if (editor->icon && !g_path_is_absolute(editor->icon)) | |
292 { | |
293 gchar *ext = strrchr(editor->icon, '.'); | |
294 | |
295 if (ext && strlen(ext) == 4 && | |
296 (!strcmp(ext, ".png") || !strcmp(ext, ".xpm") || !strcmp(ext, ".svg"))) | |
297 { | |
298 log_printf(_("Desktop file '%s' should not include extension in Icon key: '%s'\n"), | |
299 editor->file, editor->icon); | |
300 | |
301 // drop extension | |
302 *ext = '\0'; | |
303 } | |
304 } | |
259 | 305 |
260 editor->exec = g_key_file_get_string(key_file, DESKTOP_GROUP, "Exec", NULL); | 306 editor->exec = g_key_file_get_string(key_file, DESKTOP_GROUP, "Exec", NULL); |
261 | 307 |
262 /* we take only editors that accept parameters, FIXME: the test can be improved */ | 308 /* we take only editors that accept parameters */ |
263 if (!strchr(editor->exec, '%')) editor->hidden = TRUE; | 309 if (!editor_accepts_parameters(editor)) editor->hidden = TRUE; |
264 | 310 |
265 editor->menu_path = g_key_file_get_string(key_file, DESKTOP_GROUP, "X-Geeqie-Menu-Path", NULL); | 311 editor->menu_path = g_key_file_get_string(key_file, DESKTOP_GROUP, "X-Geeqie-Menu-Path", NULL); |
266 if (!editor->menu_path) editor->menu_path = g_strdup("EditMenu/ExternalMenu"); | 312 if (!editor->menu_path) editor->menu_path = g_strdup("EditMenu/ExternalMenu"); |
267 | 313 |
268 editor->hotkey = g_key_file_get_string(key_file, DESKTOP_GROUP, "X-Geeqie-Hotkey", NULL); | 314 editor->hotkey = g_key_file_get_string(key_file, DESKTOP_GROUP, "X-Geeqie-Hotkey", NULL); |
269 | 315 |
626 else | 672 else |
627 p = ""; | 673 p = ""; |
628 } | 674 } |
629 | 675 |
630 g_assert(p); | 676 g_assert(p); |
631 while (*p != '\0') | 677 string = g_string_append(string, p); |
632 { | |
633 /* must escape \, ", `, and $ to avoid problems, | |
634 * we assume system shell supports bash-like escaping | |
635 */ | |
636 if (strchr("\\\"`$", *p) != NULL) | |
637 { | |
638 string = g_string_append_c(string, '\\'); | |
639 } | |
640 string = g_string_append_c(string, *p); | |
641 p++; | |
642 } | |
643 | 678 |
644 if (type == PATH_FILE_URL) g_string_prepend(string, "file://"); | 679 if (type == PATH_FILE_URL) g_string_prepend(string, "file://"); |
645 pathl = path_from_utf8(string->str); | 680 pathl = path_from_utf8(string->str); |
646 g_string_free(string, TRUE); | 681 g_string_free(string, TRUE); |
647 | 682 |
652 } | 687 } |
653 | 688 |
654 return pathl; | 689 return pathl; |
655 } | 690 } |
656 | 691 |
692 static GString *append_quoted(GString *str, const char *s, gboolean single_quotes, gboolean double_quotes) | |
693 { | |
694 const char *p; | |
695 | |
696 if (!single_quotes) | |
697 { | |
698 if (!double_quotes) | |
699 g_string_append_c(str, '\''); | |
700 else | |
701 g_string_append(str, "\"'"); | |
702 } | |
703 | |
704 for (p = s; *p != '\0'; p++) | |
705 { | |
706 if (*p == '\'') | |
707 g_string_append(str, "'\\''"); | |
708 else | |
709 g_string_append_c(str, *p); | |
710 } | |
711 | |
712 if (!single_quotes) | |
713 { | |
714 if (!double_quotes) | |
715 g_string_append_c(str, '\''); | |
716 else | |
717 g_string_append(str, "'\""); | |
718 } | |
719 | |
720 return str; | |
721 } | |
722 | |
657 | 723 |
658 EditorFlags editor_command_parse(const EditorDescription *editor, GList *list, gchar **output) | 724 EditorFlags editor_command_parse(const EditorDescription *editor, GList *list, gchar **output) |
659 { | 725 { |
660 EditorFlags flags = 0; | 726 EditorFlags flags = 0; |
661 const gchar *p; | 727 const gchar *p; |
662 GString *result = NULL; | 728 GString *result = NULL; |
729 gboolean escape = FALSE; | |
730 gboolean single_quotes = FALSE; | |
731 gboolean double_quotes = FALSE; | |
663 | 732 |
664 if (output) | 733 if (output) |
665 result = g_string_new(""); | 734 result = g_string_new(""); |
666 | 735 |
667 if (editor->exec[0] == '\0') | 736 if (editor->exec[0] == '\0') |
676 | 745 |
677 /* command */ | 746 /* command */ |
678 | 747 |
679 while (*p) | 748 while (*p) |
680 { | 749 { |
681 if (*p != '%') | 750 if (escape) |
682 { | 751 { |
752 escape = FALSE; | |
683 if (output) result = g_string_append_c(result, *p); | 753 if (output) result = g_string_append_c(result, *p); |
684 } | 754 } |
685 else /* *p == '%' */ | 755 else if (*p == '\\') |
756 { | |
757 if (!single_quotes) escape = TRUE; | |
758 if (output) result = g_string_append_c(result, *p); | |
759 } | |
760 else if (*p == '\'') | |
761 { | |
762 if (output) result = g_string_append_c(result, *p); | |
763 if (!single_quotes && !double_quotes) | |
764 single_quotes = TRUE; | |
765 else if (single_quotes) | |
766 single_quotes = FALSE; | |
767 } | |
768 else if (*p == '"') | |
769 { | |
770 if (output) result = g_string_append_c(result, *p); | |
771 if (!single_quotes && !double_quotes) | |
772 double_quotes = TRUE; | |
773 else if (double_quotes) | |
774 double_quotes = FALSE; | |
775 } | |
776 else if (*p == '%' && p[1]) | |
686 { | 777 { |
687 gchar *pathl = NULL; | 778 gchar *pathl = NULL; |
688 | 779 |
689 p++; | 780 p++; |
690 | 781 |
714 flags |= EDITOR_ERROR_NO_FILE; | 805 flags |= EDITOR_ERROR_NO_FILE; |
715 goto err; | 806 goto err; |
716 } | 807 } |
717 if (output) | 808 if (output) |
718 { | 809 { |
719 result = g_string_append_c(result, '"'); | 810 result = append_quoted(result, pathl, single_quotes, double_quotes); |
720 result = g_string_append(result, pathl); | |
721 result = g_string_append_c(result, '"'); | |
722 } | 811 } |
723 g_free(pathl); | 812 g_free(pathl); |
724 } | 813 } |
725 break; | 814 break; |
726 | 815 |
749 | 838 |
750 if (output) | 839 if (output) |
751 { | 840 { |
752 ok = TRUE; | 841 ok = TRUE; |
753 if (work != list) g_string_append_c(result, ' '); | 842 if (work != list) g_string_append_c(result, ' '); |
754 result = g_string_append_c(result, '"'); | 843 result = append_quoted(result, pathl, single_quotes, double_quotes); |
755 result = g_string_append(result, pathl); | |
756 result = g_string_append_c(result, '"'); | |
757 } | 844 } |
758 g_free(pathl); | 845 g_free(pathl); |
759 } | 846 } |
760 work = work->next; | 847 work = work->next; |
761 } | 848 } |
765 goto err; | 852 goto err; |
766 } | 853 } |
767 } | 854 } |
768 break; | 855 break; |
769 case 'i': | 856 case 'i': |
770 if (output) | 857 if (editor->icon && *editor->icon) |
771 { | 858 { |
772 result = g_string_append(result, editor->icon); | 859 if (output) |
860 { | |
861 result = g_string_append(result, "--icon "); | |
862 result = append_quoted(result, editor->icon, single_quotes, double_quotes); | |
863 } | |
773 } | 864 } |
774 break; | 865 break; |
775 case 'c': | 866 case 'c': |
776 if (output) | 867 if (output) |
777 { | 868 { |
778 result = g_string_append(result, editor->name); | 869 result = append_quoted(result, editor->name, single_quotes, double_quotes); |
779 } | 870 } |
780 break; | 871 break; |
781 case 'k': | 872 case 'k': |
782 if (output) | 873 if (output) |
783 { | 874 { |
784 result = g_string_append(result, editor->file); | 875 result = append_quoted(result, editor->file, single_quotes, double_quotes); |
785 } | 876 } |
786 break; | 877 break; |
787 case '%': | 878 case '%': |
788 /* %% = % escaping */ | 879 /* %% = % escaping */ |
789 if (output) result = g_string_append_c(result, *p); | 880 if (output) result = g_string_append_c(result, *p); |
799 default: | 890 default: |
800 flags |= EDITOR_ERROR_SYNTAX; | 891 flags |= EDITOR_ERROR_SYNTAX; |
801 goto err; | 892 goto err; |
802 } | 893 } |
803 } | 894 } |
895 else | |
896 { | |
897 if (output) result = g_string_append_c(result, *p); | |
898 } | |
804 p++; | 899 p++; |
805 } | 900 } |
806 | 901 |
807 if (output) *output = g_string_free(result, FALSE); | 902 if (output) |
903 { | |
904 *output = g_string_free(result, FALSE); | |
905 DEBUG_3("Editor cmd: %s", *output); | |
906 } | |
907 | |
808 return flags; | 908 return flags; |
809 | 909 |
810 | 910 |
811 err: | 911 err: |
812 if (output) | 912 if (output) |