1 /* GIMP - The GNU Image Manipulation Program
2 * Copyright (C) 1995-2003 Spencer Kimball and Peter Mattis
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18 #include "config.h"
19
20 #include <stdlib.h>
21 #include <string.h>
22
23 #include <gdk-pixbuf/gdk-pixbuf.h>
24 #include <gegl.h>
25
26 #include "libgimpbase/gimpbase.h"
27
28 #include "pdb-types.h"
29
30 #include "core/gimpparamspecs-desc.h"
31
32 #include "gimppdb.h"
33 #include "gimppdb-query.h"
34 #include "gimppdberror.h"
35 #include "gimp-pdb-compat.h"
36 #include "gimpprocedure.h"
37
38 #include "gimp-intl.h"
39
40
41 #define PDB_REGEX_FLAGS (G_REGEX_CASELESS | G_REGEX_OPTIMIZE)
42
43 #define COMPAT_BLURB "This procedure is deprecated! Use '%s' instead."
44
45
46 typedef struct _PDBDump PDBDump;
47
48 struct _PDBDump
49 {
50 GimpPDB *pdb;
51 GOutputStream *output;
52 GError *error;
53
54 gboolean dumping_compat;
55 };
56
57 typedef struct _PDBQuery PDBQuery;
58
59 struct _PDBQuery
60 {
61 GimpPDB *pdb;
62
63 GRegex *name_regex;
64 GRegex *blurb_regex;
65 GRegex *help_regex;
66 GRegex *author_regex;
67 GRegex *copyright_regex;
68 GRegex *date_regex;
69 GRegex *proc_type_regex;
70
71 gchar **list_of_procs;
72 gint num_procs;
73 gboolean querying_compat;
74 };
75
76 typedef struct _PDBStrings PDBStrings;
77
78 struct _PDBStrings
79 {
80 gboolean compat;
81
82 gchar *blurb;
83 gchar *help;
84 gchar *author;
85 gchar *copyright;
86 gchar *date;
87 };
88
89
90 /* local function prototypes */
91
92 static void gimp_pdb_query_entry (gpointer key,
93 gpointer value,
94 gpointer user_data);
95 static void gimp_pdb_print_entry (gpointer key,
96 gpointer value,
97 gpointer user_data);
98 static void gimp_pdb_get_strings (PDBStrings *strings,
99 GimpProcedure *procedure,
100 gboolean compat);
101 static void gimp_pdb_free_strings (PDBStrings *strings);
102
103
104 /* public functions */
105
106 gboolean
gimp_pdb_dump(GimpPDB * pdb,GFile * file,GError ** error)107 gimp_pdb_dump (GimpPDB *pdb,
108 GFile *file,
109 GError **error)
110 {
111 PDBDump pdb_dump = { 0, };
112
113 g_return_val_if_fail (GIMP_IS_PDB (pdb), FALSE);
114 g_return_val_if_fail (G_IS_FILE (file), FALSE);
115 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
116
117 pdb_dump.pdb = pdb;
118 pdb_dump.output = G_OUTPUT_STREAM (g_file_replace (file,
119 NULL, FALSE,
120 G_FILE_CREATE_NONE,
121 NULL, error));
122 if (! pdb_dump.output)
123 return FALSE;
124
125 pdb_dump.dumping_compat = FALSE;
126
127 g_hash_table_foreach (pdb->procedures,
128 gimp_pdb_print_entry,
129 &pdb_dump);
130
131 pdb_dump.dumping_compat = TRUE;
132
133 g_hash_table_foreach (pdb->compat_proc_names,
134 gimp_pdb_print_entry,
135 &pdb_dump);
136
137 if (pdb_dump.error)
138 {
139 GCancellable *cancellable = g_cancellable_new ();
140
141 g_set_error (error, pdb_dump.error->domain, pdb_dump.error->code,
142 _("Writing PDB file '%s' failed: %s"),
143 gimp_file_get_utf8_name (file), pdb_dump.error->message);
144 g_clear_error (&pdb_dump.error);
145
146 /* Cancel the overwrite initiated by g_file_replace(). */
147 g_cancellable_cancel (cancellable);
148 g_output_stream_close (pdb_dump.output, cancellable, NULL);
149 g_object_unref (cancellable);
150 g_object_unref (pdb_dump.output);
151
152 return FALSE;
153 }
154
155 g_object_unref (pdb_dump.output);
156
157 return TRUE;
158 }
159
160 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)161 gimp_pdb_query (GimpPDB *pdb,
162 const gchar *name,
163 const gchar *blurb,
164 const gchar *help,
165 const gchar *author,
166 const gchar *copyright,
167 const gchar *date,
168 const gchar *proc_type,
169 gint *num_procs,
170 gchar ***procs,
171 GError **error)
172 {
173 PDBQuery pdb_query = { 0, };
174 gboolean success = FALSE;
175
176 g_return_val_if_fail (GIMP_IS_PDB (pdb), FALSE);
177 g_return_val_if_fail (name != NULL, FALSE);
178 g_return_val_if_fail (blurb != NULL, FALSE);
179 g_return_val_if_fail (help != NULL, FALSE);
180 g_return_val_if_fail (author != NULL, FALSE);
181 g_return_val_if_fail (copyright != NULL, FALSE);
182 g_return_val_if_fail (date != NULL, FALSE);
183 g_return_val_if_fail (proc_type != NULL, FALSE);
184 g_return_val_if_fail (num_procs != NULL, FALSE);
185 g_return_val_if_fail (procs != NULL, FALSE);
186 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
187
188 *num_procs = 0;
189 *procs = NULL;
190
191 pdb_query.name_regex = g_regex_new (name, PDB_REGEX_FLAGS, 0, error);
192 if (! pdb_query.name_regex)
193 goto cleanup;
194
195 pdb_query.blurb_regex = g_regex_new (blurb, PDB_REGEX_FLAGS, 0, error);
196 if (! pdb_query.blurb_regex)
197 goto cleanup;
198
199 pdb_query.help_regex = g_regex_new (help, PDB_REGEX_FLAGS, 0, error);
200 if (! pdb_query.help_regex)
201 goto cleanup;
202
203 pdb_query.author_regex = g_regex_new (author, PDB_REGEX_FLAGS, 0, error);
204 if (! pdb_query.author_regex)
205 goto cleanup;
206
207 pdb_query.copyright_regex = g_regex_new (copyright, PDB_REGEX_FLAGS, 0, error);
208 if (! pdb_query.copyright_regex)
209 goto cleanup;
210
211 pdb_query.date_regex = g_regex_new (date, PDB_REGEX_FLAGS, 0, error);
212 if (! pdb_query.date_regex)
213 goto cleanup;
214
215 pdb_query.proc_type_regex = g_regex_new (proc_type, PDB_REGEX_FLAGS, 0, error);
216 if (! pdb_query.proc_type_regex)
217 goto cleanup;
218
219 success = TRUE;
220
221 pdb_query.pdb = pdb;
222 pdb_query.list_of_procs = NULL;
223 pdb_query.num_procs = 0;
224 pdb_query.querying_compat = FALSE;
225
226 g_hash_table_foreach (pdb->procedures,
227 gimp_pdb_query_entry, &pdb_query);
228
229 pdb_query.querying_compat = TRUE;
230
231 g_hash_table_foreach (pdb->compat_proc_names,
232 gimp_pdb_query_entry, &pdb_query);
233
234 cleanup:
235
236 if (pdb_query.proc_type_regex)
237 g_regex_unref (pdb_query.proc_type_regex);
238
239 if (pdb_query.date_regex)
240 g_regex_unref (pdb_query.date_regex);
241
242 if (pdb_query.copyright_regex)
243 g_regex_unref (pdb_query.copyright_regex);
244
245 if (pdb_query.author_regex)
246 g_regex_unref (pdb_query.author_regex);
247
248 if (pdb_query.help_regex)
249 g_regex_unref (pdb_query.help_regex);
250
251 if (pdb_query.blurb_regex)
252 g_regex_unref (pdb_query.blurb_regex);
253
254 if (pdb_query.name_regex)
255 g_regex_unref (pdb_query.name_regex);
256
257 if (success)
258 {
259 *num_procs = pdb_query.num_procs;
260 *procs = pdb_query.list_of_procs;
261 }
262
263 return success;
264 }
265
266 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)267 gimp_pdb_proc_info (GimpPDB *pdb,
268 const gchar *proc_name,
269 gchar **blurb,
270 gchar **help,
271 gchar **author,
272 gchar **copyright,
273 gchar **date,
274 GimpPDBProcType *proc_type,
275 gint *num_args,
276 gint *num_values,
277 GError **error)
278 {
279 GimpProcedure *procedure;
280 PDBStrings strings;
281
282 g_return_val_if_fail (GIMP_IS_PDB (pdb), FALSE);
283 g_return_val_if_fail (proc_name != NULL, FALSE);
284 g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
285
286 procedure = gimp_pdb_lookup_procedure (pdb, proc_name);
287
288 if (procedure)
289 {
290 gimp_pdb_get_strings (&strings, procedure, FALSE);
291 }
292 else
293 {
294 const gchar *compat_name;
295
296 compat_name = gimp_pdb_lookup_compat_proc_name (pdb, proc_name);
297
298 if (compat_name)
299 {
300 procedure = gimp_pdb_lookup_procedure (pdb, compat_name);
301
302 if (procedure)
303 gimp_pdb_get_strings (&strings, procedure, TRUE);
304 }
305 }
306
307 if (procedure)
308 {
309 *blurb = strings.compat ? strings.blurb : g_strdup (strings.blurb);
310 *help = strings.compat ? strings.help : g_strdup (strings.help);
311 *author = strings.compat ? strings.author : g_strdup (strings.author);
312 *copyright = strings.compat ? strings.copyright : g_strdup (strings.copyright);
313 *date = strings.compat ? strings.date : g_strdup (strings.date);
314 *proc_type = procedure->proc_type;
315 *num_args = procedure->num_args;
316 *num_values = procedure->num_values;
317
318 return TRUE;
319 }
320
321 g_set_error (error, GIMP_PDB_ERROR, GIMP_PDB_ERROR_PROCEDURE_NOT_FOUND,
322 _("Procedure '%s' not found"), proc_name);
323
324 return FALSE;
325 }
326
327
328 /* private functions */
329
330 static gboolean
match_string(GRegex * regex,const gchar * string)331 match_string (GRegex *regex,
332 const gchar *string)
333 {
334 if (! string)
335 string = "";
336
337 return g_regex_match (regex, string, 0, NULL);
338 }
339
340 static void
gimp_pdb_query_entry(gpointer key,gpointer value,gpointer user_data)341 gimp_pdb_query_entry (gpointer key,
342 gpointer value,
343 gpointer user_data)
344 {
345 PDBQuery *pdb_query = user_data;
346 GList *list;
347 GimpProcedure *procedure;
348 const gchar *proc_name;
349 PDBStrings strings;
350 GEnumClass *enum_class;
351 GimpEnumDesc *type_desc;
352
353 proc_name = key;
354
355 if (pdb_query->querying_compat)
356 list = g_hash_table_lookup (pdb_query->pdb->procedures, value);
357 else
358 list = value;
359
360 if (! list)
361 return;
362
363 procedure = list->data;
364
365 gimp_pdb_get_strings (&strings, procedure, pdb_query->querying_compat);
366
367 enum_class = g_type_class_ref (GIMP_TYPE_PDB_PROC_TYPE);
368 type_desc = gimp_enum_get_desc (enum_class, procedure->proc_type);
369 g_type_class_unref (enum_class);
370
371 if (match_string (pdb_query->name_regex, proc_name) &&
372 match_string (pdb_query->blurb_regex, strings.blurb) &&
373 match_string (pdb_query->help_regex, strings.help) &&
374 match_string (pdb_query->author_regex, strings.author) &&
375 match_string (pdb_query->copyright_regex, strings.copyright) &&
376 match_string (pdb_query->date_regex, strings.date) &&
377 match_string (pdb_query->proc_type_regex, type_desc->value_desc))
378 {
379 pdb_query->num_procs++;
380 pdb_query->list_of_procs = g_renew (gchar *, pdb_query->list_of_procs,
381 pdb_query->num_procs);
382 pdb_query->list_of_procs[pdb_query->num_procs - 1] = g_strdup (proc_name);
383 }
384
385 gimp_pdb_free_strings (&strings);
386 }
387
388 /* #define DEBUG_OUTPUT 1 */
389
390 static void
output_string(GString * dest,const gchar * string)391 output_string (GString *dest,
392 const gchar *string)
393 {
394 #ifndef DEBUG_OUTPUT
395 g_string_append_printf (dest, "\"");
396 #endif
397
398 if (string)
399 while (*string)
400 {
401 switch (*string)
402 {
403 case '\\' : g_string_append_printf (dest, "\\\\"); break;
404 case '\"' : g_string_append_printf (dest, "\\\""); break;
405 case '{' : g_string_append_printf (dest, "@{"); break;
406 case '@' : g_string_append_printf (dest, "@@"); break;
407 case '}' : g_string_append_printf (dest, "@}"); break;
408
409 default:
410 g_string_append_printf (dest, "%c", *string);
411 }
412 string++;
413 }
414
415 #ifndef DEBUG_OUTPUT
416 g_string_append_printf (dest, "\"\n");
417 #endif
418 }
419
420 static void
gimp_pdb_print_entry(gpointer key,gpointer value,gpointer user_data)421 gimp_pdb_print_entry (gpointer key,
422 gpointer value,
423 gpointer user_data)
424 {
425 PDBDump *pdb_dump = user_data;
426 GOutputStream *output = pdb_dump->output;
427 const gchar *proc_name;
428 GList *list;
429 GEnumClass *arg_class;
430 GEnumClass *proc_class;
431 GString *buf;
432 GString *string;
433 gint num = 0;
434
435 if (pdb_dump->error)
436 return;
437
438 proc_name = key;
439
440 if (pdb_dump->dumping_compat)
441 list = g_hash_table_lookup (pdb_dump->pdb->procedures, value);
442 else
443 list = value;
444
445 arg_class = g_type_class_ref (GIMP_TYPE_PDB_ARG_TYPE);
446 proc_class = g_type_class_ref (GIMP_TYPE_PDB_PROC_TYPE);
447
448 buf = g_string_new (NULL);
449 string = g_string_new (NULL);
450
451 for (; list; list = list->next)
452 {
453 GimpProcedure *procedure = list->data;
454 PDBStrings strings;
455 GEnumValue *arg_value;
456 GimpEnumDesc *type_desc;
457 gint i;
458
459 num++;
460
461 gimp_pdb_get_strings (&strings, procedure, pdb_dump->dumping_compat);
462
463 #ifdef DEBUG_OUTPUT
464 g_string_append_printf (string, "(");
465 #else
466 g_string_append_printf (string, "(register-procedure ");
467 #endif
468
469 if (num != 1)
470 {
471 g_string_printf (buf, "%s <%d>", proc_name, num);
472 output_string (string, buf->str);
473 }
474 else
475 {
476 output_string (string, proc_name);
477 }
478
479 type_desc = gimp_enum_get_desc (proc_class, procedure->proc_type);
480
481 #ifdef DEBUG_OUTPUT
482
483 g_string_append_printf (string, " (");
484
485 for (i = 0; i < procedure->num_args; i++)
486 {
487 GParamSpec *pspec = procedure->args[i];
488 GimpPDBArgType arg_type;
489
490 arg_type = gimp_pdb_compat_arg_type_from_gtype (pspec->value_type);
491
492 arg_value = g_enum_get_value (arg_class, arg_type);
493
494 if (i > 0)
495 g_string_append_printf (string, " ");
496
497 output_string (string, arg_value->value_name);
498 }
499
500 g_string_append_printf (string, ") (");
501
502 for (i = 0; i < procedure->num_values; i++)
503 {
504 GParamSpec *pspec = procedure->values[i];
505 GimpPDBArgType arg_type;
506
507 arg_type = gimp_pdb_compat_arg_type_from_gtype (pspec->value_type);
508
509 arg_value = g_enum_get_value (arg_class, arg_type);
510
511 if (i > 0)
512 g_string_append_printf (string, " ");
513
514 output_string (string, arg_value->value_name);
515 }
516
517 g_string_append_printf (string, "))\n");
518
519 #else /* ! DEBUG_OUTPUT */
520
521 g_string_append_printf (string, " ");
522 output_string (string, strings.blurb);
523
524 g_string_append_printf (string, " ");
525 output_string (string, strings.help);
526
527 g_string_append_printf (string, " ");
528 output_string (string, strings.author);
529
530 g_string_append_printf (string, " ");
531 output_string (string, strings.copyright);
532
533 g_string_append_printf (string, " ");
534 output_string (string, strings.date);
535
536 g_string_append_printf (string, " ");
537 output_string (string, type_desc->value_desc);
538
539 g_string_append_printf (string, " (");
540
541 for (i = 0; i < procedure->num_args; i++)
542 {
543 GParamSpec *pspec = procedure->args[i];
544 GimpPDBArgType arg_type;
545 gchar *desc = gimp_param_spec_get_desc (pspec);
546
547 g_string_append_printf (string, "\n (\n");
548
549 arg_type = gimp_pdb_compat_arg_type_from_gtype (pspec->value_type);
550
551 arg_value = g_enum_get_value (arg_class, arg_type);
552
553 g_string_append_printf (string, " ");
554 output_string (string, g_param_spec_get_name (pspec));
555
556 g_string_append_printf (string, " ");
557 output_string (string, arg_value->value_name);
558
559 g_string_append_printf (string, " ");
560 output_string (string, desc);
561
562 g_free (desc);
563
564 g_string_append_printf (string, " )");
565 }
566
567 g_string_append_printf (string, "\n )\n");
568
569 g_string_append_printf (string, " (");
570
571 for (i = 0; i < procedure->num_values; i++)
572 {
573 GParamSpec *pspec = procedure->values[i];
574 GimpPDBArgType arg_type;
575 gchar *desc = gimp_param_spec_get_desc (pspec);
576
577 g_string_append_printf (string, "\n (\n");
578
579 arg_type = gimp_pdb_compat_arg_type_from_gtype (pspec->value_type);
580
581 arg_value = g_enum_get_value (arg_class, arg_type);
582
583 g_string_append_printf (string, " ");
584 output_string (string, g_param_spec_get_name (pspec));
585
586 g_string_append_printf (string, " ");
587 output_string (string, arg_value->value_name);
588
589 g_string_append_printf (string, " ");
590 output_string (string, desc);
591
592 g_free (desc);
593
594 g_string_append_printf (string, " )");
595 }
596
597 g_string_append_printf (string, "\n )");
598 g_string_append_printf (string, "\n)\n");
599
600 #endif /* DEBUG_OUTPUT */
601
602 gimp_pdb_free_strings (&strings);
603 }
604
605 g_output_stream_write_all (output, string->str, string->len,
606 NULL, NULL, &pdb_dump->error);
607
608 g_string_free (string, TRUE);
609 g_string_free (buf, TRUE);
610
611 g_type_class_unref (arg_class);
612 g_type_class_unref (proc_class);
613 }
614
615 static void
gimp_pdb_get_strings(PDBStrings * strings,GimpProcedure * procedure,gboolean compat)616 gimp_pdb_get_strings (PDBStrings *strings,
617 GimpProcedure *procedure,
618 gboolean compat)
619 {
620 strings->compat = compat;
621
622 if (compat)
623 {
624 strings->blurb = g_strdup_printf (COMPAT_BLURB,
625 gimp_object_get_name (procedure));
626 strings->help = g_strdup (strings->blurb);
627 strings->author = NULL;
628 strings->copyright = NULL;
629 strings->date = NULL;
630 }
631 else
632 {
633 strings->blurb = procedure->blurb;
634 strings->help = procedure->help;
635 strings->author = procedure->author;
636 strings->copyright = procedure->copyright;
637 strings->date = procedure->date;
638 }
639 }
640
641 static void
gimp_pdb_free_strings(PDBStrings * strings)642 gimp_pdb_free_strings (PDBStrings *strings)
643 {
644 if (strings->compat)
645 {
646 g_free (strings->blurb);
647 g_free (strings->help);
648 }
649 }
650