1 /* -*- Mode: C; c-basic-offset: 4 -*-
2  * Gimp-Python - allows the writing of Gimp plugins in Python.
3  * Copyright (C) 1997-2002  James Henstridge <james@daa.com.au>
4  *
5  * This program is free software: you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 3 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program.  If not, see <https://www.gnu.org/licenses/>.
17  */
18 
19 #ifdef HAVE_CONFIG_H
20 #  include <config.h>
21 #endif
22 
23 #define NO_IMPORT_PYGOBJECT
24 #include <pygobject.h>
25 
26 #include "pygimp.h"
27 
28 #define NO_IMPORT_PYGIMPCOLOR
29 #include "pygimpcolor-api.h"
30 
31 #include <structmember.h>
32 
33 #include <glib-object.h>
34 #include <glib/gprintf.h>
35 
36 #ifndef PG_DEBUG
37 # define PG_DEBUG 0
38 #endif
39 
40 /* ----------------------------------------------------- */
41 
42 /* Declarations for objects of type pdb */
43 
44 typedef struct {
45     PyObject_HEAD
46 } PyGimpPDB;
47 
48 
49 /* ---------------------------------------------------------------- */
50 
51 /* Declarations for objects of type pdbFunc */
52 
53 typedef struct {
54     PyObject_HEAD
55     char *name;
56     PyObject *proc_name, *proc_blurb, *proc_help, *proc_author,
57 	*proc_copyright, *proc_date, *proc_type, *py_params,
58 	*py_return_vals;
59     int nparams, nreturn_vals;
60     GimpParamDef *params, *return_vals;
61 } PyGimpPDBFunction;
62 
63 static PyObject *pygimp_pdb_function_new_from_proc_db(char *name);
64 
65 /* ---------------------------------------------------------------- */
66 
67 /* routines to convert between Python tuples and gimp GimpParam's */
68 
69 #if PG_DEBUG > 0
70 
71 static void
pygimp_param_print(int nparams,GimpParam * params)72 pygimp_param_print(int nparams, GimpParam *params)
73 {
74     int i;
75 
76     for (i = 0; i < nparams; i++) {
77 	g_printf("param_print: type: %d, PDB_ITEM: %d\n",  params[i].type, GIMP_PDB_ITEM);
78 	switch(params[i].type) {
79 	case GIMP_PDB_INT32:
80 	    g_printerr("%i. int %i\n", i,
81                        params[i].data.d_int32);
82 	    break;
83 	case GIMP_PDB_INT16:
84 	    g_printerr("%i. int %i\n", i,
85                        params[i].data.d_int16);
86 	    break;
87 	case GIMP_PDB_INT8:
88 	    g_printerr("%i. int %u\n", i,
89                        params[i].data.d_int8);
90 	    break;
91 	case GIMP_PDB_FLOAT:
92 	    g_printerr("%i. float %f\n", i,
93                        params[i].data.d_float);
94 	    break;
95 	case GIMP_PDB_STRING:
96 	    g_printerr("%i. string %s\n", i,
97                        params[i].data.d_string);
98 	    break;
99 	case GIMP_PDB_INT32ARRAY:
100 	case GIMP_PDB_INT16ARRAY:
101 	case GIMP_PDB_INT8ARRAY:
102 	case GIMP_PDB_FLOATARRAY:
103 	case GIMP_PDB_STRINGARRAY:
104 	    g_printerr("%i. array of type %i %s\n", i,
105                        params[i].type,
106                        params[i].data.d_int32array == NULL ? "(null)":"");
107 	    break;
108 	case GIMP_PDB_STATUS:
109 	    g_printerr("%i. status %i\n", i,
110                        params[i].data.d_status);
111 	    break;
112 	default:
113 	    g_printerr("%i. other %i\n", i,
114                        params[i].data.d_int32);
115 	    break;
116 	}
117     }
118 }
119 
120 #endif
121 
122 PyObject *
pygimp_param_to_tuple(int nparams,const GimpParam * params)123 pygimp_param_to_tuple(int nparams, const GimpParam *params)
124 {
125     PyObject *args, *tmp;
126     int i, j, n;
127 
128     args = PyTuple_New(nparams);
129     for (i = 0; i < nparams && params[i].type != GIMP_PDB_END; i++) {
130 	PyObject *value = NULL;
131 
132 #if PG_DEBUG > 1
133 	g_printf("param_to_tuple: type: %d, PDB_ITEM: %d\n",  params[i].type, GIMP_PDB_ITEM);
134 #endif
135 
136 	switch(params[i].type) {
137 	case GIMP_PDB_INT32:
138 	    value = PyInt_FromLong(params[i].data.d_int32);
139 	    break;
140 	case GIMP_PDB_INT16:
141 	    value = PyInt_FromLong(params[i].data.d_int16);
142 	    break;
143 	case GIMP_PDB_INT8:
144 	    value = PyInt_FromLong(params[i].data.d_int8);
145 	    break;
146 	case GIMP_PDB_FLOAT:
147 	    value = PyFloat_FromDouble(params[i].data.d_float);
148 	    break;
149 	case GIMP_PDB_STRING:
150 	    if (params[i].data.d_string == NULL) {
151 		Py_INCREF(Py_None);
152 		value = Py_None;
153 	    } else
154 		value = PyString_FromString(params[i].data.d_string);
155 	    break;
156 
157 	    /* For these to work, the previous argument must have
158 	     * been an integer
159 	     */
160 	case GIMP_PDB_INT32ARRAY:
161 	    if (params[i].data.d_int32array == NULL) {
162 		value = PyTuple_New(0);
163 		break;
164 	    }
165 	    if ((tmp=PyTuple_GetItem(args, i-1)) == NULL) {
166 		Py_DECREF(args);
167 		return NULL;
168 	    }
169 	    if (!PyInt_Check(tmp)) {
170 		PyErr_SetString(PyExc_TypeError,
171 				"count type must be integer");
172 		Py_DECREF(args);
173 		return NULL;
174 	    }
175 	    n = PyInt_AsLong(tmp);
176 	    value = PyTuple_New(n);
177 	    for (j = 0; j < n; j++)
178 		PyTuple_SetItem(value, j,
179 			PyInt_FromLong(params[i].data.d_int32array[j]));
180 	    break;
181 	case GIMP_PDB_INT16ARRAY:
182 	    if (params[i].data.d_int16array == NULL) {
183 		value = PyTuple_New(0);
184 		break;
185 	    }
186 	    if ((tmp=PyTuple_GetItem(args, i-1)) == NULL) {
187 		Py_DECREF(args);
188 		return NULL;
189 	    }
190 	    if (!PyInt_Check(tmp)) {
191 		PyErr_SetString(PyExc_TypeError,
192 				"count type must be integer");
193 		Py_DECREF(args);
194 		return NULL;
195 	    }
196 	    n = PyInt_AsLong(tmp);
197 	    value = PyTuple_New(n);
198 	    for (j = 0; j < n; j++)
199 		PyTuple_SetItem(value, j,
200 			PyInt_FromLong(params[i].data.d_int16array[j]));
201 	    break;
202 	case GIMP_PDB_INT8ARRAY:
203 	    if (params[i].data.d_int8array == NULL) {
204 		value = PyTuple_New(0);
205 		break;
206 	    }
207 	    if ((tmp=PyTuple_GetItem(args, i-1)) == NULL) {
208 		Py_DECREF(args);
209 		return NULL;
210 	    }
211 	    if (!PyInt_Check(tmp)) {
212 		PyErr_SetString(PyExc_TypeError,
213 				"count type must be integer");
214 		Py_DECREF(args);
215 		return NULL;
216 	    }
217 	    n = PyInt_AsLong(tmp);
218 	    value = PyTuple_New(n);
219 	    for (j = 0; j < n; j++)
220 		PyTuple_SetItem(value, j,
221 			PyInt_FromLong(params[i].data.d_int8array[j]));
222 	    break;
223 	case GIMP_PDB_FLOATARRAY:
224 	    if (params[i].data.d_floatarray == NULL) {
225 		value = PyTuple_New(0);
226 		break;
227 	    }
228 	    if ((tmp=PyTuple_GetItem(args, i-1)) == NULL) {
229 		Py_DECREF(args);
230 		return NULL;
231 	    }
232 	    if (!PyInt_Check(tmp)) {
233 		PyErr_SetString(PyExc_TypeError,
234 				"count type must be integer");
235 		Py_DECREF(args);
236 		return NULL;
237 	    }
238 	    n = PyInt_AsLong(tmp);
239 	    value = PyTuple_New(n);
240 	    for (j = 0; j < n; j++)
241 		PyTuple_SetItem(value, j,
242 			PyFloat_FromDouble(params[i].data.d_floatarray[j]));
243 	    break;
244 	case GIMP_PDB_STRINGARRAY:
245 	    if (params[i].data.d_stringarray == NULL) {
246 		value = PyTuple_New(0);
247 		break;
248 	    }
249 	    if ((tmp=PyTuple_GetItem(args, i-1)) == NULL) {
250 		Py_DECREF(args);
251 		return NULL;
252 	    }
253 	    if (!PyInt_Check(tmp)) {
254 		PyErr_SetString(PyExc_TypeError,
255 				"count type must be integer");
256 		Py_DECREF(args);
257 		return NULL;
258 	    }
259 	    n = PyInt_AsLong(tmp);
260 	    value = PyTuple_New(n);
261 	    for (j = 0; j < n; j++)
262 		PyTuple_SetItem(value, j,
263 			params[i].data.d_stringarray[j] ?
264 			PyString_FromString(params[i].data.d_stringarray[j]) :
265 			PyString_FromString(""));
266 	    break;
267 	case GIMP_PDB_COLOR:
268 	    value = pygimp_rgb_new(&params[i].data.d_color);
269 	    break;
270 	/*
271 	GIMP_PDB_REGION is deprecated in libgimpbase/gimpbaseenums.h
272 	and conflicts with GIMP_PDB_ITEM
273 	case GIMP_PDB_REGION:
274 	    value = Py_BuildValue("(iiii)",
275 				  (int) params[i].data.d_region.x,
276 				  (int) params[i].data.d_region.y,
277 				  (int) params[i].data.d_region.width,
278 				  (int) params[i].data.d_region.height);
279 	    break;
280 	*/
281 	case GIMP_PDB_DISPLAY:
282 	    value = pygimp_display_new(params[i].data.d_display);
283 	    break;
284 	case GIMP_PDB_IMAGE:
285 	    value = pygimp_image_new(params[i].data.d_image);
286 	    break;
287 	case GIMP_PDB_LAYER:
288 	    value = pygimp_layer_new(params[i].data.d_layer);
289 	    break;
290 	case GIMP_PDB_CHANNEL:
291 	    value = pygimp_channel_new(params[i].data.d_channel);
292 	    break;
293 	case GIMP_PDB_ITEM:
294 	    value = pygimp_item_new(params[i].data.d_item);
295 	    break;
296 	case GIMP_PDB_DRAWABLE:
297 	    value = pygimp_drawable_new(NULL, params[i].data.d_drawable);
298 	    break;
299 	case GIMP_PDB_SELECTION:
300 	    value = pygimp_channel_new(params[i].data.d_selection);
301 	    break;
302 	case GIMP_PDB_COLORARRAY:
303 	    if (params[i].data.d_colorarray == NULL) {
304 		value = PyTuple_New(0);
305 		break;
306 	    }
307 	    if ((tmp=PyTuple_GetItem(args, i-1)) == NULL) {
308 		Py_DECREF(args);
309 		return NULL;
310 	    }
311 	    if (!PyInt_Check(tmp)) {
312 		PyErr_SetString(PyExc_TypeError,
313 				"count type must be integer");
314 		Py_DECREF(args);
315 		return NULL;
316 	    }
317 	    n = PyInt_AsLong(tmp);
318 	    value = PyTuple_New(n);
319 	    for (j = 0; j < n; j++)
320 		PyTuple_SetItem(value, j,
321                                 pygimp_rgb_new(&params[i].data.d_colorarray[j]));
322 	    break;
323 	case GIMP_PDB_VECTORS:
324 	    value = pygimp_vectors_new(params[i].data.d_vectors);
325 	    break;
326 	case GIMP_PDB_PARASITE:
327 	    value = pygimp_parasite_new(gimp_parasite_copy(
328 					&(params[i].data.d_parasite)));
329 	    break;
330 	case GIMP_PDB_STATUS:
331 	    value = PyInt_FromLong(params[i].data.d_status);
332 	    break;
333 	case GIMP_PDB_END:
334 	    break;
335 	}
336 	PyTuple_SetItem(args, i, value);
337     }
338     return args;
339 }
340 
341 GimpParam *
pygimp_param_from_tuple(PyObject * args,const GimpParamDef * ptype,int nparams)342 pygimp_param_from_tuple(PyObject *args, const GimpParamDef *ptype, int nparams)
343 {
344     PyObject *tuple, *item, *x, *y;
345     GimpParam *ret;
346     int i, j, len;
347     gint32 *i32a; gint16 *i16a; guint8 *i8a; gdouble *fa; gchar **sa;
348 
349     if (nparams == 0)
350 	tuple = PyTuple_New(0);
351     else if (!PyTuple_Check(args) && nparams == 1)
352 	tuple = Py_BuildValue("(O)", args);
353     else {
354 	Py_INCREF(args);
355 	tuple = args;
356     }
357     if (!PyTuple_Check(tuple)) {
358 	PyErr_SetString(PyExc_TypeError, "wrong type of parameter");
359         Py_DECREF(tuple);
360 	return NULL;
361     }
362 
363     if (PyTuple_Size(tuple) != nparams) {
364 	PyErr_SetString(PyExc_TypeError, "wrong number of parameters");
365         Py_DECREF(tuple);
366 	return NULL;
367     }
368 
369     ret = g_new(GimpParam, nparams+1);
370     for (i = 0; i <= nparams; i++)
371 	ret[i].type = GIMP_PDB_STATUS;
372 #define check(expr) if (expr) { \
373 	    PyErr_SetString(PyExc_TypeError, "wrong parameter type"); \
374 	    Py_DECREF(tuple); \
375 	    gimp_destroy_params(ret, nparams); \
376 	    return NULL; \
377 	}
378 #define arraycheck(expr, ar) if (expr) { \
379 	    PyErr_SetString(PyExc_TypeError, "subscript of wrong type"); \
380 	    Py_DECREF(tuple); \
381 	    gimp_destroy_params(ret, nparams); \
382 	    g_free(ar); \
383 	    return NULL; \
384 	}
385     for (i = 1; i <= nparams; i++) {
386 	item = PyTuple_GetItem(tuple, i-1);
387 #if PG_DEBUG > 1
388 	g_printf("param_from_tuple: type: %d, PDB_ITEM: %d\n",  ptype[i-1].type, GIMP_PDB_ITEM);
389 #endif
390 	switch (ptype[i-1].type) {
391 	case GIMP_PDB_INT32:
392 	    check((x = PyNumber_Int(item)) == NULL);
393 	    ret[i].data.d_int32 = (gint32)PyInt_AsLong(x);
394 	    Py_DECREF(x);
395 	    break;
396 	case GIMP_PDB_INT16:
397 	    check((x = PyNumber_Int(item)) == NULL);
398 	    ret[i].data.d_int16 = (gint16)PyInt_AsLong(x);
399 	    Py_DECREF(x);
400 	    break;
401 	case GIMP_PDB_INT8:
402 	    check((x = PyNumber_Int(item)) == NULL);
403 	    ret[i].data.d_int8 = (guint8)PyInt_AsLong(x);
404 	    Py_DECREF(x);
405 	    break;
406 	case GIMP_PDB_FLOAT:
407 	    check((x = PyNumber_Float(item)) == NULL);
408 	    ret[i].data.d_float = PyFloat_AsDouble(x);
409 	    Py_DECREF(x);
410 	    break;
411 	case GIMP_PDB_STRING:
412 	    if (item == Py_None) {
413 		ret[i].data.d_string = NULL;
414 		break;
415 	    }
416 	    check((x = PyObject_Str(item)) == NULL);
417 	    ret[i].data.d_string = g_strdup(PyString_AsString(x));
418 	    Py_DECREF(x);
419 	    break;
420 	case GIMP_PDB_INT32ARRAY:
421 	    check(!PySequence_Check(item));
422 	    len = PySequence_Length(item);
423 	    i32a = g_new(gint32, len);
424 	    for (j = 0; j < len; j++) {
425 		x = PySequence_GetItem(item, j);
426 		arraycheck((y=PyNumber_Int(x))==NULL,
427 			   i32a);
428 		i32a[j] = PyInt_AsLong(y);
429 		Py_DECREF(y);
430 	    }
431 	    ret[i].data.d_int32array = i32a;
432 	    break;
433 	case GIMP_PDB_INT16ARRAY:
434 	    check(!PySequence_Check(item));
435 	    len = PySequence_Length(item);
436 	    i16a = g_new(gint16, len);
437 	    for (j = 0; j < len; j++) {
438 		x = PySequence_GetItem(item, j);
439 		arraycheck((y=PyNumber_Int(x))==NULL,
440 			   i16a);
441 		i16a[j] = PyInt_AsLong(y);
442 		Py_DECREF(y);
443 	    }
444 	    ret[i].data.d_int16array = i16a;
445 	    break;
446 	case GIMP_PDB_INT8ARRAY:
447 	    check(!PySequence_Check(item));
448 	    len = PySequence_Length(item);
449 	    i8a = g_new(guint8, len);
450 	    for (j = 0; j < len; j++) {
451 		x = PySequence_GetItem(item, j);
452 		arraycheck((y=PyNumber_Int(x))==NULL,
453 			   i8a);
454 		i8a[j] = PyInt_AsLong(y);
455 		Py_DECREF(y);
456 	    }
457 	    ret[i].data.d_int8array = i8a;
458 	    break;
459 	case GIMP_PDB_FLOATARRAY:
460 	    check(!PySequence_Check(item));
461 	    len = PySequence_Length(item);
462 	    fa = g_new(gdouble, len);
463 	    for (j = 0; j < len; j++) {
464 		x = PySequence_GetItem(item, j);
465 		arraycheck((y=PyNumber_Float(x))==NULL,
466 			   fa);
467 		fa[j] = PyFloat_AsDouble(y);
468 		Py_DECREF(y);
469 	    }
470 	    ret[i].data.d_floatarray = fa;
471 	    break;
472 	case GIMP_PDB_STRINGARRAY:
473 	    check(!PySequence_Check(item));
474 	    len = PySequence_Length(item);
475 	    sa = g_new(gchar *, len);
476 	    for (j = 0; j < len; j++) {
477 		x = PySequence_GetItem(item, j);
478 		if (x == Py_None) {
479 		    sa[j] = NULL;
480 		    continue;
481 		}
482 		arraycheck((y=PyObject_Str(x))==NULL,
483 			   sa);
484 		sa[j] = g_strdup(PyString_AsString(y));
485 		Py_DECREF(y);
486 	    }
487 	    ret[i].data.d_stringarray = sa;
488 	    break;
489 	case GIMP_PDB_COLOR:
490 	    {
491                 GimpRGB rgb;
492 
493                 if (!pygimp_rgb_from_pyobject(item, &rgb)) {
494                     Py_DECREF(tuple);
495                     gimp_destroy_params(ret, nparams);
496                     return NULL;
497 		}
498 
499                 ret[i].data.d_color = rgb;
500 	    }
501 	    break;
502 /*
503 	case GIMP_PDB_REGION:
504 	    check(!PySequence_Check(item) ||
505 		  PySequence_Length(item) < 4);
506 	    x = PySequence_GetItem(item, 0);
507 	    y = PySequence_GetItem(item, 1);
508 	    w = PySequence_GetItem(item, 2);
509 	    h = PySequence_GetItem(item, 3);
510 	    check(!PyInt_Check(x) || !PyInt_Check(y) ||
511 		  !PyInt_Check(w) || !PyInt_Check(h));
512 	    ret[i].data.d_region.x = PyInt_AsLong(x);
513 	    ret[i].data.d_region.y = PyInt_AsLong(y);
514 	    ret[i].data.d_region.width = PyInt_AsLong(w);
515 	    ret[i].data.d_region.height = PyInt_AsLong(h);
516 	    break;
517 */
518 	case GIMP_PDB_DISPLAY:
519             if (item == Py_None) {
520                 ret[i].data.d_display = -1;
521                 break;
522             }
523 	    check(!pygimp_display_check(item));
524 	    ret[i].data.d_display = ((PyGimpDisplay *)item)->ID;
525 	    break;
526 	case GIMP_PDB_IMAGE:
527 	    if (item == Py_None) {
528 		ret[i].data.d_image = -1;
529 		break;
530 	    }
531 	    check(!pygimp_image_check(item));
532 	    ret[i].data.d_image = ((PyGimpImage *)item)->ID;
533 	    break;
534 	case GIMP_PDB_LAYER:
535 	    if (item == Py_None) {
536 		ret[i].data.d_layer = -1;
537 		break;
538 	    }
539 	    check(!pygimp_layer_check(item));
540 	    ret[i].data.d_layer = ((PyGimpLayer *)item)->ID;
541 	    break;
542 	case GIMP_PDB_CHANNEL:
543 	    if (item == Py_None) {
544 		ret[i].data.d_channel = -1;
545 		break;
546 	    }
547 	    check(!pygimp_channel_check(item));
548 	    ret[i].data.d_channel = ((PyGimpChannel *)item)->ID;
549 	    break;
550 	case GIMP_PDB_ITEM:
551 	    if (item == Py_None) {
552 		ret[i].data.d_channel = -1;
553 		break;
554 	    }
555 	    check(!pygimp_item_check(item));
556 	    ret[i].data.d_item = ((PyGimpItem *)item)->ID;
557 	    break;
558 	case GIMP_PDB_DRAWABLE:
559 	    if (item == Py_None) {
560 		ret[i].data.d_channel = -1;
561 		break;
562 	    }
563 	    check(!pygimp_drawable_check(item));
564 	    ret[i].data.d_channel = ((PyGimpDrawable *)item)->ID;
565 	    break;
566 	case GIMP_PDB_SELECTION:
567 	    if (item == Py_None) {
568 		ret[i].data.d_channel = -1;
569 		break;
570 	    }
571 	    check(!pygimp_channel_check(item));
572 	    ret[i].data.d_selection = ((PyGimpChannel *)item)->ID;
573 	    break;
574 	case GIMP_PDB_COLORARRAY:
575 	    {
576                 GimpRGB *rgb;
577 
578 		check(!PySequence_Check(item));
579 		len = PySequence_Length(item);
580 		rgb = g_new(GimpRGB, len);
581 		for (j = 0; j < len; j++) {
582 		    if (!pygimp_rgb_from_pyobject(item, &rgb[j])) {
583 			Py_DECREF(tuple);
584 			g_free(rgb);
585 			gimp_destroy_params(ret, nparams);
586 			return NULL;
587 		    }
588 		}
589                 ret[i].data.d_colorarray = rgb;
590 	    }
591 	    break;
592 	case GIMP_PDB_VECTORS:
593 	    if (item == Py_None) {
594 		ret[i].data.d_vectors = -1;
595 		break;
596 	    }
597 	    check(!pygimp_vectors_check(item));
598 	    ret[i].data.d_vectors = ((PyGimpVectors *)item)->ID;
599 	    break;
600 	case GIMP_PDB_PARASITE:
601 	    /* can't do anything, since size of GimpParasite is not known */
602 	    break;
603 	case GIMP_PDB_STATUS:
604 	    check(!PyInt_Check(item));
605 	    ret[i].data.d_status = PyInt_AsLong(item);
606 	    break;
607 	case GIMP_PDB_END:
608 	    break;
609 	}
610 #undef check
611 #undef arraycheck
612 	ret[i].type = ptype[i-1].type;
613     }
614 
615     Py_DECREF(tuple);
616     return ret;
617 }
618 
619 /* ---------------------------------------------------------------- */
620 
621 static PyObject *
pdb_query(PyGimpPDB * self,PyObject * args)622 pdb_query(PyGimpPDB *self, PyObject *args)
623 {
624     char *n=".*", *b=".*", *h=".*", *a=".*", *c=".*", *d=".*", *t=".*";
625     int num, i;
626     char **names;
627     PyObject *ret;
628 
629     if (!PyArg_ParseTuple(args, "|zzzzzzz:gimp.pdb.query", &n, &b, &h, &a,
630 			  &c, &d, &t))
631 	return NULL;
632 
633     gimp_procedural_db_query(n, b, h, a, c, d, t, &num, &names);
634 
635     ret = PyList_New(num);
636 
637     for (i = 0; i < num; i++)
638 	PyList_SetItem(ret, i, PyString_FromString(names[i]));
639 
640     g_strfreev(names);
641 
642     return ret;
643 }
644 
645 static PyMethodDef pdb_methods[] = {
646     {"query", (PyCFunction)pdb_query, METH_VARARGS},
647     {NULL,		NULL}		/* sentinel */
648 };
649 
650 /* ---------- */
651 
652 
653 PyObject *
pygimp_pdb_new(void)654 pygimp_pdb_new(void)
655 {
656     PyGimpPDB *self = PyObject_NEW(PyGimpPDB, &PyGimpPDB_Type);
657 
658     if (self == NULL)
659 	return NULL;
660 
661     return (PyObject *)self;
662 }
663 
664 
665 static void
pdb_dealloc(PyGimpPDB * self)666 pdb_dealloc(PyGimpPDB *self)
667 {
668     PyObject_DEL(self);
669 }
670 
671 static PyObject *
pdb_repr(PyGimpPDB * self)672 pdb_repr(PyGimpPDB *self)
673 {
674     return PyString_FromString("<gimp procedural database>");
675 }
676 
677 /* Code to access pdb objects as mappings */
678 
679 static PyObject *
pdb_subscript(PyGimpPDB * self,PyObject * key)680 pdb_subscript(PyGimpPDB *self, PyObject *key)
681 {
682     PyObject *r;
683 
684     if (!PyString_Check(key)) {
685 	PyErr_SetString(PyExc_TypeError, "Subscript must be a string");
686 	return NULL;
687     }
688 
689     r = (PyObject *)pygimp_pdb_function_new_from_proc_db(PyString_AsString(key));
690 
691     if (r == NULL) {
692 	PyErr_Clear();
693 	PyErr_SetObject(PyExc_KeyError, key);
694     }
695 
696     return r;
697 }
698 
699 static PyMappingMethods pdb_as_mapping = {
700     (lenfunc)0,			/*mp_length*/
701     (binaryfunc)pdb_subscript,	/*mp_subscript*/
702     (objobjargproc)0,		/*mp_ass_subscript*/
703 };
704 
705 /* -------------------------------------------------------- */
706 
707 static PyObject *
build_procedure_list(void)708 build_procedure_list(void)
709 {
710     int num, i;
711     char **names, *name, *p;
712     PyObject *ret;
713 
714     gimp_procedural_db_query(".*", ".*", ".*", ".*", ".*", ".*", ".*",
715                              &num, &names);
716 
717     ret = PyList_New(num);
718 
719     for (i = 0; i < num; i++) {
720         name = g_strdup(names[i]);
721         for (p = name; *p != '\0'; p++) {
722             if (*p == '-')
723                 *p = '_';
724 	}
725         PyList_SetItem(ret, i, PyString_FromString(name));
726     }
727 
728     g_strfreev(names);
729 
730     return ret;
731 }
732 
733 static PyObject *
pdb_getattro(PyGimpPDB * self,PyObject * attr)734 pdb_getattro(PyGimpPDB *self, PyObject *attr)
735 {
736     char *attr_name;
737     PyObject *ret;
738 
739     attr_name = PyString_AsString(attr);
740     if (!attr_name) {
741          PyErr_Clear();
742          return PyObject_GenericGetAttr((PyObject *)self, attr);
743     }
744 
745     if (attr_name[0] == '_') {
746         if (!strcmp(attr_name, "__members__")) {
747             return build_procedure_list();
748         } else {
749             return PyObject_GenericGetAttr((PyObject *)self, attr);
750         }
751     }
752 
753     ret = PyObject_GenericGetAttr((PyObject *)self, attr);
754     if (ret)
755         return ret;
756 
757     PyErr_Clear();
758 
759     return pygimp_pdb_function_new_from_proc_db(attr_name);
760 }
761 
762 PyTypeObject PyGimpPDB_Type = {
763     PyObject_HEAD_INIT(NULL)
764     0,                                  /* ob_size */
765     "gimp.PDB",                         /* tp_name */
766     sizeof(PyGimpPDB),                  /* tp_basicsize */
767     0,                                  /* tp_itemsize */
768     /* methods */
769     (destructor)pdb_dealloc,           /* tp_dealloc */
770     (printfunc)0,                       /* tp_print */
771     (getattrfunc)0,                     /* tp_getattr */
772     (setattrfunc)0,                     /* tp_setattr */
773     (cmpfunc)0,                         /* tp_compare */
774     (reprfunc)pdb_repr,                 /* tp_repr */
775     0,                                  /* tp_as_number */
776     0,                                  /* tp_as_sequence */
777     &pdb_as_mapping,                     /* tp_as_mapping */
778     (hashfunc)0,                        /* tp_hash */
779     (ternaryfunc)0,                     /* tp_call */
780     (reprfunc)0,                        /* tp_str */
781     (getattrofunc)pdb_getattro,         /* tp_getattro */
782     (setattrofunc)0,                    /* tp_setattro */
783     0,					/* tp_as_buffer */
784     Py_TPFLAGS_DEFAULT,	                /* tp_flags */
785     NULL, /* Documentation string */
786     (traverseproc)0,			/* tp_traverse */
787     (inquiry)0,				/* tp_clear */
788     (richcmpfunc)0,			/* tp_richcompare */
789     0,					/* tp_weaklistoffset */
790     (getiterfunc)0,			/* tp_iter */
791     (iternextfunc)0,			/* tp_iternext */
792     pdb_methods,			/* tp_methods */
793     0,					/* tp_members */
794     0,					/* tp_getset */
795     (PyTypeObject *)0,			/* tp_base */
796     (PyObject *)0,			/* tp_dict */
797     0,					/* tp_descr_get */
798     0,					/* tp_descr_set */
799     0,					/* tp_dictoffset */
800     (initproc)0,	                /* tp_init */
801     (allocfunc)0,			/* tp_alloc */
802     (newfunc)0,				/* tp_new */
803 };
804 
805 /* End of code for pdb objects */
806 /* -------------------------------------------------------- */
807 
808 
809 static PyObject *
pygimp_pdb_function_new_from_proc_db(char * name)810 pygimp_pdb_function_new_from_proc_db(char *name)
811 {
812     PyObject *ret;
813     char *b,*h,*a,*c,*d;
814     int np, nr;
815     GimpPDBProcType pt;
816     GimpParamDef *p, *r;
817 
818     if (!gimp_procedural_db_proc_info (name, &b, &h, &a, &c, &d, &pt,
819 				       &np, &nr, &p, &r)) {
820 	PyErr_SetString(pygimp_error, "procedure not found");
821 	return NULL;
822     }
823 
824     ret = pygimp_pdb_function_new(name, b, h, a, c, d, pt, np, nr, p, r);
825 
826     g_free(b); g_free(h); g_free(a); g_free(c); g_free(d);
827 
828     return ret;
829 }
830 
831 static void
pf_dealloc(PyGimpPDBFunction * self)832 pf_dealloc(PyGimpPDBFunction *self)
833 {
834     g_free(self->name);
835 
836     Py_DECREF(self->proc_name);
837     Py_DECREF(self->proc_blurb);
838     Py_DECREF(self->proc_help);
839     Py_DECREF(self->proc_author);
840     Py_DECREF(self->proc_copyright);
841     Py_DECREF(self->proc_date);
842     Py_DECREF(self->proc_type);
843     Py_DECREF(self->py_params);
844     Py_DECREF(self->py_return_vals);
845 
846     gimp_destroy_paramdefs(self->params, self->nparams);
847     gimp_destroy_paramdefs(self->return_vals, self->nreturn_vals);
848 
849     PyObject_DEL(self);
850 }
851 
852 #define OFF(x) offsetof(PyGimpPDBFunction, x)
853 static struct PyMemberDef pf_members[] = {
854     {"proc_name",      T_OBJECT, OFF(proc_name),      RO},
855     {"proc_blurb",     T_OBJECT, OFF(proc_blurb),     RO},
856     {"proc_help",      T_OBJECT, OFF(proc_help),      RO},
857     {"proc_author",    T_OBJECT, OFF(proc_author),    RO},
858     {"proc_copyright", T_OBJECT, OFF(proc_copyright), RO},
859     {"proc_date",      T_OBJECT, OFF(proc_date),      RO},
860     {"proc_type",      T_OBJECT, OFF(proc_type),      RO},
861     {"nparams",        T_INT,    OFF(nparams),        RO},
862     {"nreturn_vals",   T_INT,    OFF(nreturn_vals),   RO},
863     {"params",         T_OBJECT, OFF(py_params),      RO},
864     {"return_vals",    T_OBJECT, OFF(py_return_vals), RO},
865     {NULL}  /* Sentinel */
866 };
867 #undef OFF
868 
869 static PyObject *
pf_repr(PyGimpPDBFunction * self)870 pf_repr(PyGimpPDBFunction *self)
871 {
872     return PyString_FromFormat("<pdb function '%s'>",
873 			       PyString_AsString(self->proc_name));
874 }
875 
876 static PyObject *
pf_call(PyGimpPDBFunction * self,PyObject * args,PyObject * kwargs)877 pf_call(PyGimpPDBFunction *self, PyObject *args, PyObject *kwargs)
878 {
879     GimpParam *params, *ret;
880     int nret;
881     PyObject *t = NULL, *r;
882     GimpRunMode run_mode = GIMP_RUN_NONINTERACTIVE;
883 
884 #if PG_DEBUG > 0
885     g_printerr("--- %s --- ", PyString_AsString(self->proc_name));
886 #endif
887 
888     if (kwargs) {
889         Py_ssize_t len, pos;
890         PyObject *key, *val;
891 
892         len = PyDict_Size(kwargs);
893 
894         if (len == 1) {
895             pos = 0;
896             PyDict_Next(kwargs, &pos, &key, &val);
897 
898             if (!PyString_Check(key)) {
899                 PyErr_SetString(PyExc_TypeError,
900                                 "keyword argument name is not a string");
901                 return NULL;
902             }
903 
904             if (strcmp(PyString_AsString(key), "run_mode") != 0) {
905                 PyErr_SetString(PyExc_TypeError,
906                                 "only 'run_mode' keyword argument accepted");
907                 return NULL;
908             }
909 
910             if (pyg_enum_get_value(GIMP_TYPE_RUN_MODE, val, (gpointer)&run_mode))
911                 return NULL;
912         } else if (len != 0) {
913             PyErr_SetString(PyExc_TypeError,
914                             "expecting at most one keyword argument");
915             return NULL;
916         }
917     }
918 
919     if (self->nparams > 0 && !strcmp(self->params[0].name, "run-mode")) {
920 	params = pygimp_param_from_tuple(args, self->params + 1,
921 					 self->nparams - 1);
922 
923 	if (params == NULL)
924 	    return NULL;
925 
926 	params[0].type = self->params[0].type;
927 	params[0].data.d_int32 = run_mode;
928 
929 #if PG_DEBUG > 1
930 	pygimp_param_print(self->nparams, params);
931 #endif
932 
933 	ret = gimp_run_procedure2(self->name, &nret, self->nparams, params);
934     } else {
935 	params = pygimp_param_from_tuple(args, self->params, self->nparams);
936 
937 	if (params == NULL)
938 	    return NULL;
939 
940 #if PG_DEBUG > 1
941 	pygimp_param_print(self->nparams, params+1);
942 #endif
943 
944 	ret = gimp_run_procedure2(self->name, &nret, self->nparams, params + 1);
945     }
946 
947     gimp_destroy_params(params, self->nparams);
948 
949     if (!ret) {
950 	PyErr_SetString(pygimp_error, "no status returned");
951 #if PG_DEBUG >= 1
952 	g_printerr("ret == NULL\n");
953 #endif
954 	return NULL;
955     }
956 
957     switch(ret[0].data.d_status) {
958     case GIMP_PDB_SUCCESS:
959 #if PG_DEBUG > 0
960 	g_printerr("success\n");
961 #endif
962 	t = pygimp_param_to_tuple(nret-1, ret+1);
963 	gimp_destroy_params(ret, nret);
964 
965 	if (t == NULL) {
966 	    PyErr_SetString(pygimp_error, "could not make return value");
967 	    return NULL;
968 	}
969 	break;
970 
971     case GIMP_PDB_EXECUTION_ERROR:
972 #if PG_DEBUG > 0
973 	g_printerr("execution error\n");
974 #endif
975         PyErr_SetString(PyExc_RuntimeError, gimp_get_pdb_error());
976 	gimp_destroy_params(ret, nret);
977 	return NULL;
978 
979     case GIMP_PDB_CALLING_ERROR:
980 #if PG_DEBUG > 0
981 	g_printerr("calling error\n");
982 #endif
983         PyErr_SetString(PyExc_RuntimeError, gimp_get_pdb_error());
984 	gimp_destroy_params(ret, nret);
985 	return NULL;
986 
987     case GIMP_PDB_CANCEL:
988 #if PG_DEBUG > 0
989 	g_printerr("cancel\n");
990 #endif
991         PyErr_SetString(PyExc_RuntimeError, gimp_get_pdb_error());
992 	gimp_destroy_params(ret, nret);
993 	return NULL;
994 
995     default:
996 #if PG_DEBUG > 0
997 	g_printerr("unknown - %i (type %i)\n",
998                    ret[0].data.d_status, ret[0].type);
999 #endif
1000 	PyErr_SetString(pygimp_error, "unknown return code");
1001 	return NULL;
1002     }
1003 
1004     if (PyTuple_Size(t) == 1) {
1005 	r = PyTuple_GetItem(t, 0);
1006 	Py_INCREF(r);
1007 	Py_DECREF(t);
1008 	return r;
1009     }
1010 
1011     if (PyTuple_Size(t) == 0) {
1012 	r = Py_None;
1013 	Py_INCREF(r);
1014 	Py_DECREF(t);
1015 	return r;
1016     }
1017 
1018     return t;
1019 }
1020 
1021 
1022 PyTypeObject PyGimpPDBFunction_Type = {
1023     PyObject_HEAD_INIT(NULL)
1024     0,                                  /* ob_size */
1025     "gimp.PDBFunction",                 /* tp_name */
1026     sizeof(PyGimpPDBFunction),          /* tp_basicsize */
1027     0,                                  /* tp_itemsize */
1028     /* methods */
1029     (destructor)pf_dealloc,             /* tp_dealloc */
1030     (printfunc)0,                       /* tp_print */
1031     (getattrfunc)0,                     /* tp_getattr */
1032     (setattrfunc)0,                     /* tp_setattr */
1033     (cmpfunc)0,                         /* tp_compare */
1034     (reprfunc)pf_repr,                  /* tp_repr */
1035     0,                                  /* tp_as_number */
1036     0,                                  /* tp_as_sequence */
1037     0,                                  /* tp_as_mapping */
1038     (hashfunc)0,                        /* tp_hash */
1039     (ternaryfunc)pf_call,               /* tp_call */
1040     (reprfunc)0,                        /* tp_str */
1041     (getattrofunc)0,                    /* tp_getattro */
1042     (setattrofunc)0,                    /* tp_setattro */
1043     0,					/* tp_as_buffer */
1044     Py_TPFLAGS_DEFAULT,	                /* tp_flags */
1045     NULL, /* Documentation string */
1046     (traverseproc)0,			/* tp_traverse */
1047     (inquiry)0,				/* tp_clear */
1048     (richcmpfunc)0,			/* tp_richcompare */
1049     0,					/* tp_weaklistoffset */
1050     (getiterfunc)0,			/* tp_iter */
1051     (iternextfunc)0,			/* tp_iternext */
1052     0,					/* tp_methods */
1053     pf_members,				/* tp_members */
1054     0,					/* tp_getset */
1055     (PyTypeObject *)0,			/* tp_base */
1056     (PyObject *)0,			/* tp_dict */
1057     0,					/* tp_descr_get */
1058     0,					/* tp_descr_set */
1059     0,					/* tp_dictoffset */
1060     (initproc)0,	                /* tp_init */
1061     (allocfunc)0,			/* tp_alloc */
1062     (newfunc)0,				/* tp_new */
1063 };
1064 
1065 PyObject *
pygimp_pdb_function_new(const char * name,const char * blurb,const char * help,const char * author,const char * copyright,const char * date,GimpPDBProcType proc_type,int n_params,int n_return_vals,GimpParamDef * params,GimpParamDef * return_vals)1066 pygimp_pdb_function_new(const char *name, const char *blurb, const char *help,
1067 			const char *author, const char *copyright,
1068 			const char *date, GimpPDBProcType proc_type,
1069 			int n_params, int n_return_vals,
1070 			GimpParamDef *params, GimpParamDef *return_vals)
1071 {
1072     PyGimpPDBFunction *self;
1073     int i;
1074 
1075     self = PyObject_NEW(PyGimpPDBFunction, &PyGimpPDBFunction_Type);
1076 
1077     if (self == NULL)
1078 	return NULL;
1079 
1080     self->name = g_strdup(name);
1081     self->proc_name = PyString_FromString(name ? name : "");
1082     self->proc_blurb = PyString_FromString(blurb ? blurb : "");
1083     self->proc_help = PyString_FromString(help ? help : "");
1084     self->proc_author = PyString_FromString(author ? author : "");
1085     self->proc_copyright = PyString_FromString(copyright ? copyright : "");
1086     self->proc_date = PyString_FromString(date ? date : "");
1087     self->proc_type = PyInt_FromLong(proc_type);
1088     self->nparams = n_params;
1089     self->nreturn_vals = n_return_vals;
1090     self->params = params;
1091     self->return_vals = return_vals;
1092 
1093     self->py_params = PyTuple_New(n_params);
1094     for (i = 0; i < n_params; i++)
1095 	PyTuple_SetItem(self->py_params, i,
1096 			Py_BuildValue("(iss)",
1097 				      params[i].type,
1098 				      params[i].name,
1099 				      params[i].description));
1100 
1101     self->py_return_vals = PyTuple_New(n_return_vals);
1102     for (i = 0; i < n_return_vals; i++)
1103 	PyTuple_SetItem(self->py_return_vals, i,
1104 			Py_BuildValue("(iss)",
1105 				      return_vals[i].type,
1106 				      return_vals[i].name,
1107 				      return_vals[i].description));
1108 
1109     return (PyObject *)self;
1110 }
1111