/* GIMP - The GNU Image Manipulation Program * Copyright (C) 1995-2003 Spencer Kimball and Peter Mattis * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "config.h" #include #include #include #include #include "libgimpbase/gimpbase.h" #include "pdb-types.h" #include "core/gimpparamspecs-desc.h" #include "gimppdb.h" #include "gimppdb-query.h" #include "gimppdberror.h" #include "gimp-pdb-compat.h" #include "gimpprocedure.h" #include "gimp-intl.h" #define PDB_REGEX_FLAGS (G_REGEX_CASELESS | G_REGEX_OPTIMIZE) #define COMPAT_BLURB "This procedure is deprecated! Use '%s' instead." typedef struct _PDBDump PDBDump; struct _PDBDump { GimpPDB *pdb; GOutputStream *output; GError *error; gboolean dumping_compat; }; typedef struct _PDBQuery PDBQuery; struct _PDBQuery { GimpPDB *pdb; GRegex *name_regex; GRegex *blurb_regex; GRegex *help_regex; GRegex *author_regex; GRegex *copyright_regex; GRegex *date_regex; GRegex *proc_type_regex; gchar **list_of_procs; gint num_procs; gboolean querying_compat; }; typedef struct _PDBStrings PDBStrings; struct _PDBStrings { gboolean compat; gchar *blurb; gchar *help; gchar *author; gchar *copyright; gchar *date; }; /* local function prototypes */ static void gimp_pdb_query_entry (gpointer key, gpointer value, gpointer user_data); static void gimp_pdb_print_entry (gpointer key, gpointer value, gpointer user_data); static void gimp_pdb_get_strings (PDBStrings *strings, GimpProcedure *procedure, gboolean compat); static void gimp_pdb_free_strings (PDBStrings *strings); /* public functions */ gboolean gimp_pdb_dump (GimpPDB *pdb, GFile *file, GError **error) { PDBDump pdb_dump = { 0, }; g_return_val_if_fail (GIMP_IS_PDB (pdb), FALSE); g_return_val_if_fail (G_IS_FILE (file), FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); pdb_dump.pdb = pdb; pdb_dump.output = G_OUTPUT_STREAM (g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, error)); if (! pdb_dump.output) return FALSE; pdb_dump.dumping_compat = FALSE; g_hash_table_foreach (pdb->procedures, gimp_pdb_print_entry, &pdb_dump); pdb_dump.dumping_compat = TRUE; g_hash_table_foreach (pdb->compat_proc_names, gimp_pdb_print_entry, &pdb_dump); if (pdb_dump.error) { GCancellable *cancellable = g_cancellable_new (); g_set_error (error, pdb_dump.error->domain, pdb_dump.error->code, _("Writing PDB file '%s' failed: %s"), gimp_file_get_utf8_name (file), pdb_dump.error->message); g_clear_error (&pdb_dump.error); /* Cancel the overwrite initiated by g_file_replace(). */ g_cancellable_cancel (cancellable); g_output_stream_close (pdb_dump.output, cancellable, NULL); g_object_unref (cancellable); g_object_unref (pdb_dump.output); return FALSE; } g_object_unref (pdb_dump.output); return TRUE; } gboolean gimp_pdb_query (GimpPDB *pdb, const gchar *name, const gchar *blurb, const gchar *help, const gchar *author, const gchar *copyright, const gchar *date, const gchar *proc_type, gint *num_procs, gchar ***procs, GError **error) { PDBQuery pdb_query = { 0, }; gboolean success = FALSE; g_return_val_if_fail (GIMP_IS_PDB (pdb), FALSE); g_return_val_if_fail (name != NULL, FALSE); g_return_val_if_fail (blurb != NULL, FALSE); g_return_val_if_fail (help != NULL, FALSE); g_return_val_if_fail (author != NULL, FALSE); g_return_val_if_fail (copyright != NULL, FALSE); g_return_val_if_fail (date != NULL, FALSE); g_return_val_if_fail (proc_type != NULL, FALSE); g_return_val_if_fail (num_procs != NULL, FALSE); g_return_val_if_fail (procs != NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); *num_procs = 0; *procs = NULL; pdb_query.name_regex = g_regex_new (name, PDB_REGEX_FLAGS, 0, error); if (! pdb_query.name_regex) goto cleanup; pdb_query.blurb_regex = g_regex_new (blurb, PDB_REGEX_FLAGS, 0, error); if (! pdb_query.blurb_regex) goto cleanup; pdb_query.help_regex = g_regex_new (help, PDB_REGEX_FLAGS, 0, error); if (! pdb_query.help_regex) goto cleanup; pdb_query.author_regex = g_regex_new (author, PDB_REGEX_FLAGS, 0, error); if (! pdb_query.author_regex) goto cleanup; pdb_query.copyright_regex = g_regex_new (copyright, PDB_REGEX_FLAGS, 0, error); if (! pdb_query.copyright_regex) goto cleanup; pdb_query.date_regex = g_regex_new (date, PDB_REGEX_FLAGS, 0, error); if (! pdb_query.date_regex) goto cleanup; pdb_query.proc_type_regex = g_regex_new (proc_type, PDB_REGEX_FLAGS, 0, error); if (! pdb_query.proc_type_regex) goto cleanup; success = TRUE; pdb_query.pdb = pdb; pdb_query.list_of_procs = NULL; pdb_query.num_procs = 0; pdb_query.querying_compat = FALSE; g_hash_table_foreach (pdb->procedures, gimp_pdb_query_entry, &pdb_query); pdb_query.querying_compat = TRUE; g_hash_table_foreach (pdb->compat_proc_names, gimp_pdb_query_entry, &pdb_query); cleanup: if (pdb_query.proc_type_regex) g_regex_unref (pdb_query.proc_type_regex); if (pdb_query.date_regex) g_regex_unref (pdb_query.date_regex); if (pdb_query.copyright_regex) g_regex_unref (pdb_query.copyright_regex); if (pdb_query.author_regex) g_regex_unref (pdb_query.author_regex); if (pdb_query.help_regex) g_regex_unref (pdb_query.help_regex); if (pdb_query.blurb_regex) g_regex_unref (pdb_query.blurb_regex); if (pdb_query.name_regex) g_regex_unref (pdb_query.name_regex); if (success) { *num_procs = pdb_query.num_procs; *procs = pdb_query.list_of_procs; } return success; } gboolean gimp_pdb_proc_info (GimpPDB *pdb, const gchar *proc_name, gchar **blurb, gchar **help, gchar **author, gchar **copyright, gchar **date, GimpPDBProcType *proc_type, gint *num_args, gint *num_values, GError **error) { GimpProcedure *procedure; PDBStrings strings; g_return_val_if_fail (GIMP_IS_PDB (pdb), FALSE); g_return_val_if_fail (proc_name != NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); procedure = gimp_pdb_lookup_procedure (pdb, proc_name); if (procedure) { gimp_pdb_get_strings (&strings, procedure, FALSE); } else { const gchar *compat_name; compat_name = gimp_pdb_lookup_compat_proc_name (pdb, proc_name); if (compat_name) { procedure = gimp_pdb_lookup_procedure (pdb, compat_name); if (procedure) gimp_pdb_get_strings (&strings, procedure, TRUE); } } if (procedure) { *blurb = strings.compat ? strings.blurb : g_strdup (strings.blurb); *help = strings.compat ? strings.help : g_strdup (strings.help); *author = strings.compat ? strings.author : g_strdup (strings.author); *copyright = strings.compat ? strings.copyright : g_strdup (strings.copyright); *date = strings.compat ? strings.date : g_strdup (strings.date); *proc_type = procedure->proc_type; *num_args = procedure->num_args; *num_values = procedure->num_values; return TRUE; } g_set_error (error, GIMP_PDB_ERROR, GIMP_PDB_ERROR_PROCEDURE_NOT_FOUND, _("Procedure '%s' not found"), proc_name); return FALSE; } /* private functions */ static gboolean match_string (GRegex *regex, const gchar *string) { if (! string) string = ""; return g_regex_match (regex, string, 0, NULL); } static void gimp_pdb_query_entry (gpointer key, gpointer value, gpointer user_data) { PDBQuery *pdb_query = user_data; GList *list; GimpProcedure *procedure; const gchar *proc_name; PDBStrings strings; GEnumClass *enum_class; GimpEnumDesc *type_desc; proc_name = key; if (pdb_query->querying_compat) list = g_hash_table_lookup (pdb_query->pdb->procedures, value); else list = value; if (! list) return; procedure = list->data; gimp_pdb_get_strings (&strings, procedure, pdb_query->querying_compat); enum_class = g_type_class_ref (GIMP_TYPE_PDB_PROC_TYPE); type_desc = gimp_enum_get_desc (enum_class, procedure->proc_type); g_type_class_unref (enum_class); if (match_string (pdb_query->name_regex, proc_name) && match_string (pdb_query->blurb_regex, strings.blurb) && match_string (pdb_query->help_regex, strings.help) && match_string (pdb_query->author_regex, strings.author) && match_string (pdb_query->copyright_regex, strings.copyright) && match_string (pdb_query->date_regex, strings.date) && match_string (pdb_query->proc_type_regex, type_desc->value_desc)) { pdb_query->num_procs++; pdb_query->list_of_procs = g_renew (gchar *, pdb_query->list_of_procs, pdb_query->num_procs); pdb_query->list_of_procs[pdb_query->num_procs - 1] = g_strdup (proc_name); } gimp_pdb_free_strings (&strings); } /* #define DEBUG_OUTPUT 1 */ static void output_string (GString *dest, const gchar *string) { #ifndef DEBUG_OUTPUT g_string_append_printf (dest, "\""); #endif if (string) while (*string) { switch (*string) { case '\\' : g_string_append_printf (dest, "\\\\"); break; case '\"' : g_string_append_printf (dest, "\\\""); break; case '{' : g_string_append_printf (dest, "@{"); break; case '@' : g_string_append_printf (dest, "@@"); break; case '}' : g_string_append_printf (dest, "@}"); break; default: g_string_append_printf (dest, "%c", *string); } string++; } #ifndef DEBUG_OUTPUT g_string_append_printf (dest, "\"\n"); #endif } static void gimp_pdb_print_entry (gpointer key, gpointer value, gpointer user_data) { PDBDump *pdb_dump = user_data; GOutputStream *output = pdb_dump->output; const gchar *proc_name; GList *list; GEnumClass *arg_class; GEnumClass *proc_class; GString *buf; GString *string; gint num = 0; if (pdb_dump->error) return; proc_name = key; if (pdb_dump->dumping_compat) list = g_hash_table_lookup (pdb_dump->pdb->procedures, value); else list = value; arg_class = g_type_class_ref (GIMP_TYPE_PDB_ARG_TYPE); proc_class = g_type_class_ref (GIMP_TYPE_PDB_PROC_TYPE); buf = g_string_new (NULL); string = g_string_new (NULL); for (; list; list = list->next) { GimpProcedure *procedure = list->data; PDBStrings strings; GEnumValue *arg_value; GimpEnumDesc *type_desc; gint i; num++; gimp_pdb_get_strings (&strings, procedure, pdb_dump->dumping_compat); #ifdef DEBUG_OUTPUT g_string_append_printf (string, "("); #else g_string_append_printf (string, "(register-procedure "); #endif if (num != 1) { g_string_printf (buf, "%s <%d>", proc_name, num); output_string (string, buf->str); } else { output_string (string, proc_name); } type_desc = gimp_enum_get_desc (proc_class, procedure->proc_type); #ifdef DEBUG_OUTPUT g_string_append_printf (string, " ("); for (i = 0; i < procedure->num_args; i++) { GParamSpec *pspec = procedure->args[i]; GimpPDBArgType arg_type; arg_type = gimp_pdb_compat_arg_type_from_gtype (pspec->value_type); arg_value = g_enum_get_value (arg_class, arg_type); if (i > 0) g_string_append_printf (string, " "); output_string (string, arg_value->value_name); } g_string_append_printf (string, ") ("); for (i = 0; i < procedure->num_values; i++) { GParamSpec *pspec = procedure->values[i]; GimpPDBArgType arg_type; arg_type = gimp_pdb_compat_arg_type_from_gtype (pspec->value_type); arg_value = g_enum_get_value (arg_class, arg_type); if (i > 0) g_string_append_printf (string, " "); output_string (string, arg_value->value_name); } g_string_append_printf (string, "))\n"); #else /* ! DEBUG_OUTPUT */ g_string_append_printf (string, " "); output_string (string, strings.blurb); g_string_append_printf (string, " "); output_string (string, strings.help); g_string_append_printf (string, " "); output_string (string, strings.author); g_string_append_printf (string, " "); output_string (string, strings.copyright); g_string_append_printf (string, " "); output_string (string, strings.date); g_string_append_printf (string, " "); output_string (string, type_desc->value_desc); g_string_append_printf (string, " ("); for (i = 0; i < procedure->num_args; i++) { GParamSpec *pspec = procedure->args[i]; GimpPDBArgType arg_type; gchar *desc = gimp_param_spec_get_desc (pspec); g_string_append_printf (string, "\n (\n"); arg_type = gimp_pdb_compat_arg_type_from_gtype (pspec->value_type); arg_value = g_enum_get_value (arg_class, arg_type); g_string_append_printf (string, " "); output_string (string, g_param_spec_get_name (pspec)); g_string_append_printf (string, " "); output_string (string, arg_value->value_name); g_string_append_printf (string, " "); output_string (string, desc); g_free (desc); g_string_append_printf (string, " )"); } g_string_append_printf (string, "\n )\n"); g_string_append_printf (string, " ("); for (i = 0; i < procedure->num_values; i++) { GParamSpec *pspec = procedure->values[i]; GimpPDBArgType arg_type; gchar *desc = gimp_param_spec_get_desc (pspec); g_string_append_printf (string, "\n (\n"); arg_type = gimp_pdb_compat_arg_type_from_gtype (pspec->value_type); arg_value = g_enum_get_value (arg_class, arg_type); g_string_append_printf (string, " "); output_string (string, g_param_spec_get_name (pspec)); g_string_append_printf (string, " "); output_string (string, arg_value->value_name); g_string_append_printf (string, " "); output_string (string, desc); g_free (desc); g_string_append_printf (string, " )"); } g_string_append_printf (string, "\n )"); g_string_append_printf (string, "\n)\n"); #endif /* DEBUG_OUTPUT */ gimp_pdb_free_strings (&strings); } g_output_stream_write_all (output, string->str, string->len, NULL, NULL, &pdb_dump->error); g_string_free (string, TRUE); g_string_free (buf, TRUE); g_type_class_unref (arg_class); g_type_class_unref (proc_class); } static void gimp_pdb_get_strings (PDBStrings *strings, GimpProcedure *procedure, gboolean compat) { strings->compat = compat; if (compat) { strings->blurb = g_strdup_printf (COMPAT_BLURB, gimp_object_get_name (procedure)); strings->help = g_strdup (strings->blurb); strings->author = NULL; strings->copyright = NULL; strings->date = NULL; } else { strings->blurb = procedure->blurb; strings->help = procedure->help; strings->author = procedure->author; strings->copyright = procedure->copyright; strings->date = procedure->date; } } static void gimp_pdb_free_strings (PDBStrings *strings) { if (strings->compat) { g_free (strings->blurb); g_free (strings->help); } }