diff options
author | Ray Strode <rstrode@redhat.com> | 2006-04-18 22:08:10 +0000 |
---|---|---|
committer | Ray Strode <rstrode@redhat.com> | 2006-04-18 22:08:10 +0000 |
commit | a41d9e0323054501356beccde6321268372eb237 (patch) | |
tree | b921186f5c3c753c31e7713ba38ef7af4aa9789c /src | |
parent | e0d6b8a0dd16fed932d287990b44261c5fe087eb (diff) |
Validate that desktop file categories match those specified in the spec.
2006-04-18 Ray Strode <rstrode@redhat.com>
Validate that desktop file categories match those
specified in the spec. Patch from Emmet Hikory
<emmet.hikory@gmail.com> and
Vincent Untz <vuntz@gnome.org> (bug 3337786)
* src/validate.c (validate_categories): new
function to ensure that categories are known.
2006-04-18 Vincent Untz <vuntz@gnome.org>
Use GKeyFile instead and kill egg-* usage (bug 319987).
* src/Makefile.am: remove egg-*
* src/update-desktop-database.c: (process_desktop_file): use GKeyFile
(get_default_search_path): use g_get_system_data_dirs()
2006-04-18 Vincent Untz <vuntz@gnome.org>
Port to GOption (bug 338575)
* configure.in: remove the check for popt, depend on glib >= 2.6.0
* src/install.c: (parse_options_callback): rewritten
(main): port to GOption
* src/update-desktop-database.c: (sync_database): remove warning
(main): port to GOption
Diffstat (limited to 'src')
-rw-r--r-- | src/Makefile.am | 7 | ||||
-rw-r--r-- | src/install.c | 396 | ||||
-rw-r--r-- | src/update-desktop-database.c | 82 | ||||
-rw-r--r-- | src/validate.c | 88 |
4 files changed, 313 insertions, 260 deletions
diff --git a/src/Makefile.am b/src/Makefile.am index 6904a9e..868bde7 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -24,12 +24,7 @@ desktop_file_install_SOURCES= \ install.c update_desktop_database_SOURCES = \ - update-desktop-database.c \ - eggdesktopentries.c \ - eggdesktopentries.h \ - eggintl.h \ - eggdirfuncs.c \ - eggdirfuncs.h + update-desktop-database.c desktop_file_validate_LDADD = $(DESKTOP_FILE_UTILS_LIBS) desktop_file_install_LDADD = $(DESKTOP_FILE_UTILS_LIBS) diff --git a/src/install.c b/src/install.c index 0cca410..ef9d7dd 100644 --- a/src/install.c +++ b/src/install.c @@ -2,12 +2,11 @@ #include <config.h> #include <glib.h> -#include <popt.h> +#include <glib/gi18n.h> #include "desktop_file.h" #include "validate.h" -#include <libintl.h> #include <stdlib.h> #include <string.h> #include <errno.h> @@ -15,9 +14,7 @@ #include <sys/stat.h> #include <locale.h> -#define _(x) gettext ((x)) -#define N_(x) x - +static const char** args = NULL; static gboolean delete_original = FALSE; static gboolean copy_generic_name_to_name = FALSE; static gboolean copy_name_to_generic_name = FALSE; @@ -250,288 +247,269 @@ process_one_file (const char *filename, gnome_desktop_file_free (df); } -static void parse_options_callback (poptContext ctx, - enum poptCallbackReason reason, - const struct poptOption *opt, - const char *arg, - void *data); - -enum { - OPTION_VENDOR = 1, - OPTION_DIR, - OPTION_ADD_CATEGORY, - OPTION_REMOVE_CATEGORY, - OPTION_ADD_ONLY_SHOW_IN, - OPTION_REMOVE_ONLY_SHOW_IN, - OPTION_DELETE_ORIGINAL, - OPTION_MODE, - OPTION_COPY_NAME_TO_GENERIC_NAME, - OPTION_COPY_GENERIC_NAME_TO_NAME, - OPTION_REMOVE_KEY, - OPTION_ADD_MIME_TYPE, - OPTION_REMOVE_MIME_TYPE, - OPTION_REBUILD_MIME_INFO_CACHE, - OPTION_LAST -}; +static gboolean parse_options_callback (const gchar *option_name, + const gchar *value, + gpointer data, + GError **error); -struct poptOption options[] = { - { - NULL, - '\0', - POPT_ARG_CALLBACK, - parse_options_callback, - 0, - NULL, - NULL - }, - { - NULL, - '\0', - POPT_ARG_INCLUDE_TABLE, - poptHelpOptions, - 0, - N_("Help options"), - NULL - }, + +static const GOptionEntry options[] = { { - "vendor", - '\0', - POPT_ARG_STRING, - NULL, +#define OPTION_VENDOR "vendor" OPTION_VENDOR, + '\0', + '\0', + G_OPTION_ARG_CALLBACK, + parse_options_callback, N_("Specify the vendor prefix to be applied to the desktop file. If the file already has this prefix, nothing happens."), NULL }, { - "dir", - '\0', - POPT_ARG_STRING, - NULL, +#define OPTION_DIR "dir" OPTION_DIR, + '\0', + '\0', + G_OPTION_ARG_CALLBACK, + parse_options_callback, N_("Specify the directory where files should be installed."), NULL }, { - "add-category", + "delete-original", '\0', - POPT_ARG_STRING, - NULL, - OPTION_ADD_CATEGORY, - N_("Specify a category to be added to the Categories field."), + '\0', + G_OPTION_ARG_NONE, + &delete_original, + N_("Delete the source desktop file, leaving only the target file. Effectively \"renames\" a desktop file."), NULL }, { - "remove-category", +#define OPTION_MODE "mode" + OPTION_MODE, + 'm', '\0', - POPT_ARG_STRING, - NULL, - OPTION_REMOVE_CATEGORY, - N_("Specify a category to be removed from the Categories field."), + G_OPTION_ARG_CALLBACK, + parse_options_callback, + N_("Set the given permissions on the destination file."), NULL }, { - "add-only-show-in", + "rebuild-mime-info-cache", + '\0', '\0', - POPT_ARG_STRING, + G_OPTION_ARG_NONE, + &rebuild_mime_info_cache, + N_("After installing desktop file rebuild the mime-types application database."), + NULL + }, + { G_OPTION_REMAINING, + 0, + 0, + G_OPTION_ARG_FILENAME_ARRAY, + &args, NULL, - OPTION_ADD_ONLY_SHOW_IN, - N_("Specify a product name to be added to the OnlyShowIn field."), + N_("[FILE...]") }, + { + NULL + } +}; + +static const GOptionEntry edit_options[] = { + { +#define OPTION_ADD_CATEGORY "add-category" + OPTION_ADD_CATEGORY, + '\0', + '\0', + G_OPTION_ARG_CALLBACK, + parse_options_callback, + N_("Specify a category to be added to the Categories field."), NULL }, { - "remove-only-show-in", +#define OPTION_REMOVE_CATEGORY "remove-category" + OPTION_REMOVE_CATEGORY, '\0', - POPT_ARG_STRING, - NULL, - OPTION_REMOVE_ONLY_SHOW_IN, - N_("Specify a product name to be removed from the OnlyShowIn field."), + '\0', + G_OPTION_ARG_CALLBACK, + parse_options_callback, + N_("Specify a category to be removed from the Categories field."), NULL }, { - "delete-original", +#define OPTION_ADD_ONLY_SHOW_IN "add-only-show-in" + OPTION_ADD_ONLY_SHOW_IN, '\0', - POPT_ARG_NONE, - &delete_original, - OPTION_DELETE_ORIGINAL, - N_("Delete the source desktop file, leaving only the target file. Effectively \"renames\" a desktop file."), + '\0', + G_OPTION_ARG_CALLBACK, + parse_options_callback, + N_("Specify a product name to be added to the OnlyShowIn field."), NULL }, { - "mode", - 'm', - POPT_ARG_STRING, - NULL, - OPTION_MODE, - N_("Set the given permissions on the destination file."), +#define OPTION_REMOVE_ONLY_SHOW_IN "remove-only-show-in" + OPTION_REMOVE_ONLY_SHOW_IN, + '\0', + '\0', + G_OPTION_ARG_CALLBACK, + parse_options_callback, + N_("Specify a product name to be removed from the OnlyShowIn field."), NULL }, { "copy-name-to-generic-name", '\0', - POPT_ARG_NONE, + '\0', + G_OPTION_ARG_NONE, ©_name_to_generic_name, - OPTION_COPY_NAME_TO_GENERIC_NAME, N_("Copy the contents of the \"Name\" field to the \"GenericName\" field."), NULL }, { "copy-generic-name-to-name", '\0', - POPT_ARG_NONE, + '\0', + G_OPTION_ARG_NONE, ©_generic_name_to_name, - OPTION_COPY_GENERIC_NAME_TO_NAME, N_("Copy the contents of the \"GenericName\" field to the \"Name\" field."), NULL }, { - "remove-key", - '\0', - POPT_ARG_STRING, - NULL, +#define OPTION_REMOVE_KEY "remove-key" OPTION_REMOVE_KEY, + '\0', + '\0', + G_OPTION_ARG_CALLBACK, + parse_options_callback, N_("Specify a field to be removed from the desktop file."), NULL }, { - "add-mime-type", - '\0', - POPT_ARG_STRING, - NULL, +#define OPTION_ADD_MIME_TYPE "add-mime-type" OPTION_ADD_MIME_TYPE, + '\0', + '\0', + G_OPTION_ARG_CALLBACK, + parse_options_callback, N_("Specify a mime-type to be added to the MimeType field."), NULL }, { - "remove-mime-type", - '\0', - POPT_ARG_STRING, - NULL, +#define OPTION_REMOVE_MIME_TYPE "remove-mime-type" OPTION_REMOVE_MIME_TYPE, - N_("Specify a mime-type to be removed from the MimeType field."), - NULL - }, - { - "rebuild-mime-info-cache", '\0', - POPT_ARG_NONE, - &rebuild_mime_info_cache, - OPTION_REBUILD_MIME_INFO_CACHE, - N_("After installing desktop file rebuild the mime-types application database."), + '\0', + G_OPTION_ARG_CALLBACK, + parse_options_callback, + N_("Specify a mime-type to be removed from the MimeType field."), NULL }, { - NULL, - '\0', - 0, - NULL, - 0, - NULL, NULL } }; -static void -parse_options_callback (poptContext ctx, - enum poptCallbackReason reason, - const struct poptOption *opt, - const char *arg, - void *data) +static gboolean +parse_options_callback (const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) { - const char *str; - - if (reason != POPT_CALLBACK_REASON_OPTION) - return; + /* skip "--" */ + option_name += 2; - switch (opt->val & POPT_ARG_MASK) + if (strcmp (OPTION_VENDOR, option_name) == 0) { - case OPTION_VENDOR: if (vendor_name) { - g_printerr (_("Can only specify --vendor once\n")); - exit (1); + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, + _("Can only specify --vendor once")); + return FALSE; } - str = poptGetOptArg (ctx); - vendor_name = g_strdup (str); - break; + vendor_name = g_strdup (value); + } - case OPTION_DIR: + else if (strcmp (OPTION_DIR, option_name) == 0) + { if (target_dir) { - g_printerr (_("Can only specify --dir once\n")); - exit (1); + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, + _("Can only specify --dir once")); + return FALSE; } - str = poptGetOptArg (ctx); - target_dir = g_strdup (str); - break; + target_dir = g_strdup (value); + } - case OPTION_ADD_CATEGORY: - str = poptGetOptArg (ctx); + else if (strcmp (OPTION_ADD_CATEGORY, option_name) == 0) + { added_categories = g_slist_prepend (added_categories, - g_strdup (str)); - break; + g_strdup (value)); + } - case OPTION_REMOVE_CATEGORY: - str = poptGetOptArg (ctx); + else if (strcmp (OPTION_REMOVE_CATEGORY, option_name) == 0) + { removed_categories = g_slist_prepend (removed_categories, - g_strdup (str)); - break; + g_strdup (value)); + } - case OPTION_ADD_ONLY_SHOW_IN: - str = poptGetOptArg (ctx); + else if (strcmp (OPTION_ADD_ONLY_SHOW_IN, option_name) == 0) + { added_only_show_in = g_slist_prepend (added_only_show_in, - g_strdup (str)); - break; + g_strdup (value)); + } - case OPTION_REMOVE_ONLY_SHOW_IN: - str = poptGetOptArg (ctx); + else if (strcmp (OPTION_REMOVE_ONLY_SHOW_IN, option_name) == 0) + { removed_only_show_in = g_slist_prepend (removed_only_show_in, - g_strdup (str)); - break; + g_strdup (value)); + } - case OPTION_MODE: - { - unsigned long ul; - char *end; - - str = poptGetOptArg (ctx); - - end = NULL; - ul = strtoul (str, &end, 8); - if (*str && end && *end == '\0') - permissions = ul; - else - { - g_printerr (_("Could not parse mode string \"%s\"\n"), - str); - - exit (1); - } - } - break; - - case OPTION_REMOVE_KEY: - str = poptGetOptArg (ctx); + else if (strcmp (OPTION_MODE, option_name) == 0) + { + unsigned long ul; + char *end; + + end = NULL; + ul = strtoul (value, &end, 8); + if (*value && end && *end == '\0') + permissions = ul; + else + { + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, + _("Could not parse mode string \"%s\""), value); + + return FALSE; + } + } + + else if (strcmp (OPTION_REMOVE_KEY, option_name) == 0) + { removed_keys = g_slist_prepend (removed_keys, - g_strdup (str)); - break; + g_strdup (value)); + } - case OPTION_ADD_MIME_TYPE: - str = poptGetOptArg (ctx); + else if (strcmp (OPTION_ADD_MIME_TYPE, option_name) == 0) + { added_mime_types = g_slist_prepend (added_mime_types, - g_strdup (str)); - break; + g_strdup (value)); + } - case OPTION_REMOVE_MIME_TYPE: - str = poptGetOptArg (ctx); + else if (strcmp (OPTION_REMOVE_MIME_TYPE, option_name) == 0) + { removed_mime_types = g_slist_prepend (removed_mime_types, - g_strdup (str)); - break; - - default: - break; + g_strdup (value)); + } + + else + { + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, + _("Unknown option \"%s\""), option_name); + + return FALSE; } + + return TRUE; } static void @@ -558,30 +536,30 @@ mkdir_and_parents (const char *dirname, int main (int argc, char **argv) { - poptContext ctx; - int nextopt; + GOptionContext *context; + GOptionGroup *group; GError* err = NULL; - const char** args; int i; mode_t dir_permissions; setlocale (LC_ALL, ""); - ctx = poptGetContext ("desktop-file-install", argc, (const char **) argv, options, 0); + context = g_option_context_new (""); + g_option_context_add_main_entries (context, options, NULL); - poptReadDefaultConfig (ctx, TRUE); + group = g_option_group_new ("edit", _("Edition options for desktop file"), _("Show desktop file edition options"), NULL, NULL); + g_option_group_add_entries (group, edit_options); + g_option_context_add_group (context, group); - while ((nextopt = poptGetNextOpt (ctx)) > 0) - /*nothing*/; + err = NULL; + g_option_context_parse (context, &argc, &argv, &err); - if (nextopt != -1) - { - g_printerr (_("Error on option %s: %s.\nRun '%s --help' to see a full list of available command line options.\n"), - poptBadOption (ctx, 0), - poptStrerror (nextopt), - argv[0]); - return 1; - } + if (err != NULL) { + g_printerr ("%s\n", err->message); + g_printerr (_("Run '%s --help' to see a full list of available command line options.\n"), argv[0]); + g_error_free (err); + return 1; + } if (vendor_name == NULL) vendor_name = g_strdup (g_getenv ("DESKTOP_FILE_VENDOR")); @@ -617,8 +595,6 @@ main (int argc, char **argv) mkdir_and_parents (target_dir, dir_permissions); - args = poptGetArgs (ctx); - i = 0; while (args && args[i]) { @@ -644,7 +620,7 @@ main (int argc, char **argv) return 1; } - poptFreeContext (ctx); - + g_option_context_free (context); + return 0; } diff --git a/src/update-desktop-database.c b/src/update-desktop-database.c index b7e7479..66c6034 100644 --- a/src/update-desktop-database.c +++ b/src/update-desktop-database.c @@ -24,17 +24,14 @@ #include <config.h> #include <errno.h> #include <fcntl.h> +#include <stdio.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h> #include <unistd.h> -#include <popt.h> #include <glib.h> - -#include "eggdesktopentries.h" -#include "eggdirfuncs.h" -#include "eggintl.h" +#include <glib/gi18n.h> #define NAME "update-desktop-database" #define CACHE_FILENAME "mimeinfo.cache" @@ -175,16 +172,15 @@ process_desktop_file (const char *desktop_file, GError **error) { GError *load_error; - EggDesktopEntries *entries; + GKeyFile *keyfile; char **mime_types; int i; + keyfile = g_key_file_new (); + load_error = NULL; - entries = - egg_desktop_entries_new_from_file (desktop_file, NULL, - EGG_DESKTOP_ENTRIES_DISCARD_COMMENTS | - EGG_DESKTOP_ENTRIES_DISCARD_TRANSLATIONS, - &load_error); + g_key_file_load_from_file (keyfile, desktop_file, + G_KEY_FILE_NONE, &load_error); if (load_error != NULL) { @@ -192,12 +188,11 @@ process_desktop_file (const char *desktop_file, return; } - mime_types = egg_desktop_entries_get_string_list (entries, - egg_desktop_entries_get_start_group (entries), - "MimeType", NULL, - &load_error); + mime_types = g_key_file_get_string_list (keyfile, + g_key_file_get_start_group (keyfile), + "MimeType", NULL, &load_error); - egg_desktop_entries_free (entries); + g_key_file_free (keyfile); if (load_error != NULL) { @@ -281,8 +276,8 @@ process_desktop_files (const char *desktop_dir, if (process_error != NULL) { if (!g_error_matches (process_error, - EGG_DESKTOP_ENTRIES_ERROR, - EGG_DESKTOP_ENTRIES_ERROR_KEY_NOT_FOUND)) + G_KEY_FILE_ERROR, + G_KEY_FILE_ERROR_KEY_NOT_FOUND)) { udd_print ("Could not parse file '%s': %s\n", full_path, process_error->message); @@ -377,6 +372,7 @@ sync_database (const char *dir, GError **error) char *temp_cache_file, *cache_file; FILE *tmp_file; + temp_cache_file = NULL; sync_error = NULL; tmp_file = open_temp_cache_file (dir, &temp_cache_file, &sync_error); @@ -434,13 +430,13 @@ static const char ** get_default_search_path (void) { static char **args = NULL; - char **data_dirs; + const char * const *data_dirs; int i; if (args != NULL) return (const char **) args; - data_dirs = egg_get_secondary_data_dirs (); + data_dirs = g_get_system_data_dirs (); for (i = 0; data_dirs[i] != NULL; i++); @@ -451,8 +447,6 @@ get_default_search_path (void) args[i] = NULL; - g_strfreev (data_dirs); - return (const char **) args; } @@ -478,37 +472,39 @@ main (int argc, char **argv) { GError *error; - poptContext popt_context; + GOptionContext *context; const char **desktop_dirs; int i; gboolean found_processable_dir; - struct poptOption options[] = + const GOptionEntry options[] = { - { "verbose", 'v', POPT_ARG_NONE, &verbose, 0, - N_("Display more information about processing and updating progress")}, + { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, + N_("Display more information about processing and updating progress"), + NULL}, - { "quiet", 'q', POPT_ARG_NONE, &quiet, 0, + { "quiet", 'q', 0, G_OPTION_ARG_NONE, &quiet, N_("Don't display any information about about processing and " - "updating progress")}, + "updating progress"), NULL}, - POPT_AUTOHELP - - { NULL, 0, 0, NULL, 0 } + { G_OPTION_REMAINING, 0, 0, G_OPTION_ARG_FILENAME_ARRAY, &desktop_dirs, + NULL, N_("[DIRECTORY...]") }, + { NULL } }; - popt_context = poptGetContext (NAME, argc, (const char **) argv, - options, 0); - while ((i = poptGetNextOpt (popt_context)) != -1) - { - if (i < -1) - { - poptPrintHelp (popt_context, stderr, 0); - return 1; - } - } + context = g_option_context_new (""); + g_option_context_add_main_entries (context, options, NULL); + + desktop_dirs = NULL; + error = NULL; + g_option_context_parse (context, &argc, &argv, &error); - desktop_dirs = poptGetArgs (popt_context); + if (error != NULL) { + g_printerr ("%s\n", error->message); + g_printerr (_("Run '%s --help' to see a full list of available command line options.\n"), argv[0]); + g_error_free (error); + return 1; + } if (desktop_dirs == NULL || desktop_dirs[0] == NULL) desktop_dirs = get_default_search_path (); @@ -532,7 +528,7 @@ main (int argc, else found_processable_dir = TRUE; } - poptFreeContext (popt_context); + g_option_context_free (context); if (!found_processable_dir) { diff --git a/src/validate.c b/src/validate.c index 46217a5..9317974 100644 --- a/src/validate.c +++ b/src/validate.c @@ -146,6 +146,92 @@ validate_strings (const char *value, const char *key, const char *locale, const } static void +validate_categories (const char *value, const char *key, const char *locale, const char *filename, GnomeDesktopFile *df) +{ + /* Category list from Desktop Menu Specification version 1.0-draft4 */ + const char *categories_keys[] = { + "Core", "Development", "Building", "Debugger", "IDE", "GUIDesigner", + "Profiling", "RevisionControl", "Translation", "Office", "Calendar", + "ContactManagement", "Database", "Dictionary", "Chart", "Email", + "Finance", "FlowChart", "PDA", "ProjectManagement", "Presentation", + "Spreadsheet", "WordProcessor", "Graphics", "2DGraphics", "VectorGraphics", + "RasterGraphics", "3DGraphics", "Scanning", "OCR", "Photography", + "Viewer", "Settings", "DesktopSettings", "HardwareSettings", + "PackageManager", "Network", "Dialup", "InstantMessaging", "IRCClient", + "FileTransfer", "HamRadio", "News", "P2P", "RemoteAccess", "Telephony", + "WebBrowser", "WebDevelopment", "AudioVideo", "Audio", "Midi", "Mixer", + "Sequencer", "Tuner", "Video", "TV", "AudioVideoEditing", "Player", + "Recorder", "DiscBurning", "Game", "ActionGame", "AdventureGame", + "ArcadeGame", "BoardGame", "BlocksGame", "CardGame", "KidsGame", + "LogicGame", "RolePlaying", "Simulation", "SportsGame", "StrategyGame", + "Education", "Art", "Construction", "Music", "Languages", "Science", + "Astronomy", "Biology", "Chemistry", "Geology", "Math", "MedicalSoftware", + "Physics", "Teaching", "Amusement", "Applet", "Archiving", "Electronics", + "Emulator", "Engineering", "FileManager", "Shell", "ScreenSaver", + "TeminalEmulator", "TrayIcon", "System", "Filesystem", "Monitor", + "Security", "Utility", "Accessibility", "Calculator", "Clock", + "TextEditor", "KDE", "GNOME", "GTK", "Qt", "Motif", "Java", + "ConsoleOnly", NULL + }; + char **vals; + int i; + + validate_strings (value, key, locale, filename, df); + + vals = g_strsplit (value, ";", G_MAXINT); + + i = 0; + while (vals[i]) + ++i; + + if (i == 0) + { + g_strfreev (vals); + return; + } + + /* Drop the empty string g_strsplit leaves in the vector since + * our list of strings ends in ";" + */ + --i; + g_free (vals[i]); + vals[i] = NULL; + + i = 0; + while (vals[i]) + { + int j = 0; + + while (categories_keys[j]) + { + if (g_ascii_strcasecmp (vals[i], categories_keys[j]) == 0) + { + if (strcmp (vals[i], categories_keys[j]) != 0) + { + print_fatal (filename, "%s values are case sensitive (should be \"%s\" instead of \"%s\")\n", + key, categories_keys[j], vals[i]); + } + break; + } + ++j; + } + + if (categories_keys[j] == NULL) + { + char *valid_categories; + + valid_categories = g_strjoinv ("\", \"", (gchar **) categories_keys); + print_fatal (filename, "%s values must be one of \"%s\" (found \"%s\")\n", + key, valid_categories, vals[i]); + g_free (valid_categories); + } + ++i; + } + + g_strfreev (vals); +} + +static void validate_only_show_in (const char *value, const char *key, const char *locale, const char *filename, GnomeDesktopFile *df) { const char *onlyshowin_keys[] = { @@ -374,7 +460,7 @@ struct { { "UnmountIcon", validate_string }, { "SortOrder", validate_strings /* FIXME: Also comma-separated */}, { "URL", validate_string }, - { "Categories", validate_strings }, /* FIXME: should check that each category is known */ + { "Categories", validate_categories }, { "OnlyShowIn", validate_only_show_in }, { "NotShowIn", validate_only_show_in }, { "StartupNotify", validate_boolean }, |