/* 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 "libscriptfu/script-fu-lib.h" #include "script-fu-interpreter.h" /* Implementation of the outer ScriptFuInterpreter. * This understands ScriptFu internals * i.e. uses libscriptfu shared with other ScriptFu plugins e.g. extension-script-fu. */ /* We don't need to load (into the interpreter) any .scm files handled by extension-script-fu. * Namely, the .scm in the PIKA installation /scripts or in the user local /scripts dirs. * * During startup, PIKA might call pika-script-fu-interpreter * to query new files such as /plug-ins/fu/fu.scm. * This is before extension-script-fu starts. * But all the .scm files handled by extension-script-fu are type TEMPORARY and not needed * for a /plug-ins/fu.scm to be queried. * The only Scheme executed during query are calls to script-fu-register. * Later, when a /plug-ins/fu.scm is run, it can call temporary PDB procedures * that extension-script-fu provides. * * When we call script_fu_init_embedded_interpreter(), * the passed paths should include the path to /scripts * because that is the location of scripts for initialization and compatibility * (script-fu.init, plug-in-compat.init and script-fu-compat.init, * which are really scheme files.) * * scrip-fu-interpreter always inits embedded interpreter(allow_register=TRUE) * In the "run" phase, you don't need script-fu-register to be defined, but its harmless. */ static GFile *script_fu_get_plugin_parent_path (const gchar *path_to_this_script); static void script_fu_free_path_list (GList **list); /* Return a list of PDB procedure names defined in all .scm files in * the parent dir of the given path, which is a filename of the one being queried. * * Each .scm file may contain many calls to script-fu-register, which defines a PDB procedure. * All .scm files in the parent dir are searched. * * This executable is named script-fu-interpreter * but no PDB procedure is named "script-fu-interpreter". * Instead, the interpreter registers PDB procs named from name strings * give in the in script-fu-register() calls in the interpreted scripts. * * Caller must free the list. */ GList * script_fu_interpreter_list_defined_proc_names (PikaPlugIn *plug_in, const gchar *path_to_this_script) { GList *name_list = NULL; /* list of strings */ GList *path_list = NULL; /* list of GFile */ /* path_list is /scripts dir etc. from which we will load compat and init scripts. * second argument TRUE means define script-fu-register into the interpreter. */ path_list = script_fu_search_path (); script_fu_init_embedded_interpreter (path_list, TRUE, PIKA_RUN_NONINTERACTIVE); script_fu_free_path_list (&path_list); /* Reuse path_list, now a list of one path, the parent dir of the queried script. */ path_list = g_list_append (path_list, script_fu_get_plugin_parent_path (path_to_this_script)); name_list = script_fu_find_scripts_list_proc_names (plug_in, path_list); script_fu_free_path_list (&path_list); /* Usually name_list is not NULL i.e. not empty. * But an .scm file that is not an actual PIKA plugin, or broken, may yield empty list. */ return name_list; } /* Create a PDB proc of type PLUGIN with the given name. * Unlike extension-script-fu, create proc of type PLUGIN. * * We are in "create procedure" phase of call from PIKA. * Create a PDB procedure that the script-fu-interpreter wraps. * * A PikaPDBProcedure has a run function, here script_fu_script_proc() * of this outer interpreter. * Sometime after the create, PIKA calls the run func, passing a name aka command. * In ScriptFu, the same name is used for the PDB proc and the Scheme function * which is the inner run func defined in the script. * script_fu_script_proc calls the TinyScheme interpreter to evaluate * the inner run func in the script. */ PikaProcedure * script_fu_interpreter_create_proc_at_path (PikaPlugIn *plug_in, const gchar *proc_name, const gchar *path_to_this_script ) { PikaProcedure *procedure = NULL; GList *path_list = NULL; /* list of GFile */ g_debug ("script_fu_interpreter_create_proc_at_path, name: %s", proc_name); /* Require proc_name is a suitable name for a PDB procedure eg "script-fu-test". * (Not tested for canonical name "script-fu-") * Require proc_name is a name that was queried earlier. * Require the proc_name was defined in some .scm file * in the same directory as the .scm file passed as argv[0]. * The name of the .scm file eg "/plug-ins/fu/fu.scm" * can be entirely different from proc_name. * * Otherwise, we simply won't find the proc_name defined in any .scm file, * and will fail gracefully, returning NULL. */ path_list = script_fu_search_path (); path_list = g_list_append (path_list, script_fu_get_plugin_parent_path (path_to_this_script)); /* path_list are the /scripts dir, for .init and compat.scm, plus the path to this. * second arg TRUE means define script-fu-register so it is effective. */ script_fu_init_embedded_interpreter (path_list, TRUE, PIKA_RUN_NONINTERACTIVE); /* Reuse path_list, now a list of only the path to this script. */ script_fu_free_path_list (&path_list); path_list = g_list_append (path_list, script_fu_get_plugin_parent_path (path_to_this_script)); procedure = script_fu_find_scripts_create_PDB_proc_plugin (plug_in, path_list, proc_name); script_fu_free_path_list (&path_list); /* When procedure is not NULL, assert: * some .scm was evaluated. * the script defined many PDB procedures locally, i.e. in script-tree * we created a single PDB procedure (but not put it in the PIKA PDB) * * Ensure procedure is-a PikaProcedure or NULL. * PIKA is the caller and will put non-NULL procedure in the PDB. */ return procedure; } /* Return GFile of the parent directory of this plugin, whose filename is given. * * Caller must free the GFile. */ static GFile * script_fu_get_plugin_parent_path (const gchar *path_to_this_script) { GFile *path = NULL; GFile *parent_path = NULL; /* A libpika PikaPlugin does not know its path, * but its path was passed in argv to this interpreter. * The path is to a file being queried e.g. "~/.config/PIKA/2.99/plug-ins/fu/fu.scm" */ g_debug ("path to this plugin %s", path_to_this_script); path = g_file_new_for_path (path_to_this_script); parent_path = g_file_get_parent (path); g_object_unref (path); return parent_path; } /* Free a list of paths at the given handle. * Ensures that the pointer to the list is NULL, prevents "dangling." * g_list_free_full alone does not do that. */ static void script_fu_free_path_list (GList **list) { /* !!! g_steal_pointer takes a handle. */ g_list_free_full (g_steal_pointer (list), g_object_unref); }