diff --git a/plug-ins/script-fu/libscriptfu/scheme-marshal.c b/plug-ins/script-fu/libscriptfu/scheme-marshal.c index ddcd86b8f6..ca1e1230f5 100644 --- a/plug-ins/script-fu/libscriptfu/scheme-marshal.c +++ b/plug-ins/script-fu/libscriptfu/scheme-marshal.c @@ -79,11 +79,13 @@ marshal_ID_to_item (scheme *sc, * Requires ID's of instances of GimpItem */ pointer -marshal_vector_to_item_array (scheme *sc, - pointer vector, - GValue *value) +marshal_vector_to_item_array (scheme *sc, + pointer vector, + GValue *value, + gchar **strvalue) { GObject **object_array; + GString *v = NULL; gint id; pointer error; @@ -92,6 +94,8 @@ marshal_vector_to_item_array (scheme *sc, /* empty vector will produce empty GimpObjectArray */ object_array = g_new0 (GObject *, num_elements + 1); + if (strvalue) + v = g_string_new (""); for (int j = 0; j < num_elements; ++j) { @@ -100,6 +104,8 @@ marshal_vector_to_item_array (scheme *sc, if (!sc->vptr->is_number (element)) { g_free (object_array); + if (v) + g_string_free (v, TRUE); return script_error (sc, "Expected numeric in vector of ID", vector); /* FUTURE more detailed error msg: * return script_type_error_in_container (sc, "numeric", i, j, proc_name, vector); @@ -111,8 +117,13 @@ marshal_vector_to_item_array (scheme *sc, if (error) { g_free (object_array); + if (v) + g_string_free (v, TRUE); return error; } + + if (v) + g_string_append_printf (v, "%s%d", j == 0 ? "" : " ", id); } /* Shallow copy. @@ -122,6 +133,11 @@ marshal_vector_to_item_array (scheme *sc, * and fails if we default to G_TYPE_INVALID but passes if ITEM. */ g_value_set_boxed (value, (gpointer) object_array); + if (v) + { + *strvalue = g_strdup_printf ("(%s)", v->str); + g_string_free (v, TRUE); + } g_free (object_array); @@ -258,12 +274,18 @@ get_item_from_ID_in_script (scheme *sc, * A list longer than expected (>4) is not an error, but extra list is not used. */ static void -marshal_list_of_numeric_to_rgba (scheme *sc, - pointer color_list, - guchar (*rgba)[4], /* OUT */ - guint *length) /* OUT */ +marshal_list_of_numeric_to_rgba (scheme *sc, + pointer color_list, + guchar (*rgba)[4], /* OUT */ + guint *length, /* OUT */ + gchar **strvalue) { + GString *v = NULL; + *length = 0; + if (strvalue) + v = g_string_new (""); + for (guint i=0; i<4; i++) { if (sc->vptr->is_number (sc->vptr->pair_car (color_list))) @@ -272,14 +294,31 @@ marshal_list_of_numeric_to_rgba (scheme *sc, 0, 255); *length = *length + 1; color_list = sc->vptr->pair_cdr (color_list); + + if (v) + g_string_append_printf (v, "%s%d", i == 0 ? "" : " ", (*rgba)[i]); } else { /* Reached end of list or non-numeric. */ + if (v) + { + if (*length != 0) + *strvalue = g_strdup_printf ("'(%s)", v->str); + + g_string_free (v, TRUE); + } + return; } } /* *length is in [0,4] and *rgba is filled in with same count. */ + + if (v) + { + *strvalue = g_strdup_printf ("'(%s)", v->str); + g_string_free (v, TRUE); + } } /* Walk a C array of bytes (rgba) creating Scheme list of numeric. @@ -313,16 +352,15 @@ marshal_rgba_to_list_of_numeric (scheme *sc, * - list elements not numbers. */ GeglColor * -marshal_component_list_to_color (scheme *sc, - pointer color_list) +marshal_component_list_to_color (scheme *sc, + pointer color_list, + gchar **strvalue) { GeglColor *color_result; guchar rgba[4]; guint list_length; - - - marshal_list_of_numeric_to_rgba (sc, color_list, &rgba, &list_length); + marshal_list_of_numeric_to_rgba (sc, color_list, &rgba, &list_length, strvalue); /* list_length is the count of numerics used. */ /* Dispatch on list length and create different format colors */ diff --git a/plug-ins/script-fu/libscriptfu/scheme-marshal.h b/plug-ins/script-fu/libscriptfu/scheme-marshal.h index e92415e1bf..c11f5bc2cb 100644 --- a/plug-ins/script-fu/libscriptfu/scheme-marshal.h +++ b/plug-ins/script-fu/libscriptfu/scheme-marshal.h @@ -25,7 +25,8 @@ pointer marshal_ID_to_item (scheme *sc, pointer marshal_vector_to_item_array (scheme *sc, pointer a, - GValue *value); + GValue *value, + gchar **strvalue); void marshal_path_string_to_gfile (scheme *sc, pointer a, @@ -38,7 +39,8 @@ pointer marshal_returned_object_array_to_vector (scheme *sc, gchar* marshal_returned_gfile_to_string (GValue *value); GeglColor* marshal_component_list_to_color (scheme *sc, - pointer list); + pointer list, + gchar **strvalue); pointer marshal_color_to_component_list (scheme *sc, GeglColor *color); diff --git a/plug-ins/script-fu/libscriptfu/scheme-wrapper.c b/plug-ins/script-fu/libscriptfu/scheme-wrapper.c index 99dc7ae6a3..b624769954 100644 --- a/plug-ins/script-fu/libscriptfu/scheme-wrapper.c +++ b/plug-ins/script-fu/libscriptfu/scheme-wrapper.c @@ -70,7 +70,8 @@ static pointer script_fu_marshal_arg_to_value (scheme const gchar *proc_name, gint arg_index, GParamSpec *arg_spec, - GValue *value); + GValue *value, + gchar **strvalue); static pointer script_fu_marshal_procedure_call (scheme *sc, pointer a, @@ -730,12 +731,13 @@ ts_load_file (const gchar *dirname, /* Returns pointer to sc->NIL (normal) or pointer to error. */ static pointer -script_fu_marshal_arg_to_value (scheme *sc, - pointer a, - const gchar *proc_name, - gint arg_index, - GParamSpec *arg_spec, - GValue *value) +script_fu_marshal_arg_to_value (scheme *sc, + pointer a, + const gchar *proc_name, + gint arg_index, + GParamSpec *arg_spec, + GValue *value, + gchar **strvalue) { pointer arg_val; pointer vector; @@ -763,6 +765,8 @@ script_fu_marshal_arg_to_value (scheme *sc, return script_int_range_error (sc, arg_index, proc_name, ispec->minimum, ispec->maximum, v); g_value_set_int (value, v); + if (strvalue) + *strvalue = g_strdup_printf ("%d", v); } } else if (G_VALUE_HOLDS_UINT (value)) @@ -780,6 +784,8 @@ script_fu_marshal_arg_to_value (scheme *sc, return script_int_range_error (sc, arg_index, proc_name, ispec->minimum, ispec->maximum, v); g_value_set_uint (value, v); + if (strvalue) + *strvalue = g_strdup_printf ("%u", v); } } else if (G_VALUE_HOLDS_UCHAR (value)) @@ -797,6 +803,8 @@ script_fu_marshal_arg_to_value (scheme *sc, return script_int_range_error (sc, arg_index, proc_name, cspec->minimum, cspec->maximum, c); g_value_set_uchar (value, c); + if (strvalue) + *strvalue = g_strdup_printf ("%d", c); } } else if (G_VALUE_HOLDS_DOUBLE (value)) @@ -814,26 +822,38 @@ script_fu_marshal_arg_to_value (scheme *sc, return script_float_range_error (sc, arg_index, proc_name, dspec->minimum, dspec->maximum, d); g_value_set_double (value, d); + if (strvalue) + *strvalue = g_strdup_printf ("%f", d); } } else if (G_VALUE_HOLDS_ENUM (value)) { if (! sc->vptr->is_number (arg_val)) - return script_type_error (sc, "numeric", arg_index, proc_name); + { + return script_type_error (sc, "numeric", arg_index, proc_name); + } else - g_value_set_enum (value, - sc->vptr->ivalue (arg_val)); + { + gint e = sc->vptr->ivalue (arg_val); + + g_value_set_enum (value, e); + if (strvalue) + *strvalue = g_strdup_printf ("%d", e); + } } else if (G_VALUE_HOLDS_BOOLEAN (value)) { if (sc->vptr->is_number (arg_val)) { + gboolean b = sc->vptr->ivalue (arg_val); + /* Bind according to C idiom: 0 is false, other numeric values true. * This is not strict Scheme: 0 is truthy in Scheme. * This lets FALSE still work, where FALSE is a deprecated symbol for 0. */ - g_value_set_boolean (value, - sc->vptr->ivalue (arg_val)); + g_value_set_boolean (value, b); + if (strvalue) + *strvalue = g_strdup_printf ("%s", b ? "TRUE" : "FALSE"); } else { @@ -847,6 +867,8 @@ script_fu_marshal_arg_to_value (scheme *sc, */ gboolean truth_value = ! (arg_val == sc->F); g_value_set_boolean (value, truth_value); + if (strvalue) + *strvalue = g_strdup_printf ("%s", truth_value ? "TRUE" : "FALSE"); } else { @@ -858,10 +880,21 @@ script_fu_marshal_arg_to_value (scheme *sc, else if (G_VALUE_HOLDS_STRING (value)) { if (! sc->vptr->is_string (arg_val)) - return script_type_error (sc, "string", arg_index, proc_name); + { + return script_type_error (sc, "string", arg_index, proc_name); + } else - g_value_set_string (value, - sc->vptr->string_value (arg_val)); + { + const gchar *s = sc->vptr->string_value (arg_val); + + g_value_set_string (value, s); + if (strvalue) + { + gchar *escaped = g_strescape (s, NULL); + *strvalue = g_strdup_printf ("\"%s\"", escaped); + g_free (escaped); + } + } } else if (G_VALUE_HOLDS (value, G_TYPE_STRV)) { @@ -872,11 +905,14 @@ script_fu_marshal_arg_to_value (scheme *sc, } else { - gchar **array; + gchar **array; + GString *v = NULL; n_elements = sc->vptr->list_length (sc, vector); array = g_new0 (gchar *, n_elements + 1); + if (strvalue) + v = g_string_new (""); for (j = 0; j < n_elements; j++) { @@ -888,10 +924,18 @@ script_fu_marshal_arg_to_value (scheme *sc, "Item %d in vector is not a string (argument %d for function %s)", j+1, arg_index+1, proc_name); g_strfreev (array); + if (v) + g_string_free (v, TRUE); return foreign_error (sc, error_str, vector); } array[j] = g_strdup (sc->vptr->string_value (v_element)); + if (v) + { + gchar *escaped = g_strescape (array[j], NULL); + g_string_append_printf (v, "%s\"%s\"", j == 0 ? "" : " ", escaped); + g_free (escaped); + } vector = sc->vptr->pair_cdr (vector); } @@ -911,6 +955,12 @@ script_fu_marshal_arg_to_value (scheme *sc, } } #endif + + if (v) + { + *strvalue = g_strdup_printf ("#(%s)", v->str); + g_string_free (v, TRUE); + } } } else if (GIMP_VALUE_HOLDS_DISPLAY (value)) @@ -921,10 +971,15 @@ script_fu_marshal_arg_to_value (scheme *sc, } else { - GimpDisplay *display = - gimp_display_get_by_id (sc->vptr->ivalue (arg_val)); + GimpDisplay *display; + gint id = sc->vptr->ivalue (arg_val); + + display = gimp_display_get_by_id (id); g_value_set_object (value, display); + + if (strvalue) + *strvalue = g_strdup_printf ("%d", id); } } else if (GIMP_VALUE_HOLDS_IMAGE (value)) @@ -935,10 +990,15 @@ script_fu_marshal_arg_to_value (scheme *sc, } else { - GimpImage *image = - gimp_image_get_by_id (sc->vptr->ivalue (arg_val)); + GimpImage *image; + gint id = sc->vptr->ivalue (arg_val); + + image = gimp_image_get_by_id (id); g_value_set_object (value, image); + + if (strvalue) + *strvalue = g_strdup_printf ("%d", id); } } else if (GIMP_VALUE_HOLDS_LAYER (value)) @@ -949,10 +1009,15 @@ script_fu_marshal_arg_to_value (scheme *sc, } else { - GimpLayer *layer = - gimp_layer_get_by_id (sc->vptr->ivalue (arg_val)); + GimpLayer *layer; + gint id = sc->vptr->ivalue (arg_val); + + layer = gimp_layer_get_by_id (id); g_value_set_object (value, layer); + + if (strvalue) + *strvalue = g_strdup_printf ("%d", id); } } else if (GIMP_VALUE_HOLDS_LAYER_MASK (value)) @@ -963,10 +1028,15 @@ script_fu_marshal_arg_to_value (scheme *sc, } else { - GimpLayerMask *layer_mask = - gimp_layer_mask_get_by_id (sc->vptr->ivalue (arg_val)); + GimpLayerMask *layer_mask; + gint id = sc->vptr->ivalue (arg_val); + + layer_mask = gimp_layer_mask_get_by_id (id); g_value_set_object (value, layer_mask); + + if (strvalue) + *strvalue = g_strdup_printf ("%d", id); } } else if (GIMP_VALUE_HOLDS_CHANNEL (value)) @@ -977,10 +1047,15 @@ script_fu_marshal_arg_to_value (scheme *sc, } else { - GimpChannel *channel = - gimp_channel_get_by_id (sc->vptr->ivalue (arg_val)); + GimpChannel *channel; + gint id = sc->vptr->ivalue (arg_val); + + channel = gimp_channel_get_by_id (id); g_value_set_object (value, channel); + + if (strvalue) + *strvalue = g_strdup_printf ("%d", id); } } else if (GIMP_VALUE_HOLDS_DRAWABLE (value)) @@ -996,6 +1071,9 @@ script_fu_marshal_arg_to_value (scheme *sc, pointer error = marshal_ID_to_item (sc, a, id, value); if (error) return error; + + if (strvalue) + *strvalue = g_strdup_printf ("%d", id); } } else if (GIMP_VALUE_HOLDS_PATH (value)) @@ -1006,10 +1084,15 @@ script_fu_marshal_arg_to_value (scheme *sc, } else { - GimpPath *path = - gimp_path_get_by_id (sc->vptr->ivalue (arg_val)); + GimpPath *path; + gint id = sc->vptr->ivalue (arg_val); + + path = gimp_path_get_by_id (id); g_value_set_object (value, path); + + if (strvalue) + *strvalue = g_strdup_printf ("%d", id); } } else if (GIMP_VALUE_HOLDS_ITEM (value)) @@ -1020,12 +1103,11 @@ script_fu_marshal_arg_to_value (scheme *sc, } else { - gint item_ID; - item_ID = sc->vptr->ivalue (arg_val); + gint id = sc->vptr->ivalue (arg_val); - if (gimp_item_id_is_valid (item_ID)) + if (gimp_item_id_is_valid (id)) { - GimpItem *item = gimp_item_get_by_id (item_ID); + GimpItem *item = gimp_item_get_by_id (id); g_value_set_object (value, item); } else @@ -1035,6 +1117,9 @@ script_fu_marshal_arg_to_value (scheme *sc, */ g_value_set_object (value, NULL); } + + if (strvalue) + *strvalue = g_strdup_printf ("%d", id); } } else if (GIMP_VALUE_HOLDS_DRAWABLE_FILTER (value)) @@ -1045,9 +1130,7 @@ script_fu_marshal_arg_to_value (scheme *sc, } else { - gint id; - - id = sc->vptr->ivalue (arg_val); + gint id = sc->vptr->ivalue (arg_val); if (gimp_drawable_filter_id_is_valid (id)) { @@ -1062,6 +1145,9 @@ script_fu_marshal_arg_to_value (scheme *sc, */ g_value_set_object (value, NULL); } + + if (strvalue) + *strvalue = g_strdup_printf ("%d", id); } } else if (GIMP_VALUE_HOLDS_INT32_ARRAY (value)) @@ -1092,11 +1178,15 @@ script_fu_marshal_arg_to_value (scheme *sc, * FUTURE: List must be *exactly* n_elements long. * n_elements != sc->vptr->list_length (sc, vector)) */ - gint32 *array; + gint32 *array; + GString *v = NULL; n_elements = sc->vptr->vector_length (vector); array = g_new0 (gint32, n_elements); + if (strvalue) + v = g_string_new (""); + for (j = 0; j < n_elements; j++) { pointer v_element = sc->vptr->vector_elem (vector, j); @@ -1105,13 +1195,22 @@ script_fu_marshal_arg_to_value (scheme *sc, if (! sc->vptr->is_number (v_element)) { g_free (array); + if (v) + g_string_free (v, TRUE); return script_type_error_in_container (sc, "numeric", arg_index, j, proc_name, vector); } array[j] = (gint32) sc->vptr->ivalue (v_element); + if (v) + g_string_append_printf (v, "%s%d", j == 0 ? "" : " ", array[j]); } gimp_value_take_int32_array (value, array, n_elements); + if (v) + { + *strvalue = g_strdup_printf ("#(%s)", v->str); + g_string_free (v, TRUE); + } debug_vector (sc, vector, "%ld"); } @@ -1125,11 +1224,14 @@ script_fu_marshal_arg_to_value (scheme *sc, } else { - guint8 *array; + guint8 *array; + GString *v = NULL; n_elements = sc->vptr->vector_length (vector); array = g_new0 (guint8, n_elements); + if (strvalue) + v = g_string_new (""); for (j = 0; j < n_elements; j++) { @@ -1138,13 +1240,22 @@ script_fu_marshal_arg_to_value (scheme *sc, if (!sc->vptr->is_number (v_element)) { g_free (array); + if (v) + g_string_free (v, TRUE); return script_type_error_in_container (sc, "numeric", arg_index, j, proc_name, vector); } array[j] = (guint8) sc->vptr->ivalue (v_element); + if (v) + g_string_append_printf (v, "%s%d", j == 0 ? "" : " ", array[j]); } g_value_take_boxed (value, g_bytes_new_take (array, n_elements)); + if (v) + { + *strvalue = g_strdup_printf ("#(%s)", v->str); + g_string_free (v, TRUE); + } debug_vector (sc, vector, "%ld"); } @@ -1159,9 +1270,12 @@ script_fu_marshal_arg_to_value (scheme *sc, else { gdouble *array; + GString *v = NULL; n_elements = sc->vptr->vector_length (vector); array = g_new0 (gdouble, n_elements); + if (strvalue) + v = g_string_new (""); for (j = 0; j < n_elements; j++) { @@ -1170,13 +1284,22 @@ script_fu_marshal_arg_to_value (scheme *sc, if (!sc->vptr->is_number (v_element)) { g_free (array); + if (v) + g_string_free (v, TRUE); return script_type_error_in_container (sc, "numeric", arg_index, j, proc_name, vector); } array[j] = (gdouble) sc->vptr->rvalue (v_element); + if (v) + g_string_append_printf (v, "%s%f", j == 0 ? "" : " ", array[j]); } gimp_value_take_double_array (value, array, n_elements); + if (v) + { + *strvalue = g_strdup_printf ("#(%s)", v->str); + g_string_free (v, TRUE); + } debug_vector (sc, vector, "%f"); } @@ -1191,12 +1314,15 @@ script_fu_marshal_arg_to_value (scheme *sc, if (! (color = sf_color_get_color_from_name (color_string))) return script_type_error (sc, "color string", arg_index, proc_name); + + if (strvalue) + *strvalue = g_strdup_printf ("\"%s\"", color_string); } else if (sc->vptr->is_list (sc, arg_val)) { pointer color_list = arg_val; - if (! (color = marshal_component_list_to_color (sc, color_list))) + if (! (color = marshal_component_list_to_color (sc, color_list, strvalue))) return script_type_error (sc, "color list of numeric components", arg_index, proc_name); } else @@ -1217,10 +1343,13 @@ script_fu_marshal_arg_to_value (scheme *sc, else { GeglColor **colors; + GString *v = NULL; n_elements = sc->vptr->vector_length (vector); colors = g_new0 (GeglColor *, n_elements + 1); + if (strvalue) + v = g_string_new (""); for (j = 0; j < n_elements; j++) { @@ -1238,6 +1367,8 @@ script_fu_marshal_arg_to_value (scheme *sc, "Item %d in vector is not a color " "(argument %d for function %s)", j+1, arg_index+1, proc_name); + if (v) + g_string_free (v, TRUE); return script_error (sc, error_str, 0); } @@ -1253,9 +1384,16 @@ script_fu_marshal_arg_to_value (scheme *sc, colors[j] = gegl_color_new (NULL); gegl_color_set_pixel (colors[j], babl_format ("R'G'B' u8"), rgb); + if (v) + g_string_append_printf (v, " '(%d %d %d)", rgb[0], rgb[1], rgb[2]); } g_value_take_boxed (value, colors); + if (v) + { + *strvalue = g_strdup_printf ("#(%s)", v->str); + g_string_free (v, TRUE); + } g_debug ("color vector has %ld elements", sc->vptr->vector_length (vector)); } @@ -1306,6 +1444,16 @@ script_fu_marshal_arg_to_value (scheme *sc, g_debug ("data '%s'", (char *)parasite.data); g_value_set_boxed (value, ¶site); + if (strvalue) + { + gchar *escaped_name = g_strescape (parasite.name, NULL); + gchar *escaped_data = g_strescape (parasite.data, NULL); + + *strvalue = g_strdup_printf ("(\"%s\" %d \"%s\")", + escaped_name, parasite.flags, escaped_data); + g_free (escaped_name); + g_free (escaped_data); + } } } else if (GIMP_VALUE_HOLDS_CORE_OBJECT_ARRAY (value)) @@ -1318,7 +1466,7 @@ script_fu_marshal_arg_to_value (scheme *sc, if (sc->vptr->is_vector (vector)) { - pointer error = marshal_vector_to_item_array (sc, vector, value); + pointer error = marshal_vector_to_item_array (sc, vector, value, strvalue); if (error) return error; } @@ -1332,6 +1480,9 @@ script_fu_marshal_arg_to_value (scheme *sc, if (! sc->vptr->is_string (arg_val)) return script_type_error (sc, "string for path", arg_index, proc_name); marshal_path_string_to_gfile (sc, a, value); + + if (strvalue) + *strvalue = g_strdup_printf ("%s", sc->vptr->string_value (arg_val)); } else if (G_VALUE_TYPE (value) == GIMP_TYPE_PDB_STATUS_TYPE) { @@ -1369,6 +1520,8 @@ script_fu_marshal_arg_to_value (scheme *sc, return script_error (sc, "runtime: resource ID of improper subclass.", a); } g_value_set_object (value, resource); + if (strvalue) + *strvalue = g_strdup_printf ("%d", resource_id); } } else if (GIMP_VALUE_HOLDS_EXPORT_OPTIONS (value)) @@ -1384,6 +1537,8 @@ script_fu_marshal_arg_to_value (scheme *sc, * create a GimpExportOptions (actually a proxy?) */ g_value_set_object (value, NULL); + if (strvalue) + *strvalue = g_strdup_printf ("%d", -1); } else { @@ -1455,6 +1610,8 @@ script_fu_marshal_procedure_call (scheme *sc, arg_specs = gimp_procedure_get_arguments (procedure, &n_arg_specs); actual_arg_count = sc->vptr->list_length (sc, a) - 1; + a = sc->vptr->pair_cdr (a); + /* Check the supplied number of arguments. * This only gives messages to the console. * It does not ensure that the count of supplied args equals the count of formal args. @@ -1466,67 +1623,149 @@ script_fu_marshal_procedure_call (scheme *sc, * Extra supplied args can be discarded. * Formerly, this was a deprecated behavior depending on "permissive". */ - { - if (actual_arg_count > n_arg_specs) - { - /* Permit extra args. Will discard args from script, to next right paren.*/ - g_info ("in script, permitting too many args to %s", proc_name); - } - else if (actual_arg_count < n_arg_specs) - { - /* Permit too few args. The config carries a sane default for most types. */ - g_info ("in script, permitting too few args to %s", proc_name); - } - /* else equal counts of args. */ - } + if (gimp_procedure_is_core (procedure)) + { + if (actual_arg_count > n_arg_specs) + { + /* Permit extra args. Will discard args from script, to next right paren.*/ + g_info ("in script, permitting too many args to %s", proc_name); + } + else if (actual_arg_count < n_arg_specs) + { + /* Permit too few args. The config carries a sane default for most types. */ + g_info ("in script, permitting too few args to %s", proc_name); + } + /* else equal counts of args. */ + } /* Marshall the supplied arguments */ - for (i = 0; i < n_arg_specs; i++) + if (gimp_procedure_is_core (procedure) || + ! sc->vptr->is_arg_name (sc->vptr->pair_car (a))) { - GParamSpec *arg_spec = arg_specs[i]; - GValue value = G_VALUE_INIT; + GString *deprecation_warning = NULL; - consumed_arg_count++; - - if (consumed_arg_count > actual_arg_count) + if (! gimp_procedure_is_core (procedure)) { - /* Exhausted supplied arguments before formal specs. */ - - /* Say formal type of first missing arg. */ - g_warning ("Missing arg type: %s", g_type_name (G_PARAM_SPEC_VALUE_TYPE (arg_spec))); - - /* Break loop over formal specs. Continuation is to call PDB with partial args. */ - break; - } - else - a = sc->vptr->pair_cdr (a); /* advance pointer to next arg in list. */ - - g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (arg_spec)); - - debug_in_arg (sc, a, i, g_type_name (G_VALUE_TYPE (&value))); - - return_val = script_fu_marshal_arg_to_value (sc, a, proc_name, i, arg_spec, &value); - - if (return_val != sc->NIL) - { - g_value_unset (&value); - return return_val; + deprecation_warning = g_string_new ("Calling Plug-In PDB procedures with arguments as an ordered list is deprecated.\n" + "Please use named arguments: ("); + g_string_append (deprecation_warning, proc_name); } - debug_gvalue (&value); - if (g_param_value_validate (arg_spec, &value)) + for (i = 0; i < n_arg_specs; i++) { - gchar error_message[1024]; + GParamSpec *arg_spec = arg_specs[i]; + GValue value = G_VALUE_INIT; + gchar *strvalue = NULL; - g_snprintf (error_message, sizeof (error_message), - "Invalid value for argument %d", - i); + consumed_arg_count++; + + if (consumed_arg_count > actual_arg_count) + { + /* Exhausted supplied arguments before formal specs. */ + + /* Say formal type of first missing arg. */ + g_warning ("Missing arg type: %s", g_type_name (G_PARAM_SPEC_VALUE_TYPE (arg_spec))); + + /* Break loop over formal specs. Continuation is to call PDB with partial args. */ + break; + } + + g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (arg_spec)); + + debug_in_arg (sc, a, i, g_type_name (G_VALUE_TYPE (&value))); + + return_val = script_fu_marshal_arg_to_value (sc, a, proc_name, i, arg_spec, &value, &strvalue); + + if (return_val != sc->NIL) + { + g_value_unset (&value); + return return_val; + } + + debug_gvalue (&value); + if (g_param_value_validate (arg_spec, &value)) + { + gchar error_message[1024]; + + g_snprintf (error_message, sizeof (error_message), + "Invalid value for argument %d", + i); + g_value_unset (&value); + + return script_error (sc, error_message, 0); + } + g_object_set_property (G_OBJECT (config), arg_specs[i]->name, &value); g_value_unset (&value); - return script_error (sc, error_message, 0); + if (deprecation_warning != NULL) + g_string_append_printf (deprecation_warning, " #:%s %s", + arg_specs[i]->name, strvalue); + + a = sc->vptr->pair_cdr (a); + + g_free (strvalue); + } + if (deprecation_warning != NULL) + { + g_string_append (deprecation_warning, ")"); + g_warning ("%s", deprecation_warning->str); + + g_string_free (deprecation_warning, TRUE); + } + } + else + { + for (i = 0; i < actual_arg_count; i++) + { + GParamSpec *arg_spec; + gchar *arg_name; + GValue value = G_VALUE_INIT; + + if (! sc->vptr->is_arg_name (sc->vptr->pair_car (a))) + { + g_snprintf (error_str, sizeof (error_str), + "Expected argument name for argument %d", i); + return script_error (sc, error_str, 0); + } + + arg_name = g_strdup (sc->vptr->string_value (sc->vptr->pair_car (a))); + + arg_spec = g_object_class_find_property (G_OBJECT_GET_CLASS (config), arg_name); + if (arg_spec == NULL) + { + g_snprintf (error_str, sizeof (error_str), + "Invalid argument name: %s", arg_name); + g_free (arg_name); + return script_error (sc, error_str, 0); + } + + if (i == actual_arg_count - 1) + { + g_snprintf (error_str, sizeof (error_str), + "Lonely argument with no value: %s", arg_name); + g_free (arg_name); + return script_error (sc, error_str, 0); + } + else + { + a = sc->vptr->pair_cdr (a); + i++; + } + + g_value_init (&value, arg_spec->value_type); + return_val = script_fu_marshal_arg_to_value (sc, a, proc_name, i, arg_spec, &value, NULL); + if (return_val != sc->NIL) + { + g_value_unset (&value); + g_free (arg_name); + return return_val; + } + + g_object_set_property (G_OBJECT (config), arg_name, &value); + g_value_unset (&value); + + a = sc->vptr->pair_cdr (a); } - g_object_set_property (G_OBJECT (config), arg_specs[i]->name, &value); - g_value_unset (&value); } /* Omit refresh scripts from a script, better than crashing, see #575830. */ @@ -1650,7 +1889,7 @@ script_fu_marshal_drawable_filter_configure (scheme *sc, g_value_init (&value, arg_spec->value_type); a = sc->vptr->pair_cdr (a); - return_val = script_fu_marshal_arg_to_value (sc, a, proc_name, arg_index, arg_spec, &value); + return_val = script_fu_marshal_arg_to_value (sc, a, proc_name, arg_index, arg_spec, &value, NULL); if (return_val != sc->NIL) { diff --git a/plug-ins/script-fu/libscriptfu/script-fu-register.c b/plug-ins/script-fu/libscriptfu/script-fu-register.c index bbaa397b22..d9b84b1e97 100644 --- a/plug-ins/script-fu/libscriptfu/script-fu-register.c +++ b/plug-ins/script-fu/libscriptfu/script-fu-register.c @@ -269,7 +269,7 @@ script_fu_parse_default_spec (scheme *sc, else if (sc->vptr->is_list (sc, default_spec)) { /* default_spec is list of numbers. */ - GeglColor *color = marshal_component_list_to_color (sc, default_spec); + GeglColor *color = marshal_component_list_to_color (sc, default_spec, NULL); if (color == NULL) { diff --git a/plug-ins/script-fu/libscriptfu/tinyscheme/scheme.c b/plug-ins/script-fu/libscriptfu/tinyscheme/scheme.c index 6d5cf3c1c3..de26ac398d 100644 --- a/plug-ins/script-fu/libscriptfu/tinyscheme/scheme.c +++ b/plug-ins/script-fu/libscriptfu/tinyscheme/scheme.c @@ -116,6 +116,7 @@ ts_get_error_string (scheme *sc) #define TOK_SHARP_CONST 11 #define TOK_VEC 12 #define TOK_USCORE 13 +#define TOK_ARG 14 #define BACKQUOTE '`' #define DELIMITERS "()\";\f\t\v\n\r " @@ -198,7 +199,8 @@ enum scheme_types { T_PROMISE=13, T_ENVIRONMENT=14, T_BYTE=15, - T_LAST_SYSTEM_TYPE=15 + T_ARG_SLOT=16, + T_LAST_SYSTEM_TYPE=16 }; /* ADJ is enough slack to align cells in a TYPE_BITS-bit boundary */ @@ -241,6 +243,7 @@ static num num_one; #define type(p) (typeflag(p)&T_MASKTYPE) INTERFACE INLINE int is_string(pointer p) { return (type(p)==T_STRING); } +INTERFACE INLINE int is_arg_name(pointer p) { return (type(p)==T_ARG_SLOT); } #define strvalue(p) ((p)->_object._string._svalue) #define strlength(p) ((p)->_object._string._length) @@ -442,6 +445,7 @@ static gunichar inchar(scheme *sc); static void backchar(scheme *sc, gunichar c); static char *readstr_upto(scheme *sc, char *delim); static pointer readstrexp(scheme *sc); +static pointer read_arg_name_exp(scheme *sc); static INLINE int skipspace(scheme *sc); static int token(scheme *sc); static void printslashstring(scheme *sc, char *s, int len); @@ -1159,6 +1163,21 @@ INTERFACE pointer mk_counted_string(scheme *sc, const char *str, int len) { return (x); } +INTERFACE pointer +mk_arg_name (scheme *sc, + const char *str) +{ + gint len = strlen (str); + + pointer x = get_cell (sc, sc->NIL, sc->NIL); + + typeflag(x) = (T_ARG_SLOT | T_ATOM); + strvalue(x) = store_string (sc, len, str, 0); + strlength(x) = len; + + return (x); +} + /* len is the length for the empty string in characters */ INTERFACE pointer mk_empty_string(scheme *sc, int len, gunichar fill) { pointer x = get_cell(sc, sc->NIL, sc->NIL); @@ -1989,6 +2008,35 @@ static pointer readstrexp(scheme *sc) { } } +static pointer +read_arg_name_exp (scheme *sc) +{ + char *p = sc->strbuff; + gunichar c; + + while (TRUE) + { + c = inchar (sc); + if (c == EOF || p - sc->strbuff > sizeof (sc->strbuff) - 1) + { + *p = 0; + return sc->F; + } + else if (g_unichar_isspace (c)) + { + *p = 0; + return mk_arg_name (sc, sc->strbuff); + } + else + { + gint len; + + len = g_unichar_to_utf8 (c, p); + p += len; + } + } +} + /* check c is in chars */ static INLINE int is_one_of(char *s, gunichar c) { if (c==EOF) @@ -2097,6 +2145,8 @@ static int token(scheme *sc) { { return (TOK_EOF); } else { return (token(sc));} + } else if (c == ':') { + return (TOK_ARG); } else { backchar(sc,c); if(is_one_of(" tfodxb\\",c)) { @@ -4649,6 +4699,14 @@ static pointer opexe_5(scheme *sc, enum scheme_opcodes op) { } else { s_return(sc,x); } + case TOK_ARG: { + x = read_arg_name_exp(sc); + if (x == sc->F) { + Error_0 (sc, "Error reading argument slot name"); + } + setimmutable(x); + s_return(sc,x); + } case TOK_RPAREN: Error_1 (sc, "syntax error: unexpected right parenthesis", 0); case TOK_DOT: @@ -5097,6 +5155,7 @@ static struct scheme_interface vtbl ={ mk_vector, mk_foreign_func, mk_closure, + mk_arg_name, putstr, putcharacter, @@ -5145,6 +5204,8 @@ static struct scheme_interface vtbl ={ is_immutable, setimmutable, + is_arg_name, + scheme_load_file, scheme_load_string }; diff --git a/plug-ins/script-fu/libscriptfu/tinyscheme/scheme.h b/plug-ins/script-fu/libscriptfu/tinyscheme/scheme.h index 7d928ed1ec..b814ef36db 100644 --- a/plug-ins/script-fu/libscriptfu/tinyscheme/scheme.h +++ b/plug-ins/script-fu/libscriptfu/tinyscheme/scheme.h @@ -200,6 +200,7 @@ struct scheme_interface { pointer (*mk_vector)(scheme *sc, int len); pointer (*mk_foreign_func)(scheme *sc, foreign_func f); pointer (*mk_closure)(scheme *sc, pointer c, pointer e); + pointer (*mk_arg_name)(scheme *sc, const char *str); void (*putstr)(scheme *sc, const char *s); void (*putcharacter)(scheme *sc, gunichar c); @@ -250,6 +251,8 @@ struct scheme_interface { int (*is_immutable)(pointer p); void (*setimmutable)(pointer p); + int (*is_arg_name)(pointer p); + void (*load_file)(scheme *sc, FILE *fin); void (*load_string)(scheme *sc, const char *input); };