PIKApp/app/pdb/pikapdb-query.c

564 lines
15 KiB
C

/* PIKA - Photo and Image Kooker Application
* a rebranding of The GNU Image Manipulation Program (created with heckimp)
* A derived work which may be trivial. However, any changes may be (C)2023 by Aldercone Studio
*
* Original copyright, applying to most contents (license remains unchanged):
* 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 <https://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <stdlib.h>
#include <string.h>
#include <gdk-pixbuf/gdk-pixbuf.h>
#include <gegl.h>
#include "libpikabase/pikabase.h"
#include "pdb-types.h"
#include "core/pikaparamspecs-desc.h"
#include "pikapdb.h"
#include "pikapdb-query.h"
#include "pikapdberror.h"
#include "pikaprocedure.h"
#include "pika-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
{
PikaPDB *pdb;
GOutputStream *output;
GError *error;
gboolean dumping_compat;
};
typedef struct _PDBQuery PDBQuery;
struct _PDBQuery
{
PikaPDB *pdb;
GRegex *name_regex;
GRegex *blurb_regex;
GRegex *help_regex;
GRegex *authors_regex;
GRegex *copyright_regex;
GRegex *date_regex;
GRegex *proc_type_regex;
gchar **list_of_procs;
gboolean querying_compat;
};
typedef struct _PDBStrings PDBStrings;
struct _PDBStrings
{
gboolean compat;
gchar *blurb;
gchar *help;
gchar *authors;
gchar *copyright;
gchar *date;
};
/* local function prototypes */
static void pika_pdb_query_entry (gpointer key,
gpointer value,
gpointer user_data);
static void pika_pdb_print_entry (gpointer key,
gpointer value,
gpointer user_data);
static void pika_pdb_get_strings (PDBStrings *strings,
PikaProcedure *procedure,
gboolean compat);
static void pika_pdb_free_strings (PDBStrings *strings);
/* public functions */
gboolean
pika_pdb_dump (PikaPDB *pdb,
GFile *file,
GError **error)
{
PDBDump pdb_dump = { 0, };
g_return_val_if_fail (PIKA_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,
pika_pdb_print_entry,
&pdb_dump);
pdb_dump.dumping_compat = TRUE;
g_hash_table_foreach (pdb->compat_proc_names,
pika_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"),
pika_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
pika_pdb_query (PikaPDB *pdb,
const gchar *name,
const gchar *blurb,
const gchar *help,
const gchar *authors,
const gchar *copyright,
const gchar *date,
const gchar *proc_type,
gchar ***procs,
GError **error)
{
PDBQuery pdb_query = { 0, };
gboolean success = FALSE;
g_return_val_if_fail (PIKA_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 (authors != 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 (procs != NULL, FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
*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.authors_regex = g_regex_new (authors, PDB_REGEX_FLAGS, 0, error);
if (! pdb_query.authors_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 = g_new0 (gchar *, 1);
pdb_query.querying_compat = FALSE;
g_hash_table_foreach (pdb->procedures,
pika_pdb_query_entry, &pdb_query);
pdb_query.querying_compat = TRUE;
g_hash_table_foreach (pdb->compat_proc_names,
pika_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.authors_regex)
g_regex_unref (pdb_query.authors_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)
{
*procs = pdb_query.list_of_procs;
}
return success;
}
/* private functions */
static gboolean
match_string (GRegex *regex,
const gchar *string)
{
if (! string)
string = "";
return g_regex_match (regex, string, 0, NULL);
}
static void
pika_pdb_query_entry (gpointer key,
gpointer value,
gpointer user_data)
{
PDBQuery *pdb_query = user_data;
GList *list;
PikaProcedure *procedure;
const gchar *proc_name;
PDBStrings strings;
GEnumClass *enum_class;
const PikaEnumDesc *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;
pika_pdb_get_strings (&strings, procedure, pdb_query->querying_compat);
enum_class = g_type_class_ref (PIKA_TYPE_PDB_PROC_TYPE);
type_desc = pika_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->authors_regex, strings.authors) &&
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))
{
guint num_procs = g_strv_length (pdb_query->list_of_procs);
pdb_query->list_of_procs = g_renew (gchar *, pdb_query->list_of_procs,
num_procs + 2);
pdb_query->list_of_procs[num_procs] = g_strdup (proc_name);
pdb_query->list_of_procs[num_procs + 1] = NULL;
}
pika_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
pika_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 *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;
proc_class = g_type_class_ref (PIKA_TYPE_PDB_PROC_TYPE);
buf = g_string_new (NULL);
string = g_string_new (NULL);
for (; list; list = list->next)
{
PikaProcedure *procedure = list->data;
PDBStrings strings;
const PikaEnumDesc *type_desc;
gint i;
num++;
pika_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 = pika_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];
if (i > 0)
g_string_append_printf (string, " ");
output_string (string, g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
}
g_string_append_printf (string, ") (");
for (i = 0; i < procedure->num_values; i++)
{
GParamSpec *pspec = procedure->values[i];
if (i > 0)
g_string_append_printf (string, " ");
output_string (string, g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
}
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.authors);
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];
gchar *desc = pika_param_spec_get_desc (pspec);
g_string_append_printf (string, "\n (\n");
g_string_append_printf (string, " ");
output_string (string, g_param_spec_get_name (pspec));
g_string_append_printf (string, " ");
output_string (string, g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
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];
gchar *desc = pika_param_spec_get_desc (pspec);
g_string_append_printf (string, "\n (\n");
g_string_append_printf (string, " ");
output_string (string, g_param_spec_get_name (pspec));
g_string_append_printf (string, " ");
output_string (string, g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)));
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 */
pika_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 (proc_class);
}
static void
pika_pdb_get_strings (PDBStrings *strings,
PikaProcedure *procedure,
gboolean compat)
{
strings->compat = compat;
if (compat)
{
strings->blurb = g_strdup_printf (COMPAT_BLURB,
pika_object_get_name (procedure));
strings->help = g_strdup (strings->blurb);
strings->authors = NULL;
strings->copyright = NULL;
strings->date = NULL;
}
else
{
strings->blurb = procedure->blurb;
strings->help = procedure->help;
strings->authors = procedure->authors;
strings->copyright = procedure->copyright;
strings->date = procedure->date;
}
}
static void
pika_pdb_free_strings (PDBStrings *strings)
{
if (strings->compat)
{
g_free (strings->blurb);
g_free (strings->help);
}
}