312 lines
9.4 KiB
C
312 lines
9.4 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 <string.h>
|
||
|
#include <stdlib.h>
|
||
|
|
||
|
#include <gdk-pixbuf/gdk-pixbuf.h>
|
||
|
#include <gegl.h>
|
||
|
|
||
|
#include "libpikabase/pikabase.h"
|
||
|
|
||
|
#include "core-types.h"
|
||
|
|
||
|
#include "pika.h"
|
||
|
#include "pika-batch.h"
|
||
|
#include "pikaparamspecs.h"
|
||
|
|
||
|
#include "pdb/pikapdb.h"
|
||
|
#include "pdb/pikaprocedure.h"
|
||
|
|
||
|
#include "plug-in/pikapluginmanager.h"
|
||
|
#include "plug-in/pikapluginprocedure.h"
|
||
|
|
||
|
#include "pika-intl.h"
|
||
|
|
||
|
|
||
|
static void pika_batch_exit_after_callback (Pika *pika) G_GNUC_NORETURN;
|
||
|
|
||
|
static gint pika_batch_run_cmd (Pika *pika,
|
||
|
const gchar *proc_name,
|
||
|
PikaProcedure *procedure,
|
||
|
PikaRunMode run_mode,
|
||
|
const gchar *cmd);
|
||
|
|
||
|
|
||
|
gint
|
||
|
pika_batch_run (Pika *pika,
|
||
|
const gchar *batch_interpreter,
|
||
|
const gchar **batch_commands)
|
||
|
{
|
||
|
PikaProcedure *eval_proc;
|
||
|
GSList *batch_procedures;
|
||
|
GSList *iter;
|
||
|
gulong exit_id;
|
||
|
gint retval = EXIT_SUCCESS;
|
||
|
|
||
|
if (! batch_commands || ! batch_commands[0])
|
||
|
return retval;
|
||
|
|
||
|
batch_procedures = pika_plug_in_manager_get_batch_procedures (pika->plug_in_manager);
|
||
|
if (g_slist_length (batch_procedures) == 0)
|
||
|
{
|
||
|
g_message (_("No batch interpreters are available. "
|
||
|
"Batch mode disabled."));
|
||
|
retval = 69; /* EX_UNAVAILABLE - service unavailable (sysexits.h) */
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
if (! batch_interpreter)
|
||
|
{
|
||
|
batch_interpreter = g_getenv ("PIKA_BATCH_INTERPRETER");
|
||
|
|
||
|
if (! batch_interpreter)
|
||
|
{
|
||
|
if (g_slist_length (batch_procedures) == 1)
|
||
|
{
|
||
|
batch_interpreter = pika_object_get_name (batch_procedures->data);;
|
||
|
|
||
|
if (pika->be_verbose)
|
||
|
g_printerr (_("No batch interpreter specified, using "
|
||
|
"'%s'.\n"), batch_interpreter);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
retval = 64; /* EX_USAGE - command line usage error */
|
||
|
g_print ("%s\n\n%s\n",
|
||
|
_("No batch interpreter specified."),
|
||
|
_("Available interpreters are:"));
|
||
|
|
||
|
for (iter = batch_procedures; iter; iter = iter->next)
|
||
|
{
|
||
|
PikaPlugInProcedure *proc = iter->data;
|
||
|
gchar *locale_name;
|
||
|
|
||
|
locale_name = g_locale_from_utf8 (proc->batch_interpreter_name,
|
||
|
-1, NULL, NULL, NULL);
|
||
|
|
||
|
g_print ("- %s (%s)\n",
|
||
|
pika_object_get_name (iter->data),
|
||
|
locale_name ? locale_name : proc->batch_interpreter_name);
|
||
|
|
||
|
g_free (locale_name);
|
||
|
}
|
||
|
|
||
|
g_print ("\n%s\n",
|
||
|
_("Specify one of these interpreters as --batch-interpreter option."));
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
for (iter = batch_procedures; iter; iter = iter->next)
|
||
|
{
|
||
|
if (g_strcmp0 (pika_object_get_name (iter->data),
|
||
|
batch_interpreter) == 0)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if (iter == NULL)
|
||
|
{
|
||
|
retval = 69; /* EX_UNAVAILABLE - service unavailable (sysexits.h) */
|
||
|
g_print (_("The procedure '%s' is not a valid batch interpreter."),
|
||
|
batch_interpreter);
|
||
|
g_print ("\n%s\n\n%s\n",
|
||
|
_("Batch mode disabled."),
|
||
|
_("Available interpreters are:"));
|
||
|
|
||
|
for (iter = batch_procedures; iter; iter = iter->next)
|
||
|
{
|
||
|
PikaPlugInProcedure *proc = iter->data;
|
||
|
gchar *locale_name;
|
||
|
|
||
|
locale_name = g_locale_from_utf8 (proc->batch_interpreter_name,
|
||
|
-1, NULL, NULL, NULL);
|
||
|
|
||
|
g_print ("- %s (%s)\n",
|
||
|
pika_object_get_name (iter->data),
|
||
|
locale_name ? locale_name : proc->batch_interpreter_name);
|
||
|
|
||
|
g_free (locale_name);
|
||
|
}
|
||
|
|
||
|
g_print ("\n%s\n",
|
||
|
_("Specify one of these interpreters as --batch-interpreter option."));
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
exit_id = g_signal_connect_after (pika, "exit",
|
||
|
G_CALLBACK (pika_batch_exit_after_callback),
|
||
|
NULL);
|
||
|
|
||
|
eval_proc = pika_pdb_lookup_procedure (pika->pdb, batch_interpreter);
|
||
|
if (eval_proc)
|
||
|
{
|
||
|
gint i;
|
||
|
|
||
|
retval = EXIT_SUCCESS;
|
||
|
for (i = 0; batch_commands[i]; i++)
|
||
|
{
|
||
|
retval = pika_batch_run_cmd (pika, batch_interpreter, eval_proc,
|
||
|
PIKA_RUN_NONINTERACTIVE, batch_commands[i]);
|
||
|
|
||
|
/* In case of several commands, stop and return last
|
||
|
* failed command.
|
||
|
*/
|
||
|
if (retval != EXIT_SUCCESS)
|
||
|
{
|
||
|
g_printerr ("Stopping at failing batch command [%d]: %s\n",
|
||
|
i, batch_commands[i]);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
retval = 69; /* EX_UNAVAILABLE - service unavailable (sysexits.h) */
|
||
|
g_message (_("The batch interpreter '%s' is not available. "
|
||
|
"Batch mode disabled."), batch_interpreter);
|
||
|
}
|
||
|
|
||
|
g_signal_handler_disconnect (pika, exit_id);
|
||
|
|
||
|
return retval;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* The purpose of this handler is to exit PIKA cleanly when the batch
|
||
|
* procedure calls the pika-exit procedure. Without this callback, the
|
||
|
* message "batch command experienced an execution error" would appear
|
||
|
* and pika would hang forever.
|
||
|
*/
|
||
|
static void
|
||
|
pika_batch_exit_after_callback (Pika *pika)
|
||
|
{
|
||
|
if (pika->be_verbose)
|
||
|
g_print ("EXIT: %s\n", G_STRFUNC);
|
||
|
|
||
|
gegl_exit ();
|
||
|
|
||
|
exit (EXIT_SUCCESS);
|
||
|
}
|
||
|
|
||
|
static inline gboolean
|
||
|
PIKA_IS_PARAM_SPEC_RUN_MODE (GParamSpec *pspec)
|
||
|
{
|
||
|
return (G_IS_PARAM_SPEC_ENUM (pspec) &&
|
||
|
pspec->value_type == PIKA_TYPE_RUN_MODE);
|
||
|
}
|
||
|
|
||
|
static gint
|
||
|
pika_batch_run_cmd (Pika *pika,
|
||
|
const gchar *proc_name,
|
||
|
PikaProcedure *procedure,
|
||
|
PikaRunMode run_mode,
|
||
|
const gchar *cmd)
|
||
|
{
|
||
|
PikaValueArray *args;
|
||
|
PikaValueArray *return_vals;
|
||
|
GError *error = NULL;
|
||
|
gint i = 0;
|
||
|
gint retval = EXIT_SUCCESS;
|
||
|
|
||
|
args = pika_procedure_get_arguments (procedure);
|
||
|
|
||
|
if (procedure->num_args > i &&
|
||
|
PIKA_IS_PARAM_SPEC_RUN_MODE (procedure->args[i]))
|
||
|
{
|
||
|
g_value_set_enum (pika_value_array_index (args, i++), run_mode);
|
||
|
}
|
||
|
|
||
|
if (procedure->num_args > i &&
|
||
|
G_IS_PARAM_SPEC_STRING (procedure->args[i]))
|
||
|
{
|
||
|
g_value_set_static_string (pika_value_array_index (args, i++), cmd);
|
||
|
}
|
||
|
|
||
|
return_vals =
|
||
|
pika_pdb_execute_procedure_by_name_args (pika->pdb,
|
||
|
pika_get_user_context (pika),
|
||
|
NULL, &error,
|
||
|
proc_name, args);
|
||
|
|
||
|
switch (g_value_get_enum (pika_value_array_index (return_vals, 0)))
|
||
|
{
|
||
|
case PIKA_PDB_EXECUTION_ERROR:
|
||
|
/* Using Linux's standard exit code as found in /usr/include/sysexits.h
|
||
|
* Since other platforms may not have the header, I simply
|
||
|
* hardcode the few cases.
|
||
|
*/
|
||
|
retval = 70; /* EX_SOFTWARE - internal software error */
|
||
|
if (error)
|
||
|
{
|
||
|
g_printerr ("batch command experienced an execution error:\n"
|
||
|
"%s\n", error->message);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
g_printerr ("batch command experienced an execution error\n");
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case PIKA_PDB_CALLING_ERROR:
|
||
|
retval = 64; /* EX_USAGE - command line usage error */
|
||
|
if (error)
|
||
|
{
|
||
|
g_printerr ("batch command experienced a calling error:\n"
|
||
|
"%s\n", error->message);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
g_printerr ("batch command experienced a calling error\n");
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
case PIKA_PDB_SUCCESS:
|
||
|
retval = EXIT_SUCCESS;
|
||
|
g_printerr ("batch command executed successfully\n");
|
||
|
break;
|
||
|
|
||
|
case PIKA_PDB_CANCEL:
|
||
|
/* Not in sysexits.h, but usually used for 'Script terminated by
|
||
|
* Control-C'. See: https://tldp.org/LDP/abs/html/exitcodes.html
|
||
|
*/
|
||
|
retval = 130;
|
||
|
break;
|
||
|
|
||
|
case PIKA_PDB_PASS_THROUGH:
|
||
|
retval = EXIT_FAILURE; /* Catchall. */
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pika_value_array_unref (return_vals);
|
||
|
pika_value_array_unref (args);
|
||
|
|
||
|
if (error)
|
||
|
g_error_free (error);
|
||
|
|
||
|
return retval;
|
||
|
}
|