197 lines
8.0 KiB
C
197 lines
8.0 KiB
C
/* 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 <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "config.h"
|
|
#include <glib.h>
|
|
#include <libpika/pika.h>
|
|
|
|
#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-<something>")
|
|
* 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);
|
|
}
|