/* 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 Spencer Kimball and Peter Mattis * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 3 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see . */ #include "config.h" #include #include #include "tinyscheme/scheme-private.h" #include "script-fu-errors.h" /* Enable logging by "export G_MESSAGES_DEBUG=scriptfu" in the env */ /* Used by debug_in_arg(). * FUTURE: conditional compile out when debug not enabled. */ /* These three #defines are from Tinyscheme (tinyscheme/scheme.c) */ #define T_MASKTYPE 31 #define typeflag(p) ((p)->_flag) #define type(p) (typeflag(p)&T_MASKTYPE) static const char *ts_types[] = { "T_NONE", "T_STRING", "T_NUMBER", "T_SYMBOL", "T_PROC", "T_PAIR", "T_CLOSURE", "T_CONTINUATION", "T_FOREIGN", "T_CHARACTER", "T_PORT", "T_VECTOR", "T_MACRO", "T_PROMISE", "T_ENVIRONMENT","T_ARRAY" }; /* * Called on event: language error in the author's script. * Logs the error and returns a foreign_error. * Not all foreign_error are errors in script, some are scriptfu implementation * errors or implementation errors in called procedures. * * This should specialize foreign_error by emphasizing script error. * For now, it just specializes by also logging. * foreign error does not do logging, since the caller usually logs. * Returns a value which the caller must return to its caller. */ pointer script_error (scheme *sc, const gchar *error_message, const pointer a) { /* Logs to domain "scriptfu" since G_LOG_DOMAIN is set to that. */ g_debug ("%s", error_message); /* Return message that will cross the PikaProtocol in a GError in return values * to be displayed to GUI user. */ /* FUTURE prefix with "ScriptFu: in script," */ return foreign_error (sc, error_message, a); } /* Specialized calls to script_error. */ /* Arg has wrong type. */ pointer script_type_error (scheme *sc, const gchar *expected_type, const guint arg_index, const gchar *proc_name) { gchar error_message[1024]; g_snprintf (error_message, sizeof (error_message), "in script, expected type: %s for argument %d to %s ", expected_type, arg_index+1, proc_name ); return script_error (sc, error_message, 0); } /* Arg is container (list or vector) having an element of wrong type. */ pointer script_type_error_in_container (scheme *sc, const gchar *expected_type, const guint arg_index, const guint element_index, const gchar *proc_name, const pointer container) { gchar error_message[1024]; /* convert zero based indices to ordinals */ g_snprintf (error_message, sizeof (error_message), "in script, expected type: %s for element %d of argument %d to %s ", expected_type, element_index+1, arg_index+1, proc_name ); /* pass container to foreign_error */ return script_error (sc, error_message, container); } /* Arg is vector of wrong length. !!! Arg is not a list. */ pointer script_length_error_in_vector (scheme *sc, const guint arg_index, const gchar *proc_name, const guint expected_length, const pointer vector) { gchar error_message[1024]; /* vector_length returns signed long (???) but expected_length is unsigned */ g_snprintf (error_message, sizeof (error_message), "in script, vector (argument %d) for function %s has " "length %ld but expected length %u", arg_index+1, proc_name, sc->vptr->vector_length (vector), expected_length); /* not pass vector to foreign_error */ return script_error (sc, error_message, 0); } /* Thin wrapper around foreign_error. * Does logging. * Names a kind of error: in ScriptFu code, or in external code. * Same as script_error, but FUTURE distinguish the message with a prefix. */ pointer implementation_error (scheme *sc, const gchar *error_message, const pointer a) { g_debug ("%s", error_message); return foreign_error (sc, error_message, a); } /* Debug helpers. * Enabled by G_MESSAGES_DEBUG=scriptfu env var. * FUTURE: For performance, return early if not debugging. * Or conditionally compile. */ void debug_vector (scheme *sc, const pointer vector, const char *format) { glong count = sc->vptr->vector_length (vector); g_debug ("vector has %ld elements", count); if (count > 0) { for (int j = 0; j < count; ++j) { if (strcmp (format, "%f")==0) /* real i.e. float */ g_debug (format, sc->vptr->rvalue ( sc->vptr->vector_elem (vector, j) )); else /* integer */ g_debug (format, sc->vptr->ivalue ( sc->vptr->vector_elem (vector, j) )); /* FUTURE vectors of strings or other formats? */ } } } /* TinyScheme has no polymorphic length(), elem() methods on containers. * Must walk a list with car/cdr. * * Unlike vectors, lists have a guint length, not gulong * * !!! Only for lists of strings. */ void debug_list (scheme *sc, pointer list, const char *format, const guint num_elements) { g_return_if_fail (num_elements == sc->vptr->list_length (sc, list)); g_debug ("list has %d elements", num_elements); if (num_elements > 0) { for (int j = 0; j < num_elements; ++j) { pointer v_element = sc->vptr->pair_car (list); g_debug (format, sc->vptr->string_value ( v_element )); list = sc->vptr->pair_cdr (list); } } } /* Understands the adapted type system: Scheme interpreter type system. * Log types of formal and actual args. * Scheme type names, and enum of actual type. */ void debug_in_arg (scheme *sc, const pointer a, const guint arg_index, const gchar *type_name ) { g_debug ("param %d - expecting type %s", arg_index + 1, type_name ); g_debug ("actual arg is type %s (%d)", ts_types[ type(sc->vptr->pair_car (a)) ], type(sc->vptr->pair_car (a))); } /* Log GValue: its value and its GType * FUTURE: for Pika types, pika_item_get_id (PIKA_ITEM ())); */ void debug_gvalue (const GValue *value) { char *contents_str; const char *type_name; type_name = G_VALUE_TYPE_NAME(value); contents_str = g_strdup_value_contents (value); g_debug ("Value: %s Type: %s", contents_str, type_name); g_free (contents_str); }